@remotion/paths 3.3.38 → 3.3.40

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 (42) hide show
  1. package/dist/get-bounding-box.d.ts +2 -0
  2. package/dist/get-bounding-box.js +146 -0
  3. package/dist/get-subpaths.js +4 -5
  4. package/dist/helpers/construct.d.ts +1 -2
  5. package/dist/helpers/construct.js +199 -123
  6. package/dist/helpers/iterate.d.ts +12 -0
  7. package/dist/helpers/iterate.js +53 -0
  8. package/dist/helpers/linear.d.ts +6 -1
  9. package/dist/helpers/linear.js +1 -1
  10. package/dist/helpers/remove-a-s-t-curves.d.ts +2 -0
  11. package/dist/helpers/remove-a-s-t-curves.js +260 -0
  12. package/dist/helpers/serialize.d.ts +2 -0
  13. package/dist/helpers/serialize.js +75 -0
  14. package/dist/helpers/types.d.ts +105 -1
  15. package/dist/helpers/unarc.d.ts +2 -0
  16. package/dist/helpers/unarc.js +254 -0
  17. package/dist/helpers/unshort.d.ts +2 -0
  18. package/dist/helpers/unshort.js +65 -0
  19. package/dist/index.d.ts +6 -1
  20. package/dist/index.js +11 -1
  21. package/dist/normalize-path.d.ts +2 -0
  22. package/dist/normalize-path.js +129 -275
  23. package/dist/parse-path.d.ts +2 -0
  24. package/dist/parse-path.js +259 -0
  25. package/dist/parse.d.ts +2 -0
  26. package/dist/parse.js +266 -0
  27. package/dist/reduce-instructions.d.ts +2 -0
  28. package/dist/reduce-instructions.js +10 -0
  29. package/dist/reset-path.d.ts +1 -0
  30. package/dist/reset-path.js +10 -0
  31. package/dist/serialize-instructions.d.ts +2 -0
  32. package/dist/serialize-instructions.js +72 -0
  33. package/dist/serialize.d.ts +2 -0
  34. package/dist/serialize.js +75 -0
  35. package/dist/simplify-instructions.d.ts +2 -0
  36. package/dist/simplify-instructions.js +10 -0
  37. package/dist/translate-path.js +42 -25
  38. package/dist/unarc.d.ts +2 -0
  39. package/dist/unarc.js +180 -0
  40. package/dist/unshort.d.ts +2 -0
  41. package/dist/unshort.js +118 -0
  42. package/package.json +2 -2
@@ -0,0 +1,2 @@
1
+ import type { Instruction } from './types';
2
+ export declare const unshort: (segments: Instruction[]) => Instruction[];
@@ -0,0 +1,65 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.unshort = void 0;
4
+ // Requires that the path is already normalized
5
+ const unshort = function (segments) {
6
+ let prevControlX = 0;
7
+ let prevControlY = 0;
8
+ let curControlX = 0;
9
+ let curControlY = 0;
10
+ const newSegments = segments.slice(0);
11
+ for (let i = 0; i < newSegments.length; i++) {
12
+ const s = newSegments[i];
13
+ // First command MUST be M|m, it's safe to skip.
14
+ // Protect from access to [-1] for sure.
15
+ if (!i) {
16
+ continue;
17
+ }
18
+ if (s.type === 'T') {
19
+ // quadratic curve
20
+ const prevSegment = newSegments[i - 1];
21
+ if (prevSegment.type === 'Q') {
22
+ prevControlX = prevSegment.cpx;
23
+ prevControlY = prevSegment.cpy;
24
+ }
25
+ else {
26
+ prevControlX = 0;
27
+ prevControlY = 0;
28
+ }
29
+ curControlX = -prevControlX;
30
+ curControlY = -prevControlY;
31
+ newSegments[i] = {
32
+ type: 'Q',
33
+ cpx: curControlX,
34
+ cpy: curControlY,
35
+ x: s.x,
36
+ y: s.y,
37
+ };
38
+ }
39
+ else if (s.type === 'S') {
40
+ // cubic curve
41
+ const prevSegment = newSegments[i - 1];
42
+ if (prevSegment.type === 'C') {
43
+ prevControlX = prevSegment.cp2x;
44
+ prevControlY = prevSegment.cp2y;
45
+ }
46
+ else {
47
+ prevControlX = 0;
48
+ prevControlY = 0;
49
+ }
50
+ curControlX = -prevControlX;
51
+ curControlY = -prevControlY;
52
+ newSegments[i] = {
53
+ type: 'C',
54
+ cp1x: curControlX,
55
+ cp1y: curControlY,
56
+ cp2x: s.cpx,
57
+ cp2y: s.cpy,
58
+ x: s.x,
59
+ y: s.y,
60
+ };
61
+ }
62
+ }
63
+ return newSegments;
64
+ };
65
+ exports.unshort = unshort;
package/dist/index.d.ts CHANGED
@@ -1,12 +1,17 @@
1
1
  export { evolvePath } from './evolve-path';
