Updated to latest SVGPathCommander

This commit is contained in:
thednp 2021-12-27 17:33:05 +02:00
parent 5c8b75f15b
commit 3835b6e95c
15 changed files with 1061 additions and 614 deletions

View file

@ -1,5 +1,5 @@
/*!
* KUTE.js Base v2.2.0 (http://thednp.github.io/kute.js)
* KUTE.js Base v2.2.2 (http://thednp.github.io/kute.js)
* Copyright 2015-2021 © thednp
* Licensed under MIT (https://github.com/thednp/kute.js/blob/master/LICENSE)
*/
@ -876,7 +876,7 @@
return new TweenConstructor(selector(element), startObject, endObject, options);
}
var version = "2.2.0";
var version = "2.2.2";
// @ts-ignore

File diff suppressed because one or more lines are too long

View file

@ -1,5 +1,5 @@
/*!
* KUTE.js Extra v2.2.0 (http://thednp.github.io/kute.js)
* KUTE.js Extra v2.2.2 (http://thednp.github.io/kute.js)
* Copyright 2015-2021 © thednp
* Licensed under MIT (https://github.com/thednp/kute.js/blob/master/LICENSE)
*/
@ -2935,6 +2935,7 @@
/**
* Segment params length
* @type {Record<string, number>}
*/
var paramsCount = {
a: 7, c: 6, h: 1, l: 2, m: 2, r: 4, q: 4, s: 4, t: 2, v: 1, z: 0,
@ -3198,7 +3199,6 @@
var pathValue = path.pathValue;
var index = path.index;
var cmdCode = pathValue.charCodeAt(index);
// @ts-ignore
var reqParams = paramsCount[pathValue[index].toLowerCase()];
path.segmentStart = index;
@ -3262,7 +3262,8 @@
}
/**
* The `PathParser` used by the parser.
* The `PathParser` is used by the `parsePathString` static method
* to generate a `pathArray`.
*
* @param {string} pathString
*/
@ -3307,12 +3308,13 @@
* @returns {SVGPathCommander.pathArray} the resulted `pathArray`
*/
function parsePathString(pathInput) {
if (Array.isArray(pathInput) && isPathArray(pathInput)) {
if (isPathArray(pathInput)) {
// @ts-ignore -- isPathArray also checks if it's an `Array`
return clonePath(pathInput);
}
// @ts-ignore
var path = new PathParser(pathInput); // TS expects string
// @ts-ignore -- pathInput is now string
var path = new PathParser(pathInput);
skipSpaces(path);
@ -3340,11 +3342,12 @@
* Iterates an array to check if it's a `pathArray`
* with all absolute values.
*
* @param {SVGPathCommander.pathArray} path the `pathArray` to be checked
* @param {string | SVGPathCommander.pathArray} path the `pathArray` to be checked
* @returns {boolean} iteration result
*/
function isAbsoluteArray(path) {
return isPathArray(path)
// @ts-ignore -- `isPathArray` also checks if it's `Array`
&& path.every(function (x) { return x[0] === x[0].toUpperCase(); });
}
@ -3352,11 +3355,12 @@
* Parses a path string value or object and returns an array
* of segments, all converted to absolute values.
*
* @param {SVGPathCommander.pathArray | string} pathInput the path string | object
* @param {string | SVGPathCommander.pathArray} pathInput the path string | object
* @returns {SVGPathCommander.absoluteArray} the resulted `pathArray` with absolute values
*/
function pathToAbsolute(pathInput) {
if (Array.isArray(pathInput) && isAbsoluteArray(pathInput)) {
if (isAbsoluteArray(pathInput)) {
// @ts-ignore -- `isAbsoluteArray` checks if it's `pathArray`
return clonePath(pathInput);
}
@ -3555,10 +3559,11 @@
* with all segments are in non-shorthand notation
* with absolute values.
*
* @param {SVGPathCommander.pathArray} path the `pathArray` to be checked
* @param {string | SVGPathCommander.pathArray} path the `pathArray` to be checked
* @returns {boolean} iteration result
*/
function isNormalizedArray(path) {
// @ts-ignore -- `isAbsoluteArray` also checks if it's `Array`
return isAbsoluteArray(path) && path.every(function (seg) { return 'ACLMQZ'.includes(seg[0]); });
}
@ -3574,16 +3579,19 @@
* * convert segments to absolute values
* * convert shorthand path commands to their non-shorthand notation
*
* @param {SVGPathCommander.pathArray} pathInput the string to be parsed or 'pathArray'
* @param {string | SVGPathCommander.pathArray} pathInput the string to be parsed or 'pathArray'
* @returns {SVGPathCommander.normalArray} the normalized `pathArray`
*/
function normalizePath(pathInput) {
var assign;
if (isNormalizedArray(pathInput)) {
// @ts-ignore -- `isNormalizedArray` checks if it's `pathArray`
return clonePath(pathInput);
}
/** @type {SVGPathCommander.normalArray} */
// @ts-ignore -- `absoluteArray` will become a `normalArray`
var path = pathToAbsolute(pathInput);
var params = Object.assign({}, paramsParser);
var allPathCommands = [];
@ -3611,7 +3619,6 @@
params.y2 = +(segment[seglen - 3]) || params.y1;
}
// @ts-ignore -- a `normalArray` is absolutely an `absoluteArray`
return path;
}
@ -3642,7 +3649,7 @@
var y = ref$1[1];
if (isClosed && mx === x && my === y) {
// @ts-ignore -- `pathSegment[]` is a `pathArray`
// @ts-ignore -- `pathSegment[]` is quite a `pathArray`
return pathArray.slice(0, -1);
}
return pathArray;
@ -3652,10 +3659,11 @@
* Iterates an array to check if it's a `pathArray`
* with all C (cubic bezier) segments.
*
* @param {SVGPathCommander.pathArray} path the `Array` to be checked
* @param {string | SVGPathCommander.pathArray} path the `Array` to be checked
* @returns {boolean} iteration result
*/
function isCurveArray(path) {
// @ts-ignore -- `isPathArray` also checks if it's `Array`
return isPathArray(path) && path.every(function (seg) { return 'MC'.includes(seg[0]); });
}
@ -3811,35 +3819,6 @@
x2, y2 ];
}
/**
* Returns the {x,y} coordinates of a point at a
* given length of a cubic-bezier segment.
*
* @param {number} p1x the starting point X
* @param {number} p1y the starting point Y
* @param {number} c1x the first control point X
* @param {number} c1y the first control point Y
* @param {number} c2x the second control point X
* @param {number} c2y the second control point Y
* @param {number} p2x the ending point X
* @param {number} p2y the ending point Y
* @param {number} t a [0-1] ratio
* @returns {{x: number, y: number}} the requested {x,y} coordinates
*/
function getPointAtSegLength(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, t) {
var t1 = 1 - t;
return {
x: (Math.pow( t1, 3 )) * p1x
+ t1 * t1 * 3 * t * c1x
+ t1 * 3 * t * t * c2x
+ (Math.pow( t, 3 )) * p2x,
y: (Math.pow( t1, 3 )) * p1y
+ t1 * t1 * 3 * t * c1y
+ t1 * 3 * t * t * c2y
+ (Math.pow( t, 3 )) * p2y,
};
}
/**
* Returns the coordinates of a specified distance
* ratio between two points.
@ -3856,6 +3835,51 @@
return [ax + (bx - ax) * t, ay + (by - ay) * t];
}
/**
* Returns the square root of the distance
* between two given points.
*
* @param {[number, number]} a the first point coordinates
* @param {[number, number]} b the second point coordinates
* @returns {number} the distance value
*/
function distanceSquareRoot(a, b) {
return Math.sqrt(
(a[0] - b[0]) * (a[0] - b[0])
+ (a[1] - b[1]) * (a[1] - b[1])
);
}
/**
* Returns the length of a line (L,V,H,Z) segment,
* or a point at a given length.
*
* @param {number} x1 the starting point X
* @param {number} y1 the starting point Y
* @param {number} x2 the ending point X
* @param {number} y2 the ending point Y
* @param {number=} distance the distance to point
* @returns {{x: number, y: number} | number} the segment length or point
*/
function segmentLineFactory(x1, y1, x2, y2, distance) {
var length = distanceSquareRoot([x1, y1], [x2, y2]);
var margin = 0.001;
if (typeof distance === 'number') {
if (distance < margin) {
return { x: x1, y: y1 };
}
if (distance > length + margin) {
return { x: x2, y: y2 };
}
var ref = midPoint([x1, y1], [x2, y2], distance / length);
var x = ref[0];
var y = ref[1];
return { x: x, y: y };
}
return length;
}
/**
* Converts an L (line-to) segment to C (cubic-bezier).
*
@ -3876,15 +3900,14 @@
var p4 = midPoint(p2, p3, t);
var p5 = midPoint(p3, p4, t);
var p6 = midPoint(p4, p5, t);
// const cp1 = getPointAtSegLength.apply(0, p0.concat(p2, p4, p6, t));
var seg1 = p0.concat( p2, p4, p6, [t]);
// @ts-ignore
var cp1 = getPointAtSegLength.apply(void 0, seg1);
// const cp2 = getPointAtSegLength.apply(0, p6.concat(p5, p3, p1, 0));
var cp1 = segmentLineFactory.apply(void 0, seg1);
var seg2 = p6.concat( p5, p3, p1, [0]);
// @ts-ignore
var cp2 = getPointAtSegLength.apply(void 0, seg2);
var cp2 = segmentLineFactory.apply(void 0, seg2);
// @ts-ignore
return [cp1.x, cp1.y, cp2.x, cp2.y, x2, y2];
}
@ -3944,13 +3967,14 @@
* In addition, un-necessary `Z` segment is removed if previous segment
* extends to the `M` segment.
*
* @param {SVGPathCommander.pathArray} pathInput the string to be parsed or 'pathArray'
* @param {string | SVGPathCommander.pathArray} pathInput the string to be parsed or 'pathArray'
* @returns {SVGPathCommander.curveArray} the resulted `pathArray` converted to cubic-bezier
*/
function pathToCurve(pathInput) {
var assign;
if (isCurveArray(pathInput)) {
// @ts-ignore -- `isCurveArray` checks if it's `pathArray`
return clonePath(pathInput);
}
@ -4048,38 +4072,38 @@
}
/**
* Returns the area of a single segment shape.
* Returns the area of a single cubic-bezier segment.
*
* http://objectmix.com/graphics/133553-area-closed-bezier-curve.html
*
* @param {number} x0 the starting point X
* @param {number} y0 the starting point Y
* @param {number} x1 the first control point X
* @param {number} y1 the first control point Y
* @param {number} x2 the second control point X
* @param {number} y2 the second control point Y
* @param {number} x3 the ending point X
* @param {number} y3 the ending point Y
* @param {number} x1 the starting point X
* @param {number} y1 the starting point Y
* @param {number} c1x the first control point X
* @param {number} c1y the first control point Y
* @param {number} c2x the second control point X
* @param {number} c2y the second control point Y
* @param {number} x2 the ending point X
* @param {number} y2 the ending point Y
* @returns {number} the area of the cubic-bezier segment
*/
function getCubicSegArea(x0, y0, x1, y1, x2, y2, x3, y3) {
return (3 * ((y3 - y0) * (x1 + x2) - (x3 - x0) * (y1 + y2)
+ (y1 * (x0 - x2)) - (x1 * (y0 - y2))
+ (y3 * (x2 + x0 / 3)) - (x3 * (y2 + y0 / 3)))) / 20;
function getCubicSegArea(x1, y1, c1x, c1y, c2x, c2y, x2, y2) {
return (3 * ((y2 - y1) * (c1x + c2x) - (x2 - x1) * (c1y + c2y)
+ (c1y * (x1 - c2x)) - (c1x * (y1 - c2y))
+ (y2 * (c2x + x1 / 3)) - (x2 * (c2y + y1 / 3)))) / 20;
}
/**
* Returns the area of a shape.
* @author Jürg Lehni & Jonathan Puckey
*
* => https://github.com/paperjs/paper.js/blob/develop/src/path/Path.js
* @see https://github.com/paperjs/paper.js/blob/develop/src/path/Path.js
*
* @param {SVGPathCommander.pathArray} path the shape `pathArray`
* @returns {number} the length of the cubic-bezier segment
*/
function getPathArea(path) {
var x = 0; var y = 0;
var len = 0;
var x = 0; var y = 0; var len = 0;
return pathToCurve(path).map(function (seg) {
var assign, assign$1;
@ -4090,8 +4114,8 @@
default:
// @ts-ignore -- the utility will have proper amount of params
len = getCubicSegArea.apply(void 0, [ x, y ].concat( seg.slice(1) ));
(assign$1 = seg.slice(-2).map(Number), x = assign$1[0], y = assign$1[1]);
// @ts-ignore -- the segment always has numbers
(assign$1 = seg.slice(-2), x = assign$1[0], y = assign$1[1]);
return len;
}
}).reduce(function (a, b) { return a + b; }, 0);
@ -4154,71 +4178,86 @@
}
/**
* @param {number} p1
* @param {number} p2
* @param {number} p3
* @param {number} p4
* @param {number} t a [0-1] ratio
* @returns {number}
*/
function base3(p1, p2, p3, p4, t) {
var t1 = -3 * p1 + 9 * p2 - 9 * p3 + 3 * p4;
var t2 = t * t1 + 6 * p1 - 12 * p2 + 6 * p3;
return t * t2 - 3 * p1 + 3 * p2;
}
/**
* Returns the C (cubic-bezier) segment length.
* Returns a point at a given length of a C (cubic-bezier) segment.
*
* @param {number} x1 the starting point X
* @param {number} y1 the starting point Y
* @param {number} x2 the first control point X
* @param {number} y2 the first control point Y
* @param {number} x3 the second control point X
* @param {number} y3 the second control point Y
* @param {number} x4 the ending point X
* @param {number} y4 the ending point Y
* @param {number} z a [0-1] ratio
* @returns {number} the cubic-bezier segment length
* @param {number} c1x the first control point X
* @param {number} c1y the first control point Y
* @param {number} c2x the second control point X
* @param {number} c2y the second control point Y
* @param {number} x2 the ending point X
* @param {number} y2 the ending point Y
* @param {number} t a [0-1] ratio
* @returns {{x: number, y: number}} the cubic-bezier segment length
*/
function getSegCubicLength(x1, y1, x2, y2, x3, y3, x4, y4, z) {
var Z = z;
if (z === null || Number.isNaN(+z)) { Z = 1; }
// Z = Z > 1 ? 1 : Z < 0 ? 0 : Z;
if (Z > 1) { Z = 1; }
if (Z < 0) { Z = 0; }
var z2 = Z / 2; var ct = 0; var xbase = 0; var ybase = 0; var sum = 0;
var Tvalues = [-0.1252, 0.1252, -0.3678, 0.3678,
-0.5873, 0.5873, -0.7699, 0.7699,
-0.9041, 0.9041, -0.9816, 0.9816];
var Cvalues = [0.2491, 0.2491, 0.2335, 0.2335,
0.2032, 0.2032, 0.1601, 0.1601,
0.1069, 0.1069, 0.0472, 0.0472];
Tvalues.forEach(function (T, i) {
ct = z2 * T + z2;
xbase = base3(x1, x2, x3, x4, ct);
ybase = base3(y1, y2, y3, y4, ct);
sum += Cvalues[i] * Math.sqrt(xbase * xbase + ybase * ybase);
});
return z2 * sum;
function getPointAtCubicSegmentLength(x1, y1, c1x, c1y, c2x, c2y, x2, y2, t) {
var t1 = 1 - t;
return {
x: (Math.pow( t1, 3 )) * x1
+ 3 * (Math.pow( t1, 2 )) * t * c1x
+ 3 * t1 * (Math.pow( t, 2 )) * c2x
+ (Math.pow( t, 3 )) * x2,
y: (Math.pow( t1, 3 )) * y1
+ 3 * (Math.pow( t1, 2 )) * t * c1y
+ 3 * t1 * (Math.pow( t, 2 )) * c2y
+ (Math.pow( t, 3 )) * y2,
};
}
/**
* Returns the square root of the distance
* between two given points.
* Returns the length of a C (cubic-bezier) segment,
* or an {x,y} point at a given length.
*
* @param {[number, number]} a the first point coordinates
* @param {[number, number]} b the second point coordinates
* @returns {number} the distance value
* @param {number} x1 the starting point X
* @param {number} y1 the starting point Y
* @param {number} c1x the first control point X
* @param {number} c1y the first control point Y
* @param {number} c2x the second control point X
* @param {number} c2y the second control point Y
* @param {number} x2 the ending point X
* @param {number} y2 the ending point Y
* @param {number=} distance the point distance
* @returns {{x: number, y: number} | number} the segment length or point
*/
function distanceSquareRoot(a, b) {
return Math.sqrt(
(a[0] - b[0]) * (a[0] - b[0])
+ (a[1] - b[1]) * (a[1] - b[1])
);
function segmentCubicFactory(x1, y1, c1x, c1y, c2x, c2y, x2, y2, distance) {
var assign;
var x = x1; var y = y1;
var lengthMargin = 0.001;
var totalLength = 0;
var prev = [x1, y1, totalLength];
/** @type {[number, number]} */
var cur = [x1, y1];
var t = 0;
if (typeof distance === 'number' && distance < lengthMargin) {
return { x: x, y: y };
}
var n = 100;
for (var j = 0; j <= n; j += 1) {
t = j / n;
((assign = getPointAtCubicSegmentLength(x1, y1, c1x, c1y, c2x, c2y, x2, y2, t), x = assign.x, y = assign.y));
totalLength += distanceSquareRoot(cur, [x, y]);
cur = [x, y];
if (typeof distance === 'number' && totalLength >= distance) {
var dv = (totalLength - distance) / (totalLength - prev[2]);
return {
x: cur[0] * (1 - dv) + prev[0] * dv,
y: cur[1] * (1 - dv) + prev[1] * dv,
};
}
prev = [x, y, totalLength];
}
if (typeof distance === 'number' && distance >= totalLength) {
return { x: x2, y: y2 };
}
return totalLength;
}
// Component Functions
@ -4255,7 +4294,7 @@
return pathToCurve(splitPath(source)[0])
.map(function (segment, i, pathArray) {
var segmentData = i && pathArray[i - 1].slice(-2).concat( segment.slice(1));
var curveLength = i ? getSegCubicLength.apply(void 0, segmentData) : 0;
var curveLength = i ? segmentCubicFactory.apply(void 0, segmentData) : 0;
var subsegs;
if (i) {
@ -4456,6 +4495,7 @@
reverseCurve: reverseCurve,
clonePath: clonePath,
getDrawDirection: getDrawDirection,
segmentCubicFactory: segmentCubicFactory,
splitCubic: splitCubic,
splitPath: splitPath,
fixPath: fixPath,
@ -5649,7 +5689,7 @@
Components[component] = new AnimationDevelopment(compOps);
});
var version = "2.2.0";
var version = "2.2.2";
// @ts-ignore

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -419,7 +419,8 @@ var tween2 = KUTE.to('#triangle', { path: '#square' }).start();
<!-- Placed at the end of the document so the pages load faster -->
<script src="./src/polyfill.min.js"></script>
<script src="./src/kute.min.js"></script>
<!-- <script src="./src/kute.min.js"></script> -->
<script src="../dist/kute.js"></script>
<script src="./assets/js/prism.js"></script>
<script src="./assets/js/scripts.js"></script>
<script src="./assets/js/svgMorph.js"></script>

652
dist/kute.esm.js vendored
View file

@ -1,5 +1,5 @@
/*!
* KUTE.js Standard v2.2.0 (http://thednp.github.io/kute.js)
* KUTE.js Standard v2.2.2 (http://thednp.github.io/kute.js)
* Copyright 2015-2021 © thednp
* Licensed under MIT (https://github.com/thednp/kute.js/blob/master/LICENSE)
*/
@ -2583,7 +2583,7 @@ function getEllipseLength(el) {
* @param {SVGPathCommander.shapeTypes} el target element
* @returns {number} the element length
*/
function getTotalLength(el) {
function getTotalLength$1(el) {
if (el.tagName === 'rect') {
return getRectLength(el);
} if (el.tagName === 'circle') {
@ -2608,7 +2608,7 @@ function getTotalLength(el) {
function getDraw(element, value) {
const length = /path|glyph/.test(element.tagName)
? element.getTotalLength()
: getTotalLength(element);
: getTotalLength$1(element);
let start;
let end;
let dasharray;
@ -2680,7 +2680,7 @@ const SvgDrawProperty = {
getLineLength,
getCircleLength,
getEllipseLength,
getTotalLength,
getTotalLength: getTotalLength$1,
resetDraw,
getDraw,
percent,
@ -2712,6 +2712,7 @@ function fixArc(path, allPathCommands, i) {
/**
* Segment params length
* @type {Record<string, number>}
*/
const paramsCount = {
a: 7, c: 6, h: 1, l: 2, m: 2, r: 4, q: 4, s: 4, t: 2, v: 1, z: 0,
@ -2970,7 +2971,6 @@ function isArcCommand(code) {
function scanSegment(path) {
const { max, pathValue, index } = path;
const cmdCode = pathValue.charCodeAt(index);
// @ts-ignore
const reqParams = paramsCount[pathValue[index].toLowerCase()];
path.segmentStart = index;
@ -3034,7 +3034,8 @@ function clonePath(path) {
}
/**
* The `PathParser` used by the parser.
* The `PathParser` is used by the `parsePathString` static method
* to generate a `pathArray`.
*
* @param {string} pathString
*/
@ -3079,12 +3080,13 @@ function isPathArray(path) {
* @returns {SVGPathCommander.pathArray} the resulted `pathArray`
*/
function parsePathString(pathInput) {
if (Array.isArray(pathInput) && isPathArray(pathInput)) {
if (isPathArray(pathInput)) {
// @ts-ignore -- isPathArray also checks if it's an `Array`
return clonePath(pathInput);
}
// @ts-ignore
const path = new PathParser(pathInput); // TS expects string
// @ts-ignore -- pathInput is now string
const path = new PathParser(pathInput);
skipSpaces(path);
@ -3112,11 +3114,12 @@ function parsePathString(pathInput) {
* Iterates an array to check if it's a `pathArray`
* with all absolute values.
*
* @param {SVGPathCommander.pathArray} path the `pathArray` to be checked
* @param {string | SVGPathCommander.pathArray} path the `pathArray` to be checked
* @returns {boolean} iteration result
*/
function isAbsoluteArray(path) {
return isPathArray(path)
// @ts-ignore -- `isPathArray` also checks if it's `Array`
&& path.every((x) => x[0] === x[0].toUpperCase());
}
@ -3124,11 +3127,12 @@ function isAbsoluteArray(path) {
* Parses a path string value or object and returns an array
* of segments, all converted to absolute values.
*
* @param {SVGPathCommander.pathArray | string} pathInput the path string | object
* @param {string | SVGPathCommander.pathArray} pathInput the path string | object
* @returns {SVGPathCommander.absoluteArray} the resulted `pathArray` with absolute values
*/
function pathToAbsolute(pathInput) {
if (Array.isArray(pathInput) && isAbsoluteArray(pathInput)) {
if (isAbsoluteArray(pathInput)) {
// @ts-ignore -- `isAbsoluteArray` checks if it's `pathArray`
return clonePath(pathInput);
}
@ -3296,10 +3300,11 @@ function normalizeSegment(segment, params, prevCommand) {
* with all segments are in non-shorthand notation
* with absolute values.
*
* @param {SVGPathCommander.pathArray} path the `pathArray` to be checked
* @param {string | SVGPathCommander.pathArray} path the `pathArray` to be checked
* @returns {boolean} iteration result
*/
function isNormalizedArray(path) {
// @ts-ignore -- `isAbsoluteArray` also checks if it's `Array`
return isAbsoluteArray(path) && path.every((seg) => 'ACLMQZ'.includes(seg[0]));
}
@ -3315,14 +3320,17 @@ const paramsParser = {
* * convert segments to absolute values
* * convert shorthand path commands to their non-shorthand notation
*
* @param {SVGPathCommander.pathArray} pathInput the string to be parsed or 'pathArray'
* @param {string | SVGPathCommander.pathArray} pathInput the string to be parsed or 'pathArray'
* @returns {SVGPathCommander.normalArray} the normalized `pathArray`
*/
function normalizePath(pathInput) {
if (isNormalizedArray(pathInput)) {
// @ts-ignore -- `isNormalizedArray` checks if it's `pathArray`
return clonePath(pathInput);
}
/** @type {SVGPathCommander.normalArray} */
// @ts-ignore -- `absoluteArray` will become a `normalArray`
const path = pathToAbsolute(pathInput);
const params = { ...paramsParser };
const allPathCommands = [];
@ -3350,7 +3358,6 @@ function normalizePath(pathInput) {
params.y2 = +(segment[seglen - 3]) || params.y1;
}
// @ts-ignore -- a `normalArray` is absolutely an `absoluteArray`
return path;
}
@ -3377,7 +3384,7 @@ function fixPath(pathInput) {
const [x, y] = normalArray[segBeforeZ].slice(-2);
if (isClosed && mx === x && my === y) {
// @ts-ignore -- `pathSegment[]` is a `pathArray`
// @ts-ignore -- `pathSegment[]` is quite a `pathArray`
return pathArray.slice(0, -1);
}
return pathArray;
@ -3387,10 +3394,11 @@ function fixPath(pathInput) {
* Iterates an array to check if it's a `pathArray`
* with all C (cubic bezier) segments.
*
* @param {SVGPathCommander.pathArray} path the `Array` to be checked
* @param {string | SVGPathCommander.pathArray} path the `Array` to be checked
* @returns {boolean} iteration result
*/
function isCurveArray(path) {
// @ts-ignore -- `isPathArray` also checks if it's `Array`
return isPathArray(path) && path.every((seg) => 'MC'.includes(seg[0]));
}
@ -3545,35 +3553,6 @@ function quadToCubic(x1, y1, qx, qy, x2, y2) {
];
}
/**
* Returns the {x,y} coordinates of a point at a
* given length of a cubic-bezier segment.
*
* @param {number} p1x the starting point X
* @param {number} p1y the starting point Y
* @param {number} c1x the first control point X
* @param {number} c1y the first control point Y
* @param {number} c2x the second control point X
* @param {number} c2y the second control point Y
* @param {number} p2x the ending point X
* @param {number} p2y the ending point Y
* @param {number} t a [0-1] ratio
* @returns {{x: number, y: number}} the requested {x,y} coordinates
*/
function getPointAtSegLength(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, t) {
const t1 = 1 - t;
return {
x: (t1 ** 3) * p1x
+ t1 * t1 * 3 * t * c1x
+ t1 * 3 * t * t * c2x
+ (t ** 3) * p2x,
y: (t1 ** 3) * p1y
+ t1 * t1 * 3 * t * c1y
+ t1 * 3 * t * t * c2y
+ (t ** 3) * p2y,
};
}
/**
* Returns the coordinates of a specified distance
* ratio between two points.
@ -3588,6 +3567,49 @@ function midPoint(a, b, t) {
return [ax + (bx - ax) * t, ay + (by - ay) * t];
}
/**
* Returns the square root of the distance
* between two given points.
*
* @param {[number, number]} a the first point coordinates
* @param {[number, number]} b the second point coordinates
* @returns {number} the distance value
*/
function distanceSquareRoot(a, b) {
return Math.sqrt(
(a[0] - b[0]) * (a[0] - b[0])
+ (a[1] - b[1]) * (a[1] - b[1]),
);
}
/**
* Returns the length of a line (L,V,H,Z) segment,
* or a point at a given length.
*
* @param {number} x1 the starting point X
* @param {number} y1 the starting point Y
* @param {number} x2 the ending point X
* @param {number} y2 the ending point Y
* @param {number=} distance the distance to point
* @returns {{x: number, y: number} | number} the segment length or point
*/
function segmentLineFactory(x1, y1, x2, y2, distance) {
const length = distanceSquareRoot([x1, y1], [x2, y2]);
const margin = 0.001;
if (typeof distance === 'number') {
if (distance < margin) {
return { x: x1, y: y1 };
}
if (distance > length + margin) {
return { x: x2, y: y2 };
}
const [x, y] = midPoint([x1, y1], [x2, y2], distance / length);
return { x, y };
}
return length;
}
/**
* Converts an L (line-to) segment to C (cubic-bezier).
*
@ -3608,15 +3630,14 @@ function lineToCubic(x1, y1, x2, y2) {
const p4 = midPoint(p2, p3, t);
const p5 = midPoint(p3, p4, t);
const p6 = midPoint(p4, p5, t);
// const cp1 = getPointAtSegLength.apply(0, p0.concat(p2, p4, p6, t));
const seg1 = [...p0, ...p2, ...p4, ...p6, t];
// @ts-ignore
const cp1 = getPointAtSegLength(...seg1);
// const cp2 = getPointAtSegLength.apply(0, p6.concat(p5, p3, p1, 0));
const cp1 = segmentLineFactory(...seg1);
const seg2 = [...p6, ...p5, ...p3, ...p1, 0];
// @ts-ignore
const cp2 = getPointAtSegLength(...seg2);
const cp2 = segmentLineFactory(...seg2);
// @ts-ignore
return [cp1.x, cp1.y, cp2.x, cp2.y, x2, y2];
}
@ -3674,11 +3695,12 @@ function segmentToCubic(segment, params) {
* In addition, un-necessary `Z` segment is removed if previous segment
* extends to the `M` segment.
*
* @param {SVGPathCommander.pathArray} pathInput the string to be parsed or 'pathArray'
* @param {string | SVGPathCommander.pathArray} pathInput the string to be parsed or 'pathArray'
* @returns {SVGPathCommander.curveArray} the resulted `pathArray` converted to cubic-bezier
*/
function pathToCurve(pathInput) {
if (isCurveArray(pathInput)) {
// @ts-ignore -- `isCurveArray` checks if it's `pathArray`
return clonePath(pathInput);
}
@ -3774,167 +3796,373 @@ function splitPath(pathInput) {
}
/**
* @param {number} p1
* @param {number} p2
* @param {number} p3
* @param {number} p4
* @param {number} t a [0-1] ratio
* @returns {number}
*/
function base3(p1, p2, p3, p4, t) {
const t1 = -3 * p1 + 9 * p2 - 9 * p3 + 3 * p4;
const t2 = t * t1 + 6 * p1 - 12 * p2 + 6 * p3;
return t * t2 - 3 * p1 + 3 * p2;
}
/**
* Returns the C (cubic-bezier) segment length.
* Returns a point at a given length of a C (cubic-bezier) segment.
*
* @param {number} x1 the starting point X
* @param {number} y1 the starting point Y
* @param {number} x2 the first control point X
* @param {number} y2 the first control point Y
* @param {number} x3 the second control point X
* @param {number} y3 the second control point Y
* @param {number} x4 the ending point X
* @param {number} y4 the ending point Y
* @param {number} z a [0-1] ratio
* @returns {number} the cubic-bezier segment length
* @param {number} c1x the first control point X
* @param {number} c1y the first control point Y
* @param {number} c2x the second control point X
* @param {number} c2y the second control point Y
* @param {number} x2 the ending point X
* @param {number} y2 the ending point Y
* @param {number} t a [0-1] ratio
* @returns {{x: number, y: number}} the cubic-bezier segment length
*/
function getSegCubicLength(x1, y1, x2, y2, x3, y3, x4, y4, z) {
let Z = z;
if (z === null || Number.isNaN(+z)) Z = 1;
// Z = Z > 1 ? 1 : Z < 0 ? 0 : Z;
if (Z > 1) Z = 1;
if (Z < 0) Z = 0;
const z2 = Z / 2; let ct = 0; let xbase = 0; let ybase = 0; let sum = 0;
const Tvalues = [-0.1252, 0.1252, -0.3678, 0.3678,
-0.5873, 0.5873, -0.7699, 0.7699,
-0.9041, 0.9041, -0.9816, 0.9816];
const Cvalues = [0.2491, 0.2491, 0.2335, 0.2335,
0.2032, 0.2032, 0.1601, 0.1601,
0.1069, 0.1069, 0.0472, 0.0472];
Tvalues.forEach((T, i) => {
ct = z2 * T + z2;
xbase = base3(x1, x2, x3, x4, ct);
ybase = base3(y1, y2, y3, y4, ct);
sum += Cvalues[i] * Math.sqrt(xbase * xbase + ybase * ybase);
});
return z2 * sum;
function getPointAtCubicSegmentLength(x1, y1, c1x, c1y, c2x, c2y, x2, y2, t) {
const t1 = 1 - t;
return {
x: (t1 ** 3) * x1
+ 3 * (t1 ** 2) * t * c1x
+ 3 * t1 * (t ** 2) * c2x
+ (t ** 3) * x2,
y: (t1 ** 3) * y1
+ 3 * (t1 ** 2) * t * c1y
+ 3 * t1 * (t ** 2) * c2y
+ (t ** 3) * y2,
};
}
/**
* Returns the shape total length,
* or the equivalent to `shape.getTotalLength()`
* pathToCurve version
* Returns the length of a C (cubic-bezier) segment,
* or an {x,y} point at a given length.
*
* @param {SVGPathCommander.pathArray} path the target `pathArray`
* @param {number} x1 the starting point X
* @param {number} y1 the starting point Y
* @param {number} c1x the first control point X
* @param {number} c1y the first control point Y
* @param {number} c2x the second control point X
* @param {number} c2y the second control point Y
* @param {number} x2 the ending point X
* @param {number} y2 the ending point Y
* @param {number=} distance the point distance
* @returns {{x: number, y: number} | number} the segment length or point
*/
function segmentCubicFactory(x1, y1, c1x, c1y, c2x, c2y, x2, y2, distance) {
let x = x1; let y = y1;
const lengthMargin = 0.001;
let totalLength = 0;
let prev = [x1, y1, totalLength];
/** @type {[number, number]} */
let cur = [x1, y1];
let t = 0;
if (typeof distance === 'number' && distance < lengthMargin) {
return { x, y };
}
const n = 100;
for (let j = 0; j <= n; j += 1) {
t = j / n;
({ x, y } = getPointAtCubicSegmentLength(x1, y1, c1x, c1y, c2x, c2y, x2, y2, t));
totalLength += distanceSquareRoot(cur, [x, y]);
cur = [x, y];
if (typeof distance === 'number' && totalLength >= distance) {
const dv = (totalLength - distance) / (totalLength - prev[2]);
return {
x: cur[0] * (1 - dv) + prev[0] * dv,
y: cur[1] * (1 - dv) + prev[1] * dv,
};
}
prev = [x, y, totalLength];
}
if (typeof distance === 'number' && distance >= totalLength) {
return { x: x2, y: y2 };
}
return totalLength;
}
/**
* Returns the length of a A (arc-to) segment,
* or an {x,y} point at a given length.
*
* @param {number} X1 the starting x position
* @param {number} Y1 the starting y position
* @param {number} RX x-radius of the arc
* @param {number} RY y-radius of the arc
* @param {number} angle x-axis-rotation of the arc
* @param {number} LAF large-arc-flag of the arc
* @param {number} SF sweep-flag of the arc
* @param {number} X2 the ending x position
* @param {number} Y2 the ending y position
* @param {number} distance the point distance
* @returns {{x: number, y: number} | number} the segment length or point
*/
function segmentArcFactory(X1, Y1, RX, RY, angle, LAF, SF, X2, Y2, distance) {
let [x, y] = [X1, Y1];
const cubicSeg = arcToCubic(X1, Y1, RX, RY, angle, LAF, SF, X2, Y2);
const lengthMargin = 0.001;
let totalLength = 0;
let cubicSubseg = [];
let argsc = [];
let segLen = 0;
if (typeof distance === 'number' && distance < lengthMargin) {
return { x, y };
}
for (let i = 0, ii = cubicSeg.length; i < ii; i += 6) {
cubicSubseg = cubicSeg.slice(i, i + 6);
argsc = [x, y, ...cubicSubseg];
// @ts-ignore
segLen = segmentCubicFactory(...argsc);
if (typeof distance === 'number' && totalLength + segLen >= distance) {
// @ts-ignore -- this is a `cubicSegment`
return segmentCubicFactory(...argsc, distance - totalLength);
}
totalLength += segLen;
[x, y] = cubicSubseg.slice(-2);
}
if (typeof distance === 'number' && distance >= totalLength) {
return { x: X2, y: Y2 };
}
return totalLength;
}
/**
* Returns the {x,y} coordinates of a point at a
* given length of a quad-bezier segment.
*
* @see https://github.com/substack/point-at-length
*
* @param {number} x1 the starting point X
* @param {number} y1 the starting point Y
* @param {number} cx the control point X
* @param {number} cy the control point Y
* @param {number} x2 the ending point X
* @param {number} y2 the ending point Y
* @param {number} t a [0-1] ratio
* @returns {{x: number, y: number}} the requested {x,y} coordinates
*/
function getPointAtQuadSegmentLength(x1, y1, cx, cy, x2, y2, t) {
const t1 = 1 - t;
return {
x: (t1 ** 2) * x1
+ 2 * t1 * t * cx
+ (t ** 2) * x2,
y: (t1 ** 2) * y1
+ 2 * t1 * t * cy
+ (t ** 2) * y2,
};
}
/**
* Returns the Q (quadratic-bezier) segment length,
* or an {x,y} point at a given length.
*
* @param {number} x1 the starting point X
* @param {number} y1 the starting point Y
* @param {number} qx the control point X
* @param {number} qy the control point Y
* @param {number} x2 the ending point X
* @param {number} y2 the ending point Y
* @param {number=} distance the distance to point
* @returns {{x: number, y: number} | number} the segment length or point
*/
function segmentQuadFactory(x1, y1, qx, qy, x2, y2, distance) {
let x = x1; let y = y1;
const lengthMargin = 0.001;
let totalLength = 0;
let prev = [x1, y1, totalLength];
/** @type {[number, number]} */
let cur = [x1, y1];
let t = 0;
if (typeof distance === 'number' && distance < lengthMargin) {
return { x, y };
}
const n = 100;
for (let j = 0; j <= n; j += 1) {
t = j / n;
({ x, y } = getPointAtQuadSegmentLength(x1, y1, qx, qy, x2, y2, t));
totalLength += distanceSquareRoot(cur, [x, y]);
cur = [x, y];
if (typeof distance === 'number' && totalLength >= distance) {
const dv = (totalLength - distance) / (totalLength - prev[2]);
return {
x: cur[0] * (1 - dv) + prev[0] * dv,
y: cur[1] * (1 - dv) + prev[1] * dv,
};
}
prev = [x, y, totalLength];
}
if (typeof distance === 'number' && distance >= totalLength) {
return { x: x2, y: y2 };
}
return totalLength;
}
/**
* Returns a {x,y} point at a given length of a shape or the shape total length.
*
* @param {string | SVGPathCommander.pathArray} pathInput the `pathArray` to look into
* @param {number=} distance the length of the shape to look at
* @returns {{x: number, y: number} | number} the total length or point
*/
function pathLengthFactory(pathInput, distance) {
let totalLength = 0;
let isM = true;
/** @type {number[]} */
let data = [];
let pathCommand = 'M';
let segLen = 0;
let x = 0;
let y = 0;
let mx = 0;
let my = 0;
let seg;
const path = fixPath(normalizePath(pathInput));
for (let i = 0, ll = path.length; i < ll; i += 1) {
seg = path[i];
[pathCommand] = seg;
isM = pathCommand === 'M';
// @ts-ignore
data = !isM ? [x, y, ...seg.slice(1)] : data;
// this segment is always ZERO
if (isM) {
// remember mx, my for Z
// @ts-ignore
[, mx, my] = seg;
if (typeof distance === 'number' && distance < 0.001) {
return { x: mx, y: my };
}
} else if (pathCommand === 'L') {
// @ts-ignore
segLen = segmentLineFactory(...data);
if (distance && totalLength + segLen >= distance) {
// @ts-ignore
return segmentLineFactory(...data, distance - totalLength);
}
totalLength += segLen;
} else if (pathCommand === 'A') {
// @ts-ignore
segLen = segmentArcFactory(...data);
if (distance && totalLength + segLen >= distance) {
// @ts-ignore
return segmentArcFactory(...data, distance - totalLength);
}
totalLength += segLen;
} else if (pathCommand === 'C') {
// @ts-ignore
segLen = segmentCubicFactory(...data);
if (distance && totalLength + segLen >= distance) {
// @ts-ignore
return segmentCubicFactory(...data, distance - totalLength);
}
totalLength += segLen;
} else if (pathCommand === 'Q') {
// @ts-ignore
segLen = segmentQuadFactory(...data);
if (distance && totalLength + segLen >= distance) {
// @ts-ignore
return segmentQuadFactory(...data, distance - totalLength);
}
totalLength += segLen;
} else if (pathCommand === 'Z') {
data = [x, y, mx, my];
// @ts-ignore
segLen = segmentLineFactory(...data);
if (distance && totalLength + segLen >= distance) {
// @ts-ignore
return segmentLineFactory(...data, distance - totalLength);
}
totalLength += segLen;
}
// @ts-ignore -- needed for the below
[x, y] = pathCommand !== 'Z' ? seg.slice(-2) : [mx, my];
}
// native `getPointAtLength` behavior when the given distance
// is higher than total length
if (distance && distance >= totalLength) {
return { x, y };
}
return totalLength;
}
/**
* Returns the shape total length, or the equivalent to `shape.getTotalLength()`.
*
* The `normalizePath` version is lighter, faster, more efficient and more accurate
* with paths that are not `curveArray`.
*
* @param {string | SVGPathCommander.pathArray} pathInput the target `pathArray`
* @returns {number} the shape total length
*/
function getPathLength(path) {
let totalLength = 0;
pathToCurve(path).forEach((s, i, curveArray) => {
const args = s[0] !== 'M' ? [...curveArray[i - 1].slice(-2), ...s.slice(1)] : [];
totalLength += s[0] === 'M' ? 0
// @ts-ignore
: getSegCubicLength(...args);
});
return totalLength;
function getTotalLength(pathInput) {
// @ts-ignore - it's fine
return pathLengthFactory(pathInput);
}
/**
* Returns [x,y] coordinates of a point at a given length of a shape.
*
* @param {string | SVGPathCommander.pathArray} path the `pathArray` to look into
* @param {number} length the length of the shape to look at
* @returns {number[]} the requested [x,y] coordinates
* @param {string | SVGPathCommander.pathArray} pathInput the `pathArray` to look into
* @param {number} distance the length of the shape to look at
* @returns {{x: number, y: number}} the requested {x, y} point coordinates
*/
function getPointAtLength(path, length) {
let totalLength = 0;
let segLen;
let data;
let result;
function getPointAtLength(pathInput, distance) {
// @ts-ignore
return pathToCurve(path).map((seg, i, curveArray) => {
data = i ? [...curveArray[i - 1].slice(-2), ...seg.slice(1)] : seg.slice(1);
// @ts-ignore
segLen = i ? getSegCubicLength(...data) : 0;
totalLength += segLen;
return pathLengthFactory(pathInput, distance);
}
if (i === 0) {
result = { x: data[0], y: data[1] };
} else if (totalLength > length && length > totalLength - segLen) {
const args = [...data, 1 - ((totalLength - length) / segLen)];
/**
* d3-polygon-area
* https://github.com/d3/d3-polygon
*
* Returns the area of a polygon.
*
* @param {number[][]} polygon an array of coordinates
* @returns {number} the polygon area
*/
function polygonArea(polygon) {
const n = polygon.length;
let i = -1;
let a;
let b = polygon[n - 1];
let area = 0;
/* eslint-disable-next-line */
while (++i < n) {
a = b;
b = polygon[i];
area += a[1] * b[0] - a[0] * b[1];
}
return area / 2;
}
/**
* d3-polygon-length
* https://github.com/d3/d3-polygon
*
* Returns the perimeter of a polygon.
*
* @param {number[][]} polygon an array of coordinates
* @returns {number} the polygon length
*/
function polygonLength(polygon) {
return polygon.reduce((length, point, i) => {
if (i) {
// @ts-ignore
result = getPointAtSegLength(...args);
} else {
result = null;
return length + distanceSquareRoot(polygon[i - 1], point);
}
return result;
}).filter((x) => x).slice(-1)[0]; // isolate last segment
}
/**
* Returns the area of a single segment shape.
*
* http://objectmix.com/graphics/133553-area-closed-bezier-curve.html
*
* @param {number} x0 the starting point X
* @param {number} y0 the starting point Y
* @param {number} x1 the first control point X
* @param {number} y1 the first control point Y
* @param {number} x2 the second control point X
* @param {number} y2 the second control point Y
* @param {number} x3 the ending point X
* @param {number} y3 the ending point Y
* @returns {number} the area of the cubic-bezier segment
*/
function getCubicSegArea(x0, y0, x1, y1, x2, y2, x3, y3) {
return (3 * ((y3 - y0) * (x1 + x2) - (x3 - x0) * (y1 + y2)
+ (y1 * (x0 - x2)) - (x1 * (y0 - y2))
+ (y3 * (x2 + x0 / 3)) - (x3 * (y2 + y0 / 3)))) / 20;
}
/**
* Returns the area of a shape.
* @author Jürg Lehni & Jonathan Puckey
*
* => https://github.com/paperjs/paper.js/blob/develop/src/path/Path.js
*
* @param {SVGPathCommander.pathArray} path the shape `pathArray`
* @returns {number} the length of the cubic-bezier segment
*/
function getPathArea(path) {
let x = 0; let y = 0;
let len = 0;
return pathToCurve(path).map((seg) => {
switch (seg[0]) {
case 'M':
[, x, y] = seg;
return 0;
default:
// @ts-ignore -- the utility will have proper amount of params
len = getCubicSegArea(...[x, y, ...seg.slice(1)]);
[x, y] = seg.slice(-2).map(Number);
return len;
}
}).reduce((a, b) => a + b, 0);
}
/**
* Check if a path is drawn clockwise and returns true if so,
* false otherwise.
*
* @param {SVGPathCommander.pathArray} path the path string or `pathArray`
* @returns {boolean} true when clockwise or false if not
*/
function getDrawDirection(path) {
return getPathArea(pathToCurve(path)) >= 0;
return 0;
}, 0);
}
/**
@ -3944,21 +4172,6 @@ function getDrawDirection(path) {
*/
const epsilon = 1e-9;
/**
* Returns the square root of the distance
* between two given points.
*
* @param {[number, number]} a the first point coordinates
* @param {[number, number]} b the second point coordinates
* @returns {number} the distance value
*/
function distanceSquareRoot(a, b) {
return Math.sqrt(
(a[0] - b[0]) * (a[0] - b[0])
+ (a[1] - b[1]) * (a[1] - b[1]),
);
}
/**
* Coordinates Interpolation Function.
*
@ -4006,17 +4219,6 @@ function onStartSVGMorph(tweenProp) {
// original script flubber
// https://github.com/veltman/flubber
/**
* Returns polygon length.
* @param {KUTE.polygonMorph} polygon target polygon
* @returns {number} length
*/
function polygonLength(polygon) {
return polygon.reduce((length, point, i) => (i
? length + distanceSquareRoot(polygon[i - 1], point)
: 0), 0);
}
/**
* Returns an existing polygin and its length or false if not polygon.
* @param {SVGPathCommander.pathArray} pathArray target polygon
@ -4056,8 +4258,8 @@ function exactPolygon(pathArray) {
*/
function approximatePolygon(parsed, maxLength) {
const ringPath = splitPath(pathToString(parsed))[0];
const curvePath = pathToCurve(ringPath);
const pathLength = getPathLength(curvePath);
const normalPath = normalizePath(ringPath);
const pathLength = getTotalLength(normalPath);
const polygon = [];
let numPoints = 3;
let point;
@ -4067,12 +4269,12 @@ function approximatePolygon(parsed, maxLength) {
}
for (let i = 0; i < numPoints; i += 1) {
point = getPointAtLength(curvePath, (pathLength * i) / numPoints);
point = getPointAtLength(normalPath, (pathLength * i) / numPoints);
polygon.push([point.x, point.y]);
}
// Make all rings clockwise
if (!getDrawDirection(curvePath)) {
if (polygonArea(polygon) > 0) {
polygon.reverse();
}
@ -4354,9 +4556,9 @@ const SVGMorph = {
// svg-path-commander
pathToString,
pathToCurve,
getPathLength,
getTotalLength,
getPointAtLength,
getDrawDirection,
polygonArea,
roundPath,
},
};
@ -4378,7 +4580,7 @@ Object.keys(Components).forEach((component) => {
Components[component] = new Animation(compOps);
});
var version = "2.2.0";
var version = "2.2.2";
// @ts-ignore

File diff suppressed because one or more lines are too long

666
dist/kute.js vendored
View file

@ -1,5 +1,5 @@
/*!
* KUTE.js Standard v2.2.0 (http://thednp.github.io/kute.js)
* KUTE.js Standard v2.2.2 (http://thednp.github.io/kute.js)
* Copyright 2015-2021 © thednp
* Licensed under MIT (https://github.com/thednp/kute.js/blob/master/LICENSE)
*/
@ -2589,7 +2589,7 @@
* @param {SVGPathCommander.shapeTypes} el target element
* @returns {number} the element length
*/
function getTotalLength(el) {
function getTotalLength$1(el) {
if (el.tagName === 'rect') {
return getRectLength(el);
} if (el.tagName === 'circle') {
@ -2614,7 +2614,7 @@
function getDraw(element, value) {
var length = /path|glyph/.test(element.tagName)
? element.getTotalLength()
: getTotalLength(element);
: getTotalLength$1(element);
var start;
var end;
var dasharray;
@ -2686,7 +2686,7 @@
getLineLength: getLineLength,
getCircleLength: getCircleLength,
getEllipseLength: getEllipseLength,
getTotalLength: getTotalLength,
getTotalLength: getTotalLength$1,
resetDraw: resetDraw,
getDraw: getDraw,
percent: percent,
@ -2718,6 +2718,7 @@
/**
* Segment params length
* @type {Record<string, number>}
*/
var paramsCount = {
a: 7, c: 6, h: 1, l: 2, m: 2, r: 4, q: 4, s: 4, t: 2, v: 1, z: 0,
@ -2981,7 +2982,6 @@
var pathValue = path.pathValue;
var index = path.index;
var cmdCode = pathValue.charCodeAt(index);
// @ts-ignore
var reqParams = paramsCount[pathValue[index].toLowerCase()];
path.segmentStart = index;
@ -3045,7 +3045,8 @@
}
/**
* The `PathParser` used by the parser.
* The `PathParser` is used by the `parsePathString` static method
* to generate a `pathArray`.
*
* @param {string} pathString
*/
@ -3090,12 +3091,13 @@
* @returns {SVGPathCommander.pathArray} the resulted `pathArray`
*/
function parsePathString(pathInput) {
if (Array.isArray(pathInput) && isPathArray(pathInput)) {
if (isPathArray(pathInput)) {
// @ts-ignore -- isPathArray also checks if it's an `Array`
return clonePath(pathInput);
}
// @ts-ignore
var path = new PathParser(pathInput); // TS expects string
// @ts-ignore -- pathInput is now string
var path = new PathParser(pathInput);
skipSpaces(path);
@ -3123,11 +3125,12 @@
* Iterates an array to check if it's a `pathArray`
* with all absolute values.
*
* @param {SVGPathCommander.pathArray} path the `pathArray` to be checked
* @param {string | SVGPathCommander.pathArray} path the `pathArray` to be checked
* @returns {boolean} iteration result
*/
function isAbsoluteArray(path) {
return isPathArray(path)
// @ts-ignore -- `isPathArray` also checks if it's `Array`
&& path.every(function (x) { return x[0] === x[0].toUpperCase(); });
}
@ -3135,11 +3138,12 @@
* Parses a path string value or object and returns an array
* of segments, all converted to absolute values.
*
* @param {SVGPathCommander.pathArray | string} pathInput the path string | object
* @param {string | SVGPathCommander.pathArray} pathInput the path string | object
* @returns {SVGPathCommander.absoluteArray} the resulted `pathArray` with absolute values
*/
function pathToAbsolute(pathInput) {
if (Array.isArray(pathInput) && isAbsoluteArray(pathInput)) {
if (isAbsoluteArray(pathInput)) {
// @ts-ignore -- `isAbsoluteArray` checks if it's `pathArray`
return clonePath(pathInput);
}
@ -3315,10 +3319,11 @@
* with all segments are in non-shorthand notation
* with absolute values.
*
* @param {SVGPathCommander.pathArray} path the `pathArray` to be checked
* @param {string | SVGPathCommander.pathArray} path the `pathArray` to be checked
* @returns {boolean} iteration result
*/
function isNormalizedArray(path) {
// @ts-ignore -- `isAbsoluteArray` also checks if it's `Array`
return isAbsoluteArray(path) && path.every(function (seg) { return 'ACLMQZ'.includes(seg[0]); });
}
@ -3334,16 +3339,19 @@
* * convert segments to absolute values
* * convert shorthand path commands to their non-shorthand notation
*
* @param {SVGPathCommander.pathArray} pathInput the string to be parsed or 'pathArray'
* @param {string | SVGPathCommander.pathArray} pathInput the string to be parsed or 'pathArray'
* @returns {SVGPathCommander.normalArray} the normalized `pathArray`
*/
function normalizePath(pathInput) {
var assign;
if (isNormalizedArray(pathInput)) {
// @ts-ignore -- `isNormalizedArray` checks if it's `pathArray`
return clonePath(pathInput);
}
/** @type {SVGPathCommander.normalArray} */
// @ts-ignore -- `absoluteArray` will become a `normalArray`
var path = pathToAbsolute(pathInput);
var params = Object.assign({}, paramsParser);
var allPathCommands = [];
@ -3371,7 +3379,6 @@
params.y2 = +(segment[seglen - 3]) || params.y1;
}
// @ts-ignore -- a `normalArray` is absolutely an `absoluteArray`
return path;
}
@ -3402,7 +3409,7 @@
var y = ref$1[1];
if (isClosed && mx === x && my === y) {
// @ts-ignore -- `pathSegment[]` is a `pathArray`
// @ts-ignore -- `pathSegment[]` is quite a `pathArray`
return pathArray.slice(0, -1);
}
return pathArray;
@ -3412,10 +3419,11 @@
* Iterates an array to check if it's a `pathArray`
* with all C (cubic bezier) segments.
*
* @param {SVGPathCommander.pathArray} path the `Array` to be checked
* @param {string | SVGPathCommander.pathArray} path the `Array` to be checked
* @returns {boolean} iteration result
*/
function isCurveArray(path) {
// @ts-ignore -- `isPathArray` also checks if it's `Array`
return isPathArray(path) && path.every(function (seg) { return 'MC'.includes(seg[0]); });
}
@ -3571,35 +3579,6 @@
x2, y2 ];
}
/**
* Returns the {x,y} coordinates of a point at a
* given length of a cubic-bezier segment.
*
* @param {number} p1x the starting point X
* @param {number} p1y the starting point Y
* @param {number} c1x the first control point X
* @param {number} c1y the first control point Y
* @param {number} c2x the second control point X
* @param {number} c2y the second control point Y
* @param {number} p2x the ending point X
* @param {number} p2y the ending point Y
* @param {number} t a [0-1] ratio
* @returns {{x: number, y: number}} the requested {x,y} coordinates
*/
function getPointAtSegLength(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, t) {
var t1 = 1 - t;
return {
x: (Math.pow( t1, 3 )) * p1x
+ t1 * t1 * 3 * t * c1x
+ t1 * 3 * t * t * c2x
+ (Math.pow( t, 3 )) * p2x,
y: (Math.pow( t1, 3 )) * p1y
+ t1 * t1 * 3 * t * c1y
+ t1 * 3 * t * t * c2y
+ (Math.pow( t, 3 )) * p2y,
};
}
/**
* Returns the coordinates of a specified distance
* ratio between two points.
@ -3616,6 +3595,51 @@
return [ax + (bx - ax) * t, ay + (by - ay) * t];
}
/**
* Returns the square root of the distance
* between two given points.
*
* @param {[number, number]} a the first point coordinates
* @param {[number, number]} b the second point coordinates
* @returns {number} the distance value
*/
function distanceSquareRoot(a, b) {
return Math.sqrt(
(a[0] - b[0]) * (a[0] - b[0])
+ (a[1] - b[1]) * (a[1] - b[1])
);
}
/**
* Returns the length of a line (L,V,H,Z) segment,
* or a point at a given length.
*
* @param {number} x1 the starting point X
* @param {number} y1 the starting point Y
* @param {number} x2 the ending point X
* @param {number} y2 the ending point Y
* @param {number=} distance the distance to point
* @returns {{x: number, y: number} | number} the segment length or point
*/
function segmentLineFactory(x1, y1, x2, y2, distance) {
var length = distanceSquareRoot([x1, y1], [x2, y2]);
var margin = 0.001;
if (typeof distance === 'number') {
if (distance < margin) {
return { x: x1, y: y1 };
}
if (distance > length + margin) {
return { x: x2, y: y2 };
}
var ref = midPoint([x1, y1], [x2, y2], distance / length);
var x = ref[0];
var y = ref[1];
return { x: x, y: y };
}
return length;
}
/**
* Converts an L (line-to) segment to C (cubic-bezier).
*
@ -3636,15 +3660,14 @@
var p4 = midPoint(p2, p3, t);
var p5 = midPoint(p3, p4, t);
var p6 = midPoint(p4, p5, t);
// const cp1 = getPointAtSegLength.apply(0, p0.concat(p2, p4, p6, t));
var seg1 = p0.concat( p2, p4, p6, [t]);
// @ts-ignore
var cp1 = getPointAtSegLength.apply(void 0, seg1);
// const cp2 = getPointAtSegLength.apply(0, p6.concat(p5, p3, p1, 0));
var cp1 = segmentLineFactory.apply(void 0, seg1);
var seg2 = p6.concat( p5, p3, p1, [0]);
// @ts-ignore
var cp2 = getPointAtSegLength.apply(void 0, seg2);
var cp2 = segmentLineFactory.apply(void 0, seg2);
// @ts-ignore
return [cp1.x, cp1.y, cp2.x, cp2.y, x2, y2];
}
@ -3704,13 +3727,14 @@
* In addition, un-necessary `Z` segment is removed if previous segment
* extends to the `M` segment.
*
* @param {SVGPathCommander.pathArray} pathInput the string to be parsed or 'pathArray'
* @param {string | SVGPathCommander.pathArray} pathInput the string to be parsed or 'pathArray'
* @returns {SVGPathCommander.curveArray} the resulted `pathArray` converted to cubic-bezier
*/
function pathToCurve(pathInput) {
var assign;
if (isCurveArray(pathInput)) {
// @ts-ignore -- `isCurveArray` checks if it's `pathArray`
return clonePath(pathInput);
}
@ -3806,169 +3830,383 @@
}
/**
* @param {number} p1
* @param {number} p2
* @param {number} p3
* @param {number} p4
* @param {number} t a [0-1] ratio
* @returns {number}
*/
function base3(p1, p2, p3, p4, t) {
var t1 = -3 * p1 + 9 * p2 - 9 * p3 + 3 * p4;
var t2 = t * t1 + 6 * p1 - 12 * p2 + 6 * p3;
return t * t2 - 3 * p1 + 3 * p2;
}
/**
* Returns the C (cubic-bezier) segment length.
* Returns a point at a given length of a C (cubic-bezier) segment.
*
* @param {number} x1 the starting point X
* @param {number} y1 the starting point Y
* @param {number} x2 the first control point X
* @param {number} y2 the first control point Y
* @param {number} x3 the second control point X
* @param {number} y3 the second control point Y
* @param {number} x4 the ending point X
* @param {number} y4 the ending point Y
* @param {number} z a [0-1] ratio
* @returns {number} the cubic-bezier segment length
* @param {number} c1x the first control point X
* @param {number} c1y the first control point Y
* @param {number} c2x the second control point X
* @param {number} c2y the second control point Y
* @param {number} x2 the ending point X
* @param {number} y2 the ending point Y
* @param {number} t a [0-1] ratio
* @returns {{x: number, y: number}} the cubic-bezier segment length
*/
function getSegCubicLength(x1, y1, x2, y2, x3, y3, x4, y4, z) {
var Z = z;
if (z === null || Number.isNaN(+z)) { Z = 1; }
// Z = Z > 1 ? 1 : Z < 0 ? 0 : Z;
if (Z > 1) { Z = 1; }
if (Z < 0) { Z = 0; }
var z2 = Z / 2; var ct = 0; var xbase = 0; var ybase = 0; var sum = 0;
var Tvalues = [-0.1252, 0.1252, -0.3678, 0.3678,
-0.5873, 0.5873, -0.7699, 0.7699,
-0.9041, 0.9041, -0.9816, 0.9816];
var Cvalues = [0.2491, 0.2491, 0.2335, 0.2335,
0.2032, 0.2032, 0.1601, 0.1601,
0.1069, 0.1069, 0.0472, 0.0472];
Tvalues.forEach(function (T, i) {
ct = z2 * T + z2;
xbase = base3(x1, x2, x3, x4, ct);
ybase = base3(y1, y2, y3, y4, ct);
sum += Cvalues[i] * Math.sqrt(xbase * xbase + ybase * ybase);
});
return z2 * sum;
function getPointAtCubicSegmentLength(x1, y1, c1x, c1y, c2x, c2y, x2, y2, t) {
var t1 = 1 - t;
return {
x: (Math.pow( t1, 3 )) * x1
+ 3 * (Math.pow( t1, 2 )) * t * c1x
+ 3 * t1 * (Math.pow( t, 2 )) * c2x
+ (Math.pow( t, 3 )) * x2,
y: (Math.pow( t1, 3 )) * y1
+ 3 * (Math.pow( t1, 2 )) * t * c1y
+ 3 * t1 * (Math.pow( t, 2 )) * c2y
+ (Math.pow( t, 3 )) * y2,
};
}
/**
* Returns the shape total length,
* or the equivalent to `shape.getTotalLength()`
* pathToCurve version
* Returns the length of a C (cubic-bezier) segment,
* or an {x,y} point at a given length.
*
* @param {SVGPathCommander.pathArray} path the target `pathArray`
* @param {number} x1 the starting point X
* @param {number} y1 the starting point Y
* @param {number} c1x the first control point X
* @param {number} c1y the first control point Y
* @param {number} c2x the second control point X
* @param {number} c2y the second control point Y
* @param {number} x2 the ending point X
* @param {number} y2 the ending point Y
* @param {number=} distance the point distance
* @returns {{x: number, y: number} | number} the segment length or point
*/
function segmentCubicFactory(x1, y1, c1x, c1y, c2x, c2y, x2, y2, distance) {
var assign;
var x = x1; var y = y1;
var lengthMargin = 0.001;
var totalLength = 0;
var prev = [x1, y1, totalLength];
/** @type {[number, number]} */
var cur = [x1, y1];
var t = 0;
if (typeof distance === 'number' && distance < lengthMargin) {
return { x: x, y: y };
}
var n = 100;
for (var j = 0; j <= n; j += 1) {
t = j / n;
((assign = getPointAtCubicSegmentLength(x1, y1, c1x, c1y, c2x, c2y, x2, y2, t), x = assign.x, y = assign.y));
totalLength += distanceSquareRoot(cur, [x, y]);
cur = [x, y];
if (typeof distance === 'number' && totalLength >= distance) {
var dv = (totalLength - distance) / (totalLength - prev[2]);
return {
x: cur[0] * (1 - dv) + prev[0] * dv,
y: cur[1] * (1 - dv) + prev[1] * dv,
};
}
prev = [x, y, totalLength];
}
if (typeof distance === 'number' && distance >= totalLength) {
return { x: x2, y: y2 };
}
return totalLength;
}
/**
* Returns the length of a A (arc-to) segment,
* or an {x,y} point at a given length.
*
* @param {number} X1 the starting x position
* @param {number} Y1 the starting y position
* @param {number} RX x-radius of the arc
* @param {number} RY y-radius of the arc
* @param {number} angle x-axis-rotation of the arc
* @param {number} LAF large-arc-flag of the arc
* @param {number} SF sweep-flag of the arc
* @param {number} X2 the ending x position
* @param {number} Y2 the ending y position
* @param {number} distance the point distance
* @returns {{x: number, y: number} | number} the segment length or point
*/
function segmentArcFactory(X1, Y1, RX, RY, angle, LAF, SF, X2, Y2, distance) {
var assign;
var ref = [X1, Y1];
var x = ref[0];
var y = ref[1];
var cubicSeg = arcToCubic(X1, Y1, RX, RY, angle, LAF, SF, X2, Y2);
var lengthMargin = 0.001;
var totalLength = 0;
var cubicSubseg = [];
var argsc = [];
var segLen = 0;
if (typeof distance === 'number' && distance < lengthMargin) {
return { x: x, y: y };
}
for (var i = 0, ii = cubicSeg.length; i < ii; i += 6) {
cubicSubseg = cubicSeg.slice(i, i + 6);
argsc = [x, y ].concat( cubicSubseg);
// @ts-ignore
segLen = segmentCubicFactory.apply(void 0, argsc);
if (typeof distance === 'number' && totalLength + segLen >= distance) {
// @ts-ignore -- this is a `cubicSegment`
return segmentCubicFactory.apply(void 0, argsc.concat( [distance - totalLength] ));
}
totalLength += segLen;
(assign = cubicSubseg.slice(-2), x = assign[0], y = assign[1]);
}
if (typeof distance === 'number' && distance >= totalLength) {
return { x: X2, y: Y2 };
}
return totalLength;
}
/**
* Returns the {x,y} coordinates of a point at a
* given length of a quad-bezier segment.
*
* @see https://github.com/substack/point-at-length
*
* @param {number} x1 the starting point X
* @param {number} y1 the starting point Y
* @param {number} cx the control point X
* @param {number} cy the control point Y
* @param {number} x2 the ending point X
* @param {number} y2 the ending point Y
* @param {number} t a [0-1] ratio
* @returns {{x: number, y: number}} the requested {x,y} coordinates
*/
function getPointAtQuadSegmentLength(x1, y1, cx, cy, x2, y2, t) {
var t1 = 1 - t;
return {
x: (Math.pow( t1, 2 )) * x1
+ 2 * t1 * t * cx
+ (Math.pow( t, 2 )) * x2,
y: (Math.pow( t1, 2 )) * y1
+ 2 * t1 * t * cy
+ (Math.pow( t, 2 )) * y2,
};
}
/**
* Returns the Q (quadratic-bezier) segment length,
* or an {x,y} point at a given length.
*
* @param {number} x1 the starting point X
* @param {number} y1 the starting point Y
* @param {number} qx the control point X
* @param {number} qy the control point Y
* @param {number} x2 the ending point X
* @param {number} y2 the ending point Y
* @param {number=} distance the distance to point
* @returns {{x: number, y: number} | number} the segment length or point
*/
function segmentQuadFactory(x1, y1, qx, qy, x2, y2, distance) {
var assign;
var x = x1; var y = y1;
var lengthMargin = 0.001;
var totalLength = 0;
var prev = [x1, y1, totalLength];
/** @type {[number, number]} */
var cur = [x1, y1];
var t = 0;
if (typeof distance === 'number' && distance < lengthMargin) {
return { x: x, y: y };
}
var n = 100;
for (var j = 0; j <= n; j += 1) {
t = j / n;
((assign = getPointAtQuadSegmentLength(x1, y1, qx, qy, x2, y2, t), x = assign.x, y = assign.y));
totalLength += distanceSquareRoot(cur, [x, y]);
cur = [x, y];
if (typeof distance === 'number' && totalLength >= distance) {
var dv = (totalLength - distance) / (totalLength - prev[2]);
return {
x: cur[0] * (1 - dv) + prev[0] * dv,
y: cur[1] * (1 - dv) + prev[1] * dv,
};
}
prev = [x, y, totalLength];
}
if (typeof distance === 'number' && distance >= totalLength) {
return { x: x2, y: y2 };
}
return totalLength;
}
/**
* Returns a {x,y} point at a given length of a shape or the shape total length.
*
* @param {string | SVGPathCommander.pathArray} pathInput the `pathArray` to look into
* @param {number=} distance the length of the shape to look at
* @returns {{x: number, y: number} | number} the total length or point
*/
function pathLengthFactory(pathInput, distance) {
var assign, assign$1, assign$2;
var totalLength = 0;
var isM = true;
/** @type {number[]} */
var data = [];
var pathCommand = 'M';
var segLen = 0;
var x = 0;
var y = 0;
var mx = 0;
var my = 0;
var seg;
var path = fixPath(normalizePath(pathInput));
for (var i = 0, ll = path.length; i < ll; i += 1) {
seg = path[i];
(assign = seg, pathCommand = assign[0]);
isM = pathCommand === 'M';
// @ts-ignore
data = !isM ? [x, y ].concat( seg.slice(1)) : data;
// this segment is always ZERO
if (isM) {
// remember mx, my for Z
// @ts-ignore
(assign$1 = seg, mx = assign$1[1], my = assign$1[2]);
if (typeof distance === 'number' && distance < 0.001) {
return { x: mx, y: my };
}
} else if (pathCommand === 'L') {
// @ts-ignore
segLen = segmentLineFactory.apply(void 0, data);
if (distance && totalLength + segLen >= distance) {
// @ts-ignore
return segmentLineFactory.apply(void 0, data.concat( [distance - totalLength] ));
}
totalLength += segLen;
} else if (pathCommand === 'A') {
// @ts-ignore
segLen = segmentArcFactory.apply(void 0, data);
if (distance && totalLength + segLen >= distance) {
// @ts-ignore
return segmentArcFactory.apply(void 0, data.concat( [distance - totalLength] ));
}
totalLength += segLen;
} else if (pathCommand === 'C') {
// @ts-ignore
segLen = segmentCubicFactory.apply(void 0, data);
if (distance && totalLength + segLen >= distance) {
// @ts-ignore
return segmentCubicFactory.apply(void 0, data.concat( [distance - totalLength] ));
}
totalLength += segLen;
} else if (pathCommand === 'Q') {
// @ts-ignore
segLen = segmentQuadFactory.apply(void 0, data);
if (distance && totalLength + segLen >= distance) {
// @ts-ignore
return segmentQuadFactory.apply(void 0, data.concat( [distance - totalLength] ));
}
totalLength += segLen;
} else if (pathCommand === 'Z') {
data = [x, y, mx, my];
// @ts-ignore
segLen = segmentLineFactory.apply(void 0, data);
if (distance && totalLength + segLen >= distance) {
// @ts-ignore
return segmentLineFactory.apply(void 0, data.concat( [distance - totalLength] ));
}
totalLength += segLen;
}
// @ts-ignore -- needed for the below
(assign$2 = pathCommand !== 'Z' ? seg.slice(-2) : [mx, my], x = assign$2[0], y = assign$2[1]);
}
// native `getPointAtLength` behavior when the given distance
// is higher than total length
if (distance && distance >= totalLength) {
return { x: x, y: y };
}
return totalLength;
}
/**
* Returns the shape total length, or the equivalent to `shape.getTotalLength()`.
*
* The `normalizePath` version is lighter, faster, more efficient and more accurate
* with paths that are not `curveArray`.
*
* @param {string | SVGPathCommander.pathArray} pathInput the target `pathArray`
* @returns {number} the shape total length
*/
function getPathLength(path) {
var totalLength = 0;
pathToCurve(path).forEach(function (s, i, curveArray) {
var args = s[0] !== 'M' ? curveArray[i - 1].slice(-2).concat( s.slice(1)) : [];
totalLength += s[0] === 'M' ? 0
// @ts-ignore
: getSegCubicLength.apply(void 0, args);
});
return totalLength;
function getTotalLength(pathInput) {
// @ts-ignore - it's fine
return pathLengthFactory(pathInput);
}
/**
* Returns [x,y] coordinates of a point at a given length of a shape.
*
* @param {string | SVGPathCommander.pathArray} path the `pathArray` to look into
* @param {number} length the length of the shape to look at
* @returns {number[]} the requested [x,y] coordinates
* @param {string | SVGPathCommander.pathArray} pathInput the `pathArray` to look into
* @param {number} distance the length of the shape to look at
* @returns {{x: number, y: number}} the requested {x, y} point coordinates
*/
function getPointAtLength(path, length) {
var totalLength = 0;
var segLen;
var data;
var result;
function getPointAtLength(pathInput, distance) {
// @ts-ignore
return pathToCurve(path).map(function (seg, i, curveArray) {
data = i ? curveArray[i - 1].slice(-2).concat( seg.slice(1)) : seg.slice(1);
// @ts-ignore
segLen = i ? getSegCubicLength.apply(void 0, data) : 0;
totalLength += segLen;
return pathLengthFactory(pathInput, distance);
}
if (i === 0) {
result = { x: data[0], y: data[1] };
} else if (totalLength > length && length > totalLength - segLen) {
var args = data.concat( [1 - ((totalLength - length) / segLen)]);
/**
* d3-polygon-area
* https://github.com/d3/d3-polygon
*
* Returns the area of a polygon.
*
* @param {number[][]} polygon an array of coordinates
* @returns {number} the polygon area
*/
function polygonArea(polygon) {
var n = polygon.length;
var i = -1;
var a;
var b = polygon[n - 1];
var area = 0;
/* eslint-disable-next-line */
while (++i < n) {
a = b;
b = polygon[i];
area += a[1] * b[0] - a[0] * b[1];
}
return area / 2;
}
/**
* d3-polygon-length
* https://github.com/d3/d3-polygon
*
* Returns the perimeter of a polygon.
*
* @param {number[][]} polygon an array of coordinates
* @returns {number} the polygon length
*/
function polygonLength(polygon) {
return polygon.reduce(function (length, point, i) {
if (i) {
// @ts-ignore
result = getPointAtSegLength.apply(void 0, args);
} else {
result = null;
return length + distanceSquareRoot(polygon[i - 1], point);
}
return result;
}).filter(function (x) { return x; }).slice(-1)[0]; // isolate last segment
}
/**
* Returns the area of a single segment shape.
*
* http://objectmix.com/graphics/133553-area-closed-bezier-curve.html
*
* @param {number} x0 the starting point X
* @param {number} y0 the starting point Y
* @param {number} x1 the first control point X
* @param {number} y1 the first control point Y
* @param {number} x2 the second control point X
* @param {number} y2 the second control point Y
* @param {number} x3 the ending point X
* @param {number} y3 the ending point Y
* @returns {number} the area of the cubic-bezier segment
*/
function getCubicSegArea(x0, y0, x1, y1, x2, y2, x3, y3) {
return (3 * ((y3 - y0) * (x1 + x2) - (x3 - x0) * (y1 + y2)
+ (y1 * (x0 - x2)) - (x1 * (y0 - y2))
+ (y3 * (x2 + x0 / 3)) - (x3 * (y2 + y0 / 3)))) / 20;
}
/**
* Returns the area of a shape.
* @author Jürg Lehni & Jonathan Puckey
*
* => https://github.com/paperjs/paper.js/blob/develop/src/path/Path.js
*
* @param {SVGPathCommander.pathArray} path the shape `pathArray`
* @returns {number} the length of the cubic-bezier segment
*/
function getPathArea(path) {
var x = 0; var y = 0;
var len = 0;
return pathToCurve(path).map(function (seg) {
var assign, assign$1;
switch (seg[0]) {
case 'M':
(assign = seg, x = assign[1], y = assign[2]);
return 0;
default:
// @ts-ignore -- the utility will have proper amount of params
len = getCubicSegArea.apply(void 0, [ x, y ].concat( seg.slice(1) ));
(assign$1 = seg.slice(-2).map(Number), x = assign$1[0], y = assign$1[1]);
return len;
}
}).reduce(function (a, b) { return a + b; }, 0);
}
/**
* Check if a path is drawn clockwise and returns true if so,
* false otherwise.
*
* @param {SVGPathCommander.pathArray} path the path string or `pathArray`
* @returns {boolean} true when clockwise or false if not
*/
function getDrawDirection(path) {
return getPathArea(pathToCurve(path)) >= 0;
return 0;
}, 0);
}
/**
@ -3978,21 +4216,6 @@
*/
var epsilon = 1e-9;
/**
* Returns the square root of the distance
* between two given points.
*
* @param {[number, number]} a the first point coordinates
* @param {[number, number]} b the second point coordinates
* @returns {number} the distance value
*/
function distanceSquareRoot(a, b) {
return Math.sqrt(
(a[0] - b[0]) * (a[0] - b[0])
+ (a[1] - b[1]) * (a[1] - b[1])
);
}
/**
* Coordinates Interpolation Function.
*
@ -4040,17 +4263,6 @@
// original script flubber
// https://github.com/veltman/flubber
/**
* Returns polygon length.
* @param {KUTE.polygonMorph} polygon target polygon
* @returns {number} length
*/
function polygonLength(polygon) {
return polygon.reduce(function (length, point, i) { return (i
? length + distanceSquareRoot(polygon[i - 1], point)
: 0); }, 0);
}
/**
* Returns an existing polygin and its length or false if not polygon.
* @param {SVGPathCommander.pathArray} pathArray target polygon
@ -4092,8 +4304,8 @@
*/
function approximatePolygon(parsed, maxLength) {
var ringPath = splitPath(pathToString(parsed))[0];
var curvePath = pathToCurve(ringPath);
var pathLength = getPathLength(curvePath);
var normalPath = normalizePath(ringPath);
var pathLength = getTotalLength(normalPath);
var polygon = [];
var numPoints = 3;
var point;
@ -4103,12 +4315,12 @@
}
for (var i = 0; i < numPoints; i += 1) {
point = getPointAtLength(curvePath, (pathLength * i) / numPoints);
point = getPointAtLength(normalPath, (pathLength * i) / numPoints);
polygon.push([point.x, point.y]);
}
// Make all rings clockwise
if (!getDrawDirection(curvePath)) {
if (polygonArea(polygon) > 0) {
polygon.reverse();
}
@ -4396,9 +4608,9 @@
// svg-path-commander
pathToString: pathToString,
pathToCurve: pathToCurve,
getPathLength: getPathLength,
getTotalLength: getTotalLength,
getPointAtLength: getPointAtLength,
getDrawDirection: getDrawDirection,
polygonArea: polygonArea,
roundPath: roundPath,
},
};
@ -4420,7 +4632,7 @@
Components[component] = new Animation(compOps);
});
var version = "2.2.0";
var version = "2.2.2";
// @ts-ignore

4
dist/kute.min.js vendored

File diff suppressed because one or more lines are too long

View file

@ -1,6 +1,6 @@
{
"name": "kute.js",
"version": "2.2.0",
"version": "2.2.2",
"description": "JavaScript animation engine",
"main": "dist/kute.min.js",
"module": "dist/kute.esm.js",
@ -62,7 +62,7 @@
"cubic-bezier-easing": "^1.0.18",
"minifill": "^0.0.16",
"shorter-js": "^0.2.6",
"svg-path-commander": "0.1.20"
"svg-path-commander": "0.1.23"
},
"devDependencies": {
"@rollup/plugin-buble": "^0.21.3",

View file

@ -8,7 +8,7 @@ import clonePath from 'svg-path-commander/src/process/clonePath';
import splitCubic from 'svg-path-commander/src/process/splitCubic';
import splitPath from 'svg-path-commander/src/process/splitPath';
import fixPath from 'svg-path-commander/src/process/fixPath';
import getSegCubicLength from 'svg-path-commander/src/util/getSegCubicLength';
import segmentCubicFactory from 'svg-path-commander/src/util/segmentCubicFactory';
import distanceSquareRoot from 'svg-path-commander/src/math/distanceSquareRoot';
import { onStartCubicMorph } from './svgCubicMorphBase';
@ -25,7 +25,7 @@ function getCurveArray(source) {
return pathToCurve(splitPath(source)[0])
.map((segment, i, pathArray) => {
const segmentData = i && [...pathArray[i - 1].slice(-2), ...segment.slice(1)];
const curveLength = i ? getSegCubicLength(...segmentData) : 0;
const curveLength = i ? segmentCubicFactory(...segmentData) : 0;
let subsegs;
if (i) {
@ -218,6 +218,7 @@ const svgCubicMorph = {
reverseCurve,
clonePath,
getDrawDirection,
segmentCubicFactory,
splitCubic,
splitPath,
fixPath,

View file

@ -3,10 +3,11 @@ import pathToString from 'svg-path-commander/src/convert/pathToString';
import normalizePath from 'svg-path-commander/src/process/normalizePath';
import splitPath from 'svg-path-commander/src/process/splitPath';
import roundPath from 'svg-path-commander/src/process/roundPath';
import getTotalLength from 'svg-path-commander/src/util/getTotalLength';
import invalidPathValue from 'svg-path-commander/src/parser/invalidPathValue';
import getPathLength from 'svg-path-commander/src/util/getPathLength';
import getPointAtLength from 'svg-path-commander/src/util/getPointAtLength';
import getDrawDirection from 'svg-path-commander/src/util/getDrawDirection';
import polygonArea from 'svg-path-commander/src/math/polygonArea';
import polygonLength from 'svg-path-commander/src/math/polygonLength';
import epsilon from 'svg-path-commander/src/math/epsilon';
import midPoint from 'svg-path-commander/src/math/midPoint';
import distanceSquareRoot from 'svg-path-commander/src/math/distanceSquareRoot';
@ -19,17 +20,6 @@ import selector from '../util/selector';
// original script flubber
// https://github.com/veltman/flubber
/**
* Returns polygon length.
* @param {KUTE.polygonMorph} polygon target polygon
* @returns {number} length
*/
function polygonLength(polygon) {
return polygon.reduce((length, point, i) => (i
? length + distanceSquareRoot(polygon[i - 1], point)
: 0), 0);
}
/**
* Returns an existing polygin and its length or false if not polygon.
* @param {SVGPathCommander.pathArray} pathArray target polygon
@ -69,8 +59,8 @@ function exactPolygon(pathArray) {
*/
function approximatePolygon(parsed, maxLength) {
const ringPath = splitPath(pathToString(parsed))[0];
const curvePath = pathToCurve(ringPath);
const pathLength = getPathLength(curvePath);
const normalPath = normalizePath(ringPath);
const pathLength = getTotalLength(normalPath);
const polygon = [];
let numPoints = 3;
let point;
@ -80,12 +70,12 @@ function approximatePolygon(parsed, maxLength) {
}
for (let i = 0; i < numPoints; i += 1) {
point = getPointAtLength(curvePath, (pathLength * i) / numPoints);
point = getPointAtLength(normalPath, (pathLength * i) / numPoints);
polygon.push([point.x, point.y]);
}
// Make all rings clockwise
if (!getDrawDirection(curvePath)) {
if (polygonArea(polygon) > 0) {
polygon.reverse();
}
@ -367,9 +357,9 @@ const SVGMorph = {
// svg-path-commander
pathToString,
pathToCurve,
getPathLength,
getTotalLength,
getPointAtLength,
getDrawDirection,
polygonArea,
roundPath,
},
};

View file

@ -10,12 +10,12 @@
"strict": true,
"allowJs": true,
"rootDir": "../",
// "outFile": "types/kute.d.ts", // UN-comment to generate
"outFile": "types/kute.d.ts", // UN-comment to generate
"outDir": "types",
},
"files": [
"types/index.d.ts",
"types/kute.d.ts", // comment to re-generate, delete file
// "types/kute.d.ts", // comment to re-generate, delete file
// "types/more/kute.ts",
"types/more/types.d.ts",
],

1
types/index.d.ts vendored
View file

@ -3,6 +3,7 @@ export as namespace KUTE;
// dependencies
export * as SVGPathCommander from "svg-path-commander";
import './kute';
export { default as Animation } from "kute.js/src/animation/animation";
export { default as AnimationBase } from "kute.js/src/animation/animationBase";
export { default as AnimationDevelopment } from "kute.js/src/animation/animationDevelopment";