svg-path-commander 1.0.4 → 2.0.0-alpha1
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 +29 -7
- package/dist/svg-path-commander.cjs +2 -0
- package/dist/svg-path-commander.cjs.map +1 -0
- package/dist/svg-path-commander.d.ts +454 -0
- package/dist/svg-path-commander.js +2 -3775
- package/dist/svg-path-commander.js.map +1 -0
- package/dist/svg-path-commander.mjs +1194 -0
- package/dist/svg-path-commander.mjs.map +1 -0
- package/package.json +39 -42
- package/src/convert/pathToAbsolute.ts +101 -0
- package/src/convert/{pathToCurve.js → pathToCurve.ts} +13 -15
- package/src/convert/pathToRelative.ts +92 -0
- package/src/convert/pathToString.ts +17 -0
- package/src/{svg-path-commander.js → index.ts} +143 -67
- package/src/interface.ts +129 -0
- package/src/math/distanceSquareRoot.ts +13 -0
- package/src/math/midPoint.ts +16 -0
- package/src/math/{polygonArea.js → polygonArea.ts} +6 -4
- package/src/math/{polygonLength.js → polygonLength.ts} +5 -3
- package/src/math/rotateVector.ts +16 -0
- package/src/options/options.ts +9 -0
- package/src/parser/error.ts +2 -0
- package/src/parser/finalizeSegment.ts +31 -0
- package/src/parser/{invalidPathValue.js → invalidPathValue.ts} +0 -0
- package/src/parser/{isArcCommand.js → isArcCommand.ts} +5 -4
- package/src/parser/isDigit.ts +12 -0
- package/src/parser/isDigitStart.ts +14 -0
- package/src/parser/isPathCommand.ts +28 -0
- package/src/parser/isSpace.ts +23 -0
- package/src/parser/paramsCount.ts +16 -0
- package/src/parser/paramsParser.ts +14 -0
- package/src/parser/{parsePathString.js → parsePathString.ts} +13 -7
- package/src/parser/pathParser.ts +29 -0
- package/src/parser/{scanFlag.js → scanFlag.ts} +8 -5
- package/src/parser/{scanParam.js → scanParam.ts} +12 -11
- package/src/parser/{scanSegment.js → scanSegment.ts} +9 -5
- package/src/parser/{skipSpaces.js → skipSpaces.ts} +5 -3
- package/src/process/{arcToCubic.js → arcToCubic.ts} +42 -28
- package/src/process/fixArc.ts +23 -0
- package/src/process/getSVGMatrix.ts +70 -0
- package/src/process/lineToCubic.ts +17 -0
- package/src/process/{normalizePath.js → normalizePath.ts} +10 -10
- package/src/process/normalizeSegment.ts +47 -0
- package/src/process/{optimizePath.js → optimizePath.ts} +18 -21
- package/src/process/{projection2d.js → projection2d.ts} +16 -15
- package/src/process/quadToCubic.ts +31 -0
- package/src/process/reverseCurve.ts +21 -0
- package/src/process/reversePath.ts +101 -0
- package/src/process/roundPath.ts +29 -0
- package/src/process/segmentToCubic.ts +46 -0
- package/src/process/shortenSegment.ts +79 -0
- package/src/process/splitCubic.ts +28 -0
- package/src/process/{splitPath.js → splitPath.ts} +9 -8
- package/src/process/{transformPath.js → transformPath.ts} +55 -48
- package/src/types.ts +193 -0
- package/src/util/getClosestPoint.ts +15 -0
- package/src/util/{getDrawDirection.js → getDrawDirection.ts} +7 -4
- package/src/util/getPathArea.ts +70 -0
- package/src/util/{getPathBBox.js → getPathBBox.ts} +16 -5
- package/src/util/getPointAtLength.ts +14 -0
- package/src/util/{getPropertiesAtLength.js → getPropertiesAtLength.ts} +28 -19
- package/src/util/{getPropertiesAtPoint.js → getPropertiesAtPoint.ts} +16 -12
- package/src/util/getSegmentAtLength.ts +15 -0
- package/src/util/getSegmentOfPoint.ts +18 -0
- package/src/util/{getTotalLength.js → getTotalLength.ts} +6 -4
- package/src/util/isAbsoluteArray.ts +18 -0
- package/src/util/isCurveArray.ts +15 -0
- package/src/util/{isNormalizedArray.js → isNormalizedArray.ts} +5 -3
- package/src/util/isPathArray.ts +19 -0
- package/src/util/isPointInStroke.ts +15 -0
- package/src/util/isRelativeArray.ts +18 -0
- package/src/util/{isValidPath.js → isValidPath.ts} +5 -4
- package/src/util/{pathLengthFactory.js → pathLengthFactory.ts} +38 -31
- package/src/util/{segmentArcFactory.js → segmentArcFactory.ts} +72 -56
- package/src/util/segmentCubicFactory.ts +114 -0
- package/src/util/{segmentLineFactory.js → segmentLineFactory.ts} +11 -9
- package/src/util/{segmentQuadFactory.js → segmentQuadFactory.ts} +48 -33
- package/src/util/shapeToPath.ts +214 -0
- package/dist/svg-path-commander.es5.js +0 -3888
- package/dist/svg-path-commander.es5.min.js +0 -2
- package/dist/svg-path-commander.esm.js +0 -3767
- package/dist/svg-path-commander.esm.min.js +0 -2
- package/dist/svg-path-commander.min.js +0 -2
- package/src/convert/pathToAbsolute.js +0 -93
- package/src/convert/pathToRelative.js +0 -84
- package/src/convert/pathToString.js +0 -14
- package/src/index.js +0 -10
- package/src/math/distanceSquareRoot.js +0 -14
- package/src/math/epsilon.js +0 -8
- package/src/math/midPoint.js +0 -13
- package/src/math/rotateVector.js +0 -14
- package/src/options/options.js +0 -10
- package/src/parser/error.js +0 -2
- package/src/parser/finalizeSegment.js +0 -28
- package/src/parser/isDigit.js +0 -9
- package/src/parser/isDigitStart.js +0 -13
- package/src/parser/isPathCommand.js +0 -25
- package/src/parser/isSpace.js +0 -16
- package/src/parser/paramsCount.js +0 -9
- package/src/parser/paramsParser.js +0 -8
- package/src/parser/pathParser.js +0 -25
- package/src/process/clonePath.js +0 -9
- package/src/process/fixArc.js +0 -22
- package/src/process/fixPath.js +0 -31
- package/src/process/getSVGMatrix.js +0 -61
- package/src/process/lineToCubic.js +0 -33
- package/src/process/normalizeSegment.js +0 -45
- package/src/process/quadToCubic.js +0 -22
- package/src/process/reverseCurve.js +0 -18
- package/src/process/reversePath.js +0 -89
- package/src/process/roundPath.js +0 -26
- package/src/process/segmentToCubic.js +0 -46
- package/src/process/shortenSegment.js +0 -58
- package/src/process/splitCubic.js +0 -26
- package/src/util/getClosestPoint.js +0 -12
- package/src/util/getPathArea.js +0 -47
- package/src/util/getPointAtLength.js +0 -12
- package/src/util/getSegmentAtLength.js +0 -11
- package/src/util/getSegmentOfPoint.js +0 -12
- package/src/util/isAbsoluteArray.js +0 -14
- package/src/util/isCurveArray.js +0 -13
- package/src/util/isPathArray.js +0 -14
- package/src/util/isPointInStroke.js +0 -13
- package/src/util/isRelativeArray.js +0 -14
- package/src/util/segmentCubicFactory.js +0 -97
- package/src/util/shapeToPath.js +0 -204
- package/src/util/util.js +0 -82
- package/src/version.js +0 -8
- package/types/index.d.ts +0 -120
- package/types/more/modules.ts +0 -82
- package/types/more/svg.d.ts +0 -211
- package/types/svg-path-commander.d.ts +0 -1089
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import parsePathString from '../parser/parsePathString';
|
|
2
|
+
import isAbsoluteArray from '../util/isAbsoluteArray';
|
|
3
|
+
import type {
|
|
4
|
+
PathArray,
|
|
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';
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Parses a path string value or object and returns an array
|
|
20
|
+
* of segments, all converted to absolute values.
|
|
21
|
+
*
|
|
22
|
+
* @param pathInput the path string | object
|
|
23
|
+
* @returns the resulted `pathArray` with absolute values
|
|
24
|
+
*/
|
|
25
|
+
const pathToAbsolute = (pathInput: string | PathArray): AbsoluteArray => {
|
|
26
|
+
/* istanbul ignore else */
|
|
27
|
+
if (isAbsoluteArray(pathInput)) {
|
|
28
|
+
return [...pathInput];
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
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
|
+
|
|
98
|
+
return absoluteSegment;
|
|
99
|
+
}) as AbsoluteArray;
|
|
100
|
+
};
|
|
101
|
+
export default pathToAbsolute;
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import fixArc from '../process/fixArc';
|
|
2
|
-
import fixPath from '../process/fixPath';
|
|
3
2
|
import isCurveArray from '../util/isCurveArray';
|
|
4
|
-
import clonePath from '../process/clonePath';
|
|
5
3
|
import normalizePath from '../process/normalizePath';
|
|
6
4
|
import segmentToCubic from '../process/segmentToCubic';
|
|
7
5
|
import paramsParser from '../parser/paramsParser';
|
|
6
|
+
import { CurveArray, PathArray, PathCommand } from '../types';
|
|
8
7
|
|
|
9
8
|
/**
|
|
10
9
|
* Parses a path string value or 'pathArray' and returns a new one
|
|
@@ -13,25 +12,24 @@ import paramsParser from '../parser/paramsParser';
|
|
|
13
12
|
* In addition, un-necessary `Z` segment is removed if previous segment
|
|
14
13
|
* extends to the `M` segment.
|
|
15
14
|
*
|
|
16
|
-
* @param
|
|
17
|
-
* @returns
|
|
15
|
+
* @param pathInput the string to be parsed or 'pathArray'
|
|
16
|
+
* @returns the resulted `pathArray` converted to cubic-bezier
|
|
18
17
|
*/
|
|
19
|
-
|
|
18
|
+
const pathToCurve = (pathInput: string | PathArray): CurveArray => {
|
|
20
19
|
/* istanbul ignore else */
|
|
21
20
|
if (isCurveArray(pathInput)) {
|
|
22
|
-
|
|
23
|
-
return clonePath(pathInput);
|
|
21
|
+
return [...pathInput];
|
|
24
22
|
}
|
|
25
23
|
|
|
26
|
-
const path =
|
|
24
|
+
const path = normalizePath(pathInput);
|
|
27
25
|
const params = { ...paramsParser };
|
|
28
|
-
const allPathCommands = [];
|
|
26
|
+
const allPathCommands = [] as PathCommand[];
|
|
29
27
|
let pathCommand = ''; // ts-lint
|
|
30
28
|
let ii = path.length;
|
|
31
29
|
|
|
32
30
|
for (let i = 0; i < ii; i += 1) {
|
|
33
31
|
[pathCommand] = path[i];
|
|
34
|
-
allPathCommands[i] = pathCommand;
|
|
32
|
+
allPathCommands[i] = pathCommand as PathCommand;
|
|
35
33
|
|
|
36
34
|
path[i] = segmentToCubic(path[i], params);
|
|
37
35
|
|
|
@@ -42,10 +40,10 @@ export default function pathToCurve(pathInput) {
|
|
|
42
40
|
const seglen = segment.length;
|
|
43
41
|
params.x1 = +segment[seglen - 2];
|
|
44
42
|
params.y1 = +segment[seglen - 1];
|
|
45
|
-
params.x2 = +
|
|
46
|
-
params.y2 = +
|
|
43
|
+
params.x2 = +segment[seglen - 4] || params.x1;
|
|
44
|
+
params.y2 = +segment[seglen - 3] || params.y1;
|
|
47
45
|
}
|
|
48
46
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
47
|
+
return path as CurveArray;
|
|
48
|
+
};
|
|
49
|
+
export default pathToCurve;
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
aSegment,
|
|
3
|
+
hSegment,
|
|
4
|
+
PathArray,
|
|
5
|
+
RelativeArray,
|
|
6
|
+
RelativeCommand,
|
|
7
|
+
RelativeSegment,
|
|
8
|
+
vSegment,
|
|
9
|
+
} from '../types';
|
|
10
|
+
import parsePathString from '../parser/parsePathString';
|
|
11
|
+
import isRelativeArray from '../util/isRelativeArray';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Parses a path string value or object and returns an array
|
|
15
|
+
* of segments, all converted to relative values.
|
|
16
|
+
*
|
|
17
|
+
* @param pathInput the path string | object
|
|
18
|
+
* @returns the resulted `pathArray` with relative values
|
|
19
|
+
*/
|
|
20
|
+
const pathToRelative = (pathInput: string | PathArray): RelativeArray => {
|
|
21
|
+
/* istanbul ignore else */
|
|
22
|
+
if (isRelativeArray(pathInput)) {
|
|
23
|
+
return [...pathInput];
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
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
|
+
|
|
89
|
+
return relativeSegment as typeof segment;
|
|
90
|
+
}) as RelativeArray;
|
|
91
|
+
};
|
|
92
|
+
export default pathToRelative;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { PathArray } from '../types';
|
|
2
|
+
import roundPath from '../process/roundPath';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Returns a valid `d` attribute string value created
|
|
6
|
+
* by rounding values and concatenating the `pathArray` segments.
|
|
7
|
+
*
|
|
8
|
+
* @param path the `pathArray` object
|
|
9
|
+
* @param round amount of decimals to round values to
|
|
10
|
+
* @returns the concatenated path string
|
|
11
|
+
*/
|
|
12
|
+
const pathToString = (path: PathArray, round?: number | 'off'): string => {
|
|
13
|
+
return roundPath(path, round)
|
|
14
|
+
.map(x => x[0] + x.slice(1).join(' '))
|
|
15
|
+
.join('');
|
|
16
|
+
};
|
|
17
|
+
export default pathToString;
|
|
@@ -1,24 +1,49 @@
|
|
|
1
|
+
import { PathArray, TransformObjectValues } from './types';
|
|
2
|
+
import { Options, PathBBox, TransformEntries, TransformObject } from './interface';
|
|
1
3
|
import defaultOptions from './options/options';
|
|
2
4
|
|
|
3
|
-
import
|
|
4
|
-
import pathToRelative from './convert/pathToRelative';
|
|
5
|
-
import pathToCurve from './convert/pathToCurve';
|
|
6
|
-
import pathToString from './convert/pathToString';
|
|
7
|
-
|
|
5
|
+
import error from './parser/error';
|
|
8
6
|
import parsePathString from './parser/parsePathString';
|
|
9
|
-
import reversePath from './process/reversePath';
|
|
10
7
|
|
|
11
|
-
import
|
|
8
|
+
import polygonArea from './math/polygonArea';
|
|
9
|
+
import polygonLength from './math/polygonLength';
|
|
10
|
+
|
|
11
|
+
import CSSMatrix from '@thednp/dommatrix';
|
|
12
|
+
import getPathBBox from './util/getPathBBox';
|
|
13
|
+
import getPathArea from './util/getPathArea';
|
|
14
|
+
import getTotalLength from './util/getTotalLength';
|
|
15
|
+
import getDrawDirection from './util/getDrawDirection';
|
|
16
|
+
import getPointAtLength from './util/getPointAtLength';
|
|
17
|
+
import pathLengthFactory from './util/pathLengthFactory';
|
|
18
|
+
|
|
19
|
+
import getPropertiesAtLength from './util/getPropertiesAtLength';
|
|
20
|
+
import getPropertiesAtPoint from './util/getPropertiesAtPoint';
|
|
21
|
+
import getClosestPoint from './util/getClosestPoint';
|
|
22
|
+
import getSegmentOfPoint from './util/getSegmentOfPoint';
|
|
23
|
+
import getSegmentAtLength from './util/getSegmentAtLength';
|
|
24
|
+
import isPointInStroke from './util/isPointInStroke';
|
|
25
|
+
|
|
26
|
+
import isValidPath from './util/isValidPath';
|
|
27
|
+
import isPathArray from './util/isPathArray';
|
|
28
|
+
import isAbsoluteArray from './util/isAbsoluteArray';
|
|
29
|
+
import isRelativeArray from './util/isRelativeArray';
|
|
30
|
+
import isCurveArray from './util/isCurveArray';
|
|
31
|
+
import isNormalizedArray from './util/isNormalizedArray';
|
|
32
|
+
import shapeToPath from './util/shapeToPath';
|
|
33
|
+
|
|
34
|
+
import roundPath from './process/roundPath';
|
|
12
35
|
import splitPath from './process/splitPath';
|
|
13
36
|
import optimizePath from './process/optimizePath';
|
|
37
|
+
import reverseCurve from './process/reverseCurve';
|
|
38
|
+
import reversePath from './process/reversePath';
|
|
14
39
|
import normalizePath from './process/normalizePath';
|
|
15
40
|
import transformPath from './process/transformPath';
|
|
41
|
+
import splitCubic from './process/splitCubic';
|
|
16
42
|
|
|
17
|
-
import
|
|
18
|
-
|
|
19
|
-
import
|
|
20
|
-
import
|
|
21
|
-
import getPointAtLength from './util/getPointAtLength';
|
|
43
|
+
import pathToAbsolute from './convert/pathToAbsolute';
|
|
44
|
+
import pathToRelative from './convert/pathToRelative';
|
|
45
|
+
import pathToCurve from './convert/pathToCurve';
|
|
46
|
+
import pathToString from './convert/pathToString';
|
|
22
47
|
|
|
23
48
|
/**
|
|
24
49
|
* Creates a new SVGPathCommander instance with the following properties:
|
|
@@ -31,14 +56,54 @@ import getPointAtLength from './util/getPointAtLength';
|
|
|
31
56
|
* @returns {SVGPathCommander} a new SVGPathCommander instance
|
|
32
57
|
*/
|
|
33
58
|
class SVGPathCommander {
|
|
59
|
+
// bring main utilities to front
|
|
60
|
+
public static CSSMatrix = CSSMatrix;
|
|
61
|
+
public static getPathBBox = getPathBBox;
|
|
62
|
+
public static getPathArea = getPathArea;
|
|
63
|
+
public static getTotalLength = getTotalLength;
|
|
64
|
+
public static getDrawDirection = getDrawDirection;
|
|
65
|
+
public static getPointAtLength = getPointAtLength;
|
|
66
|
+
public static pathLengthFactory = pathLengthFactory;
|
|
67
|
+
public static getPropertiesAtLength = getPropertiesAtLength;
|
|
68
|
+
public static getPropertiesAtPoint = getPropertiesAtPoint;
|
|
69
|
+
public static polygonLength = polygonLength;
|
|
70
|
+
public static polygonArea = polygonArea;
|
|
71
|
+
public static getClosestPoint = getClosestPoint;
|
|
72
|
+
public static getSegmentOfPoint = getSegmentOfPoint;
|
|
73
|
+
public static getSegmentAtLength = getSegmentAtLength;
|
|
74
|
+
public static isPointInStroke = isPointInStroke;
|
|
75
|
+
public static isValidPath = isValidPath;
|
|
76
|
+
public static isPathArray = isPathArray;
|
|
77
|
+
public static isAbsoluteArray = isAbsoluteArray;
|
|
78
|
+
public static isRelativeArray = isRelativeArray;
|
|
79
|
+
public static isCurveArray = isCurveArray;
|
|
80
|
+
public static isNormalizedArray = isNormalizedArray;
|
|
81
|
+
public static shapeToPath = shapeToPath;
|
|
82
|
+
public static parsePathString = parsePathString;
|
|
83
|
+
public static roundPath = roundPath;
|
|
84
|
+
public static splitPath = splitPath;
|
|
85
|
+
public static splitCubic = splitCubic;
|
|
86
|
+
public static optimizePath = optimizePath;
|
|
87
|
+
public static reverseCurve = reverseCurve;
|
|
88
|
+
public static reversePath = reversePath;
|
|
89
|
+
public static normalizePath = normalizePath;
|
|
90
|
+
public static transformPath = transformPath;
|
|
91
|
+
public static pathToAbsolute = pathToAbsolute;
|
|
92
|
+
public static pathToRelative = pathToRelative;
|
|
93
|
+
public static pathToCurve = pathToCurve;
|
|
94
|
+
public static pathToString = pathToString;
|
|
95
|
+
// declare class properties
|
|
96
|
+
declare segments: PathArray;
|
|
97
|
+
declare round: number | 'off';
|
|
98
|
+
declare origin: [number, number, number];
|
|
99
|
+
|
|
34
100
|
/**
|
|
35
101
|
* @constructor
|
|
36
102
|
* @param {string} pathValue the path string
|
|
37
103
|
* @param {any} config instance options
|
|
38
104
|
*/
|
|
39
|
-
constructor(pathValue, config) {
|
|
105
|
+
constructor(pathValue: string, config?: Partial<Options>) {
|
|
40
106
|
const instanceOptions = config || {};
|
|
41
|
-
|
|
42
107
|
const undefPath = typeof pathValue === 'undefined';
|
|
43
108
|
|
|
44
109
|
if (undefPath || !pathValue.length) {
|
|
@@ -46,35 +111,30 @@ class SVGPathCommander {
|
|
|
46
111
|
}
|
|
47
112
|
|
|
48
113
|
const segments = parsePathString(pathValue);
|
|
49
|
-
if (typeof segments === 'string') {
|
|
50
|
-
|
|
51
|
-
}
|
|
114
|
+
// if (typeof segments === 'string') {
|
|
115
|
+
// throw TypeError(segments);
|
|
116
|
+
// }
|
|
52
117
|
|
|
53
|
-
/**
|
|
54
|
-
* @type {SVGPath.pathArray}
|
|
55
|
-
*/
|
|
56
118
|
this.segments = segments;
|
|
57
119
|
|
|
58
|
-
const {
|
|
59
|
-
width, height, cx, cy, cz,
|
|
60
|
-
} = this.getBBox();
|
|
120
|
+
const { width, height, cx, cy, cz } = this.getBBox();
|
|
61
121
|
|
|
62
122
|
// set instance options.round
|
|
63
123
|
const { round: roundOption, origin: originOption } = instanceOptions;
|
|
64
|
-
let round;
|
|
124
|
+
let round: number | 'off';
|
|
65
125
|
|
|
66
126
|
if (roundOption === 'auto') {
|
|
67
|
-
const pathScale =
|
|
127
|
+
const pathScale = `${Math.floor(Math.max(width, height))}`.length;
|
|
68
128
|
round = pathScale >= 4 ? 0 : 4 - pathScale;
|
|
69
129
|
} else if (Number.isInteger(roundOption) || roundOption === 'off') {
|
|
70
|
-
round = roundOption;
|
|
130
|
+
round = roundOption as number | 'off';
|
|
71
131
|
} else {
|
|
72
|
-
|
|
132
|
+
round = defaultOptions.round as number;
|
|
73
133
|
}
|
|
74
134
|
|
|
75
135
|
// set instance options.origin
|
|
76
136
|
// the SVGPathCommander class will always override the default origin
|
|
77
|
-
let origin;
|
|
137
|
+
let origin: [number, number, number];
|
|
78
138
|
if (Array.isArray(originOption) && originOption.length >= 2) {
|
|
79
139
|
const [originX, originY, originZ] = originOption.map(Number);
|
|
80
140
|
origin = [
|
|
@@ -86,9 +146,7 @@ class SVGPathCommander {
|
|
|
86
146
|
origin = [cx, cy, cz];
|
|
87
147
|
}
|
|
88
148
|
|
|
89
|
-
/** @type {number | 'off'} */
|
|
90
149
|
this.round = round;
|
|
91
|
-
/** @type {[number, number, number=]} */
|
|
92
150
|
this.origin = origin;
|
|
93
151
|
|
|
94
152
|
return this;
|
|
@@ -96,17 +154,19 @@ class SVGPathCommander {
|
|
|
96
154
|
|
|
97
155
|
/**
|
|
98
156
|
* Returns the path bounding box, equivalent to native `path.getBBox()`.
|
|
157
|
+
*
|
|
99
158
|
* @public
|
|
100
|
-
* @returns
|
|
159
|
+
* @returns the pathBBox
|
|
101
160
|
*/
|
|
102
|
-
getBBox() {
|
|
161
|
+
getBBox(): PathBBox {
|
|
103
162
|
return getPathBBox(this.segments);
|
|
104
163
|
}
|
|
105
164
|
|
|
106
165
|
/**
|
|
107
166
|
* Returns the total path length, equivalent to native `path.getTotalLength()`.
|
|
167
|
+
*
|
|
108
168
|
* @public
|
|
109
|
-
* @returns
|
|
169
|
+
* @returns the path total length
|
|
110
170
|
*/
|
|
111
171
|
getTotalLength() {
|
|
112
172
|
return getTotalLength(this.segments);
|
|
@@ -117,15 +177,16 @@ class SVGPathCommander {
|
|
|
117
177
|
* equivalent to the native `path.getPointAtLength()`.
|
|
118
178
|
*
|
|
119
179
|
* @public
|
|
120
|
-
* @param
|
|
121
|
-
* @returns
|
|
180
|
+
* @param length the length
|
|
181
|
+
* @returns the requested point
|
|
122
182
|
*/
|
|
123
|
-
getPointAtLength(length) {
|
|
183
|
+
getPointAtLength(length: number): { x: number; y: number } {
|
|
124
184
|
return getPointAtLength(this.segments, length);
|
|
125
185
|
}
|
|
126
186
|
|
|
127
187
|
/**
|
|
128
188
|
* Convert path to absolute values
|
|
189
|
+
*
|
|
129
190
|
* @public
|
|
130
191
|
*/
|
|
131
192
|
toAbsolute() {
|
|
@@ -136,6 +197,7 @@ class SVGPathCommander {
|
|
|
136
197
|
|
|
137
198
|
/**
|
|
138
199
|
* Convert path to relative values
|
|
200
|
+
*
|
|
139
201
|
* @public
|
|
140
202
|
*/
|
|
141
203
|
toRelative() {
|
|
@@ -158,23 +220,26 @@ class SVGPathCommander {
|
|
|
158
220
|
|
|
159
221
|
/**
|
|
160
222
|
* Reverse the order of the segments and their values.
|
|
161
|
-
*
|
|
223
|
+
*
|
|
224
|
+
* @param onlySubpath option to reverse all sub-paths except first
|
|
162
225
|
* @public
|
|
163
226
|
*/
|
|
164
|
-
reverse(onlySubpath) {
|
|
227
|
+
reverse(onlySubpath?: boolean) {
|
|
165
228
|
this.toAbsolute();
|
|
166
229
|
|
|
167
230
|
const { segments } = this;
|
|
168
231
|
const split = splitPath(segments);
|
|
169
|
-
const subPath = split.length > 1 ? split :
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
232
|
+
const subPath = split.length > 1 ? split : false;
|
|
233
|
+
|
|
234
|
+
const absoluteMultiPath = subPath
|
|
235
|
+
? [...subPath].map((x, i) => {
|
|
236
|
+
if (onlySubpath) {
|
|
237
|
+
// return i ? reversePath(x) : parsePathString(x);
|
|
238
|
+
return i ? reversePath(x) : [...x];
|
|
239
|
+
}
|
|
240
|
+
return reversePath(x);
|
|
241
|
+
})
|
|
242
|
+
: [...segments];
|
|
178
243
|
|
|
179
244
|
let path = [];
|
|
180
245
|
if (subPath) {
|
|
@@ -183,7 +248,7 @@ class SVGPathCommander {
|
|
|
183
248
|
path = onlySubpath ? segments : reversePath(segments);
|
|
184
249
|
}
|
|
185
250
|
|
|
186
|
-
this.segments =
|
|
251
|
+
this.segments = [...path] as PathArray;
|
|
187
252
|
return this;
|
|
188
253
|
}
|
|
189
254
|
|
|
@@ -191,6 +256,7 @@ class SVGPathCommander {
|
|
|
191
256
|
* Normalize path in 2 steps:
|
|
192
257
|
* * convert `pathArray`(s) to absolute values
|
|
193
258
|
* * convert shorthand notation to standard notation
|
|
259
|
+
*
|
|
194
260
|
* @public
|
|
195
261
|
*/
|
|
196
262
|
normalize() {
|
|
@@ -204,6 +270,7 @@ class SVGPathCommander {
|
|
|
204
270
|
* * convert segments to absolute and/or relative values
|
|
205
271
|
* * select segments with shortest resulted string
|
|
206
272
|
* * round values to the specified `decimals` option value
|
|
273
|
+
*
|
|
207
274
|
* @public
|
|
208
275
|
*/
|
|
209
276
|
optimize() {
|
|
@@ -215,34 +282,40 @@ class SVGPathCommander {
|
|
|
215
282
|
|
|
216
283
|
/**
|
|
217
284
|
* Transform path using values from an `Object` defined as `transformObject`.
|
|
218
|
-
* @see SVGPath.transformObject for a quick refference
|
|
219
285
|
*
|
|
220
|
-
* @
|
|
286
|
+
* @see TransformObject for a quick refference
|
|
287
|
+
*
|
|
288
|
+
* @param source a `transformObject`as described above
|
|
221
289
|
* @public
|
|
222
290
|
*/
|
|
223
|
-
transform(source) {
|
|
224
|
-
if (
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
291
|
+
transform(source?: Partial<TransformObject>) {
|
|
292
|
+
if (
|
|
293
|
+
!source ||
|
|
294
|
+
typeof source !== 'object' ||
|
|
295
|
+
(typeof source === 'object' && !['translate', 'rotate', 'skew', 'scale'].some(x => x in source))
|
|
296
|
+
)
|
|
297
|
+
return this;
|
|
298
|
+
|
|
299
|
+
const {
|
|
300
|
+
segments,
|
|
301
|
+
origin: [cx, cy, cz],
|
|
302
|
+
} = this;
|
|
303
|
+
const transform = {} as TransformObjectValues;
|
|
304
|
+
for (const [k, v] of Object.entries(source) as TransformEntries) {
|
|
305
|
+
if (k === 'skew' && Array.isArray(v)) {
|
|
306
|
+
transform[k] = v.map(Number) as [number, number];
|
|
307
|
+
} else if ((k === 'rotate' || k === 'translate' || k === 'origin' || k === 'scale') && Array.isArray(v)) {
|
|
308
|
+
transform[k] = v.map(Number) as [number, number, number];
|
|
309
|
+
} else if (k !== 'origin' && typeof Number(v) === 'number') transform[k] = Number(v);
|
|
310
|
+
}
|
|
233
311
|
|
|
234
312
|
// if origin is not specified
|
|
235
313
|
// it's important that we have one
|
|
236
|
-
const [cx, cy, cz] = this.origin;
|
|
237
314
|
const { origin } = transform;
|
|
238
315
|
|
|
239
316
|
if (Array.isArray(origin) && origin.length >= 2) {
|
|
240
317
|
const [originX, originY, originZ] = origin.map(Number);
|
|
241
|
-
transform.origin = [
|
|
242
|
-
!Number.isNaN(originX) ? originX : cx,
|
|
243
|
-
!Number.isNaN(originY) ? originY : cy,
|
|
244
|
-
originZ || cz,
|
|
245
|
-
];
|
|
318
|
+
transform.origin = [!Number.isNaN(originX) ? originX : cx, !Number.isNaN(originY) ? originY : cy, originZ || cz];
|
|
246
319
|
} else {
|
|
247
320
|
transform.origin = [cx, cy, cz];
|
|
248
321
|
}
|
|
@@ -253,6 +326,7 @@ class SVGPathCommander {
|
|
|
253
326
|
|
|
254
327
|
/**
|
|
255
328
|
* Rotate path 180deg vertically
|
|
329
|
+
*
|
|
256
330
|
* @public
|
|
257
331
|
*/
|
|
258
332
|
flipX() {
|
|
@@ -262,6 +336,7 @@ class SVGPathCommander {
|
|
|
262
336
|
|
|
263
337
|
/**
|
|
264
338
|
* Rotate path 180deg horizontally
|
|
339
|
+
*
|
|
265
340
|
* @public
|
|
266
341
|
*/
|
|
267
342
|
flipY() {
|
|
@@ -272,8 +347,9 @@ class SVGPathCommander {
|
|
|
272
347
|
/**
|
|
273
348
|
* Export the current path to be used
|
|
274
349
|
* for the `d` (description) attribute.
|
|
350
|
+
*
|
|
275
351
|
* @public
|
|
276
|
-
* @return
|
|
352
|
+
* @return the path string
|
|
277
353
|
*/
|
|
278
354
|
toString() {
|
|
279
355
|
return pathToString(this.segments, this.round);
|