Updated to latest SVGPathCommander
This commit is contained in:
parent
5c8b75f15b
commit
3835b6e95c
|
@ -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
|
||||
|
||||
|
|
4
demo/src/kute-base.min.js
vendored
4
demo/src/kute-base.min.js
vendored
File diff suppressed because one or more lines are too long
|
@ -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
|
||||
|
||||
|
|
4
demo/src/kute-extra.min.js
vendored
4
demo/src/kute-extra.min.js
vendored
File diff suppressed because one or more lines are too long
4
demo/src/kute.min.js
vendored
4
demo/src/kute.min.js
vendored
File diff suppressed because one or more lines are too long
|
@ -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>
|
||||
|
|
638
dist/kute.esm.js
vendored
638
dist/kute.esm.js
vendored
|
@ -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)];
|
||||
// @ts-ignore
|
||||
result = getPointAtSegLength(...args);
|
||||
} else {
|
||||
result = null;
|
||||
/**
|
||||
* 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 result;
|
||||
}).filter((x) => x).slice(-1)[0]; // isolate last segment
|
||||
return area / 2;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the area of a single segment shape.
|
||||
* d3-polygon-length
|
||||
* https://github.com/d3/d3-polygon
|
||||
*
|
||||
* http://objectmix.com/graphics/133553-area-closed-bezier-curve.html
|
||||
* Returns the perimeter of a polygon.
|
||||
*
|
||||
* @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
|
||||
* @param {number[][]} polygon an array of coordinates
|
||||
* @returns {number} the polygon length
|
||||
*/
|
||||
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;
|
||||
function polygonLength(polygon) {
|
||||
return polygon.reduce((length, point, i) => {
|
||||
if (i) {
|
||||
// @ts-ignore
|
||||
return length + distanceSquareRoot(polygon[i - 1], point);
|
||||
}
|
||||
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;
|
||||
}, 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
|
||||
|
||||
|
|
4
dist/kute.esm.min.js
vendored
4
dist/kute.esm.min.js
vendored
File diff suppressed because one or more lines are too long
646
dist/kute.js
vendored
646
dist/kute.js
vendored
|
@ -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;
|
||||
|
||||
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)]);
|
||||
// @ts-ignore
|
||||
result = getPointAtSegLength.apply(void 0, args);
|
||||
} else {
|
||||
result = null;
|
||||
}
|
||||
|
||||
return result;
|
||||
}).filter(function (x) { return x; }).slice(-1)[0]; // isolate last segment
|
||||
return pathLengthFactory(pathInput, distance);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the area of a single segment shape.
|
||||
* d3-polygon-area
|
||||
* https://github.com/d3/d3-polygon
|
||||
*
|
||||
* http://objectmix.com/graphics/133553-area-closed-bezier-curve.html
|
||||
* Returns the area of a polygon.
|
||||
*
|
||||
* @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
|
||||
* @param {number[][]} polygon an array of coordinates
|
||||
* @returns {number} the polygon area
|
||||
*/
|
||||
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 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the area of a shape.
|
||||
* @author Jürg Lehni & Jonathan Puckey
|
||||
* d3-polygon-length
|
||||
* https://github.com/d3/d3-polygon
|
||||
*
|
||||
* => https://github.com/paperjs/paper.js/blob/develop/src/path/Path.js
|
||||
* Returns the perimeter of a polygon.
|
||||
*
|
||||
* @param {SVGPathCommander.pathArray} path the shape `pathArray`
|
||||
* @returns {number} the length of the cubic-bezier segment
|
||||
* @param {number[][]} polygon an array of coordinates
|
||||
* @returns {number} the polygon length
|
||||
*/
|
||||
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]);
|
||||
function polygonLength(polygon) {
|
||||
return polygon.reduce(function (length, point, i) {
|
||||
if (i) {
|
||||
// @ts-ignore
|
||||
return length + distanceSquareRoot(polygon[i - 1], point);
|
||||
}
|
||||
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;
|
||||
}, 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
4
dist/kute.min.js
vendored
File diff suppressed because one or more lines are too long
|
@ -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",
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
},
|
||||
};
|
||||
|
|
|
@ -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
1
types/index.d.ts
vendored
|
@ -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";
|
||||
|
|
Loading…
Reference in a new issue