2
2
  export { extendViewBox } from './extend-viewbox';
3
+ export { getBoundingBox } from './get-bounding-box';
3
4
  export { getLength } from './get-length';
4
5
  export { getParts } from './get-parts';
5
6
  export { getPointAtLength } from './get-point-at-length';
6
7
  export { getSubpaths } from './get-subpaths';
7
8
  export { getTangentAtLength } from './get-tangent-at-length';
8
- export { Part } from './helpers/types';
9
+ export { AbsoluteInstruction, BoundingBox, Instruction, Part, ReducedInstruction, } from './helpers/types';
9
10
  export { interpolatePath } from './interpolate-path';
10
11
  export { normalizePath } from './normalize-path';
12
+ export { parsePath } from './parse-path';
13
+ export { reduceInstructions } from './reduce-instructions';
14
+ export { resetPath } from './reset-path';
11
15
  export { reversePath } from './reverse-path';
16
+ export { serializeInstructions } from './serialize-instructions';
12
17
  export { translatePath } from './translate-path';
package/dist/index.js CHANGED
@@ -1,10 +1,12 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.translatePath = exports.reversePath = exports.normalizePath = exports.interpolatePath = exports.getTangentAtLength = exports.getSubpaths = exports.getPointAtLength = exports.getParts = exports.getLength = exports.extendViewBox = exports.evolvePath = void 0;
3
+ exports.translatePath = exports.serializeInstructions = exports.reversePath = exports.resetPath = exports.reduceInstructions = exports.parsePath = exports.normalizePath = exports.interpolatePath = exports.getTangentAtLength = exports.getSubpaths = exports.getPointAtLength = exports.getParts = exports.getLength = exports.getBoundingBox = exports.extendViewBox = exports.evolvePath = void 0;
4
4
  var evolve_path_1 = require("./evolve-path");
5
5
  Object.defineProperty(exports, "evolvePath", { enumerable: true, get: function () { return evolve_path_1.evolvePath; } });
6
6
  var extend_viewbox_1 = require("./extend-viewbox");
7
7
  Object.defineProperty(exports, "extendViewBox", { enumerable: true, get: function () { return extend_viewbox_1.extendViewBox; } });
8
+ var get_bounding_box_1 = require("./get-bounding-box");
9
+ Object.defineProperty(exports, "getBoundingBox", { enumerable: true, get: function () { return get_bounding_box_1.getBoundingBox; } });
8
10
  var get_length_1 = require("./get-length");
9
11
  Object.defineProperty(exports, "getLength", { enumerable: true, get: function () { return get_length_1.getLength; } });
10
12
  var get_parts_1 = require("./get-parts");
@@ -19,7 +21,15 @@ var interpolate_path_1 = require("./interpolate-path");
19
21
  Object.defineProperty(exports, "interpolatePath", { enumerable: true, get: function () { return interpolate_path_1.interpolatePath; } });
20
22
  var normalize_path_1 = require("./normalize-path");
21
23
  Object.defineProperty(exports, "normalizePath", { enumerable: true, get: function () { return normalize_path_1.normalizePath; } });
