@remotion/paths 4.0.0-alpha8 → 4.0.0-alpha9

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.
@@ -85,9 +85,29 @@ const getBoundingBoxFromInstructions = (instructions) => {
85
85
  let maxY = -Infinity;
86
86
  let x = 0;
87
87
  let y = 0;
88
+ let lastMoveX = 0;
89
+ let lastMoveY = 0;
88
90
  for (const seg of instructions) {
89
91
  switch (seg.type) {
90
- case 'M':
92
+ case 'M': {
93
+ lastMoveX = seg.x;
94
+ lastMoveY = seg.y;
95
+ if (minX > seg.x) {
96
+ minX = seg.x;
97
+ }
98
+ if (minY > seg.y) {
99
+ minY = seg.y;
100
+ }
101
+ if (maxX < seg.x) {
102
+ maxX = seg.x;
103
+ }
104
+ if (maxY < seg.y) {
105
+ maxY = seg.y;
106
+ }
107
+ x = seg.x;
108
+ y = seg.y;
109
+ break;
110
+ }
91
111
  case 'L': {
92
112
  if (minX > seg.x) {
93
113
  minX = seg.x;
@@ -144,6 +164,8 @@ const getBoundingBoxFromInstructions = (instructions) => {
144
164
  break;
145
165
  }
146
166
  case 'Z':
167
+ x = lastMoveX;
168
+ y = lastMoveY;
147
169
  break;
148
170
  default:
149
171
  // @ts-expect-error
@@ -3,5 +3,5 @@
3
3
  * @param {string} path A valid SVG path
4
4
  * @param {number} length The length at which the point should be sampled
5
5
  * @see [Documentation](https://remotion.dev/docs/paths/get-point-at-length)
6
- */
6
+ */
7
7
  export declare const getPointAtLength: (path: string, length: number) => import("./helpers/types").Point;
@@ -8,7 +8,7 @@ const get_part_at_length_1 = require("./helpers/get-part-at-length");
8
8
  * @param {string} path A valid SVG path
9
9
  * @param {number} length The length at which the point should be sampled
10
10
  * @see [Documentation](https://remotion.dev/docs/paths/get-point-at-length)
11
- */
11
+ */
12
12
  const getPointAtLength = (path, length) => {
13
13
  const constructed = (0, construct_1.construct)(path);
14
14
  const fractionPart = (0, get_part_at_length_1.getPartAtLength)(path, length);
@@ -8,5 +8,7 @@ export declare const iterateOverSegments: <T extends ReducedInstruction>({ segme
8
8
  y: number;
9
9
  initialX: number;
10
10
  initialY: number;
11
+ cpX: number | null;
12
+ cpY: number | null;
11
13
  }) => T[];
12
14
  }) => T[];
@@ -6,6 +6,8 @@ const iterateOverSegments = ({ segments, iterate, }) => {
6
6
  let y = 0;
7
7
  let initialX = 0;
8
8
  let initialY = 0;
9
+ let cpX = null;
10
+ let cpY = null;
9
11
  const newSegments = segments.map((s, i) => {
10
12
  var _a;
11
13
  const newSeg = iterate({
@@ -15,33 +17,73 @@ const iterateOverSegments = ({ segments, iterate, }) => {
15
17
  prevSegment: (_a = segments[i - 1]) !== null && _a !== void 0 ? _a : null,
16
18
  initialX,
17
19
  initialY,
20
+ cpX,
21
+ cpY,
18
22
  });
19
23
  switch (s.type) {
20
24
  case 'M':
21
25
  initialX = s.x;
22
26
  initialY = s.y;
23
- // fallthrough
27
+ x = s.x;
28
+ y = s.y;
29
+ cpX = null;
30
+ cpY = null;
31
+ break;
32
+ case 'Q':
33
+ x = s.x;
34
+ y = s.y;
35
+ cpX = s.cpx;
36
+ cpY = s.cpy;
37
+ break;
24
38
  case 'A':
39
+ x = s.x;
40
+ y = s.y;
41
+ cpX = null;
42
+ cpY = null;
43
+ break;
25
44
  case 'C':
26
- case 'Q':
45
+ x = s.x;
46
+ y = s.y;
47
+ cpX = s.cp2x;
48
+ cpY = s.cp2y;
49
+ break;
27
50
  case 'S':
51
+ x = s.x;
52
+ y = s.y;
53
+ cpX = s.cpx;
54
+ cpY = s.cpy;
55
+ break;
28
56
  case 'T':
29
- case 'L': {
57
+ // Order of if statement is important here
58
+ if (cpX !== null && cpY !== null) {
59
+ cpX = x - (cpX - x);
60
+ cpY = y - (cpY - y);
61
+ }
62
+ x = s.x;
63
+ y = s.y;
64
+ break;
65
+ case 'L':
30
66
  x = s.x;
31
67
  y = s.y;
68
+ cpX = null;
69
+ cpY = null;
32
70
  break;
33
- }
34
- case 'V': {
71
+ case 'V':
35
72
  y = s.y;
73
+ cpX = null;
74
+ cpY = null;
36
75
  break;
37
- }
38
- case 'H': {
76
+ case 'H':
39
77
  x = s.x;
78
+ cpX = null;
79
+ cpY = null;
40
80
  break;
41
- }
42
- case 'Z': {
81
+ case 'Z':
82
+ x = initialX;
83
+ y = initialY;
84
+ cpX = null;
85
+ cpY = null;
43
86
  break;
44
- }
45
87
  default:
46
88
  // @ts-expect-error
47
89
  throw new Error(`Unexpected instruction ${s.type}`);
@@ -92,13 +92,9 @@ function arcToCircle({ x1, y1, x2, y2, largeArcFlag, sweepFlag, rx, ry, phi, })
92
92
  }
93
93
  // Requires path to be normalized
94
94
  const removeATSHVInstructions = (segments) => {
95
- let prevControlX = 0;
96
- let prevControlY = 0;
97
- let curControlX = 0;
98
- let curControlY = 0;
99
95
  return (0, iterate_1.iterateOverSegments)({
100
96
  segments,
101
- iterate: ({ segment, prevSegment, x, y }) => {
97
+ iterate: ({ segment, prevSegment, x, y, cpX, cpY }) => {
102
98
  if (segment.type === 'H') {
103
99
  return [{ type: 'L', x: segment.x, y }];
104
100
  }
@@ -144,42 +140,57 @@ const removeATSHVInstructions = (segments) => {
144
140
  return result;
145
141
  }
146
142
  if (segment.type === 'T') {
147
- if (prevSegment && prevSegment.type === 'Q') {
148
- prevControlX = prevSegment.cpx;
149
- prevControlY = prevSegment.cpy;
143
+ let prevControlX = 0;
144
+ let prevControlY = 0;
145
+ if (prevSegment &&
146
+ (prevSegment.type === 'Q' || prevSegment.type === 'T')) {
147
+ prevControlX = cpX;
148
+ prevControlY = cpY;
150
149
  }
151
150
  else {
152
- prevControlX = 0;
153
- prevControlY = 0;
151
+ prevControlX = x;
152
+ prevControlY = y;
154
153
  }
155
- curControlX = -prevControlX;
156
- curControlY = -prevControlY;
154
+ // New first control point is reflection of previous second control point
155
+ const vectorX = prevControlX - x;
156
+ const vectorY = prevControlY - y;
157
+ const newControlX = x - vectorX;
158
+ const newControlY = y - vectorY;
157
159
  return [
158
160
  {
159
161
  type: 'Q',
160
- cpx: curControlX,
161
- cpy: curControlY,
162
+ cpx: newControlX,
163
+ cpy: newControlY,
162
164
  x: segment.x,
163
165
  y: segment.y,
164
166
  },
165
167
  ];
166
168
  }
167
169
  if (segment.type === 'S') {
170
+ let prevControlX = 0;
171
+ let prevControlY = 0;
168
172
  if (prevSegment && prevSegment.type === 'C') {
169
173
  prevControlX = prevSegment.cp2x;
170
174
  prevControlY = prevSegment.cp2y;
171
175
  }
176
+ else if (prevSegment && prevSegment.type === 'S') {
177
+ prevControlX = prevSegment.cpx;
178
+ prevControlY = prevSegment.cpy;
179
+ }
172
180
  else {
173
- prevControlX = 0;
174
- prevControlY = 0;
181
+ prevControlX = x;
182
+ prevControlY = y;
175
183
  }
176
- curControlX = -prevControlX;
177
- curControlY = -prevControlY;
184
+ // New first control point is reflection of previous second control point
185
+ const vectorX = prevControlX - x;
186
+ const vectorY = prevControlY - y;
187
+ const newControlX = x - vectorX;
188
+ const newControlY = y - vectorY;
178
189
  return [
179
190
  {
180
191
  type: 'C',
181
- cp1x: curControlX,
182
- cp1y: curControlY,
192
+ cp1x: newControlX,
193
+ cp1y: newControlY,
183
194
  cp2x: segment.cpx,
184
195
  cp2y: segment.cpy,
185
196
  x: segment.x,
@@ -19,10 +19,18 @@ const normalizeInstructions = (instructions) => {
19
19
  const normalized = [];
20
20
  let x = 0;
21
21
  let y = 0;
22
- const initialX = 0;
23
- const initialY = 0;
22
+ let moveX = 0;
23
+ let moveY = 0;
24
24
  for (let i = 0; i < instructions.length; i++) {
25
25
  const instruction = instructions[i];
26
+ if (instruction.type === 'M') {
27
+ moveX = instruction.x;
28
+ moveY = instruction.y;
29
+ }
30
+ else if (instruction.type === 'm') {
31
+ moveX += instruction.dx;
32
+ moveY += instruction.dy;
33
+ }
26
34
  if (instruction.type === 'A' ||
27
35
  instruction.type === 'C' ||
28
36
  instruction.type === 'L' ||
@@ -42,6 +50,8 @@ const normalizeInstructions = (instructions) => {
42
50
  instruction.type === 'q' ||
43
51
  instruction.type === 's' ||
44
52
  instruction.type === 't') {
53
+ const currentX = x;
54
+ const currentY = y;
45
55
  x += instruction.dx;
46
56
  y += instruction.dy;
47
57
  if (instruction.type === 'a') {
@@ -60,10 +70,10 @@ const normalizeInstructions = (instructions) => {
60
70
  if (instruction.type === 'c') {
61
71
  normalized.push({
62
72
  type: 'C',
63
- cp1x: instruction.cp1dx + x,
64
- cp1y: instruction.cp1dy + y,
65
- cp2x: instruction.cp2dx + x,
66
- cp2y: instruction.cp2dy + y,
73
+ cp1x: instruction.cp1dx + currentX,
74
+ cp1y: instruction.cp1dy + currentY,
75
+ cp2x: instruction.cp2dx + currentX,
76
+ cp2y: instruction.cp2dy + currentY,
67
77
  x,
68
78
  y,
69
79
  });
@@ -88,8 +98,8 @@ const normalizeInstructions = (instructions) => {
88
98
  if (instruction.type === 'q') {
89
99
  normalized.push({
90
100
  type: 'Q',
91
- cpx: instruction.cpdx + x,
92
- cpy: instruction.cpdy + y,
101
+ cpx: instruction.cpdx + currentX,
102
+ cpy: instruction.cpdy + currentY,
93
103
  x,
94
104
  y,
95
105
  });
@@ -98,8 +108,8 @@ const normalizeInstructions = (instructions) => {
98
108
  if (instruction.type === 's') {
99
109
  normalized.push({
100
110
  type: 'S',
101
- cpx: instruction.cpdx + x,
102
- cpy: instruction.cpdy + y,
111
+ cpx: instruction.cpdx + currentX,
112
+ cpy: instruction.cpdy + currentY,
103
113
  x,
104
114
  y,
105
115
  });
@@ -126,8 +136,8 @@ const normalizeInstructions = (instructions) => {
126
136
  }
127
137
  if (instruction.type === 'Z') {
128
138
  normalized.push(instruction);
129
- x = initialX;
130
- y = initialY;
139
+ x = moveX;
140
+ y = moveY;
131
141
  continue;
132
142
  }
133
143
  if (instruction.type === 'h') {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@remotion/paths",
3
- "version": "4.0.0-alpha8",
3
+ "version": "4.0.0-alpha9",
4
4
  "description": "Utility functions for SVG paths",
5
5
  "main": "dist/index.js",
6
6
  "sideEffects": false,
@@ -14,12 +14,12 @@
14
14
  },
15
15
  "devDependencies": {
16
16
  "@jonny/eslint-config": "3.0.266",
17
- "@types/node": "^16.7.5",
17
+ "@types/node": "18.14.6",
18
18
  "eslint": "8.25.0",
19
19
  "prettier": "^2.7.1",
20
20
  "prettier-plugin-organize-imports": "^2.3.4",
21
21
  "typescript": "^4.7.0",
22
- "vitest": "0.24.3"
22
+ "vitest": "0.31.1"
23
23
  },
24
24
  "keywords": [
25
25
  "svg",
@@ -30,6 +30,7 @@
30
30
  "access": "public"
31
31
  },
32
32
  "scripts": {
33
+ "formatting": "prettier src --check",
33
34
  "lint": "eslint src --ext ts,tsx",
34
35
  "watch": "tsc -w",
35
36
  "build": "tsc -d",