@remotion/paths 4.0.0-webhook.27 → 4.1.0-alpha2

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.
Files changed (69) hide show
  1. package/LICENSE.md +1 -1
  2. package/README.md +1 -2
  3. package/dist/evolve-path.d.ts +2 -2
  4. package/dist/evolve-path.js +2 -2
  5. package/dist/extend-viewbox.d.ts +2 -2
  6. package/dist/extend-viewbox.js +2 -2
  7. package/dist/get-bounding-box.d.ts +8 -0
  8. package/dist/get-bounding-box.js +185 -0
  9. package/dist/get-length.d.ts +2 -2
  10. package/dist/get-length.js +2 -2
  11. package/dist/get-point-at-length.d.ts +2 -2
  12. package/dist/get-point-at-length.js +2 -2
  13. package/dist/get-subpaths.d.ts +6 -0
  14. package/dist/get-subpaths.js +19 -0
  15. package/dist/get-tangent-at-length.d.ts +2 -2
  16. package/dist/get-tangent-at-length.js +2 -2
  17. package/dist/helpers/arc.d.ts +0 -0
  18. package/dist/helpers/arc.js +0 -0
  19. package/dist/helpers/bezier-functions.d.ts +0 -0
  20. package/dist/helpers/bezier-functions.js +0 -0
  21. package/dist/helpers/bezier-values.d.ts +0 -0
  22. package/dist/helpers/bezier-values.js +0 -0
  23. package/dist/helpers/bezier.d.ts +0 -0
  24. package/dist/helpers/bezier.js +0 -0
  25. package/dist/helpers/construct.d.ts +9 -1
  26. package/dist/helpers/construct.js +218 -128
  27. package/dist/helpers/get-part-at-length.d.ts +0 -0
  28. package/dist/helpers/get-part-at-length.js +0 -0
  29. package/dist/helpers/iterate.d.ts +14 -0
  30. package/dist/helpers/iterate.js +95 -0
  31. package/dist/helpers/linear.d.ts +6 -1
  32. package/dist/helpers/linear.js +1 -1
  33. package/dist/helpers/remove-a-s-t-curves.d.ts +2 -0
  34. package/dist/helpers/remove-a-s-t-curves.js +271 -0
  35. package/dist/helpers/split-curve.d.ts +1 -1
  36. package/dist/helpers/split-curve.js +0 -0
  37. package/dist/helpers/types.d.ts +109 -2
  38. package/dist/helpers/types.js +0 -0
  39. package/dist/index.d.ts +10 -2
  40. package/dist/index.js +19 -3
  41. package/dist/interpolate-path.d.ts +2 -2
  42. package/dist/interpolate-path.js +2 -2
  43. package/dist/normalize-path.d.ts +4 -2
  44. package/dist/normalize-path.js +141 -277
  45. package/dist/parse-path.d.ts +8 -0
  46. package/dist/parse-path.js +265 -0
  47. package/dist/reduce-instructions.d.ts +7 -0
  48. package/dist/reduce-instructions.js +15 -0
  49. package/dist/reset-path.d.ts +6 -0
  50. package/dist/reset-path.js +15 -0
  51. package/dist/reverse-path.d.ts +2 -2
  52. package/dist/reverse-path.js +73 -118
  53. package/dist/scale-path.d.ts +10 -0
  54. package/dist/scale-path.js +180 -0
  55. package/dist/serialize-instructions.d.ts +2 -0
  56. package/dist/serialize-instructions.js +78 -0
  57. package/dist/translate-path.d.ts +11 -0
  58. package/dist/translate-path.js +116 -0
  59. package/dist/warp-path/index.d.ts +10 -0
  60. package/dist/warp-path/index.js +26 -0
  61. package/dist/warp-path/warp-helpers.d.ts +14 -0
  62. package/dist/warp-path/warp-helpers.js +229 -0
  63. package/package.json +38 -38
  64. package/.prettierrc.js +0 -14
  65. package/dist/get-parts.d.ts +0 -7
  66. package/dist/get-parts.js +0 -31
  67. package/dist/helpers/parse.d.ts +0 -2
  68. package/dist/helpers/parse.js +0 -49
  69. package/tsconfig.json +0 -9
