svg-path-commander 2.1.0 → 2.1.2
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 +63 -7
- package/dist/svg-path-commander.cjs +1 -1
- package/dist/svg-path-commander.cjs.map +1 -1
- package/dist/svg-path-commander.d.ts +314 -40
- package/dist/svg-path-commander.js +1 -1
- package/dist/svg-path-commander.js.map +1 -1
- package/dist/svg-path-commander.mjs +1085 -1032
- package/dist/svg-path-commander.mjs.map +1 -1
- package/package.json +8 -8
- package/src/convert/pathToAbsolute.ts +5 -88
- package/src/convert/pathToCurve.ts +22 -28
- package/src/convert/pathToRelative.ts +4 -78
- package/src/convert/pathToString.ts +40 -7
- package/src/index.ts +145 -58
- package/src/interface.ts +3 -2
- package/src/math/arcTools.ts +259 -80
- package/src/math/bezier.ts +58 -58
- package/src/math/cubicTools.ts +68 -25
- package/src/math/distanceSquareRoot.ts +3 -1
- package/src/math/lineTools.ts +42 -25
- package/src/math/midPoint.ts +3 -1
- package/src/math/polygonTools.ts +48 -0
- package/src/math/quadTools.ts +46 -25
- package/src/math/rotateVector.ts +3 -2
- package/src/math/roundTo.ts +7 -0
- package/src/parser/finalizeSegment.ts +11 -7
- package/src/parser/parsePathString.ts +4 -5
- package/src/parser/pathParser.ts +1 -1
- package/src/process/absolutizeSegment.ts +63 -0
- package/src/process/arcToCubic.ts +2 -2
- package/src/process/iterate.ts +58 -0
- package/src/process/lineToCubic.ts +1 -1
- package/src/process/normalizePath.ts +17 -28
- package/src/process/normalizeSegment.ts +55 -18
- package/src/process/optimizePath.ts +40 -60
- package/src/process/projection2d.ts +4 -3
- package/src/process/relativizeSegment.ts +59 -0
- package/src/process/reverseCurve.ts +8 -5
- package/src/process/reversePath.ts +88 -75
- package/src/process/roundPath.ts +18 -14
- package/src/process/roundSegment.ts +9 -0
- package/src/process/segmentToCubic.ts +10 -8
- package/src/process/shortenSegment.ts +26 -34
- package/src/process/splitCubic.ts +10 -9
- package/src/process/splitPath.ts +38 -4
- package/src/process/transformPath.ts +75 -73
- package/src/types.ts +30 -0
- package/src/util/getPathArea.ts +3 -3
- package/src/util/getPathBBox.ts +69 -19
- package/src/util/getPointAtLength.ts +100 -4
- package/src/util/getPropertiesAtLength.ts +3 -4
- package/src/util/getPropertiesAtPoint.ts +5 -5
- package/src/util/getTotalLength.ts +56 -4
- package/test/class.test.ts +17 -14
- package/test/fixtures/shapes.js +26 -26
- package/test/fixtures/simpleShapes.js +18 -18
- package/test/static.test.ts +54 -28
- package/cypress.config.ts +0 -29
- package/src/math/polygonArea.ts +0 -27
- package/src/math/polygonLength.ts +0 -21
- package/src/process/fixArc.ts +0 -23
- package/src/process/replaceArc.ts +0 -52
- package/src/util/pathFactory.ts +0 -130
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "svg-path-commander",
|
|
3
3
|
"author": "thednp",
|
|
4
4
|
"license": "MIT",
|
|
5
|
-
"version": "2.1.
|
|
5
|
+
"version": "2.1.2",
|
|
6
6
|
"description": "Modern TypeScript tools for SVG",
|
|
7
7
|
"source": "./src/index.ts",
|
|
8
8
|
"main": "./dist/svg-path-commander.js",
|
|
@@ -40,19 +40,19 @@
|
|
|
40
40
|
"devDependencies": {
|
|
41
41
|
"@typescript-eslint/eslint-plugin": "^5.62.0",
|
|
42
42
|
"@typescript-eslint/parser": "^5.62.0",
|
|
43
|
-
"@vitest/browser": "^2.1.
|
|
44
|
-
"@vitest/coverage-istanbul": "^2.1.
|
|
45
|
-
"@vitest/ui": "^2.1.
|
|
43
|
+
"@vitest/browser": "^2.1.3",
|
|
44
|
+
"@vitest/coverage-istanbul": "^2.1.3",
|
|
45
|
+
"@vitest/ui": "^2.1.3",
|
|
46
46
|
"dts-bundle-generator": "^9.5.1",
|
|
47
47
|
"eslint": "^8.57.1",
|
|
48
48
|
"eslint-plugin-jsdoc": "^46.10.1",
|
|
49
49
|
"eslint-plugin-prefer-arrow": "^1.2.3",
|
|
50
50
|
"eslint-plugin-prettier": "^4.2.1",
|
|
51
|
-
"playwright": "^1.
|
|
51
|
+
"playwright": "^1.48.1",
|
|
52
52
|
"prettier": "^2.8.8",
|
|
53
|
-
"typescript": "^5.6.
|
|
54
|
-
"vite": "^5.4.
|
|
55
|
-
"vitest": "^2.1.
|
|
53
|
+
"typescript": "^5.6.3",
|
|
54
|
+
"vite": "^5.4.9",
|
|
55
|
+
"vitest": "^2.1.3"
|
|
56
56
|
},
|
|
57
57
|
"dependencies": {
|
|
58
58
|
"@thednp/dommatrix": "^2.0.8"
|
|
@@ -1,19 +1,7 @@
|
|
|
1
1
|
import parsePathString from '../parser/parsePathString';
|
|
2
|
-
import
|
|
3
|
-
import type {
|
|
4
|
-
|
|
5
|
-
AbsoluteArray,
|
|
6
|
-
AbsoluteCommand,
|
|
7
|
-
AbsoluteSegment,
|
|
8
|
-
VSegment,
|
|
9
|
-
HSegment,
|
|
10
|
-
QSegment,
|
|
11
|
-
TSegment,
|
|
12
|
-
ASegment,
|
|
13
|
-
SSegment,
|
|
14
|
-
CSegment,
|
|
15
|
-
MSegment,
|
|
16
|
-
} from '../types';
|
|
2
|
+
import absolutizeSegment from '../process/absolutizeSegment';
|
|
3
|
+
import type { AbsoluteArray, PathArray } from '../types';
|
|
4
|
+
import iterate from '../process/iterate';
|
|
17
5
|
|
|
18
6
|
/**
|
|
19
7
|
* Parses a path string value or object and returns an array
|
|
@@ -22,80 +10,9 @@ import type {
|
|
|
22
10
|
* @param pathInput the path string | object
|
|
23
11
|
* @returns the resulted `pathArray` with absolute values
|
|
24
12
|
*/
|
|
25
|
-
const pathToAbsolute = (pathInput: string | PathArray)
|
|
26
|
-
/* istanbul ignore else */
|
|
27
|
-
if (isAbsoluteArray(pathInput)) {
|
|
28
|
-
return pathInput.slice(0) as AbsoluteArray;
|
|
29
|
-
}
|
|
30
|
-
|
|
13
|
+
const pathToAbsolute = (pathInput: string | PathArray) => {
|
|
31
14
|
const path = parsePathString(pathInput);
|
|
32
|
-
let x = 0;
|
|
33
|
-
let y = 0;
|
|
34
|
-
let mx = 0;
|
|
35
|
-
let my = 0;
|
|
36
|
-
|
|
37
|
-
// the `absoluteSegment[]` is for sure an `absolutePath`
|
|
38
|
-
return path.map(segment => {
|
|
39
|
-
const values = segment.slice(1).map(Number);
|
|
40
|
-
const [pathCommand] = segment;
|
|
41
|
-
const absCommand = pathCommand.toUpperCase() as AbsoluteCommand;
|
|
42
|
-
|
|
43
|
-
if (pathCommand === 'M') {
|
|
44
|
-
[x, y] = values;
|
|
45
|
-
mx = x;
|
|
46
|
-
my = y;
|
|
47
|
-
return ['M', x, y] as MSegment;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
let absoluteSegment = [] as unknown as AbsoluteSegment;
|
|
51
|
-
|
|
52
|
-
if (pathCommand !== absCommand) {
|
|
53
|
-
if (absCommand === 'A') {
|
|
54
|
-
absoluteSegment = [
|
|
55
|
-
absCommand,
|
|
56
|
-
values[0],
|
|
57
|
-
values[1],
|
|
58
|
-
values[2],
|
|
59
|
-
values[3],
|
|
60
|
-
values[4],
|
|
61
|
-
values[5] + x,
|
|
62
|
-
values[6] + y,
|
|
63
|
-
] as ASegment;
|
|
64
|
-
} else if (absCommand === 'V') {
|
|
65
|
-
absoluteSegment = [absCommand, values[0] + y] as VSegment;
|
|
66
|
-
} else if (absCommand === 'H') {
|
|
67
|
-
absoluteSegment = [absCommand, values[0] + x] as HSegment;
|
|
68
|
-
} else {
|
|
69
|
-
// use brakets for `eslint: no-case-declaration`
|
|
70
|
-
// https://stackoverflow.com/a/50753272/803358
|
|
71
|
-
const absValues = values.map((n, j) => n + (j % 2 ? y : x));
|
|
72
|
-
// for n, l, c, s, q, t
|
|
73
|
-
absoluteSegment = [absCommand, ...absValues] as QSegment | TSegment | SSegment | CSegment;
|
|
74
|
-
}
|
|
75
|
-
} else {
|
|
76
|
-
absoluteSegment = [absCommand, ...values] as typeof segment;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
// const segLength = absoluteSegment.length;
|
|
80
|
-
if (absCommand === 'Z') {
|
|
81
|
-
x = mx;
|
|
82
|
-
y = my;
|
|
83
|
-
} else if (absCommand === 'H') {
|
|
84
|
-
[, x] = absoluteSegment as HSegment;
|
|
85
|
-
} else if (absCommand === 'V') {
|
|
86
|
-
[, y] = absoluteSegment as VSegment;
|
|
87
|
-
} else {
|
|
88
|
-
// x = absoluteSegment[segLength - 2];
|
|
89
|
-
// y = absoluteSegment[segLength - 1];
|
|
90
|
-
[x, y] = absoluteSegment.slice(-2) as [number, number];
|
|
91
|
-
|
|
92
|
-
if (absCommand === 'M') {
|
|
93
|
-
mx = x;
|
|
94
|
-
my = y;
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
15
|
|
|
98
|
-
|
|
99
|
-
}) as AbsoluteArray;
|
|
16
|
+
return iterate<AbsoluteArray>(path, absolutizeSegment);
|
|
100
17
|
};
|
|
101
18
|
export default pathToAbsolute;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import fixArc from '../process/fixArc';
|
|
2
|
-
import isCurveArray from '../util/isCurveArray';
|
|
3
|
-
import normalizePath from '../process/normalizePath';
|
|
4
1
|
import segmentToCubic from '../process/segmentToCubic';
|
|
2
|
+
import { AbsoluteCommand, CSegment, CurveArray, PathArray } from '../types';
|
|
3
|
+
import iterate from '../process/iterate';
|
|
4
|
+
import parsePathString from '../parser/parsePathString';
|
|
5
|
+
import normalizeSegment from '../process/normalizeSegment';
|
|
5
6
|
import paramsParser from '../parser/paramsParser';
|
|
6
|
-
import { CurveArray, PathArray, PathCommand } from '../types';
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* Parses a path string value or 'pathArray' and returns a new one
|
|
@@ -16,34 +16,28 @@ import { CurveArray, PathArray, PathCommand } from '../types';
|
|
|
16
16
|
* @returns the resulted `pathArray` converted to cubic-bezier
|
|
17
17
|
*/
|
|
18
18
|
const pathToCurve = (pathInput: string | PathArray): CurveArray => {
|
|
19
|
-
/* istanbul ignore else */
|
|
20
|
-
if (isCurveArray(pathInput)) {
|
|
21
|
-
return pathInput.slice(0) as CurveArray;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
const path = normalizePath(pathInput);
|
|
25
19
|
const params = { ...paramsParser };
|
|
26
|
-
const
|
|
27
|
-
let pathCommand = ''; // ts-lint
|
|
28
|
-
let ii = path.length;
|
|
29
|
-
|
|
30
|
-
for (let i = 0; i < ii; i += 1) {
|
|
31
|
-
[pathCommand] = path[i];
|
|
32
|
-
allPathCommands[i] = pathCommand as PathCommand;
|
|
20
|
+
const path = parsePathString(pathInput);
|
|
33
21
|
|
|
34
|
-
|
|
22
|
+
return iterate<CurveArray>(path, (seg, index, lastX, lastY) => {
|
|
23
|
+
params.x = lastX;
|
|
24
|
+
params.y = lastY;
|
|
25
|
+
const normalSegment = normalizeSegment(seg, params);
|
|
26
|
+
let result = segmentToCubic(normalSegment, params);
|
|
27
|
+
const isLongArc = result[0] === 'C' && result.length > 7;
|
|
35
28
|
|
|
36
|
-
|
|
37
|
-
|
|
29
|
+
if (isLongArc) {
|
|
30
|
+
path.splice(index + 1, 0, ['C' as AbsoluteCommand | number].concat(result.slice(7)) as CSegment);
|
|
31
|
+
result = result.slice(0, 7) as CSegment;
|
|
32
|
+
}
|
|
38
33
|
|
|
39
|
-
const
|
|
40
|
-
|
|
41
|
-
params.
|
|
42
|
-
params.
|
|
43
|
-
params.
|
|
44
|
-
params.y2 = +segment[seglen - 3] || params.y1;
|
|
45
|
-
}
|
|
34
|
+
const seglen = result.length;
|
|
35
|
+
params.x1 = +result[seglen - 2];
|
|
36
|
+
params.y1 = +result[seglen - 1];
|
|
37
|
+
params.x2 = +result[seglen - 4] || params.x1;
|
|
38
|
+
params.y2 = +result[seglen - 3] || params.y1;
|
|
46
39
|
|
|
47
|
-
|
|
40
|
+
return result;
|
|
41
|
+
});
|
|
48
42
|
};
|
|
49
43
|
export default pathToCurve;
|
|
@@ -1,14 +1,7 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
aSegment,
|
|
3
|
-
hSegment,
|
|
4
|
-
PathArray,
|
|
5
|
-
RelativeArray,
|
|
6
|
-
RelativeCommand,
|
|
7
|
-
RelativeSegment,
|
|
8
|
-
vSegment,
|
|
9
|
-
} from '../types';
|
|
1
|
+
import type { PathArray, RelativeArray } from '../types';
|
|
10
2
|
import parsePathString from '../parser/parsePathString';
|
|
11
|
-
import
|
|
3
|
+
import iterate from '../process/iterate';
|
|
4
|
+
import relativizeSegment from '../process/relativizeSegment';
|
|
12
5
|
|
|
13
6
|
/**
|
|
14
7
|
* Parses a path string value or object and returns an array
|
|
@@ -18,75 +11,8 @@ import isRelativeArray from '../util/isRelativeArray';
|
|
|
18
11
|
* @returns the resulted `pathArray` with relative values
|
|
19
12
|
*/
|
|
20
13
|
const pathToRelative = (pathInput: string | PathArray): RelativeArray => {
|
|
21
|
-
/* istanbul ignore else */
|
|
22
|
-
if (isRelativeArray(pathInput)) {
|
|
23
|
-
return pathInput.slice(0) as RelativeArray;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
14
|
const path = parsePathString(pathInput);
|
|
27
|
-
let x = 0;
|
|
28
|
-
let y = 0;
|
|
29
|
-
let mx = 0;
|
|
30
|
-
let my = 0;
|
|
31
|
-
|
|
32
|
-
return path.map(segment => {
|
|
33
|
-
const values = segment.slice(1).map(Number);
|
|
34
|
-
const [pathCommand] = segment;
|
|
35
|
-
const relativeCommand = pathCommand.toLowerCase() as RelativeCommand;
|
|
36
|
-
|
|
37
|
-
if (pathCommand === 'M') {
|
|
38
|
-
[x, y] = values;
|
|
39
|
-
mx = x;
|
|
40
|
-
my = y;
|
|
41
|
-
return ['M', x, y];
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
let relativeSegment = [];
|
|
45
|
-
|
|
46
|
-
if (pathCommand !== relativeCommand) {
|
|
47
|
-
if (relativeCommand === 'a') {
|
|
48
|
-
relativeSegment = [
|
|
49
|
-
relativeCommand,
|
|
50
|
-
values[0],
|
|
51
|
-
values[1],
|
|
52
|
-
values[2],
|
|
53
|
-
values[3],
|
|
54
|
-
values[4],
|
|
55
|
-
values[5] - x,
|
|
56
|
-
values[6] - y,
|
|
57
|
-
] as aSegment;
|
|
58
|
-
} else if (relativeCommand === 'v') {
|
|
59
|
-
relativeSegment = [relativeCommand, values[0] - y] as vSegment;
|
|
60
|
-
} else if (relativeCommand === 'h') {
|
|
61
|
-
relativeSegment = [relativeCommand, values[0] - x] as hSegment;
|
|
62
|
-
} else {
|
|
63
|
-
// use brakets for `eslint: no-case-declaration`
|
|
64
|
-
// https://stackoverflow.com/a/50753272/803358
|
|
65
|
-
const relValues = values.map((n, j) => n - (j % 2 ? y : x));
|
|
66
|
-
relativeSegment = [relativeCommand, ...relValues] as RelativeSegment;
|
|
67
|
-
}
|
|
68
|
-
} else {
|
|
69
|
-
if (pathCommand === 'm') {
|
|
70
|
-
mx = values[0] + x;
|
|
71
|
-
my = values[1] + y;
|
|
72
|
-
}
|
|
73
|
-
relativeSegment = [relativeCommand, ...values] as RelativeSegment;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
const segLength = relativeSegment.length;
|
|
77
|
-
if (relativeCommand === 'z') {
|
|
78
|
-
x = mx;
|
|
79
|
-
y = my;
|
|
80
|
-
} else if (relativeCommand === 'h') {
|
|
81
|
-
x += relativeSegment[1] as number;
|
|
82
|
-
} else if (relativeCommand === 'v') {
|
|
83
|
-
y += relativeSegment[1] as number;
|
|
84
|
-
} else {
|
|
85
|
-
x += relativeSegment[segLength - 2] as number;
|
|
86
|
-
y += relativeSegment[segLength - 1] as number;
|
|
87
|
-
}
|
|
88
15
|
|
|
89
|
-
|
|
90
|
-
}) as RelativeArray;
|
|
16
|
+
return iterate<RelativeArray>(path, relativizeSegment);
|
|
91
17
|
};
|
|
92
18
|
export default pathToRelative;
|
|
@@ -1,17 +1,50 @@
|
|
|
1
|
-
import type { PathArray } from '../types';
|
|
2
|
-
import
|
|
1
|
+
import type { PathArray, PathSegment } from '../types';
|
|
2
|
+
import defaultOptions from '../options/options';
|
|
3
|
+
import roundTo from '../math/roundTo';
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* Returns a valid `d` attribute string value created
|
|
6
7
|
* by rounding values and concatenating the `pathArray` segments.
|
|
7
8
|
*
|
|
8
9
|
* @param path the `pathArray` object
|
|
9
|
-
* @param
|
|
10
|
+
* @param roundOption amount of decimals to round values to
|
|
10
11
|
* @returns the concatenated path string
|
|
11
12
|
*/
|
|
12
|
-
const pathToString = (path: PathArray,
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
const pathToString = (path: PathArray, roundOption?: number | 'off'): string => {
|
|
14
|
+
const pathLen = path.length;
|
|
15
|
+
let { round } = defaultOptions;
|
|
16
|
+
let segment = path[0] as PathSegment;
|
|
17
|
+
let result = '';
|
|
18
|
+
|
|
19
|
+
// allow for ZERO decimals
|
|
20
|
+
round =
|
|
21
|
+
roundOption === 'off'
|
|
22
|
+
? roundOption
|
|
23
|
+
: typeof roundOption === 'number' && roundOption >= 0
|
|
24
|
+
? roundOption
|
|
25
|
+
: typeof round === 'number' && round >= 0
|
|
26
|
+
? round
|
|
27
|
+
: /* istanbul ignore next @preserve */ 'off';
|
|
28
|
+
|
|
29
|
+
for (let i = 0; i < pathLen; i += 1) {
|
|
30
|
+
segment = path[i];
|
|
31
|
+
const [pathCommand] = segment;
|
|
32
|
+
const values = segment.slice(1) as number[];
|
|
33
|
+
result += pathCommand;
|
|
34
|
+
if (round === 'off') {
|
|
35
|
+
result += values.join(' ');
|
|
36
|
+
} else {
|
|
37
|
+
let j = 0;
|
|
38
|
+
const valLen = values.length;
|
|
39
|
+
while (j < valLen) {
|
|
40
|
+
result += roundTo(values[j], round);
|
|
41
|
+
if (j !== valLen - 1) result += ' ';
|
|
42
|
+
j += 1;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return result;
|
|
16
48
|
};
|
|
49
|
+
|
|
17
50
|
export default pathToString;
|
package/src/index.ts
CHANGED
|
@@ -1,54 +1,99 @@
|
|
|
1
|
-
|
|
1
|
+
'use strict';
|
|
2
|
+
import CSSMatrix from '@thednp/dommatrix';
|
|
3
|
+
import { PointTuple, PathArray, TransformObjectValues } from './types';
|
|
2
4
|
import type { Options, TransformEntries, TransformObject } from './interface';
|
|
3
5
|
export * from './types';
|
|
4
6
|
export * from './interface';
|
|
5
7
|
import defaultOptions from './options/options';
|
|
6
8
|
|
|
9
|
+
import pathToAbsolute from './convert/pathToAbsolute';
|
|
10
|
+
import pathToRelative from './convert/pathToRelative';
|
|
11
|
+
import pathToCurve from './convert/pathToCurve';
|
|
12
|
+
import pathToString from './convert/pathToString';
|
|
13
|
+
import * as arcTools from './math/arcTools';
|
|
14
|
+
import {
|
|
15
|
+
Cvalues,
|
|
16
|
+
Tvalues,
|
|
17
|
+
minmaxC,
|
|
18
|
+
minmaxQ,
|
|
19
|
+
getBezierLength,
|
|
20
|
+
bezierLength,
|
|
21
|
+
calculateBezier,
|
|
22
|
+
computeBezier,
|
|
23
|
+
deriveBezier,
|
|
24
|
+
CBEZIER_MINMAX_EPSILON,
|
|
25
|
+
} from './math/bezier';
|
|
26
|
+
import { getCubicLength, getCubicBBox, getPointAtCubicLength, getPointAtCubicSegmentLength } from './math/cubicTools';
|
|
27
|
+
import { getPointAtLineLength, getLineBBox, getLineLength } from './math/lineTools';
|
|
28
|
+
import { getPointAtQuadSegmentLength, getQuadLength, getQuadBBox, getPointAtQuadLength } from './math/quadTools';
|
|
29
|
+
import { polygonArea, polygonLength } from './math/polygonTools';
|
|
30
|
+
|
|
31
|
+
import distanceSquareRoot from './math/distanceSquareRoot';
|
|
32
|
+
import midPoint from './math/midPoint';
|
|
33
|
+
import rotateVector from './math/rotateVector';
|
|
34
|
+
import roundTo from './math/roundTo';
|
|
35
|
+
|
|
7
36
|
import error from './parser/error';
|
|
8
37
|
import parsePathString from './parser/parsePathString';
|
|
9
|
-
|
|
10
|
-
import
|
|
11
|
-
import
|
|
12
|
-
|
|
13
|
-
import
|
|
14
|
-
import
|
|
15
|
-
import
|
|
16
|
-
import
|
|
38
|
+
import finalizeSegment from './parser/finalizeSegment';
|
|
39
|
+
import invalidPathValue from './parser/invalidPathValue';
|
|
40
|
+
import isArcCommand from './parser/isArcCommand';
|
|
41
|
+
import isDigit from './parser/isDigit';
|
|
42
|
+
import isDigitStart from './parser/isDigitStart';
|
|
43
|
+
import isMoveCommand from './parser/isMoveCommand';
|
|
44
|
+
import isPathCommand from './parser/isPathCommand';
|
|
45
|
+
import isSpace from './parser/isSpace';
|
|
46
|
+
import paramsCount from './parser/paramsCount';
|
|
47
|
+
import paramsParser from './parser/paramsParser';
|
|
48
|
+
import pathParser from './parser/pathParser';
|
|
49
|
+
import scanFlag from './parser/scanFlag';
|
|
50
|
+
import scanParam from './parser/scanParam';
|
|
51
|
+
import scanSegment from './parser/scanSegment';
|
|
52
|
+
import skipSpaces from './parser/skipSpaces';
|
|
53
|
+
|
|
54
|
+
import distanceEpsilon from './util/distanceEpsilon';
|
|
55
|
+
import getClosestPoint from './util/getClosestPoint';
|
|
17
56
|
import getDrawDirection from './util/getDrawDirection';
|
|
57
|
+
import getPathArea from './util/getPathArea';
|
|
58
|
+
import getPathBBox from './util/getPathBBox';
|
|
18
59
|
import getPointAtLength from './util/getPointAtLength';
|
|
19
|
-
import pathFactory from './util/pathFactory';
|
|
20
|
-
|
|
21
60
|
import getPropertiesAtLength from './util/getPropertiesAtLength';
|
|
22
61
|
import getPropertiesAtPoint from './util/getPropertiesAtPoint';
|
|
23
|
-
import getClosestPoint from './util/getClosestPoint';
|
|
24
|
-
import getSegmentOfPoint from './util/getSegmentOfPoint';
|
|
25
62
|
import getSegmentAtLength from './util/getSegmentAtLength';
|
|
26
|
-
import
|
|
63
|
+
import getSegmentOfPoint from './util/getSegmentOfPoint';
|
|
64
|
+
import getTotalLength from './util/getTotalLength';
|
|
27
65
|
|
|
28
|
-
import isValidPath from './util/isValidPath';
|
|
29
|
-
import isPathArray from './util/isPathArray';
|
|
30
66
|
import isAbsoluteArray from './util/isAbsoluteArray';
|
|
31
|
-
import isRelativeArray from './util/isRelativeArray';
|
|
32
67
|
import isCurveArray from './util/isCurveArray';
|
|
33
68
|
import isNormalizedArray from './util/isNormalizedArray';
|
|
34
|
-
import
|
|
69
|
+
import isPathArray from './util/isPathArray';
|
|
70
|
+
import isPointInStroke from './util/isPointInStroke';
|
|
71
|
+
import isRelativeArray from './util/isRelativeArray';
|
|
72
|
+
import isValidPath from './util/isValidPath';
|
|
73
|
+
import shapeParams from './util/shapeParams';
|
|
35
74
|
import shapeToPath from './util/shapeToPath';
|
|
75
|
+
import shapeToPathArray from './util/shapeToPathArray';
|
|
36
76
|
|
|
37
|
-
import
|
|
38
|
-
import
|
|
77
|
+
import absolutizeSegment from './process/absolutizeSegment';
|
|
78
|
+
import arcToCubic from './process/arcToCubic';
|
|
39
79
|
import getSVGMatrix from './process/getSVGMatrix';
|
|
80
|
+
import iterate from './process/iterate';
|
|
81
|
+
import lineToCubic from './process/lineToCubic';
|
|
82
|
+
import normalizePath from './process/normalizePath';
|
|
83
|
+
import normalizeSegment from './process/normalizeSegment';
|
|
40
84
|
import optimizePath from './process/optimizePath';
|
|
85
|
+
import projection2d from './process/projection2d';
|
|
86
|
+
import quadToCubic from './process/quadToCubic';
|
|
87
|
+
import relativizeSegment from './process/relativizeSegment';
|
|
41
88
|
import reverseCurve from './process/reverseCurve';
|
|
42
89
|
import reversePath from './process/reversePath';
|
|
43
|
-
import
|
|
44
|
-
import
|
|
90
|
+
import roundPath from './process/roundPath';
|
|
91
|
+
import roundSegment from './process/roundSegment';
|
|
92
|
+
import segmentToCubic from './process/segmentToCubic';
|
|
93
|
+
import shortenSegment from './process/shortenSegment';
|
|
45
94
|
import splitCubic from './process/splitCubic';
|
|
46
|
-
import
|
|
47
|
-
|
|
48
|
-
import pathToAbsolute from './convert/pathToAbsolute';
|
|
49
|
-
import pathToRelative from './convert/pathToRelative';
|
|
50
|
-
import pathToCurve from './convert/pathToCurve';
|
|
51
|
-
import pathToString from './convert/pathToString';
|
|
95
|
+
import splitPath from './process/splitPath';
|
|
96
|
+
import transformPath from './process/transformPath';
|
|
52
97
|
|
|
53
98
|
/**
|
|
54
99
|
* Creates a new SVGPathCommander instance with the following properties:
|
|
@@ -61,19 +106,55 @@ import pathToString from './convert/pathToString';
|
|
|
61
106
|
* @returns a new SVGPathCommander instance
|
|
62
107
|
*/
|
|
63
108
|
class SVGPathCommander {
|
|
64
|
-
// bring main utilities to front
|
|
65
109
|
public static CSSMatrix = CSSMatrix;
|
|
66
|
-
public static
|
|
110
|
+
public static pathToAbsolute = pathToAbsolute;
|
|
111
|
+
public static pathToRelative = pathToRelative;
|
|
112
|
+
public static pathToCurve = pathToCurve;
|
|
113
|
+
public static pathToString = pathToString;
|
|
114
|
+
public static arcTools = arcTools;
|
|
115
|
+
public static bezierTools = {
|
|
116
|
+
Cvalues,
|
|
117
|
+
Tvalues,
|
|
118
|
+
minmaxC,
|
|
119
|
+
minmaxQ,
|
|
120
|
+
getBezierLength,
|
|
121
|
+
bezierLength,
|
|
122
|
+
calculateBezier,
|
|
123
|
+
computeBezier,
|
|
124
|
+
deriveBezier,
|
|
125
|
+
CBEZIER_MINMAX_EPSILON,
|
|
126
|
+
};
|
|
127
|
+
public static cubicTools = { getCubicLength, getCubicBBox, getPointAtCubicLength, getPointAtCubicSegmentLength };
|
|
128
|
+
public static lineTools = { getPointAtLineLength, getLineBBox, getLineLength };
|
|
129
|
+
public static quadTools = { getPointAtQuadSegmentLength, getQuadLength, getQuadBBox, getPointAtQuadLength };
|
|
130
|
+
public static polygonTools = { polygonArea, polygonLength };
|
|
131
|
+
public static distanceSquareRoot = distanceSquareRoot;
|
|
132
|
+
public static distanceEpsilon = distanceEpsilon;
|
|
133
|
+
public static midPoint = midPoint;
|
|
134
|
+
public static rotateVector = rotateVector;
|
|
135
|
+
public static roundTo = roundTo;
|
|
136
|
+
public static finalizeSegment = finalizeSegment;
|
|
137
|
+
public static invalidPathValue = invalidPathValue;
|
|
138
|
+
public static isArcCommand = isArcCommand;
|
|
139
|
+
public static isDigit = isDigit;
|
|
140
|
+
public static isDigitStart = isDigitStart;
|
|
141
|
+
public static isMoveCommand = isMoveCommand;
|
|
142
|
+
public static isPathCommand = isPathCommand;
|
|
143
|
+
public static isSpace = isSpace;
|
|
144
|
+
public static paramsCount = paramsCount;
|
|
145
|
+
public static paramsParser = paramsParser;
|
|
146
|
+
public static pathParser = pathParser;
|
|
147
|
+
public static scanFlag = scanFlag;
|
|
148
|
+
public static scanParam = scanParam;
|
|
149
|
+
public static scanSegment = scanSegment;
|
|
150
|
+
public static skipSpaces = skipSpaces;
|
|
67
151
|
public static getPathBBox = getPathBBox;
|
|
68
152
|
public static getPathArea = getPathArea;
|
|
69
153
|
public static getTotalLength = getTotalLength;
|
|
70
154
|
public static getDrawDirection = getDrawDirection;
|
|
71
155
|
public static getPointAtLength = getPointAtLength;
|
|
72
|
-
public static pathFactory = pathFactory;
|
|
73
156
|
public static getPropertiesAtLength = getPropertiesAtLength;
|
|
74
157
|
public static getPropertiesAtPoint = getPropertiesAtPoint;
|
|
75
|
-
public static polygonLength = polygonLength;
|
|
76
|
-
public static polygonArea = polygonArea;
|
|
77
158
|
public static getClosestPoint = getClosestPoint;
|
|
78
159
|
public static getSegmentOfPoint = getSegmentOfPoint;
|
|
79
160
|
public static getSegmentAtLength = getSegmentAtLength;
|
|
@@ -86,20 +167,28 @@ class SVGPathCommander {
|
|
|
86
167
|
public static isNormalizedArray = isNormalizedArray;
|
|
87
168
|
public static shapeToPath = shapeToPath;
|
|
88
169
|
public static shapeToPathArray = shapeToPathArray;
|
|
170
|
+
public static shapeParams = shapeParams;
|
|
89
171
|
public static parsePathString = parsePathString;
|
|
90
|
-
public static
|
|
91
|
-
public static
|
|
92
|
-
public static
|
|
93
|
-
public static
|
|
172
|
+
public static absolutizeSegment = absolutizeSegment;
|
|
173
|
+
public static arcToCubic = arcToCubic;
|
|
174
|
+
public static getSVGMatrix = getSVGMatrix;
|
|
175
|
+
public static iterate = iterate;
|
|
176
|
+
public static lineToCubic = lineToCubic;
|
|
177
|
+
public static normalizePath = normalizePath;
|
|
178
|
+
public static normalizeSegment = normalizeSegment;
|
|
94
179
|
public static optimizePath = optimizePath;
|
|
180
|
+
public static projection2d = projection2d;
|
|
181
|
+
public static quadToCubic = quadToCubic;
|
|
182
|
+
public static relativizeSegment = relativizeSegment;
|
|
95
183
|
public static reverseCurve = reverseCurve;
|
|
96
184
|
public static reversePath = reversePath;
|
|
97
|
-
public static
|
|
185
|
+
public static roundPath = roundPath;
|
|
186
|
+
public static roundSegment = roundSegment;
|
|
187
|
+
public static segmentToCubic = segmentToCubic;
|
|
188
|
+
public static shortenSegment = shortenSegment;
|
|
189
|
+
public static splitCubic = splitCubic;
|
|
190
|
+
public static splitPath = splitPath;
|
|
98
191
|
public static transformPath = transformPath;
|
|
99
|
-
public static pathToAbsolute = pathToAbsolute;
|
|
100
|
-
public static pathToRelative = pathToRelative;
|
|
101
|
-
public static pathToCurve = pathToCurve;
|
|
102
|
-
public static pathToString = pathToString;
|
|
103
192
|
// declare class properties
|
|
104
193
|
declare segments: PathArray;
|
|
105
194
|
declare round: number | 'off';
|
|
@@ -118,18 +207,13 @@ class SVGPathCommander {
|
|
|
118
207
|
throw TypeError(`${error}: "pathValue" is ${undefPath ? 'undefined' : 'empty'}`);
|
|
119
208
|
}
|
|
120
209
|
|
|
121
|
-
|
|
122
|
-
this.segments = segments;
|
|
123
|
-
const { width, height, cx, cy, cz } = this.bbox;
|
|
210
|
+
this.segments = parsePathString(pathValue);
|
|
124
211
|
|
|
125
|
-
// set instance options.round
|
|
212
|
+
// // set instance options.round
|
|
126
213
|
const { round: roundOption, origin: originOption } = instanceOptions;
|
|
127
214
|
let round: number | 'off';
|
|
128
215
|
|
|
129
|
-
if (roundOption === '
|
|
130
|
-
const pathScale = `${Math.floor(Math.max(width, height))}`.length;
|
|
131
|
-
round = pathScale >= 4 ? 0 : 4 - pathScale;
|
|
132
|
-
} else if (Number.isInteger(roundOption) || roundOption === 'off') {
|
|
216
|
+
if (Number.isInteger(roundOption) || roundOption === 'off') {
|
|
133
217
|
round = roundOption as number | 'off';
|
|
134
218
|
} else {
|
|
135
219
|
round = defaultOptions.round as number;
|
|
@@ -137,14 +221,14 @@ class SVGPathCommander {
|
|
|
137
221
|
|
|
138
222
|
// set instance options.origin
|
|
139
223
|
// the SVGPathCommander class will always override the default origin
|
|
140
|
-
let origin =
|
|
224
|
+
let origin = defaultOptions.origin as [number, number, number];
|
|
141
225
|
/* istanbul ignore else @preserve */
|
|
142
226
|
if (Array.isArray(originOption) && originOption.length >= 2) {
|
|
143
227
|
const [originX, originY, originZ] = originOption.map(Number);
|
|
144
228
|
origin = [
|
|
145
|
-
!Number.isNaN(originX) ? originX :
|
|
146
|
-
!Number.isNaN(originY) ? originY :
|
|
147
|
-
!Number.isNaN(originZ) ? originZ :
|
|
229
|
+
!Number.isNaN(originX) ? originX : 0,
|
|
230
|
+
!Number.isNaN(originY) ? originY : 0,
|
|
231
|
+
!Number.isNaN(originZ) ? originZ : 0,
|
|
148
232
|
];
|
|
149
233
|
}
|
|
150
234
|
|
|
@@ -282,8 +366,9 @@ class SVGPathCommander {
|
|
|
282
366
|
*/
|
|
283
367
|
optimize() {
|
|
284
368
|
const { segments } = this;
|
|
369
|
+
const round = this.round === 'off' ? 2 : this.round;
|
|
285
370
|
|
|
286
|
-
this.segments = optimizePath(segments,
|
|
371
|
+
this.segments = optimizePath(segments, round);
|
|
287
372
|
return this;
|
|
288
373
|
}
|
|
289
374
|
|
|
@@ -311,7 +396,7 @@ class SVGPathCommander {
|
|
|
311
396
|
for (const [k, v] of Object.entries(source) as TransformEntries) {
|
|
312
397
|
// istanbul ignore else @preserve
|
|
313
398
|
if (k === 'skew' && Array.isArray(v)) {
|
|
314
|
-
transform[k] = v.map(Number) as
|
|
399
|
+
transform[k] = v.map(Number) as PointTuple;
|
|
315
400
|
} else if ((k === 'rotate' || k === 'translate' || k === 'origin' || k === 'scale') && Array.isArray(v)) {
|
|
316
401
|
transform[k] = v.map(Number) as [number, number, number];
|
|
317
402
|
} else if (k !== 'origin' && typeof Number(v) === 'number') transform[k] = Number(v);
|
|
@@ -338,7 +423,8 @@ class SVGPathCommander {
|
|
|
338
423
|
* @public
|
|
339
424
|
*/
|
|
340
425
|
flipX() {
|
|
341
|
-
|
|
426
|
+
const { cx, cy } = this.bbox;
|
|
427
|
+
this.transform({ rotate: [0, 180, 0], origin: [cx, cy, 0] });
|
|
342
428
|
return this;
|
|
343
429
|
}
|
|
344
430
|
|
|
@@ -348,7 +434,8 @@ class SVGPathCommander {
|
|
|
348
434
|
* @public
|
|
349
435
|
*/
|
|
350
436
|
flipY() {
|
|
351
|
-
|
|
437
|
+
const { cx, cy } = this.bbox;
|
|
438
|
+
this.transform({ rotate: [180, 0, 0], origin: [cx, cy, 0] });
|
|
352
439
|
return this;
|
|
353
440
|
}
|
|
354
441
|
|