svg-path-commander 2.1.2 → 2.1.3
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/dist/svg-path-commander.cjs +1 -1
- package/dist/svg-path-commander.cjs.map +1 -1
- package/dist/svg-path-commander.d.ts +26 -45
- package/dist/svg-path-commander.js +1 -1
- package/dist/svg-path-commander.js.map +1 -1
- package/dist/svg-path-commander.mjs +710 -605
- package/dist/svg-path-commander.mjs.map +1 -1
- package/package.json +1 -1
- package/src/math/arcTools.ts +34 -42
- package/src/math/cubicTools.ts +5 -6
- package/src/math/lineTools.ts +2 -10
- package/src/math/quadTools.ts +4 -6
- package/src/process/absolutizeSegment.ts +5 -1
- package/src/process/optimizePath.ts +2 -3
- package/src/process/relativizeSegment.ts +5 -1
- package/src/process/transformPath.ts +19 -15
- package/src/util/getPathBBox.ts +112 -39
- package/src/util/getTotalLength.ts +93 -28
- package/test/class.test.ts +2 -0
- package/test/fixtures/simpleShapes.js +12 -0
- package/vitest.config-ui.mts +5 -0
- package/vitest.config.mts +5 -0
package/package.json
CHANGED
package/src/math/arcTools.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { getPointAtLineLength } from './lineTools';
|
|
2
|
-
import type { Point } from '../types';
|
|
2
|
+
import type { Point, PointTuple } from '../types';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Returns the Arc segment length.
|
|
@@ -37,10 +37,7 @@ const arcPoint = (cx: number, cy: number, rx: number, ry: number, alpha: number,
|
|
|
37
37
|
const x = rx * cos(theta);
|
|
38
38
|
const y = ry * sin(theta);
|
|
39
39
|
|
|
40
|
-
return
|
|
41
|
-
x: cx + cosA * x - sinA * y,
|
|
42
|
-
y: cy + sinA * x + cosA * y,
|
|
43
|
-
};
|
|
40
|
+
return [cx + cosA * x - sinA * y, cy + sinA * x + cosA * y] as PointTuple;
|
|
44
41
|
};
|
|
45
42
|
|
|
46
43
|
/**
|
|
@@ -275,7 +272,9 @@ const getPointAtArcLength = (
|
|
|
275
272
|
};
|
|
276
273
|
|
|
277
274
|
/**
|
|
278
|
-
* Returns the extrema for an Arc segment
|
|
275
|
+
* Returns the extrema for an Arc segment in the following format:
|
|
276
|
+
* [MIN_X, MIN_Y, MAX_X, MAX_Y]
|
|
277
|
+
*
|
|
279
278
|
* @see https://github.com/herrstrietzel/svg-pathdata-getbbox
|
|
280
279
|
*
|
|
281
280
|
* @param x1 the starting point X
|
|
@@ -305,15 +304,9 @@ const getArcBBox = (
|
|
|
305
304
|
const deltaAngle = endAngle - startAngle;
|
|
306
305
|
const { min, max, tan, atan2, PI } = Math;
|
|
307
306
|
|
|
308
|
-
// final on path point
|
|
309
|
-
const p = { x, y };
|
|
310
|
-
|
|
311
307
|
// circle/elipse center coordinates
|
|
312
308
|
const { x: cx, y: cy } = center;
|
|
313
309
|
|
|
314
|
-
// collect extreme points – add end point
|
|
315
|
-
const extremes = [p];
|
|
316
|
-
|
|
317
310
|
// rotation to radians
|
|
318
311
|
const alpha = (angle * PI) / 180;
|
|
319
312
|
const tangent = tan(alpha);
|
|
@@ -329,12 +322,10 @@ const getArcBBox = (
|
|
|
329
322
|
const angle4 = angle3 + PI;
|
|
330
323
|
|
|
331
324
|
// inner bounding box
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
const yMin = min(...yArr);
|
|
337
|
-
const yMax = max(...yArr);
|
|
325
|
+
let xMin = min(x1, x);
|
|
326
|
+
let xMax = max(x1, x);
|
|
327
|
+
let yMin = min(y1, y);
|
|
328
|
+
let yMax = max(y1, y);
|
|
338
329
|
|
|
339
330
|
// on path point close after start
|
|
340
331
|
const angleAfterStart = endAngle - deltaAngle * 0.001;
|
|
@@ -352,45 +343,46 @@ const getArcBBox = (
|
|
|
352
343
|
*/
|
|
353
344
|
|
|
354
345
|
// right
|
|
355
|
-
|
|
356
|
-
if (pP2.x > xMax || pP3.x > xMax) {
|
|
346
|
+
if (pP2[0] > xMax || pP3[0] > xMax) {
|
|
357
347
|
// get point for this theta
|
|
358
|
-
|
|
348
|
+
const pxy = arcPoint(cx, cy, rx, ry, alpha, angle1);
|
|
349
|
+
xMin = min(xMin, pxy[0]);
|
|
350
|
+
yMin = min(yMin, pxy[1]);
|
|
351
|
+
xMax = max(xMax, pxy[0]);
|
|
352
|
+
yMax = max(yMax, pxy[1]);
|
|
359
353
|
}
|
|
360
354
|
|
|
361
355
|
// left
|
|
362
|
-
|
|
363
|
-
if (pP2.x < xMin || pP3.x < xMin) {
|
|
356
|
+
if (pP2[0] < xMin || pP3[0] < xMin) {
|
|
364
357
|
// get anti-symmetric point
|
|
365
|
-
|
|
358
|
+
const pxy = arcPoint(cx, cy, rx, ry, alpha, angle2);
|
|
359
|
+
xMin = min(xMin, pxy[0]);
|
|
360
|
+
yMin = min(yMin, pxy[1]);
|
|
361
|
+
xMax = max(xMax, pxy[0]);
|
|
362
|
+
yMax = max(yMax, pxy[1]);
|
|
366
363
|
}
|
|
367
364
|
|
|
368
365
|
// top
|
|
369
|
-
|
|
370
|
-
if (pP2.y < yMin || pP3.y < yMin) {
|
|
366
|
+
if (pP2[1] < yMin || pP3[1] < yMin) {
|
|
371
367
|
// get anti-symmetric point
|
|
372
|
-
|
|
368
|
+
const pxy = arcPoint(cx, cy, rx, ry, alpha, angle4);
|
|
369
|
+
xMin = min(xMin, pxy[0]);
|
|
370
|
+
yMin = min(yMin, pxy[1]);
|
|
371
|
+
xMax = max(xMax, pxy[0]);
|
|
372
|
+
yMax = max(yMax, pxy[1]);
|
|
373
373
|
}
|
|
374
374
|
|
|
375
375
|
// bottom
|
|
376
|
-
|
|
377
|
-
if (pP2.y > yMax || pP3.y > yMax) {
|
|
376
|
+
if (pP2[1] > yMax || pP3[1] > yMax) {
|
|
378
377
|
// get point for this theta
|
|
379
|
-
|
|
378
|
+
const pxy = arcPoint(cx, cy, rx, ry, alpha, angle3);
|
|
379
|
+
xMin = min(xMin, pxy[0]);
|
|
380
|
+
yMin = min(yMin, pxy[1]);
|
|
381
|
+
xMax = max(xMax, pxy[0]);
|
|
382
|
+
yMax = max(yMax, pxy[1]);
|
|
380
383
|
}
|
|
381
384
|
|
|
382
|
-
return
|
|
383
|
-
min: {
|
|
384
|
-
x: min(...extremes.map(n => n.x)),
|
|
385
|
-
y: min(...extremes.map(n => n.y)),
|
|
386
|
-
},
|
|
387
|
-
max: {
|
|
388
|
-
x: max(...extremes.map(n => n.x)),
|
|
389
|
-
y: max(...extremes.map(n => n.y)),
|
|
390
|
-
},
|
|
391
|
-
};
|
|
385
|
+
return [xMin, yMin, xMax, yMax] as [number, number, number, number];
|
|
392
386
|
};
|
|
393
387
|
|
|
394
388
|
export { arcPoint, angleBetween, getArcLength, arcLength, getArcBBox, getArcProps, getPointAtArcLength };
|
|
395
|
-
|
|
396
|
-
export {};
|
package/src/math/cubicTools.ts
CHANGED
|
@@ -91,7 +91,8 @@ const getPointAtCubicLength = (
|
|
|
91
91
|
};
|
|
92
92
|
|
|
93
93
|
/**
|
|
94
|
-
* Returns the boundig box of a CubicBezier segment
|
|
94
|
+
* Returns the boundig box of a CubicBezier segment in the following format:
|
|
95
|
+
* [MIN_X, MIN_Y, MAX_X, MAX_Y]
|
|
95
96
|
*
|
|
96
97
|
* @param x1 the starting point X
|
|
97
98
|
* @param y1 the starting point Y
|
|
@@ -101,7 +102,7 @@ const getPointAtCubicLength = (
|
|
|
101
102
|
* @param c2y the second control point Y
|
|
102
103
|
* @param x2 the ending point X
|
|
103
104
|
* @param y2 the ending point Y
|
|
104
|
-
* @returns the
|
|
105
|
+
* @returns the extrema of the CubicBezier segment
|
|
105
106
|
*/
|
|
106
107
|
const getCubicBBox = (
|
|
107
108
|
x1: number,
|
|
@@ -115,10 +116,8 @@ const getCubicBBox = (
|
|
|
115
116
|
) => {
|
|
116
117
|
const cxMinMax = minmaxC([x1, c1x, c2x, x2]);
|
|
117
118
|
const cyMinMax = minmaxC([y1, c1y, c2y, y2]);
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
max: { x: cxMinMax[1], y: cyMinMax[1] },
|
|
121
|
-
};
|
|
119
|
+
|
|
120
|
+
return [cxMinMax[0], cyMinMax[0], cxMinMax[1], cyMinMax[1]] as [number, number, number, number];
|
|
122
121
|
};
|
|
123
122
|
|
|
124
123
|
export { getCubicLength, getCubicBBox, getPointAtCubicLength, getPointAtCubicSegmentLength };
|
package/src/math/lineTools.ts
CHANGED
|
@@ -54,16 +54,8 @@ const getPointAtLineLength = (x1: number, y1: number, x2: number, y2: number, di
|
|
|
54
54
|
*/
|
|
55
55
|
const getLineBBox = (x1: number, y1: number, x2: number, y2: number) => {
|
|
56
56
|
const { min, max } = Math;
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
x: min(x1, x2),
|
|
60
|
-
y: min(y1, y2),
|
|
61
|
-
},
|
|
62
|
-
max: {
|
|
63
|
-
x: max(x1, x2),
|
|
64
|
-
y: max(y1, y2),
|
|
65
|
-
},
|
|
66
|
-
};
|
|
57
|
+
|
|
58
|
+
return [min(x1, x2), min(y1, y2), max(x1, x2), max(y1, y2)] as [number, number, number, number];
|
|
67
59
|
};
|
|
68
60
|
|
|
69
61
|
export { getPointAtLineLength, getLineBBox, getLineLength };
|
package/src/math/quadTools.ts
CHANGED
|
@@ -78,7 +78,8 @@ const getPointAtQuadLength = (
|
|
|
78
78
|
};
|
|
79
79
|
|
|
80
80
|
/**
|
|
81
|
-
* Returns the boundig box of a QuadraticBezier segment
|
|
81
|
+
* Returns the boundig box of a QuadraticBezier segment in the following format:
|
|
82
|
+
* [MIN_X, MIN_Y, MAX_X, MAX_Y]
|
|
82
83
|
*
|
|
83
84
|
* @param x1 the starting point X
|
|
84
85
|
* @param y1 the starting point Y
|
|
@@ -86,15 +87,12 @@ const getPointAtQuadLength = (
|
|
|
86
87
|
* @param cy the control point Y
|
|
87
88
|
* @param x2 the ending point X
|
|
88
89
|
* @param y2 the ending point Y
|
|
89
|
-
* @returns the
|
|
90
|
+
* @returns the extrema of the QuadraticBezier segment
|
|
90
91
|
*/
|
|
91
92
|
const getQuadBBox = (x1: number, y1: number, cx: number, cy: number, x2: number, y2: number) => {
|
|
92
93
|
const cxMinMax = minmaxQ([x1, cx, x2]);
|
|
93
94
|
const cyMinMax = minmaxQ([y1, cy, y2]);
|
|
94
|
-
return
|
|
95
|
-
min: { x: cxMinMax[0], y: cyMinMax[0] },
|
|
96
|
-
max: { x: cxMinMax[1], y: cyMinMax[1] },
|
|
97
|
-
};
|
|
95
|
+
return [cxMinMax[0], cyMinMax[0], cxMinMax[1], cyMinMax[1]] as [number, number, number, number];
|
|
98
96
|
};
|
|
99
97
|
|
|
100
98
|
export { getPointAtQuadSegmentLength, getQuadLength, getQuadBBox, getPointAtQuadLength };
|
|
@@ -50,7 +50,11 @@ const absolutizeSegment = (segment: PathSegment, index: number, lastX: number, l
|
|
|
50
50
|
} else {
|
|
51
51
|
// use brakets for `eslint: no-case-declaration`
|
|
52
52
|
// https://stackoverflow.com/a/50753272/803358
|
|
53
|
-
const absValues =
|
|
53
|
+
const absValues = [] as number[];
|
|
54
|
+
const seglen = segment.length;
|
|
55
|
+
for (let j = 1; j < seglen; j += 1) {
|
|
56
|
+
absValues.push((segment[j] as number) + (j % 2 ? lastX : lastY));
|
|
57
|
+
}
|
|
54
58
|
// for c, s, q, t
|
|
55
59
|
return [absCommand as typeof absCommand | number].concat(absValues) as
|
|
56
60
|
| MSegment
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
+
import type { AbsoluteSegment, PathArray, PathCommand } from '../types';
|
|
1
2
|
import pathToAbsolute from '../convert/pathToAbsolute';
|
|
2
3
|
import shortenSegment from './shortenSegment';
|
|
3
4
|
import paramsParser from '../parser/paramsParser';
|
|
4
|
-
import type { AbsoluteSegment, PathArray, PathCommand } from '../types';
|
|
5
5
|
import iterate from './iterate';
|
|
6
6
|
import normalizeSegment from './normalizeSegment';
|
|
7
7
|
import relativizeSegment from './relativizeSegment';
|
|
@@ -16,7 +16,7 @@ import roundSegment from './roundSegment';
|
|
|
16
16
|
* @param roundOption the amount of decimals to round values to
|
|
17
17
|
* @returns the optimized `pathArray`
|
|
18
18
|
*/
|
|
19
|
-
const optimizePath = (pathInput: PathArray, roundOption
|
|
19
|
+
const optimizePath = (pathInput: PathArray, roundOption?: number) => {
|
|
20
20
|
const path = pathToAbsolute(pathInput);
|
|
21
21
|
// allow for ZERO decimals or use an aggressive value of 2
|
|
22
22
|
const round =
|
|
@@ -31,7 +31,6 @@ const optimizePath = (pathInput: PathArray, roundOption: number) => {
|
|
|
31
31
|
return iterate(path, (seg, i, lastX, lastY) => {
|
|
32
32
|
optimParams.x = lastX;
|
|
33
33
|
optimParams.y = lastY;
|
|
34
|
-
// const absoluteSegment = absolutizeSegment(seg, optimParams);
|
|
35
34
|
const normalizedSegment = normalizeSegment(seg, optimParams);
|
|
36
35
|
let result = seg;
|
|
37
36
|
[pathCommand] = seg;
|
|
@@ -50,7 +50,11 @@ const relativizeSegment = (segment: PathSegment, index: number, lastX: number, l
|
|
|
50
50
|
} else {
|
|
51
51
|
// use brakets for `eslint: no-case-declaration`
|
|
52
52
|
// https://stackoverflow.com/a/50753272/803358
|
|
53
|
-
const relValues =
|
|
53
|
+
const relValues = [] as number[];
|
|
54
|
+
const seglen = segment.length;
|
|
55
|
+
for (let j = 1; j < seglen; j += 1) {
|
|
56
|
+
relValues.push((segment[j] as number) - (j % 2 ? lastX : lastY));
|
|
57
|
+
}
|
|
54
58
|
// for c, s, q, t
|
|
55
59
|
return [relCommand as RelativeCommand | number].concat(relValues) as qSegment | tSegment | sSegment | cSegment;
|
|
56
60
|
}
|
|
@@ -5,10 +5,8 @@ import type { AbsoluteArray, AbsoluteSegment, CSegment, LSegment, PathArray, Tra
|
|
|
5
5
|
import type { TransformObject } from '../interface';
|
|
6
6
|
import iterate from './iterate';
|
|
7
7
|
import parsePathString from '../parser/parsePathString';
|
|
8
|
-
import segmentToCubic from './segmentToCubic';
|
|
9
|
-
import normalizeSegment from './normalizeSegment';
|
|
10
|
-
import paramsParser from '../parser/paramsParser';
|
|
11
8
|
import absolutizeSegment from './absolutizeSegment';
|
|
9
|
+
import arcToCubic from './arcToCubic';
|
|
12
10
|
|
|
13
11
|
/**
|
|
14
12
|
* Apply a 2D / 3D transformation to a `pathArray` instance.
|
|
@@ -32,7 +30,6 @@ const transformPath = (pathInput: PathArray | string, transform?: Partial<Transf
|
|
|
32
30
|
let jj = 0;
|
|
33
31
|
let pathCommand = 'M';
|
|
34
32
|
// transform uses it's own set of params
|
|
35
|
-
const transformParams = { ...paramsParser };
|
|
36
33
|
const path = parsePathString(pathInput);
|
|
37
34
|
const transformProps = transform && Object.keys(transform);
|
|
38
35
|
|
|
@@ -49,8 +46,6 @@ const transformPath = (pathInput: PathArray | string, transform?: Partial<Transf
|
|
|
49
46
|
if (matrixInstance.isIdentity) return path.slice(0) as typeof path;
|
|
50
47
|
|
|
51
48
|
return iterate<AbsoluteArray>(path, (seg, index, lastX, lastY) => {
|
|
52
|
-
transformParams.x = lastX;
|
|
53
|
-
transformParams.y = lastY;
|
|
54
49
|
[pathCommand] = seg;
|
|
55
50
|
const absCommand = pathCommand.toUpperCase();
|
|
56
51
|
const isRelative = absCommand !== pathCommand;
|
|
@@ -60,9 +55,24 @@ const transformPath = (pathInput: PathArray | string, transform?: Partial<Transf
|
|
|
60
55
|
|
|
61
56
|
let result =
|
|
62
57
|
absCommand === 'A'
|
|
63
|
-
? segmentToCubic(absoluteSegment, transformParams)
|
|
64
|
-
|
|
65
|
-
|
|
58
|
+
? // ? segmentToCubic(absoluteSegment, transformParams)
|
|
59
|
+
(['C' as string | number].concat(
|
|
60
|
+
arcToCubic(
|
|
61
|
+
lastX,
|
|
62
|
+
lastY,
|
|
63
|
+
absoluteSegment[1] as number,
|
|
64
|
+
absoluteSegment[2] as number,
|
|
65
|
+
absoluteSegment[3] as number,
|
|
66
|
+
absoluteSegment[4] as number,
|
|
67
|
+
absoluteSegment[5] as number,
|
|
68
|
+
absoluteSegment[6] as number,
|
|
69
|
+
absoluteSegment[7] as number,
|
|
70
|
+
),
|
|
71
|
+
) as CSegment)
|
|
72
|
+
: absCommand === 'V'
|
|
73
|
+
? (['L', lastX, absoluteSegment[1]] as LSegment)
|
|
74
|
+
: absCommand === 'H'
|
|
75
|
+
? (['L', absoluteSegment[1], lastY] as LSegment)
|
|
66
76
|
: absoluteSegment;
|
|
67
77
|
|
|
68
78
|
// update pathCommand
|
|
@@ -97,12 +107,6 @@ const transformPath = (pathInput: PathArray | string, transform?: Partial<Transf
|
|
|
97
107
|
x = lx;
|
|
98
108
|
y = ly;
|
|
99
109
|
|
|
100
|
-
const seglen = tempSegment.length;
|
|
101
|
-
transformParams.x1 = +tempSegment[seglen - 2];
|
|
102
|
-
transformParams.y1 = +tempSegment[seglen - 1];
|
|
103
|
-
transformParams.x2 = +tempSegment[seglen - 4] || transformParams.x1;
|
|
104
|
-
transformParams.y2 = +tempSegment[seglen - 3] || transformParams.y1;
|
|
105
|
-
|
|
106
110
|
return result;
|
|
107
111
|
});
|
|
108
112
|
};
|
package/src/util/getPathBBox.ts
CHANGED
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
import iterate from '../process/iterate';
|
|
2
2
|
import { PathBBox } from '../interface';
|
|
3
|
-
import { MSegment, PathArray,
|
|
3
|
+
import { LSegment, MSegment, PathArray, PointTuple } from '../types';
|
|
4
4
|
import { getLineBBox } from '../math/lineTools';
|
|
5
5
|
import { getArcBBox } from '../math/arcTools';
|
|
6
6
|
import { getCubicBBox } from '../math/cubicTools';
|
|
7
7
|
import { getQuadBBox } from '../math/quadTools';
|
|
8
8
|
import parsePathString from '../parser/parsePathString';
|
|
9
|
-
import
|
|
10
|
-
import normalizeSegment from '../process/normalizeSegment';
|
|
9
|
+
import absolutizeSegment from '../process/absolutizeSegment';
|
|
11
10
|
|
|
12
11
|
const getPathBBox = (pathInput: PathArray | string) => {
|
|
13
12
|
if (!pathInput) {
|
|
@@ -25,59 +24,133 @@ const getPathBBox = (pathInput: PathArray | string) => {
|
|
|
25
24
|
}
|
|
26
25
|
|
|
27
26
|
const path = parsePathString(pathInput);
|
|
28
|
-
let data = [] as number[];
|
|
29
27
|
let pathCommand = 'M';
|
|
30
|
-
const x = 0;
|
|
31
|
-
const y = 0;
|
|
32
28
|
let mx = 0;
|
|
33
29
|
let my = 0;
|
|
34
|
-
const
|
|
35
|
-
|
|
36
|
-
let
|
|
37
|
-
let
|
|
38
|
-
|
|
30
|
+
const { max, min } = Math;
|
|
31
|
+
let xMin = Infinity;
|
|
32
|
+
let yMin = Infinity;
|
|
33
|
+
let xMax = -Infinity;
|
|
34
|
+
let yMax = -Infinity;
|
|
35
|
+
let minX = 0;
|
|
36
|
+
let minY = 0;
|
|
37
|
+
let maxX = 0;
|
|
38
|
+
let maxY = 0;
|
|
39
|
+
let paramX1 = 0;
|
|
40
|
+
let paramY1 = 0;
|
|
41
|
+
let paramX2 = 0;
|
|
42
|
+
let paramY2 = 0;
|
|
43
|
+
let paramQX = 0;
|
|
44
|
+
let paramQY = 0;
|
|
39
45
|
|
|
40
|
-
iterate(path, (seg,
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
const
|
|
44
|
-
|
|
45
|
-
|
|
46
|
+
iterate(path, (seg, index, lastX, lastY) => {
|
|
47
|
+
[pathCommand] = seg;
|
|
48
|
+
const absCommand = pathCommand.toUpperCase();
|
|
49
|
+
const isRelative = absCommand !== pathCommand;
|
|
50
|
+
const absoluteSegment = isRelative ? absolutizeSegment(seg, index, lastX, lastY) : (seg.slice(0) as typeof seg);
|
|
51
|
+
|
|
52
|
+
const normalSegment =
|
|
53
|
+
absCommand === 'V'
|
|
54
|
+
? (['L', lastX, absoluteSegment[1]] as LSegment)
|
|
55
|
+
: absCommand === 'H'
|
|
56
|
+
? (['L', absoluteSegment[1], lastY] as LSegment)
|
|
57
|
+
: absoluteSegment;
|
|
58
|
+
|
|
59
|
+
[pathCommand] = normalSegment;
|
|
60
|
+
|
|
61
|
+
if (!'TQ'.includes(absCommand)) {
|
|
62
|
+
// optional but good to be cautious
|
|
63
|
+
paramQX = 0;
|
|
64
|
+
paramQY = 0;
|
|
65
|
+
}
|
|
46
66
|
|
|
47
67
|
// this segment is always ZERO
|
|
48
68
|
/* istanbul ignore else @preserve */
|
|
49
69
|
if (pathCommand === 'M') {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
70
|
+
[, mx, my] = normalSegment as MSegment;
|
|
71
|
+
minX = mx;
|
|
72
|
+
minY = my;
|
|
73
|
+
maxX = mx;
|
|
74
|
+
maxY = my;
|
|
54
75
|
} else if (pathCommand === 'L') {
|
|
55
|
-
|
|
76
|
+
[minX, minY, maxX, maxY] = getLineBBox(lastX, lastY, normalSegment[1] as number, normalSegment[2] as number);
|
|
56
77
|
} else if (pathCommand === 'A') {
|
|
57
|
-
|
|
78
|
+
[minX, minY, maxX, maxY] = getArcBBox(
|
|
79
|
+
lastX,
|
|
80
|
+
lastY,
|
|
81
|
+
normalSegment[1] as number,
|
|
82
|
+
normalSegment[2] as number,
|
|
83
|
+
normalSegment[3] as number,
|
|
84
|
+
normalSegment[4] as number,
|
|
85
|
+
normalSegment[5] as number,
|
|
86
|
+
normalSegment[6] as number,
|
|
87
|
+
normalSegment[7] as number,
|
|
88
|
+
);
|
|
89
|
+
} else if (pathCommand === 'S') {
|
|
90
|
+
const cp1x = paramX1 * 2 - paramX2;
|
|
91
|
+
const cp1y = paramY1 * 2 - paramY2;
|
|
92
|
+
|
|
93
|
+
[minX, minY, maxX, maxY] = getCubicBBox(
|
|
94
|
+
lastX,
|
|
95
|
+
lastY,
|
|
96
|
+
cp1x,
|
|
97
|
+
cp1y,
|
|
98
|
+
normalSegment[1] as number,
|
|
99
|
+
normalSegment[2] as number,
|
|
100
|
+
normalSegment[3] as number,
|
|
101
|
+
normalSegment[4] as number,
|
|
102
|
+
);
|
|
58
103
|
} else if (pathCommand === 'C') {
|
|
59
|
-
|
|
104
|
+
[minX, minY, maxX, maxY] = getCubicBBox(
|
|
105
|
+
lastX,
|
|
106
|
+
lastY,
|
|
107
|
+
normalSegment[1] as number,
|
|
108
|
+
normalSegment[2] as number,
|
|
109
|
+
normalSegment[3] as number,
|
|
110
|
+
normalSegment[4] as number,
|
|
111
|
+
normalSegment[5] as number,
|
|
112
|
+
normalSegment[6] as number,
|
|
113
|
+
);
|
|
114
|
+
} else if (pathCommand === 'T') {
|
|
115
|
+
paramQX = paramX1 * 2 - paramQX;
|
|
116
|
+
paramQY = paramY1 * 2 - paramQY;
|
|
117
|
+
[minX, minY, maxX, maxY] = getQuadBBox(
|
|
118
|
+
lastX,
|
|
119
|
+
lastY,
|
|
120
|
+
paramQX,
|
|
121
|
+
paramQY,
|
|
122
|
+
normalSegment[1] as number,
|
|
123
|
+
normalSegment[2] as number,
|
|
124
|
+
);
|
|
60
125
|
} else if (pathCommand === 'Q') {
|
|
61
|
-
|
|
126
|
+
paramQX = normalSegment[1] as number;
|
|
127
|
+
paramQY = normalSegment[2] as number;
|
|
128
|
+
[minX, minY, maxX, maxY] = getQuadBBox(
|
|
129
|
+
lastX,
|
|
130
|
+
lastY,
|
|
131
|
+
normalSegment[1] as number,
|
|
132
|
+
normalSegment[2] as number,
|
|
133
|
+
normalSegment[3] as number,
|
|
134
|
+
normalSegment[4] as number,
|
|
135
|
+
);
|
|
62
136
|
} else if (pathCommand === 'Z') {
|
|
63
|
-
|
|
64
|
-
({ min, max } = getLineBBox(data[0], data[1], data[2], data[3]));
|
|
137
|
+
[minX, minY, maxX, maxY] = getLineBBox(lastX, lastY, mx, my);
|
|
65
138
|
}
|
|
139
|
+
xMin = min(minX, xMin);
|
|
140
|
+
yMin = min(minY, yMin);
|
|
141
|
+
xMax = max(maxX, xMax);
|
|
142
|
+
yMax = max(maxY, yMax);
|
|
66
143
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
144
|
+
// update params
|
|
145
|
+
[paramX1, paramY1] = pathCommand === 'Z' ? [mx, my] : (normalSegment.slice(-2) as PointTuple);
|
|
146
|
+
[paramX2, paramY2] =
|
|
147
|
+
pathCommand === 'C'
|
|
148
|
+
? ([normalSegment[3], normalSegment[4]] as PointTuple)
|
|
149
|
+
: pathCommand === 'S'
|
|
150
|
+
? ([normalSegment[1], normalSegment[2]] as PointTuple)
|
|
151
|
+
: [paramX1, paramY1];
|
|
75
152
|
});
|
|
76
153
|
|
|
77
|
-
const xMin = Math.min(...MIN.map(n => n.x));
|
|
78
|
-
const xMax = Math.max(...MAX.map(n => n.x));
|
|
79
|
-
const yMin = Math.min(...MIN.map(n => n.y));
|
|
80
|
-
const yMax = Math.max(...MAX.map(n => n.y));
|
|
81
154
|
const width = xMax - xMin;
|
|
82
155
|
const height = yMax - yMin;
|
|
83
156
|
|