svg-path-commander 2.0.10 → 2.1.1
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/.eslintrc.cjs +1 -0
- package/README.md +64 -8
- package/dist/svg-path-commander.cjs +1 -1
- package/dist/svg-path-commander.cjs.map +1 -1
- package/dist/svg-path-commander.d.ts +236 -43
- package/dist/svg-path-commander.js +1 -1
- package/dist/svg-path-commander.js.map +1 -1
- package/dist/svg-path-commander.mjs +790 -650
- package/dist/svg-path-commander.mjs.map +1 -1
- package/package.json +20 -22
- package/src/convert/pathToAbsolute.ts +16 -70
- package/src/convert/pathToCurve.ts +36 -28
- package/src/convert/pathToRelative.ts +33 -62
- package/src/index.ts +37 -39
- package/src/interface.ts +33 -33
- package/src/math/arcTools.ts +394 -0
- package/src/math/bezier.ts +253 -0
- package/src/math/cubicTools.ts +122 -0
- package/src/math/distanceSquareRoot.ts +3 -1
- package/src/math/lineTools.ts +67 -0
- package/src/math/midPoint.ts +3 -1
- package/src/math/polygonArea.ts +3 -1
- package/src/math/polygonLength.ts +2 -1
- package/src/math/quadTools.ts +98 -0
- package/src/parser/isMoveCommand.ts +17 -0
- package/src/parser/parsePathString.ts +5 -5
- package/src/parser/scanSegment.ts +12 -3
- package/src/process/absolutizeSegment.ts +58 -0
- package/src/process/iterate.ts +33 -0
- package/src/process/normalizePath.ts +34 -28
- package/src/process/normalizeSegment.ts +8 -9
- package/src/process/projection2d.ts +2 -1
- package/src/process/relativizeSegment.ts +61 -0
- package/src/process/reversePath.ts +1 -1
- package/src/process/roundPath.ts +8 -10
- package/src/process/segmentToCubic.ts +1 -1
- package/src/process/shortenSegment.ts +3 -3
- package/src/process/splitCubic.ts +8 -7
- package/src/process/splitPath.ts +39 -5
- package/src/process/transformPath.ts +81 -94
- package/src/types.ts +40 -1
- package/src/util/distanceEpsilon.ts +3 -0
- package/src/util/getClosestPoint.ts +1 -1
- package/src/util/getPathArea.ts +3 -3
- package/src/util/getPathBBox.ts +86 -18
- package/src/util/getPointAtLength.ts +98 -4
- package/src/util/getPropertiesAtLength.ts +4 -3
- package/src/util/getPropertiesAtPoint.ts +4 -1
- package/src/util/getTotalLength.ts +71 -4
- package/src/util/isPointInStroke.ts +2 -1
- package/src/util/shapeToPathArray.ts +8 -4
- package/test/class.test.ts +502 -0
- package/test/fixtures/getMarkup.ts +17 -0
- package/{cypress → test}/fixtures/shapes.js +39 -39
- package/test/fixtures/simpleShapes.js +75 -0
- package/test/static.test.ts +324 -0
- package/tsconfig.json +9 -4
- package/{vite.config.ts → vite.config.mts} +10 -1
- package/vitest.config-ui.mts +26 -0
- package/vitest.config.mts +26 -0
- package/cypress/e2e/svg-path-commander.spec.ts +0 -868
- package/cypress/fixtures/simpleShapes.js +0 -75
- package/cypress/plugins/esbuild-istanbul.ts +0 -50
- package/cypress/plugins/tsCompile.ts +0 -34
- package/cypress/support/commands.ts +0 -37
- package/cypress/support/e2e.ts +0 -21
- package/cypress/test.html +0 -36
- package/cypress.config.ts +0 -29
- package/src/process/fixArc.ts +0 -23
- package/src/util/pathLengthFactory.ts +0 -114
- package/src/util/segmentArcFactory.ts +0 -219
- package/src/util/segmentCubicFactory.ts +0 -114
- package/src/util/segmentLineFactory.ts +0 -45
- package/src/util/segmentQuadFactory.ts +0 -109
- /package/{cypress/fixtures/shapeObjects.js → test/fixtures/shapeObjects.ts} +0 -0
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.
|
|
5
|
+
"version": "2.1.1",
|
|
6
6
|
"description": "Modern TypeScript tools for SVG",
|
|
7
7
|
"source": "./src/index.ts",
|
|
8
8
|
"main": "./dist/svg-path-commander.js",
|
|
@@ -38,28 +38,24 @@
|
|
|
38
38
|
},
|
|
39
39
|
"homepage": "http://thednp.github.io/svg-path-commander",
|
|
40
40
|
"devDependencies": {
|
|
41
|
-
"@bahmutov/cypress-esbuild-preprocessor": "^2.2.2",
|
|
42
|
-
"@cypress/code-coverage": "^3.12.44",
|
|
43
|
-
"@types/istanbul-lib-instrument": "^1.7.7",
|
|
44
41
|
"@typescript-eslint/eslint-plugin": "^5.62.0",
|
|
45
42
|
"@typescript-eslint/parser": "^5.62.0",
|
|
46
|
-
"
|
|
43
|
+
"@vitest/browser": "^2.1.2",
|
|
44
|
+
"@vitest/coverage-istanbul": "^2.1.2",
|
|
45
|
+
"@vitest/ui": "^2.1.2",
|
|
47
46
|
"dts-bundle-generator": "^9.5.1",
|
|
48
|
-
"eslint": "^8.57.
|
|
47
|
+
"eslint": "^8.57.1",
|
|
49
48
|
"eslint-plugin-jsdoc": "^46.10.1",
|
|
50
49
|
"eslint-plugin-prefer-arrow": "^1.2.3",
|
|
51
50
|
"eslint-plugin-prettier": "^4.2.1",
|
|
52
|
-
"
|
|
53
|
-
"istanbul-lib-instrument": "^5.2.1",
|
|
54
|
-
"ncp": "^2.0.0",
|
|
55
|
-
"nyc": "^17.0.0",
|
|
51
|
+
"playwright": "^1.48.0",
|
|
56
52
|
"prettier": "^2.8.8",
|
|
57
|
-
"
|
|
58
|
-
"
|
|
59
|
-
"
|
|
53
|
+
"typescript": "^5.6.3",
|
|
54
|
+
"vite": "^5.4.8",
|
|
55
|
+
"vitest": "^2.1.2"
|
|
60
56
|
},
|
|
61
57
|
"dependencies": {
|
|
62
|
-
"@thednp/dommatrix": "^2.0.
|
|
58
|
+
"@thednp/dommatrix": "^2.0.8"
|
|
63
59
|
},
|
|
64
60
|
"engines": {
|
|
65
61
|
"node": ">=16",
|
|
@@ -67,17 +63,19 @@
|
|
|
67
63
|
},
|
|
68
64
|
"scripts": {
|
|
69
65
|
"pre-test": "pnpm clean-coverage",
|
|
70
|
-
"badges": "npx -p dependency-version-badge update-badge typescript
|
|
71
|
-
"
|
|
72
|
-
"
|
|
73
|
-
"
|
|
74
|
-
"coverage
|
|
66
|
+
"badges": "npx -p dependency-version-badge update-badge typescript eslint prettier vitest vite",
|
|
67
|
+
"dev": "vite serve docs --port 3000",
|
|
68
|
+
"test": "pnpm pre-test && vitest --config vitest.config.mts",
|
|
69
|
+
"test-ui": "pnpm pre-test && vitest --config vitest.config-ui.mts --browser=chrome",
|
|
70
|
+
"clean-coverage": "rm -rf coverage .nyc_output",
|
|
75
71
|
"format": "prettier --write \"src/**/*.ts\"",
|
|
72
|
+
"lint": "pnpm lint:ts && pnpm check:ts",
|
|
76
73
|
"fix:ts": "eslint src --config .eslintrc.cjs --fix",
|
|
77
74
|
"lint:ts": "eslint src --config .eslintrc.cjs",
|
|
78
|
-
"
|
|
79
|
-
"build
|
|
75
|
+
"check:ts": "tsc --noEmit",
|
|
76
|
+
"build": "pnpm lint && pnpm build-vite && pnpm build-ts",
|
|
77
|
+
"build-vite": "vite build && pnpm copy-docs",
|
|
80
78
|
"build-ts": "dts-bundle-generator --config ./dts.config.ts",
|
|
81
|
-
"
|
|
79
|
+
"copy-docs": "cp dist/svg-path-commander.js docs/svg-path-commander.js && cp dist/svg-path-commander.js.map docs/svg-path-commander.js.map"
|
|
82
80
|
}
|
|
83
81
|
}
|
|
@@ -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, AbsoluteCommand, HSegment, PathArray, PointTuple, VSegment } 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,72 +10,28 @@ 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];
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
const path = parsePathString(pathInput);
|
|
13
|
+
const pathToAbsolute = (pathInput: string | PathArray) => {
|
|
32
14
|
let x = 0;
|
|
33
15
|
let y = 0;
|
|
34
16
|
let mx = 0;
|
|
35
17
|
let my = 0;
|
|
18
|
+
let pathCommand = 'M';
|
|
19
|
+
const path = parsePathString(pathInput);
|
|
36
20
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
const
|
|
40
|
-
const [pathCommand] = segment;
|
|
21
|
+
return iterate<AbsoluteArray>(path, (seg, params) => {
|
|
22
|
+
[pathCommand] = seg;
|
|
23
|
+
const result = absolutizeSegment(seg, params);
|
|
41
24
|
const absCommand = pathCommand.toUpperCase() as AbsoluteCommand;
|
|
42
25
|
|
|
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
26
|
if (absCommand === 'Z') {
|
|
81
27
|
x = mx;
|
|
82
28
|
y = my;
|
|
83
29
|
} else if (absCommand === 'H') {
|
|
84
|
-
[, x] =
|
|
30
|
+
[, x] = result as HSegment;
|
|
85
31
|
} else if (absCommand === 'V') {
|
|
86
|
-
[, y] =
|
|
32
|
+
[, y] = result as VSegment;
|
|
87
33
|
} else {
|
|
88
|
-
|
|
89
|
-
// y = absoluteSegment[segLength - 1];
|
|
90
|
-
[x, y] = absoluteSegment.slice(-2) as [number, number];
|
|
34
|
+
[x, y] = result.slice(-2) as PointTuple;
|
|
91
35
|
|
|
92
36
|
if (absCommand === 'M') {
|
|
93
37
|
mx = x;
|
|
@@ -95,7 +39,9 @@ const pathToAbsolute = (pathInput: string | PathArray): AbsoluteArray => {
|
|
|
95
39
|
}
|
|
96
40
|
}
|
|
97
41
|
|
|
98
|
-
|
|
99
|
-
|
|
42
|
+
params.x = x;
|
|
43
|
+
params.y = y;
|
|
44
|
+
return result;
|
|
45
|
+
});
|
|
100
46
|
};
|
|
101
47
|
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';
|
|
5
|
-
import
|
|
6
|
-
import
|
|
2
|
+
import { AbsoluteCommand, CSegment, CurveArray, PathArray, PointTuple } from '../types';
|
|
3
|
+
import iterate from '../process/iterate';
|
|
4
|
+
import parsePathString from '../parser/parsePathString';
|
|
5
|
+
import normalizeSegment from '../process/normalizeSegment';
|
|
6
|
+
import absolutizeSegment from '../process/absolutizeSegment';
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* Parses a path string value or 'pathArray' and returns a new one
|
|
@@ -16,34 +16,42 @@ 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
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
19
|
+
let x = 0;
|
|
20
|
+
let y = 0;
|
|
21
|
+
let mx = 0;
|
|
22
|
+
let my = 0;
|
|
23
|
+
let pathCommand = 'M';
|
|
23
24
|
|
|
24
|
-
const path =
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
let ii = path.length;
|
|
25
|
+
const path = parsePathString(pathInput);
|
|
26
|
+
return iterate<CurveArray>(path, (seg, params, i) => {
|
|
27
|
+
const absSegment = absolutizeSegment(seg, params);
|
|
28
|
+
[pathCommand] = absSegment;
|
|
29
29
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
30
|
+
const absCommand = pathCommand.toUpperCase() as AbsoluteCommand;
|
|
31
|
+
const normalSegment = normalizeSegment(absSegment, params);
|
|
32
|
+
let result = segmentToCubic(normalSegment, params);
|
|
33
|
+
const isLongArc = result[0] === 'C' && result.length > 7;
|
|
33
34
|
|
|
34
|
-
|
|
35
|
+
if (isLongArc) {
|
|
36
|
+
path.splice(i + 1, 0, ['C', ...result.slice(7)] as CSegment);
|
|
37
|
+
result = result.slice(0, 7) as CSegment;
|
|
38
|
+
}
|
|
35
39
|
|
|
36
|
-
|
|
37
|
-
|
|
40
|
+
if (absCommand === 'Z') {
|
|
41
|
+
x = mx;
|
|
42
|
+
y = my;
|
|
43
|
+
} else {
|
|
44
|
+
[x, y] = result.slice(-2) as PointTuple;
|
|
38
45
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
params.y2 = +segment[seglen - 3] || params.y1;
|
|
45
|
-
}
|
|
46
|
+
if (absCommand === 'M') {
|
|
47
|
+
mx = x;
|
|
48
|
+
my = y;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
46
51
|
|
|
47
|
-
|
|
52
|
+
params.x = x;
|
|
53
|
+
params.y = y;
|
|
54
|
+
return result;
|
|
55
|
+
});
|
|
48
56
|
};
|
|
49
57
|
export default pathToCurve;
|
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
import type {
|
|
2
|
-
|
|
2
|
+
AbsoluteCommand,
|
|
3
3
|
hSegment,
|
|
4
4
|
PathArray,
|
|
5
|
+
PointTuple,
|
|
5
6
|
RelativeArray,
|
|
6
7
|
RelativeCommand,
|
|
7
|
-
RelativeSegment,
|
|
8
8
|
vSegment,
|
|
9
9
|
} from '../types';
|
|
10
10
|
import parsePathString from '../parser/parsePathString';
|
|
11
|
-
import
|
|
11
|
+
import iterate from '../process/iterate';
|
|
12
|
+
import relativizeSegment from '../process/relativizeSegment';
|
|
12
13
|
|
|
13
14
|
/**
|
|
14
15
|
* Parses a path string value or object and returns an array
|
|
@@ -18,75 +19,45 @@ import isRelativeArray from '../util/isRelativeArray';
|
|
|
18
19
|
* @returns the resulted `pathArray` with relative values
|
|
19
20
|
*/
|
|
20
21
|
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
22
|
let x = 0;
|
|
28
23
|
let y = 0;
|
|
29
24
|
let mx = 0;
|
|
30
25
|
let my = 0;
|
|
26
|
+
let pathCommand = 'M';
|
|
27
|
+
const path = parsePathString(pathInput);
|
|
31
28
|
|
|
32
|
-
return path
|
|
33
|
-
|
|
34
|
-
const
|
|
35
|
-
const
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
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
|
-
}
|
|
29
|
+
return iterate<RelativeArray>(path, (seg, params, i) => {
|
|
30
|
+
[pathCommand] = seg;
|
|
31
|
+
const result = relativizeSegment(seg, params, i);
|
|
32
|
+
const [resultedCommand] = result;
|
|
33
|
+
const absCommand = pathCommand.toUpperCase() as AbsoluteCommand;
|
|
34
|
+
const relCommand = pathCommand.toLowerCase() as RelativeCommand;
|
|
35
|
+
const isRelative = resultedCommand === relCommand;
|
|
75
36
|
|
|
76
|
-
|
|
77
|
-
if (relativeCommand === 'z') {
|
|
37
|
+
if (absCommand === 'Z') {
|
|
78
38
|
x = mx;
|
|
79
39
|
y = my;
|
|
80
|
-
} else if (
|
|
81
|
-
x
|
|
82
|
-
|
|
83
|
-
|
|
40
|
+
} else if (absCommand === 'H') {
|
|
41
|
+
[, x] = result as hSegment;
|
|
42
|
+
x += isRelative ? params.x : /* istanbul ignore next @preserve */ 0;
|
|
43
|
+
} else if (absCommand === 'V') {
|
|
44
|
+
[, y] = result as vSegment;
|
|
45
|
+
y += isRelative ? params.y : /* istanbul ignore next @preserve */ 0;
|
|
84
46
|
} else {
|
|
85
|
-
x
|
|
86
|
-
|
|
47
|
+
[x, y] = result.slice(-2) as PointTuple;
|
|
48
|
+
x += isRelative ? params.x : 0;
|
|
49
|
+
y += isRelative ? params.y : 0;
|
|
50
|
+
|
|
51
|
+
if (absCommand === 'M') {
|
|
52
|
+
mx = x;
|
|
53
|
+
my = y;
|
|
54
|
+
}
|
|
87
55
|
}
|
|
88
56
|
|
|
89
|
-
|
|
90
|
-
|
|
57
|
+
params.x = x;
|
|
58
|
+
params.y = y;
|
|
59
|
+
|
|
60
|
+
return result;
|
|
61
|
+
});
|
|
91
62
|
};
|
|
92
63
|
export default pathToRelative;
|
package/src/index.ts
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
import {
|
|
1
|
+
'use strict';
|
|
2
|
+
import { PointTuple, PathArray, TransformObjectValues } from './types';
|
|
3
|
+
import type { Options, TransformEntries, TransformObject } from './interface';
|
|
4
|
+
export * from './types';
|
|
5
|
+
export * from './interface';
|
|
3
6
|
import defaultOptions from './options/options';
|
|
4
7
|
|
|
5
8
|
import error from './parser/error';
|
|
@@ -14,7 +17,6 @@ import getPathArea from './util/getPathArea';
|
|
|
14
17
|
import getTotalLength from './util/getTotalLength';
|
|
15
18
|
import getDrawDirection from './util/getDrawDirection';
|
|
16
19
|
import getPointAtLength from './util/getPointAtLength';
|
|
17
|
-
import pathLengthFactory from './util/pathLengthFactory';
|
|
18
20
|
|
|
19
21
|
import getPropertiesAtLength from './util/getPropertiesAtLength';
|
|
20
22
|
import getPropertiesAtPoint from './util/getPropertiesAtPoint';
|
|
@@ -55,10 +57,9 @@ import pathToString from './convert/pathToString';
|
|
|
55
57
|
*
|
|
56
58
|
* @class
|
|
57
59
|
* @author thednp <https://github.com/thednp/svg-path-commander>
|
|
58
|
-
* @returns
|
|
60
|
+
* @returns a new SVGPathCommander instance
|
|
59
61
|
*/
|
|
60
62
|
class SVGPathCommander {
|
|
61
|
-
// bring main utilities to front
|
|
62
63
|
public static CSSMatrix = CSSMatrix;
|
|
63
64
|
public static getSVGMatrix = getSVGMatrix;
|
|
64
65
|
public static getPathBBox = getPathBBox;
|
|
@@ -66,7 +67,6 @@ class SVGPathCommander {
|
|
|
66
67
|
public static getTotalLength = getTotalLength;
|
|
67
68
|
public static getDrawDirection = getDrawDirection;
|
|
68
69
|
public static getPointAtLength = getPointAtLength;
|
|
69
|
-
public static pathLengthFactory = pathLengthFactory;
|
|
70
70
|
public static getPropertiesAtLength = getPropertiesAtLength;
|
|
71
71
|
public static getPropertiesAtPoint = getPropertiesAtPoint;
|
|
72
72
|
public static polygonLength = polygonLength;
|
|
@@ -103,8 +103,8 @@ class SVGPathCommander {
|
|
|
103
103
|
|
|
104
104
|
/**
|
|
105
105
|
* @constructor
|
|
106
|
-
* @param
|
|
107
|
-
* @param
|
|
106
|
+
* @param pathValue the path string
|
|
107
|
+
* @param config instance options
|
|
108
108
|
*/
|
|
109
109
|
constructor(pathValue: string, config?: Partial<Options>) {
|
|
110
110
|
const instanceOptions = config || {};
|
|
@@ -115,22 +115,13 @@ class SVGPathCommander {
|
|
|
115
115
|
}
|
|
116
116
|
|
|
117
117
|
const segments = parsePathString(pathValue);
|
|
118
|
-
// if (typeof segments === 'string') {
|
|
119
|
-
// throw TypeError(segments);
|
|
120
|
-
// }
|
|
121
|
-
|
|
122
118
|
this.segments = segments;
|
|
123
119
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
// set instance options.round
|
|
120
|
+
// // set instance options.round
|
|
127
121
|
const { round: roundOption, origin: originOption } = instanceOptions;
|
|
128
122
|
let round: number | 'off';
|
|
129
123
|
|
|
130
|
-
if (roundOption === '
|
|
131
|
-
const pathScale = `${Math.floor(Math.max(width, height))}`.length;
|
|
132
|
-
round = pathScale >= 4 ? 0 : 4 - pathScale;
|
|
133
|
-
} else if (Number.isInteger(roundOption) || roundOption === 'off') {
|
|
124
|
+
if (Number.isInteger(roundOption) || roundOption === 'off') {
|
|
134
125
|
round = roundOption as number | 'off';
|
|
135
126
|
} else {
|
|
136
127
|
round = defaultOptions.round as number;
|
|
@@ -138,16 +129,15 @@ class SVGPathCommander {
|
|
|
138
129
|
|
|
139
130
|
// set instance options.origin
|
|
140
131
|
// the SVGPathCommander class will always override the default origin
|
|
141
|
-
let origin
|
|
132
|
+
let origin = defaultOptions.origin as [number, number, number];
|
|
133
|
+
/* istanbul ignore else @preserve */
|
|
142
134
|
if (Array.isArray(originOption) && originOption.length >= 2) {
|
|
143
135
|
const [originX, originY, originZ] = originOption.map(Number);
|
|
144
136
|
origin = [
|
|
145
|
-
!Number.isNaN(originX) ? originX :
|
|
146
|
-
!Number.isNaN(originY) ? originY :
|
|
147
|
-
!Number.isNaN(originZ) ? originZ :
|
|
137
|
+
!Number.isNaN(originX) ? originX : 0,
|
|
138
|
+
!Number.isNaN(originY) ? originY : 0,
|
|
139
|
+
!Number.isNaN(originZ) ? originZ : 0,
|
|
148
140
|
];
|
|
149
|
-
} else {
|
|
150
|
-
origin = [cx, cy, cz];
|
|
151
141
|
}
|
|
152
142
|
|
|
153
143
|
this.round = round;
|
|
@@ -155,6 +145,12 @@ class SVGPathCommander {
|
|
|
155
145
|
|
|
156
146
|
return this;
|
|
157
147
|
}
|
|
148
|
+
get bbox() {
|
|
149
|
+
return getPathBBox(this.segments);
|
|
150
|
+
}
|
|
151
|
+
get length() {
|
|
152
|
+
return getTotalLength(this.segments);
|
|
153
|
+
}
|
|
158
154
|
|
|
159
155
|
/**
|
|
160
156
|
* Returns the path bounding box, equivalent to native `path.getBBox()`.
|
|
@@ -162,8 +158,8 @@ class SVGPathCommander {
|
|
|
162
158
|
* @public
|
|
163
159
|
* @returns the pathBBox
|
|
164
160
|
*/
|
|
165
|
-
getBBox()
|
|
166
|
-
return
|
|
161
|
+
getBBox() {
|
|
162
|
+
return this.bbox;
|
|
167
163
|
}
|
|
168
164
|
|
|
169
165
|
/**
|
|
@@ -173,7 +169,7 @@ class SVGPathCommander {
|
|
|
173
169
|
* @returns the path total length
|
|
174
170
|
*/
|
|
175
171
|
getTotalLength() {
|
|
176
|
-
return
|
|
172
|
+
return this.length;
|
|
177
173
|
}
|
|
178
174
|
|
|
179
175
|
/**
|
|
@@ -184,7 +180,7 @@ class SVGPathCommander {
|
|
|
184
180
|
* @param length the length
|
|
185
181
|
* @returns the requested point
|
|
186
182
|
*/
|
|
187
|
-
getPointAtLength(length: number)
|
|
183
|
+
getPointAtLength(length: number) {
|
|
188
184
|
return getPointAtLength(this.segments, length);
|
|
189
185
|
}
|
|
190
186
|
|
|
@@ -236,23 +232,22 @@ class SVGPathCommander {
|
|
|
236
232
|
const subPath = split.length > 1 ? split : false;
|
|
237
233
|
|
|
238
234
|
const absoluteMultiPath = subPath
|
|
239
|
-
?
|
|
235
|
+
? subPath.map((x, i) => {
|
|
240
236
|
if (onlySubpath) {
|
|
241
|
-
|
|
242
|
-
return i ? reversePath(x) : [...x];
|
|
237
|
+
return i ? reversePath(x) : x.slice(0);
|
|
243
238
|
}
|
|
244
239
|
return reversePath(x);
|
|
245
240
|
})
|
|
246
|
-
:
|
|
241
|
+
: segments.slice(0);
|
|
247
242
|
|
|
248
|
-
let path = [];
|
|
243
|
+
let path = [] as unknown as PathArray;
|
|
249
244
|
if (subPath) {
|
|
250
|
-
path = absoluteMultiPath.flat(1);
|
|
245
|
+
path = absoluteMultiPath.flat(1) as PathArray;
|
|
251
246
|
} else {
|
|
252
247
|
path = onlySubpath ? segments : reversePath(segments);
|
|
253
248
|
}
|
|
254
249
|
|
|
255
|
-
this.segments =
|
|
250
|
+
this.segments = path.slice(0) as PathArray;
|
|
256
251
|
return this;
|
|
257
252
|
}
|
|
258
253
|
|
|
@@ -306,8 +301,9 @@ class SVGPathCommander {
|
|
|
306
301
|
} = this;
|
|
307
302
|
const transform = {} as TransformObjectValues;
|
|
308
303
|
for (const [k, v] of Object.entries(source) as TransformEntries) {
|
|
304
|
+
// istanbul ignore else @preserve
|
|
309
305
|
if (k === 'skew' && Array.isArray(v)) {
|
|
310
|
-
transform[k] = v.map(Number) as
|
|
306
|
+
transform[k] = v.map(Number) as PointTuple;
|
|
311
307
|
} else if ((k === 'rotate' || k === 'translate' || k === 'origin' || k === 'scale') && Array.isArray(v)) {
|
|
312
308
|
transform[k] = v.map(Number) as [number, number, number];
|
|
313
309
|
} else if (k !== 'origin' && typeof Number(v) === 'number') transform[k] = Number(v);
|
|
@@ -334,7 +330,8 @@ class SVGPathCommander {
|
|
|
334
330
|
* @public
|
|
335
331
|
*/
|
|
336
332
|
flipX() {
|
|
337
|
-
|
|
333
|
+
const { cx, cy } = this.bbox;
|
|
334
|
+
this.transform({ rotate: [0, 180, 0], origin: [cx, cy, 0] });
|
|
338
335
|
return this;
|
|
339
336
|
}
|
|
340
337
|
|
|
@@ -344,7 +341,8 @@ class SVGPathCommander {
|
|
|
344
341
|
* @public
|
|
345
342
|
*/
|
|
346
343
|
flipY() {
|
|
347
|
-
|
|
344
|
+
const { cx, cy } = this.bbox;
|
|
345
|
+
this.transform({ rotate: [180, 0, 0], origin: [cx, cy, 0] });
|
|
348
346
|
return this;
|
|
349
347
|
}
|
|
350
348
|
|