@@ -0,0 +1,180 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.scalePath = void 0;
4
+ const get_bounding_box_1 = require("./get-bounding-box");
5
+ const parse_path_1 = require("./parse-path");
6
+ const reduce_instructions_1 = require("./reduce-instructions");
7
+ const serialize_instructions_1 = require("./serialize-instructions");
8
+ const translate_path_1 = require("./translate-path");
9
+ /**
10
+ * @description Allows you to grow or shrink the size of a path.
11
+ * @param {string} path A valid SVG path
12
+ * @param {string} d
13
+ * @param {Number} scaleX
14
+ * @param {Number} scaleY
15
+ * @returns a new path with respect to the scale values provided
16
+ * @see [Documentation](https://www.remotion.dev/docs/paths/scale-path)
17
+ */
18
+ const scalePath = (d, scaleX, scaleY) => {
19
+ const reduced = (0, reduce_instructions_1.reduceInstructions)((0, parse_path_1.parsePath)(d));
20
+ const bounded = (0, get_bounding_box_1.getBoundingBoxFromInstructions)(reduced);
21
+ const zeroed = (0, translate_path_1.translateSegments)(reduced, -bounded.x1, -bounded.y1);
22
+ const mapped = zeroed.map((instruction) => {
23
+ if (instruction.type === 'L') {
24
+ return {
25
+ type: 'L',
26
+ x: scaleX * instruction.x,
27
+ y: scaleY * instruction.y,
28
+ };
29
+ }
30
+ if (instruction.type === 'C') {
31
+ return {
32
+ type: 'C',
33
+ x: scaleX * instruction.x,
34
+ y: scaleY * instruction.y,
35
+ cp1x: scaleX * instruction.cp1x,
36
+ cp1y: scaleY * instruction.cp1y,
37
+ cp2x: scaleX * instruction.cp2x,
38
+ cp2y: scaleY * instruction.cp2y,
39
+ };
40
+ }
41
+ if (instruction.type === 'M') {
42
+ return {
43
+ type: 'M',
44
+ x: scaleX * instruction.x,
45
+ y: scaleY * instruction.y,
46
+ };
47
+ }
48
+ if (instruction.type === 'Q') {
49
+ return {
50
+ type: 'Q',
51
+ x: scaleX * instruction.x,
52
+ y: scaleY * instruction.y,
53
+ cpx: scaleX * instruction.cpx,
54
+ cpy: scaleY * instruction.cpy,
55
+ };
56
+ }
57
+ if (instruction.type === 'Z') {
58
+ return {
59
+ type: 'Z',
60
+ };
61
+ }
62
+ if (instruction.type === 'A') {
63
+ return {
64
+ type: 'A',
65
+ largeArcFlag: instruction.largeArcFlag,
66
+ rx: scaleX * instruction.rx,
67
+ ry: scaleY * instruction.ry,
68
+ sweepFlag: instruction.sweepFlag,
69
+ xAxisRotation: instruction.xAxisRotation,
70
+ x: scaleX * instruction.x,
71
+ y: scaleY * instruction.y,
72
+ };
73
+ }
74
+ if (instruction.type === 'H') {
75
+ return {
76
+ type: 'H',
77
+ x: scaleX * instruction.x,
78
+ };
79
+ }
80
+ if (instruction.type === 'S') {
81
+ return {
82
+ type: 'S',
83
+ cpx: scaleX * instruction.cpx,
84
+ cpy: scaleY * instruction.cpy,
85
+ x: scaleX * instruction.x,
86
+ y: scaleY * instruction.y,
87
+ };
88
+ }
89
+ if (instruction.type === 'T') {
90
+ return {
91
+ type: 'T',
92
+ x: scaleX * instruction.x,
93
+ y: scaleY * instruction.y,
94
+ };
95
+ }
96
+ if (instruction.type === 'V') {
97
+ return {
98
+ type: 'V',
99
+ y: scaleY * instruction.y,
100
+ };
101
+ }
102
+ if (instruction.type === 'a') {
103
+ return {
104
+ type: 'a',
105
+ dx: scaleX * instruction.dx,
106
+ dy: scaleY * instruction.dy,
107
+ largeArcFlag: instruction.largeArcFlag,
108
+ rx: scaleX * instruction.rx,
109
+ ry: scaleY * instruction.ry,
110
+ sweepFlag: instruction.sweepFlag,
111
+ xAxisRotation: instruction.xAxisRotation,
112
+ };
113
+ }
114
+ if (instruction.type === 'c') {
115
+ return {
116
+ type: 'c',
117
+ cp1dx: scaleX * instruction.cp1dx,
118
+ cp1dy: scaleY * instruction.cp1dy,
119
+ cp2dx: scaleX * instruction.cp2dx,
120
+ cp2dy: scaleY * instruction.cp2dy,
121
+ dx: scaleX * instruction.dx,
122
+ dy: scaleY * instruction.dy,
123
+ };
124
+ }
125
+ if (instruction.type === 'h') {
126
+ return {
127
+ type: 'h',
128
+ dx: scaleX * instruction.dx,
129
+ };
130
+ }
131
+ if (instruction.type === 'l') {
132
+ return {
133
+ type: 'l',
134
+ dx: scaleX * instruction.dx,
135
+ dy: scaleY * instruction.dy,
136
+ };
137
+ }
138
+ if (instruction.type === 'm') {
139
+ return {
140
+ type: 'm',
141
+ dx: scaleX * instruction.dx,
142
+ dy: scaleY * instruction.dy,
143
+ };
144
+ }
145
+ if (instruction.type === 'q') {
146
+ return {
147
+ type: 'q',
148
+ cpdx: scaleX * instruction.cpdx,
149
+ cpdy: scaleY * instruction.cpdy,
150
+ dx: scaleX * instruction.dx,
151
+ dy: scaleY * instruction.dy,
152
+ };
153
+ }
154
+ if (instruction.type === 's') {
155
+ return {
156
+ type: 's',
157
+ cpdx: scaleX * instruction.cpdx,
158
+ cpdy: scaleY * instruction.cpdy,
159
+ dx: scaleX * instruction.dx,
160
+ dy: scaleY * instruction.dy,
161
+ };
162
+ }
163
+ if (instruction.type === 't') {
164
+ return {
165
+ type: 't',
166
+ dx: scaleX * instruction.dx,
167
+ dy: scaleY * instruction.dy,
168
+ };
169
+ }
170
+ if (instruction.type === 'v') {
171
+ return {
172
+ type: 'v',
173
+ dy: scaleY * instruction.dy,
174
+ };
175
+ }
176
+ throw new Error('unexpected function');
177
+ });
178
+ return (0, serialize_instructions_1.serializeInstructions)((0, translate_path_1.translateSegments)(mapped, bounded.x1, bounded.y1));
179
+ };
180
+ exports.scalePath = scalePath;
@@ -0,0 +1,2 @@
1
+ import type { Instruction } from './helpers/types';
2
+ export declare const serializeInstructions: (path: Instruction[]) => string;
@@ -0,0 +1,78 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.serializeInstructions = void 0;
4
+ /**
5
+ * @description Takes an array of Instruction's and serializes it into an SVG path string.
6
+ * @param {Array} instruction
7
+ * @returns a serialized SVG path string
8
+ * @see [Documentation](https://www.remotion.dev/docs/paths/serialize-instructions)
9
+ */
10
+ const serializeInstruction = (instruction) => {
11
+ if (instruction.type === 'A') {
12
+ return `A ${instruction.rx} ${instruction.ry} ${instruction.xAxisRotation} ${Number(instruction.largeArcFlag)} ${Number(instruction.sweepFlag)} ${instruction.x} ${instruction.y}`;
13
+ }
14
+ if (instruction.type === 'a') {
15
+ return `a ${instruction.rx} ${instruction.ry} ${instruction.xAxisRotation} ${Number(instruction.largeArcFlag)} ${Number(instruction.sweepFlag)} ${instruction.dx} ${instruction.dy}`;
16
+ }
17
+ if (instruction.type === 'C') {
18
+ return `C ${instruction.cp1x} ${instruction.cp1y} ${instruction.cp2x} ${instruction.cp2y} ${instruction.x} ${instruction.y}`;
19
+ }
20
+ if (instruction.type === 'c') {
21
+ return `c ${instruction.cp1dx} ${instruction.cp1dy} ${instruction.cp2dx} ${instruction.cp2dy} ${instruction.dx} ${instruction.dy}`;
22
+ }
23
+ if (instruction.type === 'S') {
24
+ return `S ${instruction.cpx} ${instruction.cpy} ${instruction.x} ${instruction.y}`;
25
+ }
26
+ if (instruction.type === 's') {
27
+ return `s ${instruction.cpdx} ${instruction.cpdy} ${instruction.dx} ${instruction.dy}`;
28
+ }
29
+ if (instruction.type === 'Q') {
30
+ return `Q ${instruction.cpx} ${instruction.cpy} ${instruction.x} ${instruction.y}`;
31
+ }
32
+ if (instruction.type === 'q') {
33
+ return `q ${instruction.cpdx} ${instruction.cpdy} ${instruction.dx} ${instruction.dy}`;
34
+ }
35
+ if (instruction.type === 'Z') {
36
+ return 'Z';
37
+ }
38
+ if (instruction.type === 'H') {
39
+ return `H ${instruction.x}`;
40
+ }
41
+ if (instruction.type === 'h') {
42
+ return `h ${instruction.dx}`;
43
+ }
44
+ if (instruction.type === 'V') {
45
+ return `V ${instruction.y}`;
46
+ }
47
+ if (instruction.type === 'v') {
48
+ return `v ${instruction.dy}`;
49
+ }
50
+ if (instruction.type === 'L') {
51
+ return `L ${instruction.x} ${instruction.y}`;
52
+ }
53
+ if (instruction.type === 'l') {
54
+ return `l ${instruction.dx} ${instruction.dy}`;
55
+ }
56
+ if (instruction.type === 'M') {
57
+ return `M ${instruction.x} ${instruction.y}`;
58
+ }
59
+ if (instruction.type === 'm') {
60
+ return `m ${instruction.dx} ${instruction.dy}`;
61
+ }
62
+ if (instruction.type === 'T') {
63
+ return `T ${instruction.x} ${instruction.y}`;
64
+ }
65
+ if (instruction.type === 't') {
66
+ return `t ${instruction.dx} ${instruction.dy}`;
67
+ }
68
+ // @ts-expect-error
69
+ throw new Error(`Unknown instruction type: ${instruction.type}`);
70
+ };
71
+ const serializeInstructions = (path) => {
72
+ return path
73
+ .map((p) => {
74
+ return serializeInstruction(p);
75
+ })
76
+ .join(' ');
77
+ };
78
+ exports.serializeInstructions = serializeInstructions;
@@ -0,0 +1,11 @@
1
+ import type { Instruction } from './helpers/types';
2
+ export declare const translateSegments: (segments: Instruction[], x: number, y: number) => Instruction[];
3
+ /**
4
+ * @description Translates the path by the given x and y coordinates.
5
+ * @param {string} path the originalSVG path
6
+ * @param {Number} x the amount of horizontal translation
7
+ * @param {Number} y the amount of vertical translation
8
+ * @returns a new string containing a path, if it is valid
9
+ * @see [Documentation](https://www.remotion.dev/docs/paths/translate-path)
10
+ */
11
+ export declare const translatePath: (path: string, x: number, y: number) => string;
@@ -0,0 +1,116 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.translatePath = exports.translateSegments = void 0;
4
+ const parse_path_1 = require("./parse-path");
5
+ const serialize_instructions_1 = require("./serialize-instructions");
6
+ const translateSegments = (segments, x, y) => {
7
+ return segments.map((segment) => {
8
+ // Shift coords only for commands with absolute values
9
+ if (segment.type === 'a' ||
10
+ segment.type === 'c' ||
11
+ segment.type === 'v' ||
12
+ segment.type === 's' ||
13
+ segment.type === 'h' ||
14
+ segment.type === 'l' ||
15
+ segment.type === 'm' ||
16
+ segment.type === 'q' ||
17
+ segment.type === 't') {
18
+ return segment;
19
+ }
20
+ // V is the only command, with shifted coords parity
21
+ if (segment.type === 'V') {
22
+ return {
23
+ type: 'V',
24
+ y: segment.y + y,
25
+ };
26
+ }
27
+ if (segment.type === 'H') {
28
+ return {
29
+ type: 'H',
30
+ x: segment.x + x,
31
+ };
32
+ }
33
+ // ARC is: ['A', rx, ry, x-axis-rotation, large-arc-flag, sweep-flag, x, y]
34
+ // touch x, y only
35
+ if (segment.type === 'A') {
36
+ return {
37
+ type: 'A',
38
+ rx: segment.rx,
39
+ ry: segment.ry,
40
+ largeArcFlag: segment.largeArcFlag,
41
+ sweepFlag: segment.sweepFlag,
42
+ xAxisRotation: segment.xAxisRotation,
43
+ x: segment.x + x,
44
+ y: segment.y + y,
45
+ };
46
+ }
47
+ if (segment.type === 'Z') {
48
+ return segment;
49
+ }
50
+ if (segment.type === 'C') {
51
+ return {
52
+ type: 'C',
53
+ cp1x: segment.cp1x + x,
54
+ cp1y: segment.cp1y + y,
55
+ cp2x: segment.cp2x + x,
56
+ cp2y: segment.cp2y + y,
57
+ x: segment.x + x,
58
+ y: segment.y + y,
59
+ };
60
+ }
61
+ if (segment.type === 'Q') {
62
+ return {
63
+ type: 'Q',
64
+ cpx: segment.cpx + x,
65
+ cpy: segment.cpy + y,
66
+ x: segment.x + x,
67
+ y: segment.y + y,
68
+ };
69
+ }
70
+ if (segment.type === 'S') {
71
+ return {
72
+ type: 'S',
73
+ cpx: segment.cpx + x,
74
+ cpy: segment.cpy + y,
75
+ x: segment.x + x,
76
+ y: segment.y + y,
77
+ };
78
+ }
79
+ if (segment.type === 'T') {
80
+ return {
81
+ type: 'T',
82
+ x: segment.x + x,
83
+ y: segment.y + y,
84
+ };
85
+ }
86
+ if (segment.type === 'L') {
87
+ return {
88
+ type: 'L',
89
+ x: segment.x + x,
90
+ y: segment.y + y,
91
+ };
92
+ }
93
+ if (segment.type === 'M') {
94
+ return {
95
+ type: 'M',
96
+ x: segment.x + x,
97
+ y: segment.y + y,
98
+ };
99
+ }
100
+ // @ts-expect-error
101
+ throw new Error(`Unknown segment type: ${segment.type}`);
102
+ });
103
+ };
104
+ exports.translateSegments = translateSegments;
105
+ /**
106
+ * @description Translates the path by the given x and y coordinates.
107
+ * @param {string} path the originalSVG path
108
+ * @param {Number} x the amount of horizontal translation
109
+ * @param {Number} y the amount of vertical translation
110
+ * @returns a new string containing a path, if it is valid
111
+ * @see [Documentation](https://www.remotion.dev/docs/paths/translate-path)
112
+ */
113
+ const translatePath = (path, x, y) => {
114
+ return (0, serialize_instructions_1.serializeInstructions)((0, exports.translateSegments)((0, parse_path_1.parsePath)(path), x, y));
115
+ };
116
+ exports.translatePath = translatePath;
@@ -0,0 +1,10 @@
1
+ import type { WarpPathFn } from './warp-helpers';
2
+ /**
3
+ * @description This function works by splitting SVG instructions into many smaller SVG instructions and then remapping the coordinates of each instruction.
4
+ * @param {string} path an SVG path string
5
+ * @see [Documentation](https://www.remotion.dev/docs/paths/warp-path)
6
+ */
7
+ export declare const warpPath: (path: string, transformer: WarpPathFn, options?: {
8
+ interpolationThreshold?: number;
9
+ }) => string;
10
+ export type { WarpPathFn } from './warp-helpers';
@@ -0,0 +1,26 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.warpPath = void 0;
4
+ const get_bounding_box_1 = require("../get-bounding-box");
5
+ const parse_path_1 = require("../parse-path");
6
+ const reduce_instructions_1 = require("../reduce-instructions");
7
+ const serialize_instructions_1 = require("../serialize-instructions");
8
+ const warp_helpers_1 = require("./warp-helpers");
9
+ const getDefaultInterpolationThreshold = (instructions) => {
10
+ const boundingBox = (0, get_bounding_box_1.getBoundingBoxFromInstructions)(instructions);
11
+ const longer = Math.max(boundingBox.y2 - boundingBox.y1, boundingBox.x2 - boundingBox.x1);
12
+ return longer * 0.01;
13
+ };
14
+ /**
15
+ * @description This function works by splitting SVG instructions into many smaller SVG instructions and then remapping the coordinates of each instruction.
16
+ * @param {string} path an SVG path string
17
+ * @see [Documentation](https://www.remotion.dev/docs/paths/warp-path)
18
+ */
19
+ const warpPath = (path, transformer, options) => {
20
+ var _a;
21
+ const reduced = (0, reduce_instructions_1.reduceInstructions)((0, parse_path_1.parsePath)(path));
22
+ const withZFix = (0, warp_helpers_1.fixZInstruction)(reduced);
23
+ const interpolated = (0, warp_helpers_1.svgPathInterpolate)(withZFix, (_a = options === null || options === void 0 ? void 0 : options.interpolationThreshold) !== null && _a !== void 0 ? _a : getDefaultInterpolationThreshold(withZFix));
24
+ return (0, serialize_instructions_1.serializeInstructions)((0, warp_helpers_1.warpTransform)(interpolated, transformer));
25
+ };
26
+ exports.warpPath = warpPath;
@@ -0,0 +1,14 @@
1
+ import type { ReducedInstruction } from '../helpers/types';
2
+ export type WarpPathFn = (point: {
3
+ x: number;
4
+ y: number;
5
+ }) => {
6
+ x: number;
7
+ y: number;
8
+ };
9
+ export declare function svgPathInterpolate(path: ReducedInstruction[], threshold: number): ReducedInstruction[];
10
+ export declare const warpTransform: (path: ReducedInstruction[], transformer: WarpPathFn) => ReducedInstruction[];
11
+ export declare const fixZInstruction: (instructions: ReducedInstruction[]) => ReducedInstruction[];
12
+ export declare function interpolateUntil(points: [number, number][], threshold: number, deltaFunction?: (points: [number, number][]) => number): [number, number][][];
13
+ export declare function split(p: number[][], t?: number): number[][][];
14
+ export declare function createLineSegment(points: number[][]): ReducedInstruction;
@@ -0,0 +1,229 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createLineSegment = exports.split = exports.interpolateUntil = exports.fixZInstruction = exports.warpTransform = exports.svgPathInterpolate = void 0;
4
+ function svgPathInterpolate(path, threshold) {
5
+ let didWork = false;
6
+ const deltaFunction = (points) => {
7
+ const linearPoints = [
8
+ points[0].slice(0, 2),
9
+ points[points.length - 1].slice(0, 2),
10
+ ];
11
+ const delta = euclideanDistance(linearPoints);
12
+ didWork = didWork || delta > threshold;
13
+ return delta;
14
+ };
15
+ return warpInterpolate(path, threshold, deltaFunction);
16
+ }
17
+ exports.svgPathInterpolate = svgPathInterpolate;
18
+ function warpInterpolate(path, threshold, deltaFunction) {
19
+ let prexX = 0;
20
+ let prexY = 0;
21
+ return path
22
+ .map((segment) => {
23
+ const points = [[prexX, prexY]];
24
+ if (segment.type !== 'Z') {
25
+ prexX = segment.x;
26
+ prexY = segment.y;
27
+ }
28
+ if (segment.type === 'C') {
29
+ points.push([segment.cp1x, segment.cp1y]);
30
+ points.push([segment.cp2x, segment.cp2y]);
31
+ points.push([segment.x, segment.y]);
32
+ }
33
+ if (segment.type === 'L') {
34
+ points.push([segment.x, segment.y]);
35
+ }
36
+ if (segment.type === 'Q') {
37
+ points.push([segment.cpx, segment.cpy]);
38
+ points.push([segment.x, segment.y]);
39
+ }
40
+ if (segment.type === 'C' ||
41
+ segment.type === 'Q' ||
42
+ segment.type === 'L') {
43
+ return interpolateUntil(points, threshold, deltaFunction).map((rawSegment) => createLineSegment(rawSegment));
44
+ }
45
+ return [segment];
46
+ })
47
+ .flat(1);
48
+ }
49
+ const warpTransform = (path, transformer) => {
50
+ return path
51
+ .map((segment) => {
52
+ if (segment.type === 'L') {
53
+ const { x, y } = transformer({ x: segment.x, y: segment.y });
54
+ return [
55
+ {
56
+ type: 'L',
57
+ x,
58
+ y,
59
+ },
60
+ ];
61
+ }
62
+ if (segment.type === 'Q') {
63
+ const { x, y } = transformer({ x: segment.x, y: segment.y });
64
+ const { x: cpx, y: cpy } = transformer({
65
+ x: segment.cpx,
66
+ y: segment.cpy,
67
+ });
68
+ return [
69
+ {
70
+ type: 'Q',
71
+ x,
72
+ y,
73
+ cpx,
74
+ cpy,
75
+ },
76
+ ];
77
+ }
78
+ if (segment.type === 'C') {
79
+ const { x, y } = transformer({ x: segment.x, y: segment.y });
80
+ const { x: cp1x, y: cp1y } = transformer({
81
+ x: segment.cp1x,
82
+ y: segment.cp1y,
83
+ });
84
+ const { x: cp2x, y: cp2y } = transformer({
85
+ x: segment.cp2x,
86
+ y: segment.cp2y,
87
+ });
88
+ return [
89
+ {
90
+ type: 'C',
91
+ x,
92
+ y,
93
+ cp1x,
94
+ cp1y,
95
+ cp2x,
96
+ cp2y,
97
+ },
98
+ ];
99
+ }
100
+ if (segment.type === 'M') {
101
+ const { x, y } = transformer({ x: segment.x, y: segment.y });
102
+ return [
103
+ {
104
+ type: 'M',
105
+ x,
106
+ y,
107
+ },
108
+ ];
109
+ }
110
+ return [segment];
111
+ })
112
+ .flat(1);
113
+ };
114
+ exports.warpTransform = warpTransform;
115
+ // Add a line from second to last point to last point and then keep Z so it can be transformed as well
116
+ const fixZInstruction = (instructions) => {
117
+ let prevX = 0;
118
+ let prevY = 0;
119
+ return instructions
120
+ .map((instruction) => {
121
+ if (instruction.type === 'Z') {
122
+ return [
123
+ {
124
+ type: 'L',
125
+ x: prevX,
126
+ y: prevY,
127
+ },
128
+ {
129
+ type: 'Z',
130
+ },
131
+ ];
132
+ }
133
+ if (instruction.type === 'M') {
134
+ prevX = instruction.x;
135
+ prevY = instruction.y;
136
+ }
137
+ return [instruction];
138
+ })
139
+ .flat(1);
140
+ };
141
+ exports.fixZInstruction = fixZInstruction;
142
+ const euclideanDistance = (points) => {
143
+ const startPoint = points[0];
144
+ const endPoint = points[points.length - 1];
145
+ let d2 = 0;
146
+ for (let i = 0; i < startPoint.length; i++) {
147
+ const d = endPoint[i] - startPoint[i];
148
+ d2 += d ** 2;
149
+ }
150
+ return Math.sqrt(d2);
151
+ };
152
+ function interpolateUntil(points, threshold, deltaFunction = euclideanDistance) {
153
+ const stack = [points];
154
+ const segments = [];
155
+ while (stack.length > 0) {
156
+ const currentPoints = stack.pop();
157
+ if (deltaFunction(currentPoints) > threshold) {
158
+ const newPoints = split(currentPoints);
159
+ // Add new segments backwards so they end up in correct order
160
+ for (let i = newPoints.length - 1; i >= 0; i--) {
161
+ stack.push(newPoints[i]);
162
+ }
163
+ }
164
+ else {
165
+ segments.push(currentPoints);
166
+ }
167
+ }
168
+ return segments;
169
+ }
170
+ exports.interpolateUntil = interpolateUntil;
171
+ function split(p, t = 0.5) {
172
+ const seg0 = [];
173
+ const seg1 = [];
174
+ const orders = [p];
175
+ while (orders.length < p.length) {
176
+ const q = orders[orders.length - 1];
177
+ const r = [];
178
+ for (let i = 1; i < q.length; i++) {
179
+ const q0 = q[i - 1];
180
+ const q1 = q[i];
181
+ const s = [];
182
+ const dim = Math.max(q0.length, q1.length);
183
+ for (let j = 0; j < dim; j++) {
184
+ const s0 = q0[j] || 0;
185
+ const s1 = q1[j] || 0;
186
+ s.push(s0 + (s1 - s0) * t);
187
+ }
188
+ r.push(s);
189
+ }
190
+ orders.push(r);
191
+ }
192
+ for (let i = 0; i < orders.length; i++) {
193
+ seg0.push(orders[i][0]);
194
+ seg1.push(orders[orders.length - 1 - i][i]);
195
+ }
196
+ return [seg0, seg1];
197
+ }
198
+ exports.split = split;
199
+ function createLineSegment(points) {
200
+ switch (points.length) {
201
+ case 2:
202
+ return {
203
+ type: 'L',
204
+ x: points[1][0],
205
+ y: points[1][1],
206
+ };
207
+ case 3:
208
+ return {
209
+ type: 'Q',
210
+ cpx: points[1][0],
211
+ cpy: points[1][1],
212
+ x: points[2][0],
213
+ y: points[2][1],
214
+ };
215
+ case 4:
216
+ return {
217
+ type: 'C',
218
+ cp1x: points[1][0],
219
+ cp1y: points[1][1],
220
+ cp2x: points[2][0],
221
+ cp2y: points[2][1],
222
+ x: points[3][0],
223
+ y: points[3][1],
224
+ };
225
+ default:
226
+ throw new Error('Expected 2, 3 or 4 points for a line segment, got ' + points.length);
227
+ }
228
+ }
229
+ exports.createLineSegment = createLineSegment;