svg-path-commander 2.1.2 → 2.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -4
- package/dist/svg-path-commander.cjs +1 -1
- package/dist/svg-path-commander.cjs.map +1 -1
- package/dist/svg-path-commander.d.ts +755 -849
- package/dist/svg-path-commander.js +1 -1
- package/dist/svg-path-commander.js.map +1 -1
- package/dist/svg-path-commander.mjs +947 -611
- package/dist/svg-path-commander.mjs.map +1 -1
- package/package.json +14 -22
- package/.eslintrc.cjs +0 -225
- package/.prettierrc.json +0 -15
- package/dts.config.ts +0 -15
- package/src/convert/pathToAbsolute.ts +0 -18
- package/src/convert/pathToCurve.ts +0 -43
- package/src/convert/pathToRelative.ts +0 -18
- package/src/convert/pathToString.ts +0 -50
- package/src/index.ts +0 -454
- package/src/interface.ts +0 -130
- package/src/math/arcTools.ts +0 -396
- package/src/math/bezier.ts +0 -261
- package/src/math/cubicTools.ts +0 -124
- package/src/math/distanceSquareRoot.ts +0 -15
- package/src/math/lineTools.ts +0 -69
- package/src/math/midPoint.ts +0 -18
- package/src/math/polygonTools.ts +0 -48
- package/src/math/quadTools.ts +0 -100
- package/src/math/rotateVector.ts +0 -17
- package/src/math/roundTo.ts +0 -7
- package/src/options/options.ts +0 -9
- package/src/parser/error.ts +0 -2
- package/src/parser/finalizeSegment.ts +0 -35
- package/src/parser/invalidPathValue.ts +0 -2
- package/src/parser/isArcCommand.ts +0 -11
- package/src/parser/isDigit.ts +0 -12
- package/src/parser/isDigitStart.ts +0 -14
- package/src/parser/isMoveCommand.ts +0 -17
- package/src/parser/isPathCommand.ts +0 -28
- package/src/parser/isSpace.ts +0 -23
- package/src/parser/paramsCount.ts +0 -16
- package/src/parser/paramsParser.ts +0 -14
- package/src/parser/parsePathString.ts +0 -33
- package/src/parser/pathParser.ts +0 -29
- package/src/parser/scanFlag.ts +0 -29
- package/src/parser/scanParam.ts +0 -102
- package/src/parser/scanSegment.ts +0 -84
- package/src/parser/skipSpaces.ts +0 -17
- package/src/process/absolutizeSegment.ts +0 -63
- package/src/process/arcToCubic.ts +0 -128
- package/src/process/getSVGMatrix.ts +0 -70
- package/src/process/iterate.ts +0 -58
- package/src/process/lineToCubic.ts +0 -17
- package/src/process/normalizePath.ts +0 -33
- package/src/process/normalizeSegment.ts +0 -84
- package/src/process/optimizePath.ts +0 -63
- package/src/process/projection2d.ts +0 -52
- package/src/process/quadToCubic.ts +0 -31
- package/src/process/relativizeSegment.ts +0 -59
- package/src/process/reverseCurve.ts +0 -24
- package/src/process/reversePath.ts +0 -114
- package/src/process/roundPath.ts +0 -33
- package/src/process/roundSegment.ts +0 -9
- package/src/process/segmentToCubic.ts +0 -48
- package/src/process/shortenSegment.ts +0 -71
- package/src/process/splitCubic.ts +0 -29
- package/src/process/splitPath.ts +0 -63
- package/src/process/transformPath.ts +0 -110
- package/src/types.ts +0 -228
- package/src/util/distanceEpsilon.ts +0 -3
- package/src/util/getClosestPoint.ts +0 -15
- package/src/util/getDrawDirection.ts +0 -16
- package/src/util/getPathArea.ts +0 -70
- package/src/util/getPathBBox.ts +0 -98
- package/src/util/getPointAtLength.ts +0 -110
- package/src/util/getPropertiesAtLength.ts +0 -67
- package/src/util/getPropertiesAtPoint.ts +0 -84
- package/src/util/getSegmentAtLength.ts +0 -15
- package/src/util/getSegmentOfPoint.ts +0 -18
- package/src/util/getTotalLength.ts +0 -68
- package/src/util/isAbsoluteArray.ts +0 -18
- package/src/util/isCurveArray.ts +0 -15
- package/src/util/isNormalizedArray.ts +0 -16
- package/src/util/isPathArray.ts +0 -24
- package/src/util/isPointInStroke.ts +0 -16
- package/src/util/isRelativeArray.ts +0 -18
- package/src/util/isValidPath.ts +0 -27
- package/src/util/shapeParams.ts +0 -16
- package/src/util/shapeToPath.ts +0 -86
- package/src/util/shapeToPathArray.ts +0 -183
- package/test/class.test.ts +0 -504
- package/test/fixtures/getMarkup.ts +0 -17
- package/test/fixtures/shapeObjects.ts +0 -11
- package/test/fixtures/shapes.js +0 -104
- package/test/fixtures/simpleShapes.js +0 -75
- package/test/static.test.ts +0 -330
- package/vite.config.mts +0 -41
- package/vitest.config-ui.mts +0 -26
- package/vitest.config.mts +0 -26
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
import pathToAbsolute from '../convert/pathToAbsolute';
|
|
2
|
-
import shortenSegment from './shortenSegment';
|
|
3
|
-
import paramsParser from '../parser/paramsParser';
|
|
4
|
-
import type { AbsoluteSegment, PathArray, PathCommand } from '../types';
|
|
5
|
-
import iterate from './iterate';
|
|
6
|
-
import normalizeSegment from './normalizeSegment';
|
|
7
|
-
import relativizeSegment from './relativizeSegment';
|
|
8
|
-
import roundSegment from './roundSegment';
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* Optimizes a `pathArray` object:
|
|
12
|
-
* * convert segments to shorthand if possible
|
|
13
|
-
* * select shortest segments from absolute and relative `pathArray`s
|
|
14
|
-
*
|
|
15
|
-
* @param pathInput a string or `pathArray`
|
|
16
|
-
* @param roundOption the amount of decimals to round values to
|
|
17
|
-
* @returns the optimized `pathArray`
|
|
18
|
-
*/
|
|
19
|
-
const optimizePath = (pathInput: PathArray, roundOption: number) => {
|
|
20
|
-
const path = pathToAbsolute(pathInput);
|
|
21
|
-
// allow for ZERO decimals or use an aggressive value of 2
|
|
22
|
-
const round =
|
|
23
|
-
typeof roundOption === 'number' && roundOption >= 0 ? roundOption : /* istanbul ignore next @preserve */ 2;
|
|
24
|
-
// this utility overrides the iterator params
|
|
25
|
-
const optimParams = { ...paramsParser };
|
|
26
|
-
|
|
27
|
-
const allPathCommands = [] as PathCommand[];
|
|
28
|
-
let pathCommand = 'M' as PathCommand;
|
|
29
|
-
let prevCommand = 'Z' as PathCommand;
|
|
30
|
-
|
|
31
|
-
return iterate(path, (seg, i, lastX, lastY) => {
|
|
32
|
-
optimParams.x = lastX;
|
|
33
|
-
optimParams.y = lastY;
|
|
34
|
-
// const absoluteSegment = absolutizeSegment(seg, optimParams);
|
|
35
|
-
const normalizedSegment = normalizeSegment(seg, optimParams);
|
|
36
|
-
let result = seg;
|
|
37
|
-
[pathCommand] = seg;
|
|
38
|
-
|
|
39
|
-
// Save current path command
|
|
40
|
-
allPathCommands[i] = pathCommand;
|
|
41
|
-
if (i) {
|
|
42
|
-
// Get previous path command for `shortenSegment`
|
|
43
|
-
prevCommand = allPathCommands[i - 1];
|
|
44
|
-
const shortSegment = shortenSegment(seg as AbsoluteSegment, normalizedSegment, optimParams, prevCommand);
|
|
45
|
-
const absSegment = roundSegment(shortSegment, round);
|
|
46
|
-
const absString = absSegment.join('');
|
|
47
|
-
const relativeSegment = relativizeSegment(shortSegment, i, lastX, lastY);
|
|
48
|
-
const relSegment = roundSegment(relativeSegment, round);
|
|
49
|
-
const relString = relSegment.join('');
|
|
50
|
-
result = absString.length < relString.length ? absSegment : relSegment;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
const seglen = normalizedSegment.length;
|
|
54
|
-
optimParams.x1 = +normalizedSegment[seglen - 2];
|
|
55
|
-
optimParams.y1 = +normalizedSegment[seglen - 1];
|
|
56
|
-
optimParams.x2 = +normalizedSegment[seglen - 4] || optimParams.x1;
|
|
57
|
-
optimParams.y2 = +normalizedSegment[seglen - 3] || optimParams.y1;
|
|
58
|
-
|
|
59
|
-
return result;
|
|
60
|
-
});
|
|
61
|
-
};
|
|
62
|
-
|
|
63
|
-
export default optimizePath;
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
import CSSMatrix from '@thednp/dommatrix';
|
|
2
|
-
import { type PointTuple } from '../types';
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Transforms a specified point using a matrix, returning a new
|
|
6
|
-
* Tuple *Object* comprising of the transformed point.
|
|
7
|
-
* Neither the matrix nor the original point are altered.
|
|
8
|
-
*
|
|
9
|
-
* @copyright thednp © 2021
|
|
10
|
-
*
|
|
11
|
-
* @param cssm CSSMatrix instance
|
|
12
|
-
* @param v Tuple
|
|
13
|
-
* @return the resulting Tuple
|
|
14
|
-
*/
|
|
15
|
-
const translatePoint = (cssm: CSSMatrix, v: [number, number, number, number]): [number, number, number, number] => {
|
|
16
|
-
let m = CSSMatrix.Translate(v[0], v[1], v[2]);
|
|
17
|
-
|
|
18
|
-
[, , , m.m44] = v;
|
|
19
|
-
m = cssm.multiply(m);
|
|
20
|
-
|
|
21
|
-
return [m.m41, m.m42, m.m43, m.m44];
|
|
22
|
-
};
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* Returns the [x,y] projected coordinates for a given an [x,y] point
|
|
26
|
-
* and an [x,y,z] perspective origin point.
|
|
27
|
-
*
|
|
28
|
-
* Equation found here =>
|
|
29
|
-
* http://en.wikipedia.org/wiki/3D_projection#Diagram
|
|
30
|
-
* Details =>
|
|
31
|
-
* https://stackoverflow.com/questions/23792505/predicted-rendering-of-css-3d-transformed-pixel
|
|
32
|
-
*
|
|
33
|
-
* @param m the transformation matrix
|
|
34
|
-
* @param point2D the initial [x,y] coordinates
|
|
35
|
-
* @param origin the [x,y,z] transform origin
|
|
36
|
-
* @returns the projected [x,y] coordinates
|
|
37
|
-
*/
|
|
38
|
-
const projection2d = (m: CSSMatrix, point2D: PointTuple, origin: [number, number, number]): PointTuple => {
|
|
39
|
-
const [originX, originY, originZ] = origin;
|
|
40
|
-
const [x, y, z] = translatePoint(m, [point2D[0], point2D[1], 0, 1]);
|
|
41
|
-
|
|
42
|
-
const relativePositionX = x - originX;
|
|
43
|
-
const relativePositionY = y - originY;
|
|
44
|
-
const relativePositionZ = z - originZ;
|
|
45
|
-
|
|
46
|
-
return [
|
|
47
|
-
// protect against division by ZERO
|
|
48
|
-
relativePositionX * (Math.abs(originZ) / Math.abs(relativePositionZ) || 1) + originX,
|
|
49
|
-
relativePositionY * (Math.abs(originZ) / Math.abs(relativePositionZ) || 1) + originY,
|
|
50
|
-
];
|
|
51
|
-
};
|
|
52
|
-
export default projection2d;
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Converts a Q (quadratic-bezier) segment to C (cubic-bezier).
|
|
3
|
-
*
|
|
4
|
-
* @param x1 curve start x
|
|
5
|
-
* @param y1 curve start y
|
|
6
|
-
* @param qx control point x
|
|
7
|
-
* @param qy control point y
|
|
8
|
-
* @param x2 curve end x
|
|
9
|
-
* @param y2 curve end y
|
|
10
|
-
* @returns the cubic-bezier segment
|
|
11
|
-
*/
|
|
12
|
-
const quadToCubic = (
|
|
13
|
-
x1: number,
|
|
14
|
-
y1: number,
|
|
15
|
-
qx: number,
|
|
16
|
-
qy: number,
|
|
17
|
-
x2: number,
|
|
18
|
-
y2: number,
|
|
19
|
-
): [number, number, number, number, number, number] => {
|
|
20
|
-
const r13 = 1 / 3;
|
|
21
|
-
const r23 = 2 / 3;
|
|
22
|
-
return [
|
|
23
|
-
r13 * x1 + r23 * qx, // cpx1
|
|
24
|
-
r13 * y1 + r23 * qy, // cpy1
|
|
25
|
-
r13 * x2 + r23 * qx, // cpx2
|
|
26
|
-
r13 * y2 + r23 * qy, // cpy2
|
|
27
|
-
x2,
|
|
28
|
-
y2, // x,y
|
|
29
|
-
];
|
|
30
|
-
};
|
|
31
|
-
export default quadToCubic;
|
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
RelativeSegment,
|
|
3
|
-
RelativeCommand,
|
|
4
|
-
PathSegment,
|
|
5
|
-
aSegment,
|
|
6
|
-
vSegment,
|
|
7
|
-
hSegment,
|
|
8
|
-
qSegment,
|
|
9
|
-
tSegment,
|
|
10
|
-
sSegment,
|
|
11
|
-
cSegment,
|
|
12
|
-
MSegment,
|
|
13
|
-
lSegment,
|
|
14
|
-
} from '../types';
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* Returns a relative segment of a `PathArray` object.
|
|
18
|
-
*
|
|
19
|
-
* @param segment the segment object
|
|
20
|
-
* @param index the segment index
|
|
21
|
-
* @param lastX the last known X value
|
|
22
|
-
* @param lastY the last known Y value
|
|
23
|
-
* @returns the relative segment
|
|
24
|
-
*/
|
|
25
|
-
const relativizeSegment = (segment: PathSegment, index: number, lastX: number, lastY: number) => {
|
|
26
|
-
const [pathCommand] = segment;
|
|
27
|
-
const relCommand = pathCommand.toLowerCase() as RelativeCommand;
|
|
28
|
-
const isRelative = pathCommand === relCommand;
|
|
29
|
-
|
|
30
|
-
/* istanbul ignore else @preserve */
|
|
31
|
-
if (index === 0 || isRelative) return segment as MSegment | RelativeSegment;
|
|
32
|
-
|
|
33
|
-
if (relCommand === 'a') {
|
|
34
|
-
return [
|
|
35
|
-
relCommand,
|
|
36
|
-
segment[1],
|
|
37
|
-
segment[2],
|
|
38
|
-
segment[3],
|
|
39
|
-
segment[4],
|
|
40
|
-
segment[5],
|
|
41
|
-
(segment as aSegment)[6] - lastX,
|
|
42
|
-
(segment as aSegment)[7] - lastY,
|
|
43
|
-
] as aSegment;
|
|
44
|
-
} else if (relCommand === 'v') {
|
|
45
|
-
return [relCommand, (segment as vSegment)[1] - lastY] as vSegment;
|
|
46
|
-
} else if (relCommand === 'h') {
|
|
47
|
-
return [relCommand, (segment as hSegment)[1] - lastX] as hSegment;
|
|
48
|
-
} else if (relCommand === 'l') {
|
|
49
|
-
return [relCommand, (segment as lSegment)[1] - lastX, (segment as lSegment)[2] - lastY] as lSegment;
|
|
50
|
-
} else {
|
|
51
|
-
// use brakets for `eslint: no-case-declaration`
|
|
52
|
-
// https://stackoverflow.com/a/50753272/803358
|
|
53
|
-
const relValues = (segment.slice(1) as number[]).map((n, j) => n - (j % 2 ? lastY : lastX));
|
|
54
|
-
// for c, s, q, t
|
|
55
|
-
return [relCommand as RelativeCommand | number].concat(relValues) as qSegment | tSegment | sSegment | cSegment;
|
|
56
|
-
}
|
|
57
|
-
};
|
|
58
|
-
|
|
59
|
-
export default relativizeSegment;
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import type { CSegment, CurveArray, MSegment, PathCommand } from '../types';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Reverses all segments of a `pathArray`
|
|
5
|
-
* which consists of only C (cubic-bezier) path commands.
|
|
6
|
-
*
|
|
7
|
-
* @param path the source `pathArray`
|
|
8
|
-
* @returns the reversed `pathArray`
|
|
9
|
-
*/
|
|
10
|
-
const reverseCurve = (path: CurveArray) => {
|
|
11
|
-
const rotatedCurve = path
|
|
12
|
-
.slice(1)
|
|
13
|
-
.map((x, i, curveOnly) =>
|
|
14
|
-
!i ? path[0].slice(1).concat(x.slice(1) as number[]) : curveOnly[i - 1].slice(-2).concat(x.slice(1)),
|
|
15
|
-
)
|
|
16
|
-
.map(x => x.map((_, i) => x[x.length - i - 2 * (1 - (i % 2))]))
|
|
17
|
-
.reverse() as (MSegment | CSegment)[];
|
|
18
|
-
|
|
19
|
-
return [['M' as PathCommand | number].concat(rotatedCurve[0].slice(0, 2))].concat(
|
|
20
|
-
rotatedCurve.map(x => ['C' as PathCommand | number].concat(x.slice(2))),
|
|
21
|
-
) as CurveArray;
|
|
22
|
-
};
|
|
23
|
-
|
|
24
|
-
export default reverseCurve;
|
|
@@ -1,114 +0,0 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
ASegment,
|
|
3
|
-
CSegment,
|
|
4
|
-
HSegment,
|
|
5
|
-
MSegment,
|
|
6
|
-
PathArray,
|
|
7
|
-
PathSegment,
|
|
8
|
-
PointTuple,
|
|
9
|
-
QSegment,
|
|
10
|
-
SSegment,
|
|
11
|
-
TSegment,
|
|
12
|
-
VSegment,
|
|
13
|
-
} from '../types';
|
|
14
|
-
import pathToAbsolute from '../convert/pathToAbsolute';
|
|
15
|
-
import normalizePath from './normalizePath';
|
|
16
|
-
import iterate from './iterate';
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* Reverses all segments of a `pathArray` and returns a new `pathArray` instance
|
|
20
|
-
* with absolute values.
|
|
21
|
-
*
|
|
22
|
-
* @param pathInput the source `pathArray`
|
|
23
|
-
* @returns the reversed `pathArray`
|
|
24
|
-
*/
|
|
25
|
-
const reversePath = (pathInput: PathArray) => {
|
|
26
|
-
const absolutePath = pathToAbsolute(pathInput);
|
|
27
|
-
const normalizedPath = normalizePath(absolutePath);
|
|
28
|
-
const pLen = absolutePath.length;
|
|
29
|
-
const isClosed = absolutePath[pLen - 1][0] === 'Z';
|
|
30
|
-
|
|
31
|
-
const reversedPath = iterate(absolutePath, (segment, i) => {
|
|
32
|
-
const normalizedSegment = normalizedPath[i];
|
|
33
|
-
const prevSeg = i && absolutePath[i - 1];
|
|
34
|
-
const prevCommand = prevSeg && prevSeg[0];
|
|
35
|
-
const nextSeg = absolutePath[i + 1];
|
|
36
|
-
const nextCommand = nextSeg && nextSeg[0];
|
|
37
|
-
const [pathCommand] = segment;
|
|
38
|
-
const [x, y] = normalizedPath[i ? i - 1 : pLen - 1].slice(-2) as PointTuple;
|
|
39
|
-
let result = segment;
|
|
40
|
-
|
|
41
|
-
switch (pathCommand) {
|
|
42
|
-
case 'M':
|
|
43
|
-
result = (isClosed ? ['Z'] : [pathCommand, x, y]) as PathSegment;
|
|
44
|
-
break;
|
|
45
|
-
case 'A':
|
|
46
|
-
result = [
|
|
47
|
-
pathCommand,
|
|
48
|
-
segment[1],
|
|
49
|
-
segment[2],
|
|
50
|
-
segment[3],
|
|
51
|
-
segment[4],
|
|
52
|
-
segment[5] === 1 ? 0 : 1,
|
|
53
|
-
x,
|
|
54
|
-
y,
|
|
55
|
-
] as ASegment;
|
|
56
|
-
break;
|
|
57
|
-
case 'C':
|
|
58
|
-
if (nextSeg && nextCommand === 'S') {
|
|
59
|
-
result = ['S', segment[1], segment[2], x, y] as SSegment;
|
|
60
|
-
} else {
|
|
61
|
-
result = [pathCommand, segment[3], segment[4], segment[1], segment[2], x, y] as CSegment;
|
|
62
|
-
}
|
|
63
|
-
break;
|
|
64
|
-
case 'S':
|
|
65
|
-
if (prevCommand && 'CS'.includes(prevCommand) && (!nextSeg || nextCommand !== 'S')) {
|
|
66
|
-
result = [
|
|
67
|
-
'C',
|
|
68
|
-
normalizedSegment[3],
|
|
69
|
-
normalizedSegment[4],
|
|
70
|
-
normalizedSegment[1],
|
|
71
|
-
normalizedSegment[2],
|
|
72
|
-
x,
|
|
73
|
-
y,
|
|
74
|
-
] as CSegment;
|
|
75
|
-
} else {
|
|
76
|
-
result = [pathCommand, normalizedSegment[1], normalizedSegment[2], x, y] as SSegment;
|
|
77
|
-
}
|
|
78
|
-
break;
|
|
79
|
-
case 'Q':
|
|
80
|
-
if (nextSeg && nextCommand === 'T') {
|
|
81
|
-
result = ['T', x, y] as TSegment;
|
|
82
|
-
} else {
|
|
83
|
-
result = [pathCommand, segment[1], segment[2], x, y] as QSegment;
|
|
84
|
-
}
|
|
85
|
-
break;
|
|
86
|
-
case 'T':
|
|
87
|
-
if (prevCommand && 'QT'.includes(prevCommand) && (!nextSeg || nextCommand !== 'T')) {
|
|
88
|
-
result = ['Q', normalizedSegment[1], normalizedSegment[2], x, y] as QSegment;
|
|
89
|
-
} else {
|
|
90
|
-
result = [pathCommand, x, y] as TSegment;
|
|
91
|
-
}
|
|
92
|
-
break;
|
|
93
|
-
case 'Z':
|
|
94
|
-
result = ['M', x, y] as MSegment;
|
|
95
|
-
break;
|
|
96
|
-
case 'H':
|
|
97
|
-
result = [pathCommand, x] as HSegment;
|
|
98
|
-
break;
|
|
99
|
-
case 'V':
|
|
100
|
-
result = [pathCommand, y] as VSegment;
|
|
101
|
-
break;
|
|
102
|
-
default:
|
|
103
|
-
result = [pathCommand as typeof pathCommand | number].concat(segment.slice(1, -2), x, y) as PathSegment;
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
return result;
|
|
107
|
-
});
|
|
108
|
-
|
|
109
|
-
return (
|
|
110
|
-
isClosed ? reversedPath.reverse() : [reversedPath[0] as PathSegment].concat(reversedPath.slice(1).reverse())
|
|
111
|
-
) as PathArray;
|
|
112
|
-
};
|
|
113
|
-
|
|
114
|
-
export default reversePath;
|
package/src/process/roundPath.ts
DELETED
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
import type { PathArray } from '../types';
|
|
2
|
-
import defaultOptions from '../options/options';
|
|
3
|
-
import iterate from './iterate';
|
|
4
|
-
import roundSegment from './roundSegment';
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Rounds the values of a `pathArray` instance to
|
|
8
|
-
* a specified amount of decimals and returns it.
|
|
9
|
-
*
|
|
10
|
-
* @param path the source `pathArray`
|
|
11
|
-
* @param roundOption the amount of decimals to round numbers to
|
|
12
|
-
* @returns the resulted `pathArray` with rounded values
|
|
13
|
-
*/
|
|
14
|
-
const roundPath = (path: PathArray, roundOption?: number | 'off') => {
|
|
15
|
-
let { round } = defaultOptions;
|
|
16
|
-
// allow for ZERO decimals
|
|
17
|
-
round =
|
|
18
|
-
roundOption === 'off'
|
|
19
|
-
? roundOption
|
|
20
|
-
: typeof roundOption === 'number' && roundOption >= 0
|
|
21
|
-
? roundOption
|
|
22
|
-
: typeof round === 'number' && round >= 0
|
|
23
|
-
? round
|
|
24
|
-
: /* istanbul ignore next @preserve */ 'off';
|
|
25
|
-
|
|
26
|
-
/* istanbul ignore else @preserve */
|
|
27
|
-
if (round === 'off') return path.slice(0) as PathArray;
|
|
28
|
-
|
|
29
|
-
return iterate<typeof path>(path, segment => {
|
|
30
|
-
return roundSegment(segment, round);
|
|
31
|
-
});
|
|
32
|
-
};
|
|
33
|
-
export default roundPath;
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import type { PathCommand, PathSegment } from '../types';
|
|
2
|
-
import roundTo from '../math/roundTo';
|
|
3
|
-
|
|
4
|
-
const roundSegment = <T extends PathSegment>(segment: T, roundOption: number) => {
|
|
5
|
-
const values = (segment.slice(1) as number[]).map(n => roundTo(n, roundOption));
|
|
6
|
-
return [segment[0] as PathCommand | number].concat(values) as T;
|
|
7
|
-
};
|
|
8
|
-
|
|
9
|
-
export default roundSegment;
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
import arcToCubic from './arcToCubic';
|
|
2
|
-
import quadToCubic from './quadToCubic';
|
|
3
|
-
import lineToCubic from './lineToCubic';
|
|
4
|
-
import type { CSegment, MSegment, PathSegment } from '../types';
|
|
5
|
-
import type { ParserParams } from '../interface';
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* Converts any segment to C (cubic-bezier).
|
|
9
|
-
*
|
|
10
|
-
* @param segment the source segment
|
|
11
|
-
* @param params the source segment parameters
|
|
12
|
-
* @returns the cubic-bezier segment
|
|
13
|
-
*/
|
|
14
|
-
const segmentToCubic = (segment: PathSegment, params: ParserParams) => {
|
|
15
|
-
const [pathCommand] = segment;
|
|
16
|
-
const values = segment.slice(1).map(Number);
|
|
17
|
-
const [x, y] = values;
|
|
18
|
-
// let args;
|
|
19
|
-
const { x1: px1, y1: py1, x: px, y: py } = params;
|
|
20
|
-
|
|
21
|
-
if (!'TQ'.includes(pathCommand)) {
|
|
22
|
-
params.qx = null;
|
|
23
|
-
params.qy = null;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
if (pathCommand === 'M') {
|
|
27
|
-
params.x = x;
|
|
28
|
-
params.y = y;
|
|
29
|
-
return segment;
|
|
30
|
-
} else if (pathCommand === 'A') {
|
|
31
|
-
return ['C' as string | number].concat(
|
|
32
|
-
arcToCubic(px1, py1, values[0], values[1], values[2], values[3], values[4], values[5], values[6]),
|
|
33
|
-
) as CSegment;
|
|
34
|
-
} else if (pathCommand === 'Q') {
|
|
35
|
-
params.qx = x;
|
|
36
|
-
params.qy = y;
|
|
37
|
-
return ['C' as string | number].concat(
|
|
38
|
-
quadToCubic(px1, py1, values[0], values[1], values[2], values[3]),
|
|
39
|
-
) as CSegment;
|
|
40
|
-
} else if (pathCommand === 'L') {
|
|
41
|
-
return ['C' as string | number].concat(lineToCubic(px1, py1, x, y)) as CSegment;
|
|
42
|
-
} else if (pathCommand === 'Z') {
|
|
43
|
-
return ['C' as string | number].concat(lineToCubic(px1, py1, px, py)) as CSegment;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
return segment as MSegment | CSegment;
|
|
47
|
-
};
|
|
48
|
-
export default segmentToCubic;
|
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
import defaultOptions from '../options/options';
|
|
2
|
-
import type { ParserParams } from '../interface';
|
|
3
|
-
import roundTo from '../math/roundTo';
|
|
4
|
-
import type { AbsoluteSegment, NormalSegment, PathCommand, ShortSegment, SSegment, TSegment } from '../types';
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Shorten a single segment of a `pathArray` object.
|
|
8
|
-
*
|
|
9
|
-
* @param segment the `absoluteSegment` object
|
|
10
|
-
* @param normalSegment the `normalSegment` object
|
|
11
|
-
* @param params the coordinates of the previous segment
|
|
12
|
-
* @param prevCommand the path command of the previous segment
|
|
13
|
-
* @returns the shortened segment
|
|
14
|
-
*/
|
|
15
|
-
const shortenSegment = (
|
|
16
|
-
segment: AbsoluteSegment,
|
|
17
|
-
normalSegment: NormalSegment,
|
|
18
|
-
params: ParserParams,
|
|
19
|
-
prevCommand: PathCommand,
|
|
20
|
-
): ShortSegment => {
|
|
21
|
-
const [pathCommand] = segment;
|
|
22
|
-
const { round: defaultRound } = defaultOptions;
|
|
23
|
-
const round = typeof defaultRound === 'number' ? defaultRound : /* istanbul ignore next */ 4;
|
|
24
|
-
const normalValues = normalSegment.slice(1) as number[];
|
|
25
|
-
const { x1, y1, x2, y2, x, y } = params;
|
|
26
|
-
const [nx, ny] = normalValues.slice(-2);
|
|
27
|
-
const result = segment;
|
|
28
|
-
|
|
29
|
-
if (!'TQ'.includes(pathCommand)) {
|
|
30
|
-
// optional but good to be cautious
|
|
31
|
-
params.qx = null;
|
|
32
|
-
params.qy = null;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
if (pathCommand === 'L') {
|
|
36
|
-
if (roundTo(x, round) === roundTo(nx, round)) {
|
|
37
|
-
return ['V', ny];
|
|
38
|
-
} else if (roundTo(y, round) === roundTo(ny, round)) {
|
|
39
|
-
return ['H', nx];
|
|
40
|
-
}
|
|
41
|
-
} else if (pathCommand === 'C') {
|
|
42
|
-
const [nx1, ny1] = normalValues;
|
|
43
|
-
params.x1 = nx1;
|
|
44
|
-
params.y1 = ny1;
|
|
45
|
-
|
|
46
|
-
if (
|
|
47
|
-
'CS'.includes(prevCommand) &&
|
|
48
|
-
((roundTo(nx1, round) === roundTo(x1 * 2 - x2, round) && roundTo(ny1, round) === roundTo(y1 * 2 - y2, round)) ||
|
|
49
|
-
(roundTo(x1, round) === roundTo(x2 * 2 - x, round) && roundTo(y1, round) === roundTo(y2 * 2 - y, round)))
|
|
50
|
-
) {
|
|
51
|
-
return ['S', normalValues[2], normalValues[3], normalValues[4], normalValues[5]] as SSegment;
|
|
52
|
-
}
|
|
53
|
-
} else if (pathCommand === 'Q') {
|
|
54
|
-
const [qx, qy] = normalValues;
|
|
55
|
-
params.qx = qx;
|
|
56
|
-
params.qy = qy;
|
|
57
|
-
|
|
58
|
-
if (
|
|
59
|
-
'QT'.includes(prevCommand) &&
|
|
60
|
-
roundTo(qx, round) === roundTo(x1 * 2 - x2, round) &&
|
|
61
|
-
roundTo(qy, round) === roundTo(y1 * 2 - y2, round)
|
|
62
|
-
) {
|
|
63
|
-
return ['T', normalValues[2], normalValues[3]] as TSegment;
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
// ['V', 'H', 'S', 'T', 'Z'].includes(pathCommand)
|
|
68
|
-
return result as ShortSegment;
|
|
69
|
-
};
|
|
70
|
-
|
|
71
|
-
export default shortenSegment;
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
import midPoint from '../math/midPoint';
|
|
2
|
-
import type { CubicSegment, PointTuple } from '../types';
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Split a cubic-bezier segment into two.
|
|
6
|
-
*
|
|
7
|
-
* @param pts the cubic-bezier parameters
|
|
8
|
-
* @param ratio the cubic-bezier parameters
|
|
9
|
-
* @return two new cubic-bezier segments
|
|
10
|
-
*/
|
|
11
|
-
const splitCubic = (pts: number[], ratio = 0.5): [CubicSegment, CubicSegment] => {
|
|
12
|
-
const t = ratio;
|
|
13
|
-
const p0 = pts.slice(0, 2) as PointTuple;
|
|
14
|
-
const p1 = pts.slice(2, 4) as PointTuple;
|
|
15
|
-
const p2 = pts.slice(4, 6) as PointTuple;
|
|
16
|
-
const p3 = pts.slice(6, 8) as PointTuple;
|
|
17
|
-
const p4 = midPoint(p0, p1, t);
|
|
18
|
-
const p5 = midPoint(p1, p2, t);
|
|
19
|
-
const p6 = midPoint(p2, p3, t);
|
|
20
|
-
const p7 = midPoint(p4, p5, t);
|
|
21
|
-
const p8 = midPoint(p5, p6, t);
|
|
22
|
-
const p9 = midPoint(p7, p8, t);
|
|
23
|
-
|
|
24
|
-
return [
|
|
25
|
-
['C', p4[0], p4[1], p7[0], p7[1], p9[0], p9[1]],
|
|
26
|
-
['C', p8[0], p8[1], p6[0], p6[1], p3[0], p3[1]],
|
|
27
|
-
];
|
|
28
|
-
};
|
|
29
|
-
export default splitCubic;
|
package/src/process/splitPath.ts
DELETED
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
import paramsParser from '../parser/paramsParser';
|
|
2
|
-
import type { AbsoluteCommand, HSegment, MSegment, PathArray, PointTuple, RelativeCommand, VSegment } from '../types';
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Split a path into an `Array` of sub-path strings.
|
|
6
|
-
*
|
|
7
|
-
* In the process, values are converted to absolute
|
|
8
|
-
* for visual consistency.
|
|
9
|
-
*
|
|
10
|
-
* @param pathInput the source `pathArray`
|
|
11
|
-
* @return an array with all sub-path strings
|
|
12
|
-
*/
|
|
13
|
-
const splitPath = (pathInput: PathArray): PathArray[] => {
|
|
14
|
-
const composite = [] as PathArray[];
|
|
15
|
-
let path: PathArray;
|
|
16
|
-
let pi = -1;
|
|
17
|
-
let x = 0;
|
|
18
|
-
let y = 0;
|
|
19
|
-
let mx = 0;
|
|
20
|
-
let my = 0;
|
|
21
|
-
const params = { ...paramsParser };
|
|
22
|
-
|
|
23
|
-
pathInput.forEach(seg => {
|
|
24
|
-
const [pathCommand] = seg;
|
|
25
|
-
const absCommand = pathCommand.toUpperCase() as AbsoluteCommand;
|
|
26
|
-
const relCommand = pathCommand.toLowerCase() as RelativeCommand;
|
|
27
|
-
const isRelative = pathCommand === relCommand;
|
|
28
|
-
const values = seg.slice(1) as number[];
|
|
29
|
-
|
|
30
|
-
if (absCommand === 'M') {
|
|
31
|
-
pi += 1;
|
|
32
|
-
[x, y] = values as PointTuple;
|
|
33
|
-
x += isRelative ? params.x : 0;
|
|
34
|
-
y += isRelative ? params.y : 0;
|
|
35
|
-
mx = x;
|
|
36
|
-
my = y;
|
|
37
|
-
path = [(isRelative ? [absCommand, mx, my] : seg) as MSegment];
|
|
38
|
-
} else {
|
|
39
|
-
if (absCommand === 'Z') {
|
|
40
|
-
x = mx;
|
|
41
|
-
y = my;
|
|
42
|
-
} else if (absCommand === 'H') {
|
|
43
|
-
[, x] = seg as HSegment;
|
|
44
|
-
x += isRelative ? params.x : /* istanbul ignore next @preserve */ 0;
|
|
45
|
-
} else if (absCommand === 'V') {
|
|
46
|
-
[, y] = seg as VSegment;
|
|
47
|
-
y += isRelative ? params.y : /* istanbul ignore next @preserve */ 0;
|
|
48
|
-
} else {
|
|
49
|
-
[x, y] = seg.slice(-2) as PointTuple;
|
|
50
|
-
x += isRelative ? params.x : 0;
|
|
51
|
-
y += isRelative ? params.y : 0;
|
|
52
|
-
}
|
|
53
|
-
path.push(seg);
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
params.x = x;
|
|
57
|
-
params.y = y;
|
|
58
|
-
composite[pi] = path;
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
return composite;
|
|
62
|
-
};
|
|
63
|
-
export default splitPath;
|