svg-path-commander 2.1.0 → 2.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +63 -7
- package/dist/svg-path-commander.cjs +1 -1
- package/dist/svg-path-commander.cjs.map +1 -1
- package/dist/svg-path-commander.d.ts +314 -40
- package/dist/svg-path-commander.js +1 -1
- package/dist/svg-path-commander.js.map +1 -1
- package/dist/svg-path-commander.mjs +1085 -1032
- package/dist/svg-path-commander.mjs.map +1 -1
- package/package.json +8 -8
- package/src/convert/pathToAbsolute.ts +5 -88
- package/src/convert/pathToCurve.ts +22 -28
- package/src/convert/pathToRelative.ts +4 -78
- package/src/convert/pathToString.ts +40 -7
- package/src/index.ts +145 -58
- package/src/interface.ts +3 -2
- package/src/math/arcTools.ts +259 -80
- package/src/math/bezier.ts +58 -58
- package/src/math/cubicTools.ts +68 -25
- package/src/math/distanceSquareRoot.ts +3 -1
- package/src/math/lineTools.ts +42 -25
- package/src/math/midPoint.ts +3 -1
- package/src/math/polygonTools.ts +48 -0
- package/src/math/quadTools.ts +46 -25
- package/src/math/rotateVector.ts +3 -2
- package/src/math/roundTo.ts +7 -0
- package/src/parser/finalizeSegment.ts +11 -7
- package/src/parser/parsePathString.ts +4 -5
- package/src/parser/pathParser.ts +1 -1
- package/src/process/absolutizeSegment.ts +63 -0
- package/src/process/arcToCubic.ts +2 -2
- package/src/process/iterate.ts +58 -0
- package/src/process/lineToCubic.ts +1 -1
- package/src/process/normalizePath.ts +17 -28
- package/src/process/normalizeSegment.ts +55 -18
- package/src/process/optimizePath.ts +40 -60
- package/src/process/projection2d.ts +4 -3
- package/src/process/relativizeSegment.ts +59 -0
- package/src/process/reverseCurve.ts +8 -5
- package/src/process/reversePath.ts +88 -75
- package/src/process/roundPath.ts +18 -14
- package/src/process/roundSegment.ts +9 -0
- package/src/process/segmentToCubic.ts +10 -8
- package/src/process/shortenSegment.ts +26 -34
- package/src/process/splitCubic.ts +10 -9
- package/src/process/splitPath.ts +38 -4
- package/src/process/transformPath.ts +75 -73
- package/src/types.ts +30 -0
- package/src/util/getPathArea.ts +3 -3
- package/src/util/getPathBBox.ts +69 -19
- package/src/util/getPointAtLength.ts +100 -4
- package/src/util/getPropertiesAtLength.ts +3 -4
- package/src/util/getPropertiesAtPoint.ts +5 -5
- package/src/util/getTotalLength.ts +56 -4
- package/test/class.test.ts +17 -14
- package/test/fixtures/shapes.js +26 -26
- package/test/fixtures/simpleShapes.js +18 -18
- package/test/static.test.ts +54 -28
- package/cypress.config.ts +0 -29
- package/src/math/polygonArea.ts +0 -27
- package/src/math/polygonLength.ts +0 -21
- package/src/process/fixArc.ts +0 -23
- package/src/process/replaceArc.ts +0 -52
- package/src/util/pathFactory.ts +0 -130
|
@@ -3,7 +3,7 @@ const simpleShapes = {
|
|
|
3
3
|
'M10 10l80 80V10H50', // line
|
|
4
4
|
'M10 90C30 90 25 10 50 10s20 80 40 80s15 -80 40 -80s20 80 40 80', // cubic
|
|
5
5
|
'M10 50q15 -25 30 0t30 0t30 0t30 0t30 0t30 0', // quad
|
|
6
|
-
'M6 10a6 4 10 1 0 8
|
|
6
|
+
'M6 10a6 4 10 1 0 8 0m-8 0a6 4 10 1 1 8 0m-8 0a6 4 10 0 1 8 0m-8 0a6 4 10 0 0 8 0' // arc
|
|
7
7
|
],
|
|
8
8
|
// {translate: 15, rotate: 15, scale: 0.5}
|
|
9
9
|
normalized: [
|
|
@@ -13,32 +13,32 @@ const simpleShapes = {
|
|
|
13
13
|
"M6 10A6 4 10 1 0 14 10M6 10A6 4 10 1 1 14 10M6 10A6 4 10 0 1 14 10M6 10A6 4 10 0 0 14 10"
|
|
14
14
|
],
|
|
15
15
|
transformed: [
|
|
16
|
-
"
|
|
17
|
-
"
|
|
18
|
-
"
|
|
19
|
-
"
|
|
16
|
+
"M18.54 6.12L46.82 55.11L57.17 16.48L37.85 11.3",
|
|
17
|
+
"M8.18 44.76C17.84 47.35 25.78 8.06 37.85 11.3S37.16 52.53 46.82 55.11S64.42 18.42 76.49 21.65S75.8 62.88 85.46 65.47",
|
|
18
|
+
"M13.36 25.44Q23.84 15.31 27.85 29.32T42.34 33.21T56.83 37.09T71.31 40.97T85.8 44.85T100.29 48.74",
|
|
19
|
+
"M16.6 5.61C14.93 6.26 15.42 8.37 17.49 9.41C19.55 10.44 21.64 9.62 21.25 7.93C21.14 7.49 20.87 7.04 20.47 6.64M16.6 5.61C15.06 4.09 15.78 2.3 17.9 2.39C20.02 2.48 21.95 4.37 21.37 5.8C21.22 6.18 20.91 6.47 20.47 6.64M16.6 5.61C17.74 5.16 19.42 5.61 20.47 6.64M16.6 5.61C17.65 6.63 19.33 7.09 20.47 6.64"
|
|
20
20
|
],
|
|
21
21
|
// {scale: [0.55,0.6,0.65]}
|
|
22
22
|
scaled3d: [
|
|
23
|
-
"
|
|
24
|
-
"
|
|
25
|
-
"
|
|
26
|
-
"
|
|
23
|
+
"M5.5 6L49.5 54V6H27.5",
|
|
24
|
+
"M5.5 54C16.5 54 13.75 6 27.5 6S38.5 54 49.5 54S57.75 6 71.5 6S82.5 54 93.5 54",
|
|
25
|
+
"M5.5 30Q13.75 15 22 30T38.5 30T55 30T71.5 30T88 30T104.5 30",
|
|
26
|
+
"M3.3 6C1.71 7.28 2.83 9.57 5.32 10.13C7.81 10.69 9.79 9.09 8.9 7.25C8.66 6.77 8.24 6.34 7.7 6M3.3 6C1.23 4.72 1.48 2.43 3.76 1.87C6.04 1.31 8.63 2.91 8.42 4.75C8.37 5.23 8.12 5.66 7.7 6M3.3 6C4.38 5.13 6.29 5.13 7.7 6M3.3 6C4.71 6.87 6.62 6.87 7.7 6"
|
|
27
27
|
],
|
|
28
28
|
// {skew: 45}
|
|
29
29
|
// {skew: [45,0]}
|
|
30
30
|
skewedX: [
|
|
31
|
-
"
|
|
32
|
-
"
|
|
33
|
-
"
|
|
34
|
-
"
|
|
31
|
+
"M20 10L180 90L100 10H60",
|
|
32
|
+
"M100 90C120 90 35 10 60 10S160 90 180 90S115 10 140 10S240 90 260 90",
|
|
33
|
+
"M60 50Q50 25 90 50T120 50T150 50T180 50T210 50T240 50",
|
|
34
|
+
"M16 10C15.24 12.13 21.11 15.95 26.56 16.88C32.01 17.81 32.96 15.15 28.26 12.09C27.03 11.29 25.55 10.56 24 10M16 10C10.1 7.87 6.74 4.05 9.96 3.12C13.17 2.19 20.54 4.85 23.22 7.91C23.93 8.71 24.2 9.44 24 10M16 10C16.52 8.56 20 8.56 24 10M16 10C20 11.44 23.48 11.44 24 10"
|
|
35
35
|
],
|
|
36
36
|
// {skew: [0,45]}
|
|
37
37
|
skewedY: [
|
|
38
|
-
"M10
|
|
39
|
-
"M10
|
|
40
|
-
"M10
|
|
41
|
-
"M6
|
|
38
|
+
"M10 20L90 180V100L50 60",
|
|
39
|
+
"M10 100C30 120 25 35 50 60S70 160 90 180S105 115 130 140S150 240 170 260",
|
|
40
|
+
"M10 60Q25 50 40 90T70 120T100 150T130 180T160 210T190 240",
|
|
41
|
+
"M6 16C3.11 15.24 5.15 21.11 9.67 26.56C14.2 32.01 17.81 32.96 16.17 28.26C15.75 27.03 14.99 25.55 14 24M6 16C2.23 10.1 2.7 6.74 6.84 9.96C10.98 13.17 15.69 20.54 15.31 23.22C15.22 23.93 14.76 24.2 14 24M6 16C7.96 16.52 11.44 20 14 24M6 16C8.56 20 12.04 23.48 14 24"
|
|
42
42
|
],
|
|
43
43
|
reversed: [
|
|
44
44
|
"M50 10H90V90L10 10",
|
|
@@ -68,7 +68,7 @@ const simpleShapes = {
|
|
|
68
68
|
{ x: 45.35533905932737, y: 45.35533905932737 },
|
|
69
69
|
{ x: 28.85808806500117, y: 46.6836898667648 },
|
|
70
70
|
{ x: 46.84696090751847, y: 58.807108530914896 },
|
|
71
|
-
{ x:
|
|
71
|
+
{ x: 7.697454886004856, y: 9.193767828563768 }
|
|
72
72
|
]
|
|
73
73
|
};
|
|
74
74
|
|
package/test/static.test.ts
CHANGED
|
@@ -1,13 +1,11 @@
|
|
|
1
1
|
import { expect, it, describe, beforeEach, vi } from 'vitest';
|
|
2
|
-
import SVGPathCommander, { type CurveArray, type ShapeTypes } from '~/index';
|
|
2
|
+
import SVGPathCommander, { PathArray, type CurveArray, type ShapeTypes } from '~/index';
|
|
3
3
|
import invalidPathValue from '../src/parser/invalidPathValue';
|
|
4
|
-
import getCubicProperties from '../src/math/cubicTools';
|
|
5
|
-
import getQuadProperties from '../src/math/quadTools';
|
|
6
|
-
import getArcProperties from '../src/math/arcTools';
|
|
7
4
|
import error from '../src/parser/error';
|
|
8
5
|
|
|
9
6
|
import getMarkup from './fixtures/getMarkup';
|
|
10
7
|
import simpleShapes from './fixtures/simpleShapes';
|
|
8
|
+
import shapes from './fixtures/shapes';
|
|
11
9
|
import shapeObjects from './fixtures/shapeObjects';
|
|
12
10
|
|
|
13
11
|
import "../docs/assets/style.css";
|
|
@@ -117,11 +115,12 @@ describe('SVGPathCommander Static Methods', () => {
|
|
|
117
115
|
});
|
|
118
116
|
});
|
|
119
117
|
|
|
120
|
-
it(`Can revert back to default round option`, () => {
|
|
121
|
-
const sample = [["M", 0, 0], ["L", 181.99955, 0], ["L", 91, 72], ["L", 0, 0], ["Z"]];
|
|
122
|
-
const rounded = [["M", 0, 0], ["L", 181.9996, 0], ["L", 91, 72], ["L", 0, 0], ["Z"]];
|
|
118
|
+
it(`Can disable round, use a given decimal amount or revert back to default round option`, () => {
|
|
119
|
+
const sample = [["M", 0, 0], ["L", 181.99955, 0], ["L", 91, 72], ["L", 0, 0], ["Z"]] as PathArray;
|
|
120
|
+
const rounded = [["M", 0, 0], ["L", 181.9996, 0], ["L", 91, 72], ["L", 0, 0], ["Z"]] as PathArray;
|
|
123
121
|
|
|
124
|
-
|
|
122
|
+
expect(SVGPathCommander.roundPath(sample, 4), `can use number setting`).to.deep.equal(rounded);
|
|
123
|
+
expect(SVGPathCommander.roundPath(sample, 'off'), `can use "off" setting`).to.deep.equal(sample);
|
|
125
124
|
expect(SVGPathCommander.roundPath(sample, -1), `use 4 decimals when negative number is provided`).to.deep.equal(rounded);
|
|
126
125
|
// @ts-expect-error
|
|
127
126
|
expect(SVGPathCommander.roundPath(sample, 'wombat'), `use 4 decimals when string is provided`).to.deep.equal(rounded);
|
|
@@ -200,7 +199,7 @@ describe('SVGPathCommander Static Methods', () => {
|
|
|
200
199
|
const propsPoint0 = getPropertiesAtPoint(simpleShapes.initial[1], { "x": 10, "y": 90 });
|
|
201
200
|
expect(propsPoint0.closest).to.deep.equal({ x: 10, y: 90 });
|
|
202
201
|
expect(propsPoint0.distance).to.equal(0);
|
|
203
|
-
expect(propsPoint0.segment).to.deep.equal({ segment: ["M", 10, 90], index: 0, length: 0,
|
|
202
|
+
expect(propsPoint0.segment).to.deep.equal({ segment: ["M", 10, 90], index: 0, length: 0, lengthAtSegment: 0 })
|
|
204
203
|
|
|
205
204
|
// getPropertiesAtPoint mid point
|
|
206
205
|
const propsPoint50 = getPropertiesAtPoint(simpleShapes.initial[1], { x: 30.072453006153214, y: 41.42818552481854 });
|
|
@@ -212,7 +211,7 @@ describe('SVGPathCommander Static Methods', () => {
|
|
|
212
211
|
const propsPoint400 = getPropertiesAtPoint(simpleShapes.initial[1], { "x": 50, "y": 10 });
|
|
213
212
|
expect(propsPoint400.closest).to.deep.equal({ x: 50.000003520199236, y: 10.000000000000531 })
|
|
214
213
|
expect(propsPoint400.distance).to.equal(0.0000035201992361067316)
|
|
215
|
-
expect(propsPoint400.segment).to.deep.equal({ segment: ['s', 20, 80, 40, 80], index: 2, length: 94.75724347727943, lengthAtSegment: 94.75724347727943})
|
|
214
|
+
expect(propsPoint400.segment).to.deep.equal({ segment: ['s', 20, 80, 40, 80], index: 2, length: 94.75724347727943, lengthAtSegment: 94.75724347727943 })
|
|
216
215
|
});
|
|
217
216
|
|
|
218
217
|
it(`Can do getSegmentAtLength`, () => {
|
|
@@ -226,9 +225,9 @@ describe('SVGPathCommander Static Methods', () => {
|
|
|
226
225
|
it(`Can do getSegmentOfPoint`, () => {
|
|
227
226
|
const { getSegmentOfPoint } = SVGPathCommander;
|
|
228
227
|
// first point
|
|
229
|
-
expect(getSegmentOfPoint(simpleShapes.initial[1], { x: 10, y: 90 })).to.deep.equal({ segment: ["M", 10, 90], index: 0, length: 0,
|
|
228
|
+
expect(getSegmentOfPoint(simpleShapes.initial[1], { x: 10, y: 90 })).to.deep.equal({ segment: ["M", 10, 90], index: 0, length: 0, lengthAtSegment: 0 });
|
|
230
229
|
// mid point
|
|
231
|
-
expect(getSegmentOfPoint(simpleShapes.initial[3], { x: 9, y: 9 })).to.deep.equal({ segment: ["a", 6, 4, 10, 0,
|
|
230
|
+
expect(getSegmentOfPoint(simpleShapes.initial[3], { x: 9, y: 9 })).to.deep.equal({ segment: ["a", 6, 4, 10, 0, 1, 8, 0], index: 5, length: 7.498916687913066,/* point: { x: 6, y: 10 },*/ lengthAtSegment: 48.11479095890485 });
|
|
232
231
|
});
|
|
233
232
|
|
|
234
233
|
it(`Can do getClosestPoint`, () => {
|
|
@@ -236,7 +235,7 @@ describe('SVGPathCommander Static Methods', () => {
|
|
|
236
235
|
// first point
|
|
237
236
|
expect(getClosestPoint(simpleShapes.initial[1], { x: 10, y: 90 })).to.deep.equal({ x: 10, y: 90 });
|
|
238
237
|
// mid point
|
|
239
|
-
expect(getClosestPoint(simpleShapes.initial[3], { x: 9, y: 9 })).to.deep.equal({ x: 8.
|
|
238
|
+
expect(getClosestPoint(simpleShapes.initial[3], { x: 9, y: 9 })).to.deep.equal({ x: 8.995511191469355, y: 8.952970323068374 });
|
|
240
239
|
});
|
|
241
240
|
|
|
242
241
|
it(`Can do isPointInStroke`, () => {
|
|
@@ -245,7 +244,7 @@ describe('SVGPathCommander Static Methods', () => {
|
|
|
245
244
|
expect(isPointInStroke(simpleShapes.initial[1], { x: 10, y: 90 })).to.be.true;
|
|
246
245
|
// mid point'
|
|
247
246
|
// expect(isPointInStroke(simpleShapes.initial[1], { x: 28.94438057441916, y: 46.29922469345143 })).to.be.true;
|
|
248
|
-
expect(isPointInStroke(simpleShapes.initial[1], {x: 90, y: 90})).to.be.true;
|
|
247
|
+
expect(isPointInStroke(simpleShapes.initial[1], { x: 90, y: 90 })).to.be.true;
|
|
249
248
|
// ({ x: 10, y: 10 })
|
|
250
249
|
expect(isPointInStroke(simpleShapes.initial[1], { x: 10, y: 10 })).to.be.false;
|
|
251
250
|
// ({ x: 45.355339, y: 45.355339 })
|
|
@@ -269,13 +268,13 @@ describe('SVGPathCommander Static Methods', () => {
|
|
|
269
268
|
});
|
|
270
269
|
|
|
271
270
|
it(`Can do polygonLength`, () => {
|
|
272
|
-
const {
|
|
273
|
-
expect(polygonLength([[100, 100], [150, 25], [150, 75], [200, 0]])).to.equal(230.27756377319946);
|
|
271
|
+
const { polygonTools } = SVGPathCommander;
|
|
272
|
+
expect(polygonTools.polygonLength([[100, 100], [150, 25], [150, 75], [200, 0]])).to.equal(230.27756377319946);
|
|
274
273
|
});
|
|
275
274
|
|
|
276
275
|
it(`Can do polygonArea`, () => {
|
|
277
|
-
const {
|
|
278
|
-
expect(polygonArea([[107.4, 13], [113.7, 28.8], [127.9, 31.3], [117.6, 43.5], [120.1, 60.8], [107.4, 52.6], [94.6, 60.8], [97.1, 43.5], [86.8, 31.3], [101, 28.8]])).to.equal(-836.69);
|
|
276
|
+
const { polygonTools } = SVGPathCommander;
|
|
277
|
+
expect(polygonTools.polygonArea([[107.4, 13], [113.7, 28.8], [127.9, 31.3], [117.6, 43.5], [120.1, 60.8], [107.4, 52.6], [94.6, 60.8], [97.1, 43.5], [86.8, 31.3], [101, 28.8]])).to.equal(-836.69);
|
|
279
278
|
});
|
|
280
279
|
|
|
281
280
|
it(`Can do transformPath with empty object`, () => {
|
|
@@ -288,17 +287,44 @@ describe('SVGPathCommander Static Methods', () => {
|
|
|
288
287
|
expect(path2).to.equal(simpleShapes.normalized[0]);
|
|
289
288
|
});
|
|
290
289
|
|
|
290
|
+
it(`Can check path type`, () => {
|
|
291
|
+
const { parsePathString, isPathArray, isCurveArray, isAbsoluteArray, isRelativeArray, isNormalizedArray } = SVGPathCommander;
|
|
292
|
+
// const
|
|
293
|
+
expect(isPathArray(simpleShapes.initial[0])).to.be.false;
|
|
294
|
+
expect(isPathArray(parsePathString(simpleShapes.initial[0]))).to.be.true;
|
|
295
|
+
expect(isAbsoluteArray(simpleShapes.normalized[0])).to.be.false;
|
|
296
|
+
expect(isAbsoluteArray(parsePathString(simpleShapes.normalized[0]))).to.be.true;
|
|
297
|
+
expect(isRelativeArray(shapes.relative[7])).to.be.false;
|
|
298
|
+
// console.log(parsePathString(shapes.relative[7]))
|
|
299
|
+
expect(isRelativeArray(parsePathString(shapes.relative[7]))).to.be.true;
|
|
300
|
+
expect(isNormalizedArray(simpleShapes.normalized[0])).to.be.false;
|
|
301
|
+
expect(isNormalizedArray(parsePathString(simpleShapes.normalized[0]))).to.be.true;
|
|
302
|
+
expect(isCurveArray(simpleShapes.normalized[1])).to.be.false;
|
|
303
|
+
expect(isCurveArray(parsePathString(simpleShapes.normalized[1]))).to.be.true;
|
|
304
|
+
|
|
305
|
+
});
|
|
306
|
+
|
|
291
307
|
it(`Can cover all remaining branches`, () => {
|
|
292
|
-
const {
|
|
293
|
-
|
|
294
|
-
expect(path.length).to.be.above(0);
|
|
308
|
+
const { splitPath, pathToString, optimizePath, parsePathString, getPathBBox, getPointAtLength, getTotalLength } = SVGPathCommander;
|
|
309
|
+
expect(getPointAtLength(simpleShapes.normalized[3], 24.057395479452424)).to.deep.equal({ x: 14, y: 10 });
|
|
295
310
|
expect(getPointAtLength(simpleShapes.normalized[0], 0)).to.deep.equal({ x: 10, y: 10 });
|
|
296
|
-
expect(
|
|
297
|
-
|
|
298
|
-
expect(
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
311
|
+
expect(getPointAtLength(simpleShapes.normalized[3], undefined)).to.deep.equal({ x: 6, y: 10 });
|
|
312
|
+
expect(getTotalLength(simpleShapes.normalized[0])).to.be.above(233);
|
|
313
|
+
expect(getPathBBox(simpleShapes.normalized[2])).to.deep.equal({
|
|
314
|
+
"cx": 100, "cy": 50, "cz": 192.5,
|
|
315
|
+
"height": 25, "width": 180,
|
|
316
|
+
"x": 10, "y": 37.5, "x2": 190, "y2": 62.5,
|
|
317
|
+
});
|
|
318
|
+
expect(getPathBBox(simpleShapes.normalized[1])).to.deep.equal({
|
|
319
|
+
"cx": 90, "cy": 50, "cz": 200,
|
|
320
|
+
"height": 80, "width": 160,
|
|
321
|
+
"x": 10, "y": 10, "x2": 170,"y2": 90,
|
|
322
|
+
});
|
|
323
|
+
expect(splitPath(parsePathString(shapes.relative[1])).length).to.equal(7);
|
|
324
|
+
expect(pathToString(optimizePath(parsePathString(
|
|
325
|
+
// 'M10 50q15 -25 30 0Q55 75 70 50Q85 25 100 50T130 50Q145 25 160 50t30 0'
|
|
326
|
+
simpleShapes.normalized[2]
|
|
327
|
+
), 2))).to.equal(simpleShapes.initial[2]);
|
|
328
|
+
// M10 50q15 -25 30 0t30 0t30 0t30 0t30 0t30 0
|
|
303
329
|
});
|
|
304
330
|
});
|
package/cypress.config.ts
DELETED
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
import { defineConfig } from "cypress";
|
|
2
|
-
import createBundler from "@bahmutov/cypress-esbuild-preprocessor";
|
|
3
|
-
import createEsbuildIstanbulPlugin from "./cypress/plugins/esbuild-istanbul";
|
|
4
|
-
|
|
5
|
-
async function setupNodeEvents(
|
|
6
|
-
on: Cypress.PluginEvents,
|
|
7
|
-
config: Cypress.PluginConfigOptions
|
|
8
|
-
): Promise<Cypress.PluginConfigOptions> {
|
|
9
|
-
await require("@cypress/code-coverage/task")(on, config);
|
|
10
|
-
|
|
11
|
-
on(
|
|
12
|
-
"file:preprocessor",
|
|
13
|
-
createBundler({
|
|
14
|
-
plugins: [createEsbuildIstanbulPlugin()],
|
|
15
|
-
})
|
|
16
|
-
);
|
|
17
|
-
|
|
18
|
-
// Make sure to return the config object as it might have been modified by the plugin.
|
|
19
|
-
return config;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
export default defineConfig({
|
|
23
|
-
e2e: {
|
|
24
|
-
specPattern: "cypress/e2e/**/*.{js,jsx,ts,tsx}",
|
|
25
|
-
supportFile: "cypress/support/e2e.ts",
|
|
26
|
-
video: false,
|
|
27
|
-
setupNodeEvents,
|
|
28
|
-
},
|
|
29
|
-
});
|
package/src/math/polygonArea.ts
DELETED
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* d3-polygon-area
|
|
3
|
-
* https://github.com/d3/d3-polygon
|
|
4
|
-
*
|
|
5
|
-
* Returns the area of a polygon.
|
|
6
|
-
*
|
|
7
|
-
* @param polygon an array of coordinates
|
|
8
|
-
* @returns the polygon area
|
|
9
|
-
*/
|
|
10
|
-
const polygonArea = (polygon: [number, number][]): number => {
|
|
11
|
-
const n = polygon.length;
|
|
12
|
-
let i = -1;
|
|
13
|
-
let a;
|
|
14
|
-
let b = polygon[n - 1];
|
|
15
|
-
let area = 0;
|
|
16
|
-
|
|
17
|
-
/* eslint-disable-next-line */
|
|
18
|
-
while (++i < n) {
|
|
19
|
-
a = b;
|
|
20
|
-
b = polygon[i];
|
|
21
|
-
area += a[1] * b[0] - a[0] * b[1];
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
return area / 2;
|
|
25
|
-
};
|
|
26
|
-
|
|
27
|
-
export default polygonArea;
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import distanceSquareRoot from './distanceSquareRoot';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* d3-polygon-length
|
|
5
|
-
* https://github.com/d3/d3-polygon
|
|
6
|
-
*
|
|
7
|
-
* Returns the perimeter of a polygon.
|
|
8
|
-
*
|
|
9
|
-
* @param polygon an array of coordinates
|
|
10
|
-
* @returns {number} the polygon length
|
|
11
|
-
*/
|
|
12
|
-
const polygonLength = (polygon: [number, number][]): number => {
|
|
13
|
-
return polygon.reduce((length, point, i) => {
|
|
14
|
-
if (i) {
|
|
15
|
-
return length + distanceSquareRoot(polygon[i - 1], point);
|
|
16
|
-
}
|
|
17
|
-
return 0;
|
|
18
|
-
}, 0);
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
export default polygonLength;
|
package/src/process/fixArc.ts
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import { CSegment, PathArray, PathCommand } from '../types';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Splits an extended A (arc-to) segment into two cubic-bezier segments.
|
|
5
|
-
*
|
|
6
|
-
* @param path the `pathArray` this segment belongs to
|
|
7
|
-
* @param allPathCommands all previous path commands
|
|
8
|
-
* @param i the segment index
|
|
9
|
-
*/
|
|
10
|
-
const fixArc = (path: PathArray, allPathCommands: PathCommand[], i: number) => {
|
|
11
|
-
if (path[i].length > 7) {
|
|
12
|
-
path[i].shift();
|
|
13
|
-
const segment = path[i];
|
|
14
|
-
let ni = i; // ESLint
|
|
15
|
-
while (segment.length) {
|
|
16
|
-
// if created multiple C:s, their original seg is saved
|
|
17
|
-
allPathCommands[i] = 'A';
|
|
18
|
-
path.splice((ni += 1), 0, ['C', ...segment.splice(0, 6)] as CSegment);
|
|
19
|
-
}
|
|
20
|
-
path.splice(i, 1);
|
|
21
|
-
}
|
|
22
|
-
};
|
|
23
|
-
export default fixArc;
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
import type { PathArray, PathCommand, PathSegment } from '../types';
|
|
2
|
-
import isNormalizedArray from '../util/isNormalizedArray';
|
|
3
|
-
import segmentToCubic from './segmentToCubic';
|
|
4
|
-
import paramsParser from '../parser/paramsParser';
|
|
5
|
-
import normalizePath from './normalizePath';
|
|
6
|
-
import fixArc from './fixArc';
|
|
7
|
-
import isAbsoluteArray from '../util/isAbsoluteArray';
|
|
8
|
-
import pathToAbsolute from '../convert/pathToAbsolute';
|
|
9
|
-
|
|
10
|
-
const replaceArc = (pathInput: PathArray | string): PathArray => {
|
|
11
|
-
const absolutePath = isAbsoluteArray(pathInput) ? pathInput : pathToAbsolute(pathInput);
|
|
12
|
-
const normalizedPath = isNormalizedArray(absolutePath) ? absolutePath : normalizePath(absolutePath);
|
|
13
|
-
const params = { ...paramsParser };
|
|
14
|
-
const allPathCommands = [] as PathCommand[]; // needed for arc to curve transformation
|
|
15
|
-
let segment = [] as unknown as PathSegment;
|
|
16
|
-
let seglen = 0;
|
|
17
|
-
let pathCommand = '';
|
|
18
|
-
const resultedPath = [] as unknown as PathArray;
|
|
19
|
-
let i = 0;
|
|
20
|
-
let ii = absolutePath.length;
|
|
21
|
-
|
|
22
|
-
for (i = 0; i < ii; i += 1) {
|
|
23
|
-
/* istanbul ignore else @preserve */
|
|
24
|
-
if (absolutePath[i]) [pathCommand] = absolutePath[i];
|
|
25
|
-
allPathCommands[i] = pathCommand as PathCommand;
|
|
26
|
-
|
|
27
|
-
/* istanbul ignore else @preserve */
|
|
28
|
-
if (pathCommand === 'A') {
|
|
29
|
-
segment = segmentToCubic(normalizedPath[i], params);
|
|
30
|
-
|
|
31
|
-
absolutePath[i] = segmentToCubic(normalizedPath[i], params);
|
|
32
|
-
fixArc(absolutePath, allPathCommands, i);
|
|
33
|
-
|
|
34
|
-
normalizedPath[i] = segmentToCubic(normalizedPath[i], params);
|
|
35
|
-
fixArc(normalizedPath, allPathCommands, i);
|
|
36
|
-
ii = Math.max(absolutePath.length, normalizedPath.length);
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
segment = normalizedPath[i];
|
|
40
|
-
seglen = segment.length;
|
|
41
|
-
|
|
42
|
-
params.x1 = +segment[seglen - 2];
|
|
43
|
-
params.y1 = +segment[seglen - 1];
|
|
44
|
-
params.x2 = +segment[seglen - 4] || params.x1;
|
|
45
|
-
params.y2 = +segment[seglen - 3] || params.y1;
|
|
46
|
-
|
|
47
|
-
resultedPath.push(absolutePath[i]);
|
|
48
|
-
}
|
|
49
|
-
return resultedPath;
|
|
50
|
-
};
|
|
51
|
-
|
|
52
|
-
export default replaceArc;
|
package/src/util/pathFactory.ts
DELETED
|
@@ -1,130 +0,0 @@
|
|
|
1
|
-
import type { MSegment, PathArray, PathSegment, Point } from '../types';
|
|
2
|
-
// import type { LengthFactory } from '../interface';
|
|
3
|
-
import normalizePath from '../process/normalizePath';
|
|
4
|
-
import getLineSegmentProperties from '../math/lineTools';
|
|
5
|
-
import getArcSegmentProperties from '../math/arcTools';
|
|
6
|
-
import getCubicSegmentProperties from '../math/cubicTools';
|
|
7
|
-
import getQuadSegmentProperties from '../math/quadTools';
|
|
8
|
-
import DISTANCE_EPSILON from './distanceEpsilon';
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* Returns a {x,y} point at a given length
|
|
12
|
-
* of a shape, the shape total length and
|
|
13
|
-
* the shape minimum and maximum {x,y} coordinates.
|
|
14
|
-
*
|
|
15
|
-
* @param pathInput the `pathArray` to look into
|
|
16
|
-
* @param distance the length of the shape to look at
|
|
17
|
-
* @returns the path length, point, min & max
|
|
18
|
-
*/
|
|
19
|
-
const pathFactory = (pathInput: string | PathArray, distance?: number) => {
|
|
20
|
-
const path = normalizePath(pathInput);
|
|
21
|
-
const distanceIsNumber = typeof distance === 'number';
|
|
22
|
-
let isM = false;
|
|
23
|
-
let data = [] as number[];
|
|
24
|
-
let pathCommand = 'M';
|
|
25
|
-
let x = 0;
|
|
26
|
-
let y = 0;
|
|
27
|
-
let mx = 0;
|
|
28
|
-
let my = 0;
|
|
29
|
-
let seg = path[0] as PathSegment;
|
|
30
|
-
const MIN = [] as Point[];
|
|
31
|
-
const MAX = [] as Point[];
|
|
32
|
-
let min = { x: 0, y: 0 };
|
|
33
|
-
let max = { x: 0, y: 0 };
|
|
34
|
-
let POINT = min;
|
|
35
|
-
let LENGTH = 0;
|
|
36
|
-
let props = {
|
|
37
|
-
point: { x: 0, y: 0 },
|
|
38
|
-
length: 0,
|
|
39
|
-
bbox: {
|
|
40
|
-
min: { x: 0, y: 0 },
|
|
41
|
-
max: { x: 0, y: 0 },
|
|
42
|
-
},
|
|
43
|
-
};
|
|
44
|
-
|
|
45
|
-
for (let i = 0, ll = path.length; i < ll; i += 1) {
|
|
46
|
-
seg = path[i];
|
|
47
|
-
[pathCommand] = seg;
|
|
48
|
-
isM = pathCommand === 'M';
|
|
49
|
-
data = !isM ? [x, y, ...(seg.slice(1) as number[])] : data;
|
|
50
|
-
|
|
51
|
-
if (distanceIsNumber && distance < DISTANCE_EPSILON) {
|
|
52
|
-
POINT = min;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
// this segment is always ZERO
|
|
56
|
-
/* istanbul ignore else @preserve */
|
|
57
|
-
if (isM) {
|
|
58
|
-
// remember mx, my for Z
|
|
59
|
-
[, mx, my] = seg as MSegment;
|
|
60
|
-
min = { x: mx, y: my };
|
|
61
|
-
max = { x: mx, y: my };
|
|
62
|
-
props = {
|
|
63
|
-
point: min,
|
|
64
|
-
length: 0,
|
|
65
|
-
bbox: { min, max },
|
|
66
|
-
};
|
|
67
|
-
} else if (pathCommand === 'L') {
|
|
68
|
-
props = getLineSegmentProperties(
|
|
69
|
-
...(data as [number, number, number, number]),
|
|
70
|
-
distanceIsNumber ? distance - LENGTH : undefined,
|
|
71
|
-
);
|
|
72
|
-
} else if (pathCommand === 'A') {
|
|
73
|
-
props = getArcSegmentProperties(
|
|
74
|
-
...(data as [number, number, number, number, number, number, number, number, number]),
|
|
75
|
-
distanceIsNumber ? distance - LENGTH : undefined,
|
|
76
|
-
);
|
|
77
|
-
} else if (pathCommand === 'C') {
|
|
78
|
-
props = getCubicSegmentProperties(
|
|
79
|
-
...(data as [number, number, number, number, number, number, number, number]),
|
|
80
|
-
distanceIsNumber ? distance - LENGTH : undefined,
|
|
81
|
-
);
|
|
82
|
-
} else if (pathCommand === 'Q') {
|
|
83
|
-
props = getQuadSegmentProperties(
|
|
84
|
-
...(data as [number, number, number, number, number, number]),
|
|
85
|
-
distanceIsNumber ? distance - LENGTH : undefined,
|
|
86
|
-
);
|
|
87
|
-
} else if (pathCommand === 'Z') {
|
|
88
|
-
data = [x, y, mx, my];
|
|
89
|
-
props = getLineSegmentProperties(
|
|
90
|
-
...(data as [number, number, number, number]),
|
|
91
|
-
distanceIsNumber ? distance - LENGTH : undefined,
|
|
92
|
-
);
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
if (distanceIsNumber && LENGTH < distance && LENGTH + props.length >= distance) {
|
|
96
|
-
POINT = props.point;
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
MIN.push(props.bbox.min);
|
|
100
|
-
MAX.push(props.bbox.max);
|
|
101
|
-
LENGTH += props.length;
|
|
102
|
-
|
|
103
|
-
[x, y] = pathCommand !== 'Z' ? (seg.slice(-2) as [number, number]) : [mx, my];
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
// native `getPointAtLength` behavior when the given distance
|
|
107
|
-
// is higher than total length
|
|
108
|
-
if (distanceIsNumber && distance > LENGTH - DISTANCE_EPSILON) {
|
|
109
|
-
POINT = { x, y };
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
return {
|
|
113
|
-
point: POINT,
|
|
114
|
-
length: LENGTH,
|
|
115
|
-
get bbox() {
|
|
116
|
-
return {
|
|
117
|
-
min: {
|
|
118
|
-
x: Math.min(...MIN.map(n => n.x)),
|
|
119
|
-
y: Math.min(...MIN.map(n => n.y)),
|
|
120
|
-
},
|
|
121
|
-
max: {
|
|
122
|
-
x: Math.max(...MAX.map(n => n.x)),
|
|
123
|
-
y: Math.max(...MAX.map(n => n.y)),
|
|
124
|
-
},
|
|
125
|
-
};
|
|
126
|
-
},
|
|
127
|
-
};
|
|
128
|
-
};
|
|
129
|
-
|
|
130
|
-
export default pathFactory;
|