24
+ var parse_path_1 = require("./parse-path");
25
+ Object.defineProperty(exports, "parsePath", { enumerable: true, get: function () { return parse_path_1.parsePath; } });
26
+ var reduce_instructions_1 = require("./reduce-instructions");
27
+ Object.defineProperty(exports, "reduceInstructions", { enumerable: true, get: function () { return reduce_instructions_1.reduceInstructions; } });
28
+ var reset_path_1 = require("./reset-path");
29
+ Object.defineProperty(exports, "resetPath", { enumerable: true, get: function () { return reset_path_1.resetPath; } });
22
30
  var reverse_path_1 = require("./reverse-path");
23
31
  Object.defineProperty(exports, "reversePath", { enumerable: true, get: function () { return reverse_path_1.reversePath; } });
32
+ var serialize_instructions_1 = require("./serialize-instructions");
33
+ Object.defineProperty(exports, "serializeInstructions", { enumerable: true, get: function () { return serialize_instructions_1.serializeInstructions; } });
24
34
  var translate_path_1 = require("./translate-path");
25
35
  Object.defineProperty(exports, "translatePath", { enumerable: true, get: function () { return translate_path_1.translatePath; } });
@@ -1,6 +1,8 @@
1
+ import type { AbsoluteInstruction, Instruction } from './helpers/types';
1
2
  /**
2
3
  * Removes all relative coordinates from an SVG path and converts them into absolute coordinates.
3
4
  * @param {string} path A valid SVG path
4
5
  * @link https://remotion.dev/docs/paths/normalize-path
5
6
  */
6
7
  export declare const normalizePath: (path: string) => string;
8
+ export declare const normalizeInstructions: (instructions: Instruction[]) => AbsoluteInstruction[];
@@ -1,300 +1,154 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.normalizePath = void 0;
3
+ exports.normalizeInstructions = exports.normalizePath = void 0;
4
+ const parse_path_1 = require("./parse-path");
5
+ const serialize_instructions_1 = require("./serialize-instructions");
4
6
  /**
5
7
  * Removes all relative coordinates from an SVG path and converts them into absolute coordinates.
6
8
  * @param {string} path A valid SVG path
7
9
  * @link https://remotion.dev/docs/paths/normalize-path
8
10
  */
