@canvas-commons/2d 0.2.0
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/LICENSE +22 -0
- package/editor/index.css +40 -0
- package/editor/index.js +525 -0
- package/editor/index.js.map +1 -0
- package/lib/index-OvpZ-GsA.d.ts +5673 -0
- package/lib/index-OvpZ-GsA.d.ts.map +1 -0
- package/lib/index.d.ts +2 -0
- package/lib/index.js +10326 -0
- package/lib/index.js.map +1 -0
- package/lib/jsx-dev-runtime.d.ts +2 -0
- package/lib/jsx-dev-runtime.js +2 -0
- package/lib/jsx-runtime.d.ts +2 -0
- package/lib/jsx-runtime.js +28 -0
- package/lib/jsx-runtime.js.map +1 -0
- package/package.json +79 -0
- package/src/editor/NodeInspectorConfig.tsx +76 -0
- package/src/editor/PreviewOverlayConfig.tsx +65 -0
- package/src/editor/Provider.tsx +109 -0
- package/src/editor/SceneGraphTabConfig.tsx +87 -0
- package/src/editor/icons/CircleIcon.tsx +7 -0
- package/src/editor/icons/CodeIcon.tsx +8 -0
- package/src/editor/icons/CurveIcon.tsx +7 -0
- package/src/editor/icons/GridIcon.tsx +7 -0
- package/src/editor/icons/IconMap.ts +35 -0
- package/src/editor/icons/ImgIcon.tsx +8 -0
- package/src/editor/icons/LayoutIcon.tsx +9 -0
- package/src/editor/icons/LineIcon.tsx +7 -0
- package/src/editor/icons/NodeIcon.tsx +7 -0
- package/src/editor/icons/RayIcon.tsx +7 -0
- package/src/editor/icons/RectIcon.tsx +7 -0
- package/src/editor/icons/ShapeIcon.tsx +7 -0
- package/src/editor/icons/TxtIcon.tsx +8 -0
- package/src/editor/icons/VideoIcon.tsx +7 -0
- package/src/editor/icons/View2DIcon.tsx +10 -0
- package/src/editor/index.css +0 -0
- package/src/editor/index.ts +19 -0
- package/src/editor/shortcuts.ts +27 -0
- package/src/editor/tree/DetachedRoot.tsx +27 -0
- package/src/editor/tree/NodeElement.tsx +72 -0
- package/src/editor/tree/TreeElement.tsx +70 -0
- package/src/editor/tree/TreeRoot.tsx +10 -0
- package/src/editor/tree/ViewRoot.tsx +20 -0
- package/src/editor/tree/index.module.scss +45 -0
- package/src/editor/tree/index.ts +4 -0
- package/src/editor/tree/navigation.ts +145 -0
- package/src/editor/tsconfig.build.json +5 -0
- package/src/editor/tsconfig.json +12 -0
- package/src/editor/tsdoc.json +4 -0
- package/src/editor/utils/SignalSet.ts +37 -0
- package/src/editor/utils/index.ts +1 -0
- package/src/editor/vite-env.d.ts +1 -0
- package/src/lib/code/CodeCursor.ts +468 -0
- package/src/lib/code/CodeDiffer.ts +77 -0
- package/src/lib/code/CodeFragment.ts +96 -0
- package/src/lib/code/CodeHighlighter.ts +73 -0
- package/src/lib/code/CodeMetrics.ts +47 -0
- package/src/lib/code/CodeRange.test.ts +113 -0
- package/src/lib/code/CodeRange.ts +222 -0
- package/src/lib/code/CodeScope.ts +100 -0
- package/src/lib/code/CodeSelection.ts +28 -0
- package/src/lib/code/CodeSignal.ts +348 -0
- package/src/lib/code/CodeTokenizer.ts +54 -0
- package/src/lib/code/DefaultHighlightStyle.ts +98 -0
- package/src/lib/code/LezerHighlighter.ts +113 -0
- package/src/lib/code/diff.test.ts +311 -0
- package/src/lib/code/diff.ts +319 -0
- package/src/lib/code/extractRange.ts +125 -0
- package/src/lib/code/index.ts +13 -0
- package/src/lib/components/Bezier.ts +103 -0
- package/src/lib/components/Camera.ts +401 -0
- package/src/lib/components/Circle.ts +310 -0
- package/src/lib/components/Code.ts +532 -0
- package/src/lib/components/CubicBezier.ts +115 -0
- package/src/lib/components/Curve.ts +460 -0
- package/src/lib/components/Grid.ts +134 -0
- package/src/lib/components/Icon.ts +153 -0
- package/src/lib/components/Img.ts +328 -0
- package/src/lib/components/Knot.ts +156 -0
- package/src/lib/components/Latex.ts +537 -0
- package/src/lib/components/Layout.ts +1101 -0
- package/src/lib/components/Line.ts +394 -0
- package/src/lib/components/Node.ts +1941 -0
- package/src/lib/components/Path.ts +132 -0
- package/src/lib/components/Polygon.ts +266 -0
- package/src/lib/components/QuadBezier.ts +103 -0
- package/src/lib/components/Ray.ts +126 -0
- package/src/lib/components/Rect.ts +219 -0
- package/src/lib/components/SVG.ts +853 -0
- package/src/lib/components/Shape.ts +322 -0
- package/src/lib/components/Spline.ts +318 -0
- package/src/lib/components/Txt.test.tsx +81 -0
- package/src/lib/components/Txt.ts +204 -0
- package/src/lib/components/TxtLeaf.ts +210 -0
- package/src/lib/components/Video.ts +368 -0
- package/src/lib/components/View2D.ts +85 -0
- package/src/lib/components/__logs__/image-without-source.ts +18 -0
- package/src/lib/components/__logs__/line-without-points.ts +31 -0
- package/src/lib/components/__logs__/reactive-playback-rate.ts +22 -0
- package/src/lib/components/__logs__/spline-with-insufficient-knots.ts +25 -0
- package/src/lib/components/__tests__/Camera.test.tsx +73 -0
- package/src/lib/components/__tests__/children.test.tsx +142 -0
- package/src/lib/components/__tests__/clone.test.tsx +126 -0
- package/src/lib/components/__tests__/fontInheritance.test.tsx +102 -0
- package/src/lib/components/__tests__/generatorTest.ts +27 -0
- package/src/lib/components/__tests__/mockScene2D.ts +50 -0
- package/src/lib/components/__tests__/query.test.tsx +122 -0
- package/src/lib/components/__tests__/state.test.tsx +60 -0
- package/src/lib/components/index.ts +26 -0
- package/src/lib/components/types.ts +35 -0
- package/src/lib/curves/ArcSegment.ts +169 -0
- package/src/lib/curves/CircleSegment.ts +99 -0
- package/src/lib/curves/CubicBezierSegment.ts +80 -0
- package/src/lib/curves/CurveDrawingInfo.ts +11 -0
- package/src/lib/curves/CurvePoint.ts +15 -0
- package/src/lib/curves/CurveProfile.ts +28 -0
- package/src/lib/curves/KnotInfo.ts +10 -0
- package/src/lib/curves/LineSegment.ts +75 -0
- package/src/lib/curves/Polynomial.ts +355 -0
- package/src/lib/curves/Polynomial2D.ts +62 -0
- package/src/lib/curves/PolynomialSegment.ts +151 -0
- package/src/lib/curves/QuadBezierSegment.ts +66 -0
- package/src/lib/curves/Segment.ts +31 -0
- package/src/lib/curves/UniformPolynomialCurveSampler.ts +93 -0
- package/src/lib/curves/createCurveProfileLerp.ts +471 -0
- package/src/lib/curves/getBezierSplineProfile.ts +227 -0
- package/src/lib/curves/getCircleProfile.ts +86 -0
- package/src/lib/curves/getPathProfile.ts +177 -0
- package/src/lib/curves/getPointAtDistance.ts +21 -0
- package/src/lib/curves/getPolylineProfile.test.ts +21 -0
- package/src/lib/curves/getPolylineProfile.ts +88 -0
- package/src/lib/curves/getRectProfile.ts +138 -0
- package/src/lib/curves/index.ts +16 -0
- package/src/lib/decorators/canvasStyleSignal.ts +15 -0
- package/src/lib/decorators/colorSignal.ts +9 -0
- package/src/lib/decorators/compound.ts +85 -0
- package/src/lib/decorators/computed.ts +18 -0
- package/src/lib/decorators/defaultStyle.ts +15 -0
- package/src/lib/decorators/filtersSignal.ts +133 -0
- package/src/lib/decorators/index.ts +10 -0
- package/src/lib/decorators/initializers.ts +32 -0
- package/src/lib/decorators/nodeName.ts +13 -0
- package/src/lib/decorators/signal.test.ts +89 -0
- package/src/lib/decorators/signal.ts +348 -0
- package/src/lib/decorators/spacingSignal.ts +15 -0
- package/src/lib/decorators/transformSignals.test.ts +858 -0
- package/src/lib/decorators/transformSignals.ts +1633 -0
- package/src/lib/decorators/vector2Signal.ts +35 -0
- package/src/lib/globals.d.ts +2 -0
- package/src/lib/index.ts +9 -0
- package/src/lib/jsx-dev-runtime.ts +2 -0
- package/src/lib/jsx-runtime.ts +45 -0
- package/src/lib/morphers/PathMorpher.ts +8 -0
- package/src/lib/morphers/defaultMorpher.ts +43 -0
- package/src/lib/morphers/index.ts +4 -0
- package/src/lib/morphers/manimMorpher.ts +658 -0
- package/src/lib/parse-svg-path.d.ts +14 -0
- package/src/lib/partials/Filter.ts +185 -0
- package/src/lib/partials/Gradient.ts +103 -0
- package/src/lib/partials/Pattern.ts +35 -0
- package/src/lib/partials/RoughConfig.ts +180 -0
- package/src/lib/partials/ShaderConfig.ts +122 -0
- package/src/lib/partials/index.ts +5 -0
- package/src/lib/partials/types.ts +58 -0
- package/src/lib/scenes/Scene2D.ts +167 -0
- package/src/lib/scenes/index.ts +3 -0
- package/src/lib/scenes/makeScene2D.ts +19 -0
- package/src/lib/scenes/useScene2D.ts +6 -0
- package/src/lib/tsconfig.build.json +5 -0
- package/src/lib/tsconfig.json +11 -0
- package/src/lib/tsdoc.json +4 -0
- package/src/lib/utils/CanvasUtils.ts +304 -0
- package/src/lib/utils/PathDataBuilder.ts +320 -0
- package/src/lib/utils/diff.test.ts +453 -0
- package/src/lib/utils/diff.ts +148 -0
- package/src/lib/utils/index.ts +5 -0
- package/src/lib/utils/is.ts +11 -0
- package/src/lib/utils/makeSignalExtensions.ts +29 -0
- package/src/lib/utils/rough.ts +513 -0
- package/src/lib/utils/withDefaults.tsx +26 -0
- package/src/tsconfig.base.json +18 -0
- package/src/tsconfig.build.json +8 -0
- package/src/tsconfig.json +5 -0
- package/tsconfig.project.json +7 -0
|
@@ -0,0 +1,320 @@
|
|
|
1
|
+
import {Vector2} from '@canvas-commons/core';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* A builder for constructing SVG path data strings.
|
|
5
|
+
*
|
|
6
|
+
* @remarks
|
|
7
|
+
* This class provides a fluent API for building SVG path data, which can be
|
|
8
|
+
* used to create Path2D objects or passed to other renderers like Rough.js.
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```ts
|
|
12
|
+
* const builder = new PathDataBuilder();
|
|
13
|
+
* builder.moveTo(0, 0).lineTo(100, 100).closePath();
|
|
14
|
+
* const pathData = builder.toString(); // "M 0 0 L 100 100 Z"
|
|
15
|
+
* const path = new Path2D(pathData);
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
export class PathDataBuilder {
|
|
19
|
+
private commands: string[] = [];
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Move to a point without drawing.
|
|
23
|
+
*
|
|
24
|
+
* @param x - The x coordinate
|
|
25
|
+
* @param y - The y coordinate
|
|
26
|
+
*/
|
|
27
|
+
public moveTo(x: number, y: number): this {
|
|
28
|
+
this.commands.push(`M ${x} ${y}`);
|
|
29
|
+
return this;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Draw a line to a point.
|
|
34
|
+
*
|
|
35
|
+
* @param x - The x coordinate
|
|
36
|
+
* @param y - The y coordinate
|
|
37
|
+
*/
|
|
38
|
+
public lineTo(x: number, y: number): this {
|
|
39
|
+
this.commands.push(`L ${x} ${y}`);
|
|
40
|
+
return this;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Draw a cubic Bezier curve.
|
|
45
|
+
*
|
|
46
|
+
* @param cp1x - First control point x
|
|
47
|
+
* @param cp1y - First control point y
|
|
48
|
+
* @param cp2x - Second control point x
|
|
49
|
+
* @param cp2y - Second control point y
|
|
50
|
+
* @param x - End point x
|
|
51
|
+
* @param y - End point y
|
|
52
|
+
*/
|
|
53
|
+
public bezierCurveTo(
|
|
54
|
+
cp1x: number,
|
|
55
|
+
cp1y: number,
|
|
56
|
+
cp2x: number,
|
|
57
|
+
cp2y: number,
|
|
58
|
+
x: number,
|
|
59
|
+
y: number,
|
|
60
|
+
): this {
|
|
61
|
+
this.commands.push(`C ${cp1x} ${cp1y} ${cp2x} ${cp2y} ${x} ${y}`);
|
|
62
|
+
return this;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Draw a quadratic Bezier curve.
|
|
67
|
+
*
|
|
68
|
+
* @param cpx - Control point x
|
|
69
|
+
* @param cpy - Control point y
|
|
70
|
+
* @param x - End point x
|
|
71
|
+
* @param y - End point y
|
|
72
|
+
*/
|
|
73
|
+
public quadraticCurveTo(
|
|
74
|
+
cpx: number,
|
|
75
|
+
cpy: number,
|
|
76
|
+
x: number,
|
|
77
|
+
y: number,
|
|
78
|
+
): this {
|
|
79
|
+
this.commands.push(`Q ${cpx} ${cpy} ${x} ${y}`);
|
|
80
|
+
return this;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Draw an elliptical arc.
|
|
85
|
+
*
|
|
86
|
+
* @remarks
|
|
87
|
+
* Converts canvas ellipse parameters to SVG arc commands. For full ellipses,
|
|
88
|
+
* this generates two arc commands to work around SVG's limitation of 180-degree
|
|
89
|
+
* maximum arc sweeps.
|
|
90
|
+
*
|
|
91
|
+
* @param x - Center x coordinate
|
|
92
|
+
* @param y - Center y coordinate
|
|
93
|
+
* @param radiusX - Horizontal radius
|
|
94
|
+
* @param radiusY - Vertical radius
|
|
95
|
+
* @param rotation - Rotation angle in radians
|
|
96
|
+
* @param startAngle - Start angle in radians
|
|
97
|
+
* @param endAngle - End angle in radians
|
|
98
|
+
* @param counterclockwise - Whether to draw counterclockwise
|
|
99
|
+
*/
|
|
100
|
+
public ellipse(
|
|
101
|
+
x: number,
|
|
102
|
+
y: number,
|
|
103
|
+
radiusX: number,
|
|
104
|
+
radiusY: number,
|
|
105
|
+
rotation: number,
|
|
106
|
+
startAngle: number,
|
|
107
|
+
endAngle: number,
|
|
108
|
+
counterclockwise = false,
|
|
109
|
+
): this {
|
|
110
|
+
const start = startAngle;
|
|
111
|
+
const end = endAngle;
|
|
112
|
+
|
|
113
|
+
let angleDiff = end - start;
|
|
114
|
+
if (counterclockwise && angleDiff > 0) {
|
|
115
|
+
angleDiff -= 2 * Math.PI;
|
|
116
|
+
} else if (!counterclockwise && angleDiff < 0) {
|
|
117
|
+
angleDiff += 2 * Math.PI;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
const startPoint = Vector2.fromRadians(start).mul(
|
|
121
|
+
new Vector2(radiusX, radiusY),
|
|
122
|
+
);
|
|
123
|
+
const rotatedStart = startPoint.rotate(rotation);
|
|
124
|
+
const startX = x + rotatedStart.x;
|
|
125
|
+
const startY = y + rotatedStart.y;
|
|
126
|
+
|
|
127
|
+
const endPoint = Vector2.fromRadians(end).mul(
|
|
128
|
+
new Vector2(radiusX, radiusY),
|
|
129
|
+
);
|
|
130
|
+
const rotatedEnd = endPoint.rotate(rotation);
|
|
131
|
+
const endX = x + rotatedEnd.x;
|
|
132
|
+
const endY = y + rotatedEnd.y;
|
|
133
|
+
|
|
134
|
+
if (this.commands.length === 0) {
|
|
135
|
+
this.moveTo(startX, startY);
|
|
136
|
+
} else {
|
|
137
|
+
this.lineTo(startX, startY);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// Determine if this is a large arc (> 180 degrees)
|
|
141
|
+
const largeArc = Math.abs(angleDiff) > Math.PI ? 1 : 0;
|
|
142
|
+
const sweep = counterclockwise ? 0 : 1;
|
|
143
|
+
|
|
144
|
+
// Convert rotation from radians to degrees
|
|
145
|
+
const rotationDeg = (rotation * 180) / Math.PI;
|
|
146
|
+
|
|
147
|
+
if (Math.abs(Math.abs(angleDiff) - 2 * Math.PI) < 0.001) {
|
|
148
|
+
const midAngle = start + angleDiff / 2;
|
|
149
|
+
const midPoint = Vector2.fromRadians(midAngle).mul(
|
|
150
|
+
new Vector2(radiusX, radiusY),
|
|
151
|
+
);
|
|
152
|
+
const rotatedMid = midPoint.rotate(rotation);
|
|
153
|
+
const midX = x + rotatedMid.x;
|
|
154
|
+
const midY = y + rotatedMid.y;
|
|
155
|
+
|
|
156
|
+
this.commands.push(
|
|
157
|
+
`A ${radiusX} ${radiusY} ${rotationDeg} 0 ${sweep} ${midX} ${midY}`,
|
|
158
|
+
);
|
|
159
|
+
this.commands.push(
|
|
160
|
+
`A ${radiusX} ${radiusY} ${rotationDeg} 0 ${sweep} ${endX} ${endY}`,
|
|
161
|
+
);
|
|
162
|
+
} else {
|
|
163
|
+
// Partial arc
|
|
164
|
+
this.commands.push(
|
|
165
|
+
`A ${radiusX} ${radiusY} ${rotationDeg} ${largeArc} ${sweep} ${endX} ${endY}`,
|
|
166
|
+
);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
return this;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Draw a circular arc using the arc command.
|
|
174
|
+
*
|
|
175
|
+
* @remarks
|
|
176
|
+
* This is a convenience method that calls {@link ellipse} with equal radii.
|
|
177
|
+
*
|
|
178
|
+
* @param x - Center x coordinate
|
|
179
|
+
* @param y - Center y coordinate
|
|
180
|
+
* @param radius - Arc radius
|
|
181
|
+
* @param startAngle - Start angle in radians
|
|
182
|
+
* @param endAngle - End angle in radians
|
|
183
|
+
* @param counterclockwise - Whether to draw counterclockwise
|
|
184
|
+
*/
|
|
185
|
+
public arc(
|
|
186
|
+
x: number,
|
|
187
|
+
y: number,
|
|
188
|
+
radius: number,
|
|
189
|
+
startAngle: number,
|
|
190
|
+
endAngle: number,
|
|
191
|
+
counterclockwise = false,
|
|
192
|
+
): this {
|
|
193
|
+
return this.ellipse(
|
|
194
|
+
x,
|
|
195
|
+
y,
|
|
196
|
+
radius,
|
|
197
|
+
radius,
|
|
198
|
+
0,
|
|
199
|
+
startAngle,
|
|
200
|
+
endAngle,
|
|
201
|
+
counterclockwise,
|
|
202
|
+
);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* Draw an arc to a point with a given radius.
|
|
207
|
+
*
|
|
208
|
+
* @remarks
|
|
209
|
+
* This matches the Canvas API's arcTo method. It draws a straight line from
|
|
210
|
+
* the current point to the start of an arc, then draws an arc with the given
|
|
211
|
+
* radius that is tangent to the line from the current point to (x1, y1) and
|
|
212
|
+
* the line from (x1, y1) to (x2, y2).
|
|
213
|
+
*
|
|
214
|
+
* @param x1 - First control point x
|
|
215
|
+
* @param y1 - First control point y
|
|
216
|
+
* @param x2 - Second control point x
|
|
217
|
+
* @param y2 - Second control point y
|
|
218
|
+
* @param radius - Arc radius
|
|
219
|
+
*/
|
|
220
|
+
public arcTo(
|
|
221
|
+
x1: number,
|
|
222
|
+
y1: number,
|
|
223
|
+
x2: number,
|
|
224
|
+
y2: number,
|
|
225
|
+
radius: number,
|
|
226
|
+
): this {
|
|
227
|
+
if (this.commands.length === 0) {
|
|
228
|
+
this.moveTo(x1, y1);
|
|
229
|
+
return this;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
const lastCommand = this.commands[this.commands.length - 1];
|
|
233
|
+
const coords = lastCommand.split(' ').slice(1).map(Number);
|
|
234
|
+
const p0 = new Vector2(
|
|
235
|
+
coords[coords.length - 2],
|
|
236
|
+
coords[coords.length - 1],
|
|
237
|
+
);
|
|
238
|
+
const p1 = new Vector2(x1, y1);
|
|
239
|
+
const p2 = new Vector2(x2, y2);
|
|
240
|
+
|
|
241
|
+
const v1 = p0.sub(p1);
|
|
242
|
+
const v2 = p2.sub(p1);
|
|
243
|
+
|
|
244
|
+
const v1Length = v1.magnitude;
|
|
245
|
+
const v2Length = v2.magnitude;
|
|
246
|
+
|
|
247
|
+
if (v1Length === 0 || v2Length === 0) {
|
|
248
|
+
this.lineTo(x1, y1);
|
|
249
|
+
return this;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
const v1n = v1.normalized;
|
|
253
|
+
const v2n = v2.normalized;
|
|
254
|
+
|
|
255
|
+
const angle = Math.acos(v1n.dot(v2n));
|
|
256
|
+
|
|
257
|
+
if (Math.abs(angle) < 0.0001 || Math.abs(angle - Math.PI) < 0.0001) {
|
|
258
|
+
this.lineTo(x1, y1);
|
|
259
|
+
return this;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
const tangentLength = radius / Math.tan(angle / 2);
|
|
263
|
+
|
|
264
|
+
const t1 = p1.add(v1n.scale(tangentLength));
|
|
265
|
+
const t2 = p1.add(v2n.scale(tangentLength));
|
|
266
|
+
|
|
267
|
+
this.lineTo(t1.x, t1.y);
|
|
268
|
+
|
|
269
|
+
const bisector = v1n.add(v2n).normalized;
|
|
270
|
+
const centerDistance = radius / Math.sin(angle / 2);
|
|
271
|
+
const center = p1.add(bisector.scale(centerDistance));
|
|
272
|
+
|
|
273
|
+
const startAngle = Math.atan2(t1.y - center.y, t1.x - center.x);
|
|
274
|
+
const endAngle = Math.atan2(t2.y - center.y, t2.x - center.x);
|
|
275
|
+
|
|
276
|
+
let angleDiff = endAngle - startAngle;
|
|
277
|
+
const cross = v1n.x * v2n.y - v1n.y * v2n.x;
|
|
278
|
+
const counterclockwise = cross > 0;
|
|
279
|
+
|
|
280
|
+
if (counterclockwise && angleDiff > 0) {
|
|
281
|
+
angleDiff -= 2 * Math.PI;
|
|
282
|
+
} else if (!counterclockwise && angleDiff < 0) {
|
|
283
|
+
angleDiff += 2 * Math.PI;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
const largeArc = Math.abs(angleDiff) > Math.PI ? 1 : 0;
|
|
287
|
+
const sweep = counterclockwise ? 0 : 1;
|
|
288
|
+
|
|
289
|
+
this.commands.push(
|
|
290
|
+
`A ${radius} ${radius} 0 ${largeArc} ${sweep} ${t2.x} ${t2.y}`,
|
|
291
|
+
);
|
|
292
|
+
|
|
293
|
+
return this;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
/**
|
|
297
|
+
* Close the current path.
|
|
298
|
+
*/
|
|
299
|
+
public closePath(): this {
|
|
300
|
+
this.commands.push('Z');
|
|
301
|
+
return this;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
/**
|
|
305
|
+
* Get the SVG path data string.
|
|
306
|
+
*
|
|
307
|
+
* @returns The complete SVG path data
|
|
308
|
+
*/
|
|
309
|
+
public toString(): string {
|
|
310
|
+
return this.commands.join(' ');
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
/**
|
|
314
|
+
* Reset the builder to empty state.
|
|
315
|
+
*/
|
|
316
|
+
public clear(): this {
|
|
317
|
+
this.commands = [];
|
|
318
|
+
return this;
|
|
319
|
+
}
|
|
320
|
+
}
|