svg-path-commander 2.1.0 → 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/README.md +61 -5
- package/dist/svg-path-commander.cjs +1 -1
- package/dist/svg-path-commander.cjs.map +1 -1
- package/dist/svg-path-commander.d.ts +119 -33
- package/dist/svg-path-commander.js +1 -1
- package/dist/svg-path-commander.js.map +1 -1
- package/dist/svg-path-commander.mjs +798 -828
- package/dist/svg-path-commander.mjs.map +1 -1
- package/package.json +3 -3
- 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 +13 -19
- package/src/interface.ts +1 -1
- package/src/math/arcTools.ts +248 -71
- package/src/math/bezier.ts +19 -27
- package/src/math/cubicTools.ts +67 -26
- package/src/math/distanceSquareRoot.ts +3 -1
- package/src/math/lineTools.ts +41 -26
- 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 +45 -26
- package/src/parser/parsePathString.ts +4 -4
- 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 +38 -4
- package/src/process/transformPath.ts +80 -73
- package/src/types.ts +35 -1
- package/src/util/getPathArea.ts +3 -3
- package/src/util/getPathBBox.ts +86 -19
- package/src/util/getPointAtLength.ts +98 -4
- package/src/util/getPropertiesAtLength.ts +2 -2
- package/src/util/getTotalLength.ts +71 -4
- package/test/class.test.ts +15 -14
- package/test/fixtures/shapes.js +27 -27
- package/test/fixtures/simpleShapes.js +18 -18
- package/test/static.test.ts +37 -17
- package/cypress.config.ts +0 -29
- 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.1",
|
|
6
6
|
"description": "Modern TypeScript tools for SVG",
|
|
7
7
|
"source": "./src/index.ts",
|
|
8
8
|
"main": "./dist/svg-path-commander.js",
|
|
@@ -48,9 +48,9 @@
|
|
|
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.0",
|
|
52
52
|
"prettier": "^2.8.8",
|
|
53
|
-
"typescript": "^5.6.
|
|
53
|
+
"typescript": "^5.6.3",
|
|
54
54
|
"vite": "^5.4.8",
|
|
55
55
|
"vitest": "^2.1.2"
|
|
56
56
|
},
|
|
@@ -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.slice(0) as AbsoluteArray;
|
|
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.slice(0) as RelativeArray;
|
|
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,4 +1,5 @@
|
|
|
1
|
-
|
|
1
|
+
'use strict';
|
|
2
|
+
import { PointTuple, PathArray, TransformObjectValues } from './types';
|
|
2
3
|
import type { Options, TransformEntries, TransformObject } from './interface';
|
|
3
4
|
export * from './types';
|
|
4
5
|
export * from './interface';
|
|
@@ -16,7 +17,6 @@ import getPathArea from './util/getPathArea';
|
|
|
16
17
|
import getTotalLength from './util/getTotalLength';
|
|
17
18
|
import getDrawDirection from './util/getDrawDirection';
|
|
18
19
|
import getPointAtLength from './util/getPointAtLength';
|
|
19
|
-
import pathFactory from './util/pathFactory';
|
|
20
20
|
|
|
21
21
|
import getPropertiesAtLength from './util/getPropertiesAtLength';
|
|
22
22
|
import getPropertiesAtPoint from './util/getPropertiesAtPoint';
|
|
@@ -43,7 +43,6 @@ import reversePath from './process/reversePath';
|
|
|
43
43
|
import normalizePath from './process/normalizePath';
|
|
44
44
|
import transformPath from './process/transformPath';
|
|
45
45
|
import splitCubic from './process/splitCubic';
|
|
46
|
-
import replaceArc from './process/replaceArc';
|
|
47
46
|
|
|
48
47
|
import pathToAbsolute from './convert/pathToAbsolute';
|
|
49
48
|
import pathToRelative from './convert/pathToRelative';
|
|
@@ -61,7 +60,6 @@ import pathToString from './convert/pathToString';
|
|
|
61
60
|
* @returns a new SVGPathCommander instance
|
|
62
61
|
*/
|
|
63
62
|
class SVGPathCommander {
|
|
64
|
-
// bring main utilities to front
|
|
65
63
|
public static CSSMatrix = CSSMatrix;
|
|
66
64
|
public static getSVGMatrix = getSVGMatrix;
|
|
67
65
|
public static getPathBBox = getPathBBox;
|
|
@@ -69,7 +67,6 @@ class SVGPathCommander {
|
|
|
69
67
|
public static getTotalLength = getTotalLength;
|
|
70
68
|
public static getDrawDirection = getDrawDirection;
|
|
71
69
|
public static getPointAtLength = getPointAtLength;
|
|
72
|
-
public static pathFactory = pathFactory;
|
|
73
70
|
public static getPropertiesAtLength = getPropertiesAtLength;
|
|
74
71
|
public static getPropertiesAtPoint = getPropertiesAtPoint;
|
|
75
72
|
public static polygonLength = polygonLength;
|
|
@@ -90,7 +87,6 @@ class SVGPathCommander {
|
|
|
90
87
|
public static roundPath = roundPath;
|
|
91
88
|
public static splitPath = splitPath;
|
|
92
89
|
public static splitCubic = splitCubic;
|
|
93
|
-
public static replaceArc = replaceArc;
|
|
94
90
|
public static optimizePath = optimizePath;
|
|
95
91
|
public static reverseCurve = reverseCurve;
|
|
96
92
|
public static reversePath = reversePath;
|
|
@@ -120,16 +116,12 @@ class SVGPathCommander {
|
|
|
120
116
|
|
|
121
117
|
const segments = parsePathString(pathValue);
|
|
122
118
|
this.segments = segments;
|
|
123
|
-
const { width, height, cx, cy, cz } = this.bbox;
|
|
124
119
|
|
|
125
|
-
// set instance options.round
|
|
120
|
+
// // set instance options.round
|
|
126
121
|
const { round: roundOption, origin: originOption } = instanceOptions;
|
|
127
122
|
let round: number | 'off';
|
|
128
123
|
|
|
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') {
|
|
124
|
+
if (Number.isInteger(roundOption) || roundOption === 'off') {
|
|
133
125
|
round = roundOption as number | 'off';
|
|
134
126
|
} else {
|
|
135
127
|
round = defaultOptions.round as number;
|
|
@@ -137,14 +129,14 @@ class SVGPathCommander {
|
|
|
137
129
|
|
|
138
130
|
// set instance options.origin
|
|
139
131
|
// the SVGPathCommander class will always override the default origin
|
|
140
|
-
let origin =
|
|
132
|
+
let origin = defaultOptions.origin as [number, number, number];
|
|
141
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
141
|
}
|
|
150
142
|
|
|
@@ -311,7 +303,7 @@ class SVGPathCommander {
|
|
|
311
303
|
for (const [k, v] of Object.entries(source) as TransformEntries) {
|
|
312
304
|
// istanbul ignore else @preserve
|
|
313
305
|
if (k === 'skew' && Array.isArray(v)) {
|
|
314
|
-
transform[k] = v.map(Number) as
|
|
306
|
+
transform[k] = v.map(Number) as PointTuple;
|
|
315
307
|
} else if ((k === 'rotate' || k === 'translate' || k === 'origin' || k === 'scale') && Array.isArray(v)) {
|
|
316
308
|
transform[k] = v.map(Number) as [number, number, number];
|
|
317
309
|
} else if (k !== 'origin' && typeof Number(v) === 'number') transform[k] = Number(v);
|
|
@@ -338,7 +330,8 @@ class SVGPathCommander {
|
|
|
338
330
|
* @public
|
|
339
331
|
*/
|
|
340
332
|
flipX() {
|
|
341
|
-
|
|
333
|
+
const { cx, cy } = this.bbox;
|
|
334
|
+
this.transform({ rotate: [0, 180, 0], origin: [cx, cy, 0] });
|
|
342
335
|
return this;
|
|
343
336
|
}
|
|
344
337
|
|
|
@@ -348,7 +341,8 @@ class SVGPathCommander {
|
|
|
348
341
|
* @public
|
|
349
342
|
*/
|
|
350
343
|
flipY() {
|
|
351
|
-
|
|
344
|
+
const { cx, cy } = this.bbox;
|
|
345
|
+
this.transform({ rotate: [180, 0, 0], origin: [cx, cy, 0] });
|
|
352
346
|
return this;
|
|
353
347
|
}
|
|
354
348
|
|