9
11
  const normalizePath = (path) => {
10
- // preprocess "d" so that we have spaces between values
11
- path = path
12
- .replace(/,/g, ' ')
13
- .replace(/([^eE])-/g, '$1 -')
14
- .replace(/\s*([achlmqstvzACHLMQSTVZ])\s*/g, ' $1 ')
15
- .replace(/\s+/g, ' ');
16
- // set up the variables used in this function
17
- const instructions = path
18
- .replace(/([achlmqstvzACHLMQSTVZ])\s?/g, '|$1')
19
- .split('|');
20
- const instructionLength = instructions.length;
21
- let i;
22
- let instruction;
23
- let op;
24
- let lop;
25
- let alen;
26
- let a;
27
- let sx = 0;
28
- let sy = 0;
12
+ const instructions = (0, parse_path_1.parsePath)(path);
13
+ const normalized = (0, exports.normalizeInstructions)(instructions);
14
+ return (0, serialize_instructions_1.serializeInstructions)(normalized);
15
+ };
16
+ exports.normalizePath = normalizePath;
17
+ const normalizeInstructions = (instructions) => {
18
+ // Extended properties must already be normalized
19
+ const normalized = [];
29
20
  let x = 0;
30
21
  let y = 0;
31
- let cx = 0;
32
- let cy = 0;
33
- let cx2 = 0;
34
- let cy2 = 0;
35
- let rx = 0;
36
- let ry = 0;
37
- let xrot = 0;
38
- let lflag = 0;
39
- let sweep = 0;
40
- let normalized = '';
41
- // we run through the instruction list starting at 1, not 0,
42
- // because we split up "|M x y ...." so the first element will
43
- // always be an empty string. By design.
44
- for (i = 1; i < instructionLength; i++) {
45
- // which instruction is this?
46
- instruction = instructions[i];
47
- op = instruction.substring(0, 1);
48
- lop = op.toLowerCase();
49
- // what are the arguments? note that we need to convert
50
- // all strings into numbers, or + will do silly things.
51
- const oargs = instruction
52
- .replace(op, '')
53
- .trim()
54
- .split(' ')
55
- .filter((v) => {
56
- return v !== '';
57
- });
58
- const args = oargs.map((_a) => parseFloat(String(_a)));
59
- alen = args.length;
60
- // we could use a switch, but elaborate code in a "case" with
61
- // fallthrough is just horrid to read. So let's use ifthen
62
- // statements instead.
63
- // moveto command (plus possible lineto)
64
- if (lop === 'm') {
65
- normalized += 'M ';
66
- if (op === 'm') {
67
- x += args[0];
68
- y += args[1];
22
+ const initialX = 0;
23
+ const initialY = 0;
24
+ for (let i = 0; i < instructions.length; i++) {
25
+ const instruction = instructions[i];
26
+ if (instruction.type === 'A' ||
27
+ instruction.type === 'C' ||
28
+ instruction.type === 'L' ||
29
+ instruction.type === 'M' ||
30
+ instruction.type === 'Q' ||
31
+ instruction.type === 'S' ||
32
+ instruction.type === 'T') {
33
+ normalized.push(instruction);
34
+ x = instruction.x;
35
+ y = instruction.y;
36
+ continue;
37
+ }
38
+ if (instruction.type === 'a' ||
39
+ instruction.type === 'c' ||
40
+ instruction.type === 'l' ||
41
+ instruction.type === 'm' ||
42
+ instruction.type === 'q' ||
43
+ instruction.type === 's' ||
44
+ instruction.type === 't') {
45
+ x += instruction.dx;
46
+ y += instruction.dy;
47
+ if (instruction.type === 'a') {
48
+ normalized.push({
49
+ type: 'A',
50
+ largeArcFlag: instruction.largeArcFlag,
51
+ rx: instruction.rx,
52
+ ry: instruction.ry,
53
+ sweepFlag: instruction.sweepFlag,
54
+ xAxisRotation: instruction.xAxisRotation,
55
+ x,
56
+ y,
57
+ });
58
+ continue;
69
59
  }
70
- else {
71
- x = args[0];
72
- y = args[1];
60
+ if (instruction.type === 'c') {
61
+ normalized.push({
62
+ type: 'C',
63
+ cp1x: instruction.cp1dx + x,
64
+ cp1y: instruction.cp1dy + y,
65
+ cp2x: instruction.cp2dx + x,
66
+ cp2y: instruction.cp2dy + y,
67
+ x,
68
+ y,
69
+ });
70
+ continue;
73
71
  }
74
- // records start position, for dealing
75
- // with the shape close operator ('Z')
76
- sx = x;
77
- sy = y;
78
- normalized += x + ' ' + y + ' ';
79
- if (alen > 2) {
80
- for (a = 0; a < alen; a += 2) {
81
- // eslint-disable-next-line max-depth
82
- if (op === 'm') {
83
- x += args[a];
84
- y += args[a + 1];
85
- }
86
- else {
87
- x = args[a];
88
- y = args[a + 1];
89
- }
90
- normalized += 'L ' + x + ' ' + y + ' ';
91
- }
72
+ if (instruction.type === 'l') {
73
+ normalized.push({
74
+ type: 'L',
75
+ x,
76
+ y,
77
+ });
78
+ continue;
92
79
  }
93
- }
94
- // lineto commands
95
- else if (lop === 'l') {
96
- for (a = 0; a < alen; a += 2) {
97
- if (op === 'l') {
98
- x += args[a];
99
- y += args[a + 1];
100
- }
101
- else {
102
- x = args[a];
103
- y = args[a + 1];
104
- }
105
- normalized += 'L ' + x + ' ' + y + ' ';
80
+ if (instruction.type === 'm') {
81
+ normalized.push({
82
+ type: 'M',
83
+ x,
84
+ y,
85
+ });
86
+ continue;
106
87
  }
107
- }
108
- else if (lop === 'h') {
109
- for (a = 0; a < alen; a++) {
110
- if (op === 'h') {
111
- x += args[a];
112
- }
113
- else {
114
- x = args[a];
115
- }
116
- normalized += 'L ' + x + ' ' + y + ' ';
88
+ if (instruction.type === 'q') {
89
+ normalized.push({
90
+ type: 'Q',
91
+ cpx: instruction.cpdx + x,
92
+ cpy: instruction.cpdy + y,
93
+ x,
94
+ y,
95
+ });
96
+ continue;
117
97
  }
118
- }
119
- else if (lop === 'v') {
120
- for (a = 0; a < alen; a++) {
121
- if (op === 'v') {
122
- y += args[a];
123
- }
124
- else {
125
- y = args[a];
126
- }
127
- normalized += 'L ' + x + ' ' + y + ' ';
98
+ if (instruction.type === 's') {
99
+ normalized.push({
100
+ type: 'S',
101
+ cpx: instruction.cpdx + x,
102
+ cpy: instruction.cpdy + y,
103
+ x,
104
+ y,
105
+ });
106
+ continue;
128
107
  }
129
- }
130
- // quadratic curveto commands
131
- else if (lop === 'q') {
132
- for (a = 0; a < alen; a += 4) {
133
- if (op === 'q') {
134
- cx = x + args[a];
135
- cy = y + args[a + 1];
136
- x += args[a + 2];
137
- y += args[a + 3];
138
- }
139
- else {
140
- cx = args[a];
141
- cy = args[a + 1];
142
- x = args[a + 2];
143
- y = args[a + 3];
144
- }
145
- normalized += 'Q ' + cx + ' ' + cy + ' ' + x + ' ' + y + ' ';
108
+ if (instruction.type === 't') {
109
+ normalized.push({
110
+ type: 'T',
111
+ x,
112
+ y,
113
+ });
114
+ continue;
146
115
  }
147
116
  }
148
- else if (lop === 't') {
149
- for (a = 0; a < alen; a += 2) {
150
- // reflect previous cx/cy over x/y
151
- cx = x + (x - cx);
152
- cy = y + (y - cy);
153
- // then get real end point
154
- if (op === 't') {
155
- x += args[a];
156
- y += args[a + 1];
157
- }
158
- else {
159
- x = args[a];
160
- y = args[a + 1];
161
- }
162
- normalized += 'Q ' + cx + ' ' + cy + ' ' + x + ' ' + y + ' ';
163
- }
117
+ if (instruction.type === 'H') {
118
+ normalized.push(instruction);
119
+ x = instruction.x;
120
+ continue;
164
121
  }
165
- // cubic curveto commands
166
- else if (lop === 'c') {
167
- for (a = 0; a < alen; a += 6) {
168
- if (op === 'c') {
169
- cx = x + args[a];
170
- cy = y + args[a + 1];
171
- cx2 = x + args[a + 2];
172
- cy2 = y + args[a + 3];
173
- x += args[a + 4];
174
- y += args[a + 5];
175
- }
176
- else {
177
- cx = args[a];
178
- cy = args[a + 1];
179
- cx2 = args[a + 2];
180
- cy2 = args[a + 3];
181
- x = args[a + 4];
182
- y = args[a + 5];
183
- }
184
- normalized +=
185
- 'C ' +
186
- cx +
187
- ' ' +
188
- cy +
189
- ' ' +
190
- cx2 +
191
- ' ' +
192
- cy2 +
193
- ' ' +
194
- x +
195
- ' ' +
196
- y +
197
- ' ';
198
- }
122
+ if (instruction.type === 'V') {
123
+ normalized.push(instruction);
124
+ y = instruction.y;
125
+ continue;
199
126
  }
200
- else if (lop === 's') {
201
- for (a = 0; a < alen; a += 4) {
202
- // reflect previous cx2/cy2 over x/y
203
- cx = x + (x - cx2);
204
- cy = y + (y - cy2);
205
- // then get real control and end point
206
- if (op === 's') {
207
- cx2 = x + args[a];
208
- cy2 = y + args[a + 1];
209
- x += args[a + 2];
210
- y += args[a + 3];
211
- }
212
- else {
213
- cx2 = args[a];
214
- cy2 = args[a + 1];
215
- x = args[a + 2];
216
- y = args[a + 3];
217
- }
218
- normalized +=
219
- 'C ' +
220
- cx +
221
- ' ' +
222
- cy +
223
- ' ' +
224
- cx2 +
225
- ' ' +
226
- cy2 +
227
- ' ' +
228
- x +
229
- ' ' +
230
- y +
231
- ' ';
232
- }
127
+ if (instruction.type === 'Z') {
128
+ normalized.push(instruction);
129
+ x = initialX;
130
+ y = initialY;
131
+ continue;
233
132
  }
234
- // rx ry x-axis-rotation large-arc-flag sweep-flag x y
235
- // a 25,25 -30 0, 1 50,-25
236
- // arc command
237
- else if (lop === 'a') {
238
- for (a = 0; a < alen; a += 7) {
239
- rx = args[a];
240
- ry = args[a + 1];
241
- xrot = args[a + 2];
242
- lflag = oargs[a + 3]; // we need the original string to deal with leading zeroes
243
- let fixed = false;
244
- if (lflag.length > 1) {
245
- const b1 = parseInt(lflag[0], 10);
246
- const b2 = parseInt(lflag[1], 10);
247
- let rest;
248
- // eslint-disable-next-line max-depth
249
- if (lflag.length > 2)
250
- rest = parseFloat(lflag.substring(2));
251
- args[a + 3] = b1;
252
- args.splice(a + 4, 0, b2);
253
- // eslint-disable-next-line max-depth
254
- if (rest !== undefined)
255
- args.splice(a + 5, 0, rest);
256
- fixed = true;
257
- }
258
- lflag = args[a + 3];
259
- sweep = fixed ? args[a + 4] : oargs[a + 4]; // we need the original string to deal with leading zeroes
260
- if (!fixed && sweep.length > 1) {
261
- args[a + 4] = parseInt(sweep[0], 10);
262
- args.splice(a + 5, 0, parseFloat(sweep.substring(1)));
263
- }
264
- sweep = args[a + 4];
265
- if (op === 'a') {
266
- x += args[a + 5];
267
- y += args[a + 6];
268
- }
269
- else {
270
- x = args[a + 5];
271
- y = args[a + 6];
272
- }
273
- normalized +=
274
- 'A ' +
275
- rx +
276
- ' ' +
277
- ry +
278
- ' ' +
279
- xrot +
280
- ' ' +
281
- lflag +
282
- ' ' +
283
- sweep +
284
- ' ' +
285
- x +
286
- ' ' +
287
- y +
288
- ' ';
289
- }
133
+ if (instruction.type === 'h') {
134
+ x += instruction.dx;
135
+ normalized.push({
136
+ type: 'H',
137
+ x,
138
+ });
139
+ continue;
290
140
  }
291
- else if (lop === 'z') {
292
- normalized += 'Z ';
293
- // not unimportant: path closing changes the current x/y coordinate
294
- x = sx;
295
- y = sy;
141
+ if (instruction.type === 'v') {
142
+ y += instruction.dy;
143
+ normalized.push({
144
+ type: 'V',
145
+ y,
146
+ });
147
+ continue;
296
148
  }
149
+ // @ts-expect-error
150
+ throw new Error('Unknown instruction type: ' + instruction.type);
297
151
  }
298
- return normalized.trim();
152
+ return normalized;
299
153
  };
300
- exports.normalizePath = normalizePath;
154
+ exports.normalizeInstructions = normalizeInstructions;
@@ -0,0 +1,2 @@
1
+ import type { Instruction } from './helpers/types';
2
+ export declare const parsePath: (path: string) => Instruction[];