locusing 0.1.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/dist/index.mjs ADDED
@@ -0,0 +1,3487 @@
1
+ import {
2
+ Morphing,
3
+ MoveToTarget,
4
+ ReplacementTransform,
5
+ Timeline,
6
+ Transform,
7
+ TransformMatchingShapes,
8
+ __objRest,
9
+ __spreadProps,
10
+ __spreadValues,
11
+ createTimeline,
12
+ easingMap,
13
+ getGSAPEasing
14
+ } from "./chunk-2THKOSBL.mjs";
15
+
16
+ // src/math/index.ts
17
+ function V2(x, y) {
18
+ return [x, y];
19
+ }
20
+ function V3(x, y, z) {
21
+ return [x, y, z];
22
+ }
23
+ var ORIGIN = [0, 0];
24
+ var UP = [0, -1];
25
+ var DOWN = [0, 1];
26
+ var LEFT = [-1, 0];
27
+ var RIGHT = [1, 0];
28
+ var UL = [-1, -1];
29
+ var UR = [1, -1];
30
+ var DL = [-1, 1];
31
+ var DR = [1, 1];
32
+ function add(a, b) {
33
+ return [a[0] + b[0], a[1] + b[1]];
34
+ }
35
+ function sub(a, b) {
36
+ return [a[0] - b[0], a[1] - b[1]];
37
+ }
38
+ function mul(v, scalar) {
39
+ return [v[0] * scalar, v[1] * scalar];
40
+ }
41
+ function div(v, scalar) {
42
+ return [v[0] / scalar, v[1] / scalar];
43
+ }
44
+ function dot(a, b) {
45
+ return a[0] * b[0] + a[1] * b[1];
46
+ }
47
+ function cross(a, b) {
48
+ return a[0] * b[1] - a[1] * b[0];
49
+ }
50
+ function length(v) {
51
+ return Math.sqrt(v[0] * v[0] + v[1] * v[1]);
52
+ }
53
+ function normalize(v) {
54
+ const len = length(v);
55
+ if (len === 0) return [0, 0];
56
+ return [v[0] / len, v[1] / len];
57
+ }
58
+ function distance(a, b) {
59
+ return length(sub(b, a));
60
+ }
61
+ function angle(v) {
62
+ return Math.atan2(v[1], v[0]);
63
+ }
64
+ function angleBetween(a, b) {
65
+ return Math.atan2(cross(a, b), dot(a, b));
66
+ }
67
+ function rotate(v, radians) {
68
+ const cos = Math.cos(radians);
69
+ const sin = Math.sin(radians);
70
+ return [v[0] * cos - v[1] * sin, v[0] * sin + v[1] * cos];
71
+ }
72
+ function lerp(a, b, t) {
73
+ return [a[0] + (b[0] - a[0]) * t, a[1] + (b[1] - a[1]) * t];
74
+ }
75
+ function midpoint(a, b) {
76
+ return lerp(a, b, 0.5);
77
+ }
78
+ function perpendicular(v) {
79
+ return [-v[1], v[0]];
80
+ }
81
+ function reflect(v, normal) {
82
+ const n = normalize(normal);
83
+ const d = 2 * dot(v, n);
84
+ return sub(v, mul(n, d));
85
+ }
86
+ var IDENTITY = [
87
+ 1,
88
+ 0,
89
+ 0,
90
+ 0,
91
+ 1,
92
+ 0,
93
+ 0,
94
+ 0,
95
+ 1
96
+ ];
97
+ function matrixMultiply(a, b) {
98
+ return [
99
+ a[0] * b[0] + a[1] * b[3] + a[2] * b[6],
100
+ a[0] * b[1] + a[1] * b[4] + a[2] * b[7],
101
+ a[0] * b[2] + a[1] * b[5] + a[2] * b[8],
102
+ a[3] * b[0] + a[4] * b[3] + a[5] * b[6],
103
+ a[3] * b[1] + a[4] * b[4] + a[5] * b[7],
104
+ a[3] * b[2] + a[4] * b[5] + a[5] * b[8],
105
+ a[6] * b[0] + a[7] * b[3] + a[8] * b[6],
106
+ a[6] * b[1] + a[7] * b[4] + a[8] * b[7],
107
+ a[6] * b[2] + a[7] * b[5] + a[8] * b[8]
108
+ ];
109
+ }
110
+ function applyMatrix(m, v) {
111
+ return [
112
+ m[0] * v[0] + m[1] * v[1] + m[2],
113
+ m[3] * v[0] + m[4] * v[1] + m[5]
114
+ ];
115
+ }
116
+ function translationMatrix(tx, ty) {
117
+ return [
118
+ 1,
119
+ 0,
120
+ tx,
121
+ 0,
122
+ 1,
123
+ ty,
124
+ 0,
125
+ 0,
126
+ 1
127
+ ];
128
+ }
129
+ function rotationMatrix(radians) {
130
+ const cos = Math.cos(radians);
131
+ const sin = Math.sin(radians);
132
+ return [
133
+ cos,
134
+ -sin,
135
+ 0,
136
+ sin,
137
+ cos,
138
+ 0,
139
+ 0,
140
+ 0,
141
+ 1
142
+ ];
143
+ }
144
+ function scaleMatrix(sx, sy = sx) {
145
+ return [
146
+ sx,
147
+ 0,
148
+ 0,
149
+ 0,
150
+ sy,
151
+ 0,
152
+ 0,
153
+ 0,
154
+ 1
155
+ ];
156
+ }
157
+ function quadraticBezier(p0, p1, p2, t) {
158
+ const t1 = 1 - t;
159
+ return [
160
+ t1 * t1 * p0[0] + 2 * t1 * t * p1[0] + t * t * p2[0],
161
+ t1 * t1 * p0[1] + 2 * t1 * t * p1[1] + t * t * p2[1]
162
+ ];
163
+ }
164
+ function cubicBezier(p0, p1, p2, p3, t) {
165
+ const t1 = 1 - t;
166
+ const t12 = t1 * t1;
167
+ const t13 = t12 * t1;
168
+ const t2 = t * t;
169
+ const t3 = t2 * t;
170
+ return [
171
+ t13 * p0[0] + 3 * t12 * t * p1[0] + 3 * t1 * t2 * p2[0] + t3 * p3[0],
172
+ t13 * p0[1] + 3 * t12 * t * p1[1] + 3 * t1 * t2 * p2[1] + t3 * p3[1]
173
+ ];
174
+ }
175
+ function sampleParametric(fn, start = 0, end = 1, segments = 100) {
176
+ const points = [];
177
+ for (let i = 0; i <= segments; i++) {
178
+ const t = start + (end - start) * (i / segments);
179
+ points.push(fn(t));
180
+ }
181
+ return points;
182
+ }
183
+ var easing = {
184
+ linear: (t) => t,
185
+ easeInQuad: (t) => t * t,
186
+ easeOutQuad: (t) => t * (2 - t),
187
+ easeInOutQuad: (t) => t < 0.5 ? 2 * t * t : -1 + (4 - 2 * t) * t,
188
+ easeInCubic: (t) => t * t * t,
189
+ easeOutCubic: (t) => --t * t * t + 1,
190
+ easeInOutCubic: (t) => t < 0.5 ? 4 * t * t * t : (t - 1) * (2 * t - 2) * (2 * t - 2) + 1,
191
+ easeInSine: (t) => 1 - Math.cos(t * Math.PI / 2),
192
+ easeOutSine: (t) => Math.sin(t * Math.PI / 2),
193
+ easeInOutSine: (t) => -(Math.cos(Math.PI * t) - 1) / 2,
194
+ easeInExpo: (t) => t === 0 ? 0 : Math.pow(2, 10 * t - 10),
195
+ easeOutExpo: (t) => t === 1 ? 1 : 1 - Math.pow(2, -10 * t),
196
+ easeInOutExpo: (t) => t === 0 ? 0 : t === 1 ? 1 : t < 0.5 ? Math.pow(2, 20 * t - 10) / 2 : (2 - Math.pow(2, -20 * t + 10)) / 2,
197
+ easeInBack: (t) => {
198
+ const c = 1.70158;
199
+ return (c + 1) * t * t * t - c * t * t;
200
+ },
201
+ easeOutBack: (t) => {
202
+ const c = 1.70158;
203
+ return 1 + (c + 1) * Math.pow(t - 1, 3) + c * Math.pow(t - 1, 2);
204
+ },
205
+ easeInOutBack: (t) => {
206
+ const c = 1.70158 * 1.525;
207
+ return t < 0.5 ? Math.pow(2 * t, 2) * ((c + 1) * 2 * t - c) / 2 : (Math.pow(2 * t - 2, 2) * ((c + 1) * (t * 2 - 2) + c) + 2) / 2;
208
+ },
209
+ easeInElastic: (t) => {
210
+ if (t === 0 || t === 1) return t;
211
+ return -Math.pow(2, 10 * t - 10) * Math.sin((t * 10 - 10.75) * (2 * Math.PI / 3));
212
+ },
213
+ easeOutElastic: (t) => {
214
+ if (t === 0 || t === 1) return t;
215
+ return Math.pow(2, -10 * t) * Math.sin((t * 10 - 0.75) * (2 * Math.PI / 3)) + 1;
216
+ },
217
+ easeInBounce: (t) => 1 - easing.easeOutBounce(1 - t),
218
+ easeOutBounce: (t) => {
219
+ if (t < 1 / 2.75) {
220
+ return 7.5625 * t * t;
221
+ } else if (t < 2 / 2.75) {
222
+ return 7.5625 * (t -= 1.5 / 2.75) * t + 0.75;
223
+ } else if (t < 2.5 / 2.75) {
224
+ return 7.5625 * (t -= 2.25 / 2.75) * t + 0.9375;
225
+ } else {
226
+ return 7.5625 * (t -= 2.625 / 2.75) * t + 0.984375;
227
+ }
228
+ }
229
+ };
230
+ var PI = Math.PI;
231
+ var TAU = Math.PI * 2;
232
+ var DEGREES = PI / 180;
233
+ function degToRad(degrees) {
234
+ return degrees * DEGREES;
235
+ }
236
+ function radToDeg(radians) {
237
+ return radians / DEGREES;
238
+ }
239
+ function clamp(value, min, max) {
240
+ return Math.max(min, Math.min(max, value));
241
+ }
242
+ function mapRange(value, inMin, inMax, outMin, outMax) {
243
+ return (value - inMin) / (inMax - inMin) * (outMax - outMin) + outMin;
244
+ }
245
+ function lerpNumber(a, b, t) {
246
+ return a + (b - a) * t;
247
+ }
248
+
249
+ // src/core/diagram.ts
250
+ var idCounter = 0;
251
+ function generateId() {
252
+ return `shape_${++idCounter}`;
253
+ }
254
+ var Diagram = class _Diagram {
255
+ constructor(shape) {
256
+ this.shape = shape;
257
+ }
258
+ // ========== 样式方法 ==========
259
+ /** 设置填充颜色 */
260
+ fill(color) {
261
+ return this.style({ fill: color });
262
+ }
263
+ /** 设置描边颜色 */
264
+ stroke(color) {
265
+ return this.style({ stroke: color });
266
+ }
267
+ /** 设置描边宽度 */
268
+ strokeWidth(width) {
269
+ return this.style({ strokeWidth: width });
270
+ }
271
+ /** 设置透明度 */
272
+ opacity(value) {
273
+ return this.style({ opacity: value });
274
+ }
275
+ /** 设置虚线样式 */
276
+ dashed(dasharray = "5,5") {
277
+ return this.style({ strokeDasharray: dasharray });
278
+ }
279
+ /** 批量设置样式 */
280
+ style(newStyle) {
281
+ return new _Diagram(__spreadProps(__spreadValues({}, this.shape), {
282
+ style: __spreadValues(__spreadValues({}, this.shape.style), newStyle)
283
+ }));
284
+ }
285
+ translate(xOrV, y) {
286
+ const [tx, ty] = typeof xOrV === "number" ? [xOrV, y] : xOrV;
287
+ return this.transform(translationMatrix(tx, ty));
288
+ }
289
+ position(xOrV, y) {
290
+ const [px, py] = typeof xOrV === "number" ? [xOrV, y] : xOrV;
291
+ const center = this.center();
292
+ return this.translate(px - center[0], py - center[1]);
293
+ }
294
+ /** 旋转(弧度) */
295
+ rotate(radians, center) {
296
+ if (center) {
297
+ const [cx, cy] = center;
298
+ return this.translate(-cx, -cy).transform(rotationMatrix(radians)).translate(cx, cy);
299
+ }
300
+ const c = this.center();
301
+ return this.translate(-c[0], -c[1]).transform(rotationMatrix(radians)).translate(c[0], c[1]);
302
+ }
303
+ /** 旋转(度数) */
304
+ rotateDeg(degrees, center) {
305
+ return this.rotate(degToRad(degrees), center);
306
+ }
307
+ scale(sxOrFactor, syOrCenter, center) {
308
+ let sx, sy, c;
309
+ if (typeof syOrCenter === "number") {
310
+ sx = sxOrFactor;
311
+ sy = syOrCenter;
312
+ c = center;
313
+ } else {
314
+ sx = sy = sxOrFactor;
315
+ c = syOrCenter;
316
+ }
317
+ if (c) {
318
+ return this.translate(-c[0], -c[1]).transform(scaleMatrix(sx, sy)).translate(c[0], c[1]);
319
+ }
320
+ const cc = this.center();
321
+ return this.translate(-cc[0], -cc[1]).transform(scaleMatrix(sx, sy)).translate(cc[0], cc[1]);
322
+ }
323
+ /** 应用变换矩阵 */
324
+ transform(matrix) {
325
+ return new _Diagram(__spreadProps(__spreadValues({}, this.shape), {
326
+ transform: matrixMultiply(matrix, this.shape.transform)
327
+ }));
328
+ }
329
+ // ========== 组合方法 ==========
330
+ /** 组合多个图形 */
331
+ combine(...others) {
332
+ const children = [this.shape, ...others.map((d) => d.shape)];
333
+ return new _Diagram({
334
+ id: generateId(),
335
+ type: "group",
336
+ style: {},
337
+ transform: IDENTITY,
338
+ children
339
+ });
340
+ }
341
+ /** 添加子图形 */
342
+ add(...others) {
343
+ if (this.shape.type === "group") {
344
+ return new _Diagram(__spreadProps(__spreadValues({}, this.shape), {
345
+ children: [...this.shape.children, ...others.map((d) => d.shape)]
346
+ }));
347
+ }
348
+ return this.combine(...others);
349
+ }
350
+ // ========== 几何查询 ==========
351
+ /** 获取中心点 */
352
+ center() {
353
+ const bounds = this.bounds();
354
+ return V2(bounds.x + bounds.width / 2, bounds.y + bounds.height / 2);
355
+ }
356
+ /** 获取包围盒 */
357
+ bounds() {
358
+ return calculateBounds(this.shape);
359
+ }
360
+ /** 获取指定方向的边缘点 */
361
+ edge(direction) {
362
+ const c = this.center();
363
+ const b = this.bounds();
364
+ const [dx, dy] = direction;
365
+ const x = dx > 0 ? b.x + b.width : dx < 0 ? b.x : c[0];
366
+ const y = dy > 0 ? b.y + b.height : dy < 0 ? b.y : c[1];
367
+ return V2(x, y);
368
+ }
369
+ /** 获取相对于另一个图形的位置 */
370
+ nextTo(other, direction, buffer = 10) {
371
+ const otherEdge = other.edge(direction);
372
+ const myEdge = this.edge(V2(-direction[0], -direction[1]));
373
+ const offset = V2(
374
+ otherEdge[0] - myEdge[0] + direction[0] * buffer,
375
+ otherEdge[1] - myEdge[1] + direction[1] * buffer
376
+ );
377
+ return this.translate(offset);
378
+ }
379
+ // ========== 复制方法 ==========
380
+ /** 克隆图形 */
381
+ clone() {
382
+ return new _Diagram(cloneShape(this.shape));
383
+ }
384
+ /** 复制到指定位置 */
385
+ copy() {
386
+ const cloned = this.clone();
387
+ return new _Diagram(__spreadProps(__spreadValues({}, cloned.shape), {
388
+ id: generateId()
389
+ }));
390
+ }
391
+ };
392
+ function calculateBounds(shape) {
393
+ if (shape._bounds) return shape._bounds;
394
+ let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
395
+ const updateBounds = (point) => {
396
+ const transformed = applyMatrix(shape.transform, point);
397
+ minX = Math.min(minX, transformed[0]);
398
+ minY = Math.min(minY, transformed[1]);
399
+ maxX = Math.max(maxX, transformed[0]);
400
+ maxY = Math.max(maxY, transformed[1]);
401
+ };
402
+ switch (shape.type) {
403
+ case "rect":
404
+ updateBounds([shape.x, shape.y]);
405
+ updateBounds([shape.x + shape.width, shape.y]);
406
+ updateBounds([shape.x, shape.y + shape.height]);
407
+ updateBounds([shape.x + shape.width, shape.y + shape.height]);
408
+ break;
409
+ case "circle":
410
+ updateBounds([shape.cx - shape.r, shape.cy - shape.r]);
411
+ updateBounds([shape.cx + shape.r, shape.cy + shape.r]);
412
+ break;
413
+ case "ellipse":
414
+ updateBounds([shape.cx - shape.rx, shape.cy - shape.ry]);
415
+ updateBounds([shape.cx + shape.rx, shape.cy + shape.ry]);
416
+ break;
417
+ case "line":
418
+ updateBounds([shape.x1, shape.y1]);
419
+ updateBounds([shape.x2, shape.y2]);
420
+ break;
421
+ case "polygon":
422
+ case "polyline":
423
+ shape.points.forEach(updateBounds);
424
+ break;
425
+ case "text":
426
+ const fontSize = shape.style.fontSize || 16;
427
+ const width = shape.content.length * fontSize * 0.6;
428
+ updateBounds([shape.x, shape.y - fontSize]);
429
+ updateBounds([shape.x + width, shape.y]);
430
+ break;
431
+ case "arc":
432
+ updateBounds([shape.cx - shape.r, shape.cy - shape.r]);
433
+ updateBounds([shape.cx + shape.r, shape.cy + shape.r]);
434
+ break;
435
+ case "path":
436
+ shape.commands.forEach((cmd) => {
437
+ if ("x" in cmd && "y" in cmd) {
438
+ updateBounds([cmd.x, cmd.y]);
439
+ }
440
+ });
441
+ break;
442
+ case "group":
443
+ shape.children.forEach((child) => {
444
+ const childBounds = calculateBounds(child);
445
+ updateBounds([childBounds.x, childBounds.y]);
446
+ updateBounds([childBounds.x + childBounds.width, childBounds.y + childBounds.height]);
447
+ });
448
+ break;
449
+ }
450
+ if (minX === Infinity) {
451
+ return { x: 0, y: 0, width: 0, height: 0 };
452
+ }
453
+ return { x: minX, y: minY, width: maxX - minX, height: maxY - minY };
454
+ }
455
+ function cloneShape(shape) {
456
+ if (shape.type === "group") {
457
+ return __spreadProps(__spreadValues({}, shape), {
458
+ id: generateId(),
459
+ children: shape.children.map(cloneShape)
460
+ });
461
+ }
462
+ return __spreadProps(__spreadValues({}, shape), { id: generateId() });
463
+ }
464
+
465
+ // src/core/shapes.ts
466
+ var DEFAULT_STYLE = {
467
+ fill: "none",
468
+ stroke: "#374151",
469
+ // gray-700
470
+ strokeWidth: 2,
471
+ strokeLinecap: "round",
472
+ strokeLinejoin: "round"
473
+ };
474
+ var DEFAULT_FILL_STYLE = {
475
+ fill: "#EA580C",
476
+ // orange-600
477
+ stroke: "none",
478
+ strokeWidth: 0
479
+ };
480
+ function rect(width, height, options) {
481
+ const { rx = 0, ry = 0, centered = true } = options || {};
482
+ const x = centered ? -width / 2 : 0;
483
+ const y = centered ? -height / 2 : 0;
484
+ const shape = {
485
+ id: generateId(),
486
+ type: "rect",
487
+ x,
488
+ y,
489
+ width,
490
+ height,
491
+ rx,
492
+ ry,
493
+ style: __spreadValues({}, DEFAULT_FILL_STYLE),
494
+ transform: IDENTITY
495
+ };
496
+ return new Diagram(shape);
497
+ }
498
+ function square(size, options) {
499
+ return rect(size, size, options);
500
+ }
501
+ function circle(radius) {
502
+ const shape = {
503
+ id: generateId(),
504
+ type: "circle",
505
+ cx: 0,
506
+ cy: 0,
507
+ r: radius,
508
+ style: __spreadValues({}, DEFAULT_FILL_STYLE),
509
+ transform: IDENTITY
510
+ };
511
+ return new Diagram(shape);
512
+ }
513
+ function ellipse(rx, ry) {
514
+ const shape = {
515
+ id: generateId(),
516
+ type: "ellipse",
517
+ cx: 0,
518
+ cy: 0,
519
+ rx,
520
+ ry,
521
+ style: __spreadValues({}, DEFAULT_FILL_STYLE),
522
+ transform: IDENTITY
523
+ };
524
+ return new Diagram(shape);
525
+ }
526
+ function dot2(position, radius = 4) {
527
+ const [x, y] = position || [0, 0];
528
+ return circle(radius).translate(x, y);
529
+ }
530
+ function line(from, to) {
531
+ const shape = {
532
+ id: generateId(),
533
+ type: "line",
534
+ x1: from[0],
535
+ y1: from[1],
536
+ x2: to[0],
537
+ y2: to[1],
538
+ style: __spreadValues({}, DEFAULT_STYLE),
539
+ transform: IDENTITY
540
+ };
541
+ return new Diagram(shape);
542
+ }
543
+ function arrow(from, to, options) {
544
+ const { headSize = 10, headAngle = PI / 6 } = options || {};
545
+ const dx = to[0] - from[0];
546
+ const dy = to[1] - from[1];
547
+ const angle2 = Math.atan2(dy, dx);
548
+ const head1 = [
549
+ to[0] - headSize * Math.cos(angle2 - headAngle),
550
+ to[1] - headSize * Math.sin(angle2 - headAngle)
551
+ ];
552
+ const head2 = [
553
+ to[0] - headSize * Math.cos(angle2 + headAngle),
554
+ to[1] - headSize * Math.sin(angle2 + headAngle)
555
+ ];
556
+ const mainLine = line(from, to);
557
+ const headLine1 = line(to, head1);
558
+ const headLine2 = line(to, head2);
559
+ return mainLine.combine(headLine1, headLine2);
560
+ }
561
+ function doubleArrow(from, to, options) {
562
+ const a1 = arrow(from, to, options);
563
+ const a2 = arrow(to, from, options);
564
+ return a1.combine(a2);
565
+ }
566
+ function polygon(...points) {
567
+ const shape = {
568
+ id: generateId(),
569
+ type: "polygon",
570
+ points,
571
+ style: __spreadValues({}, DEFAULT_FILL_STYLE),
572
+ transform: IDENTITY
573
+ };
574
+ return new Diagram(shape);
575
+ }
576
+ function regularPolygon(sides, radius) {
577
+ const points = [];
578
+ const angleStep = TAU / sides;
579
+ const startAngle = -PI / 2;
580
+ for (let i = 0; i < sides; i++) {
581
+ const angle2 = startAngle + i * angleStep;
582
+ points.push([
583
+ radius * Math.cos(angle2),
584
+ radius * Math.sin(angle2)
585
+ ]);
586
+ }
587
+ return polygon(...points);
588
+ }
589
+ function triangle(width, height) {
590
+ return polygon(
591
+ [0, -height / 2],
592
+ [width / 2, height / 2],
593
+ [-width / 2, height / 2]
594
+ );
595
+ }
596
+ function equilateralTriangle(sideLength) {
597
+ return regularPolygon(3, sideLength / Math.sqrt(3));
598
+ }
599
+ function star(points, outerRadius, innerRadius) {
600
+ const inner = innerRadius != null ? innerRadius : outerRadius * 0.4;
601
+ const starPoints = [];
602
+ const angleStep = PI / points;
603
+ const startAngle = -PI / 2;
604
+ for (let i = 0; i < points * 2; i++) {
605
+ const angle2 = startAngle + i * angleStep;
606
+ const r = i % 2 === 0 ? outerRadius : inner;
607
+ starPoints.push([
608
+ r * Math.cos(angle2),
609
+ r * Math.sin(angle2)
610
+ ]);
611
+ }
612
+ return polygon(...starPoints);
613
+ }
614
+ function polyline(...points) {
615
+ const shape = {
616
+ id: generateId(),
617
+ type: "polyline",
618
+ points,
619
+ style: __spreadValues({}, DEFAULT_STYLE),
620
+ transform: IDENTITY
621
+ };
622
+ return new Diagram(shape);
623
+ }
624
+ function arc(radius, startAngle, endAngle) {
625
+ const shape = {
626
+ id: generateId(),
627
+ type: "arc",
628
+ cx: 0,
629
+ cy: 0,
630
+ r: radius,
631
+ startAngle,
632
+ endAngle,
633
+ style: __spreadValues({}, DEFAULT_STYLE),
634
+ transform: IDENTITY
635
+ };
636
+ return new Diagram(shape);
637
+ }
638
+ function sector(radius, startAngle, endAngle) {
639
+ const startX = radius * Math.cos(startAngle);
640
+ const startY = radius * Math.sin(startAngle);
641
+ const endX = radius * Math.cos(endAngle);
642
+ const endY = radius * Math.sin(endAngle);
643
+ const largeArc = Math.abs(endAngle - startAngle) > PI;
644
+ const commands = [
645
+ { type: "M", x: 0, y: 0 },
646
+ { type: "L", x: startX, y: startY },
647
+ { type: "A", rx: radius, ry: radius, angle: 0, largeArc, sweep: true, x: endX, y: endY },
648
+ { type: "Z" }
649
+ ];
650
+ return path(commands).fill("#EA580C");
651
+ }
652
+ function path(commands) {
653
+ const shape = {
654
+ id: generateId(),
655
+ type: "path",
656
+ commands,
657
+ style: __spreadValues({}, DEFAULT_STYLE),
658
+ transform: IDENTITY
659
+ };
660
+ return new Diagram(shape);
661
+ }
662
+ function pathFromString(d) {
663
+ const commands = parseSVGPath(d);
664
+ return path(commands);
665
+ }
666
+ function text(content, options) {
667
+ const {
668
+ fontSize = 16,
669
+ fontFamily = "system-ui, sans-serif",
670
+ fontWeight = "normal",
671
+ fontStyle = "normal",
672
+ anchor = "middle"
673
+ } = options || {};
674
+ const style = {
675
+ fill: "#374151",
676
+ stroke: "none",
677
+ fontSize,
678
+ fontFamily,
679
+ fontWeight,
680
+ fontStyle,
681
+ textAnchor: anchor,
682
+ dominantBaseline: "middle"
683
+ };
684
+ const shape = {
685
+ id: generateId(),
686
+ type: "text",
687
+ x: 0,
688
+ y: 0,
689
+ content,
690
+ style,
691
+ transform: IDENTITY
692
+ };
693
+ return new Diagram(shape);
694
+ }
695
+ function tex(latex, options) {
696
+ return text(latex, options);
697
+ }
698
+ function combine(...diagrams) {
699
+ if (diagrams.length === 0) {
700
+ return new Diagram({
701
+ id: generateId(),
702
+ type: "group",
703
+ style: {},
704
+ transform: IDENTITY,
705
+ children: []
706
+ });
707
+ }
708
+ return diagrams[0].combine(...diagrams.slice(1));
709
+ }
710
+ function group() {
711
+ return combine();
712
+ }
713
+ function parseSVGPath(d) {
714
+ var _a;
715
+ const commands = [];
716
+ const regex = /([MmLlHhVvCcSsQqTtAaZz])([^MmLlHhVvCcSsQqTtAaZz]*)/g;
717
+ let match;
718
+ while ((match = regex.exec(d)) !== null) {
719
+ const type = match[1];
720
+ const argsRaw = ((_a = match[2]) == null ? void 0 : _a.trim().split(/[\s,]+/).map(Number).filter((n) => !isNaN(n))) || [];
721
+ const args = argsRaw;
722
+ switch (type == null ? void 0 : type.toUpperCase()) {
723
+ case "M":
724
+ if (args.length >= 2) commands.push({ type: "M", x: args[0], y: args[1] });
725
+ break;
726
+ case "L":
727
+ if (args.length >= 2) commands.push({ type: "L", x: args[0], y: args[1] });
728
+ break;
729
+ case "H":
730
+ if (args.length >= 1) commands.push({ type: "H", x: args[0] });
731
+ break;
732
+ case "V":
733
+ if (args.length >= 1) commands.push({ type: "V", y: args[0] });
734
+ break;
735
+ case "C":
736
+ if (args.length >= 6) {
737
+ commands.push({
738
+ type: "C",
739
+ x1: args[0],
740
+ y1: args[1],
741
+ x2: args[2],
742
+ y2: args[3],
743
+ x: args[4],
744
+ y: args[5]
745
+ });
746
+ }
747
+ break;
748
+ case "S":
749
+ if (args.length >= 4) {
750
+ commands.push({
751
+ type: "S",
752
+ x2: args[0],
753
+ y2: args[1],
754
+ x: args[2],
755
+ y: args[3]
756
+ });
757
+ }
758
+ break;
759
+ case "Q":
760
+ if (args.length >= 4) {
761
+ commands.push({
762
+ type: "Q",
763
+ x1: args[0],
764
+ y1: args[1],
765
+ x: args[2],
766
+ y: args[3]
767
+ });
768
+ }
769
+ break;
770
+ case "T":
771
+ if (args.length >= 2) commands.push({ type: "T", x: args[0], y: args[1] });
772
+ break;
773
+ case "A":
774
+ if (args.length >= 7) {
775
+ commands.push({
776
+ type: "A",
777
+ rx: args[0],
778
+ ry: args[1],
779
+ angle: args[2],
780
+ largeArc: args[3] === 1,
781
+ sweep: args[4] === 1,
782
+ x: args[5],
783
+ y: args[6]
784
+ });
785
+ }
786
+ break;
787
+ case "Z":
788
+ commands.push({ type: "Z" });
789
+ break;
790
+ }
791
+ }
792
+ return commands;
793
+ }
794
+
795
+ // src/core/render-svg.ts
796
+ var SVG_NS = "http://www.w3.org/2000/svg";
797
+ function renderToSVG(diagram, container, options = {}) {
798
+ const { width = 800, height = 600, background } = options;
799
+ let svg;
800
+ if (container instanceof SVGSVGElement) {
801
+ svg = container;
802
+ } else {
803
+ svg = document.createElementNS(SVG_NS, "svg");
804
+ container.appendChild(svg);
805
+ }
806
+ svg.setAttribute("width", String(width));
807
+ svg.setAttribute("height", String(height));
808
+ svg.setAttribute("viewBox", `0 0 ${width} ${height}`);
809
+ while (svg.firstChild) {
810
+ svg.removeChild(svg.firstChild);
811
+ }
812
+ if (background) {
813
+ const rect2 = document.createElementNS(SVG_NS, "rect");
814
+ rect2.setAttribute("width", "100%");
815
+ rect2.setAttribute("height", "100%");
816
+ rect2.setAttribute("fill", background);
817
+ svg.appendChild(rect2);
818
+ }
819
+ const defs = document.createElementNS(SVG_NS, "defs");
820
+ svg.appendChild(defs);
821
+ const element = renderShape(diagram.shape);
822
+ if (element) {
823
+ svg.appendChild(element);
824
+ }
825
+ return svg;
826
+ }
827
+ function toSVGString(diagram, options = {}) {
828
+ const { width = 800, height = 600, background } = options;
829
+ let content = "";
830
+ if (background) {
831
+ content += `<rect width="100%" height="100%" fill="${background}"/>`;
832
+ }
833
+ content += shapeToSVGString(diagram.shape);
834
+ return `<svg xmlns="${SVG_NS}" width="${width}" height="${height}" viewBox="0 0 ${width} ${height}">${content}</svg>`;
835
+ }
836
+ function renderShape(shape) {
837
+ let element = null;
838
+ switch (shape.type) {
839
+ case "rect":
840
+ element = document.createElementNS(SVG_NS, "rect");
841
+ element.setAttribute("x", String(shape.x));
842
+ element.setAttribute("y", String(shape.y));
843
+ element.setAttribute("width", String(shape.width));
844
+ element.setAttribute("height", String(shape.height));
845
+ if (shape.rx) element.setAttribute("rx", String(shape.rx));
846
+ if (shape.ry) element.setAttribute("ry", String(shape.ry));
847
+ break;
848
+ case "circle":
849
+ element = document.createElementNS(SVG_NS, "circle");
850
+ element.setAttribute("cx", String(shape.cx));
851
+ element.setAttribute("cy", String(shape.cy));
852
+ element.setAttribute("r", String(shape.r));
853
+ break;
854
+ case "ellipse":
855
+ element = document.createElementNS(SVG_NS, "ellipse");
856
+ element.setAttribute("cx", String(shape.cx));
857
+ element.setAttribute("cy", String(shape.cy));
858
+ element.setAttribute("rx", String(shape.rx));
859
+ element.setAttribute("ry", String(shape.ry));
860
+ break;
861
+ case "line":
862
+ element = document.createElementNS(SVG_NS, "line");
863
+ element.setAttribute("x1", String(shape.x1));
864
+ element.setAttribute("y1", String(shape.y1));
865
+ element.setAttribute("x2", String(shape.x2));
866
+ element.setAttribute("y2", String(shape.y2));
867
+ break;
868
+ case "polyline":
869
+ element = document.createElementNS(SVG_NS, "polyline");
870
+ element.setAttribute("points", shape.points.map((p) => `${p[0]},${p[1]}`).join(" "));
871
+ break;
872
+ case "polygon":
873
+ element = document.createElementNS(SVG_NS, "polygon");
874
+ element.setAttribute("points", shape.points.map((p) => `${p[0]},${p[1]}`).join(" "));
875
+ break;
876
+ case "path":
877
+ element = document.createElementNS(SVG_NS, "path");
878
+ element.setAttribute("d", commandsToPath(shape.commands));
879
+ break;
880
+ case "arc":
881
+ element = document.createElementNS(SVG_NS, "path");
882
+ element.setAttribute("d", arcToPath(shape.cx, shape.cy, shape.r, shape.startAngle, shape.endAngle));
883
+ break;
884
+ case "text":
885
+ element = document.createElementNS(SVG_NS, "text");
886
+ element.setAttribute("x", String(shape.x));
887
+ element.setAttribute("y", String(shape.y));
888
+ element.textContent = shape.content;
889
+ applyTextStyle(element, shape.style);
890
+ break;
891
+ case "group":
892
+ element = document.createElementNS(SVG_NS, "g");
893
+ for (const child of shape.children) {
894
+ const childElement = renderShape(child);
895
+ if (childElement) {
896
+ element.appendChild(childElement);
897
+ }
898
+ }
899
+ break;
900
+ }
901
+ if (element) {
902
+ element.setAttribute("id", shape.id);
903
+ applyStyle(element, shape.style);
904
+ applyTransform(element, shape.transform);
905
+ }
906
+ return element;
907
+ }
908
+ function shapeToSVGString(shape) {
909
+ const attrs = [`id="${shape.id}"`];
910
+ const style = styleToString(shape.style);
911
+ const transform = transformToString(shape.transform);
912
+ if (style) attrs.push(style);
913
+ if (transform) attrs.push(`transform="${transform}"`);
914
+ switch (shape.type) {
915
+ case "rect":
916
+ attrs.push(`x="${shape.x}" y="${shape.y}" width="${shape.width}" height="${shape.height}"`);
917
+ if (shape.rx) attrs.push(`rx="${shape.rx}"`);
918
+ if (shape.ry) attrs.push(`ry="${shape.ry}"`);
919
+ return `<rect ${attrs.join(" ")}/>`;
920
+ case "circle":
921
+ attrs.push(`cx="${shape.cx}" cy="${shape.cy}" r="${shape.r}"`);
922
+ return `<circle ${attrs.join(" ")}/>`;
923
+ case "ellipse":
924
+ attrs.push(`cx="${shape.cx}" cy="${shape.cy}" rx="${shape.rx}" ry="${shape.ry}"`);
925
+ return `<ellipse ${attrs.join(" ")}/>`;
926
+ case "line":
927
+ attrs.push(`x1="${shape.x1}" y1="${shape.y1}" x2="${shape.x2}" y2="${shape.y2}"`);
928
+ return `<line ${attrs.join(" ")}/>`;
929
+ case "polyline":
930
+ attrs.push(`points="${shape.points.map((p) => `${p[0]},${p[1]}`).join(" ")}"`);
931
+ return `<polyline ${attrs.join(" ")}/>`;
932
+ case "polygon":
933
+ attrs.push(`points="${shape.points.map((p) => `${p[0]},${p[1]}`).join(" ")}"`);
934
+ return `<polygon ${attrs.join(" ")}/>`;
935
+ case "path":
936
+ attrs.push(`d="${commandsToPath(shape.commands)}"`);
937
+ return `<path ${attrs.join(" ")}/>`;
938
+ case "arc":
939
+ attrs.push(`d="${arcToPath(shape.cx, shape.cy, shape.r, shape.startAngle, shape.endAngle)}"`);
940
+ return `<path ${attrs.join(" ")}/>`;
941
+ case "text":
942
+ const textStyle = textStyleToString(shape.style);
943
+ if (textStyle) attrs.push(textStyle);
944
+ attrs.push(`x="${shape.x}" y="${shape.y}"`);
945
+ return `<text ${attrs.join(" ")}>${escapeXML(shape.content)}</text>`;
946
+ case "group":
947
+ const children = shape.children.map(shapeToSVGString).join("");
948
+ return `<g ${attrs.join(" ")}>${children}</g>`;
949
+ default:
950
+ return "";
951
+ }
952
+ }
953
+ function applyStyle(element, style) {
954
+ if (style.fill) element.setAttribute("fill", style.fill);
955
+ if (style.fillOpacity !== void 0) element.setAttribute("fill-opacity", String(style.fillOpacity));
956
+ if (style.stroke) element.setAttribute("stroke", style.stroke);
957
+ if (style.strokeWidth !== void 0) element.setAttribute("stroke-width", String(style.strokeWidth));
958
+ if (style.strokeOpacity !== void 0) element.setAttribute("stroke-opacity", String(style.strokeOpacity));
959
+ if (style.strokeDasharray) element.setAttribute("stroke-dasharray", style.strokeDasharray);
960
+ if (style.strokeLinecap) element.setAttribute("stroke-linecap", style.strokeLinecap);
961
+ if (style.strokeLinejoin) element.setAttribute("stroke-linejoin", style.strokeLinejoin);
962
+ if (style.opacity !== void 0) element.setAttribute("opacity", String(style.opacity));
963
+ }
964
+ function applyTextStyle(element, style) {
965
+ if (style.fontSize) element.setAttribute("font-size", String(style.fontSize));
966
+ if (style.fontFamily) element.setAttribute("font-family", style.fontFamily);
967
+ if (style.fontWeight) element.setAttribute("font-weight", String(style.fontWeight));
968
+ if (style.textAnchor) element.setAttribute("text-anchor", style.textAnchor);
969
+ if (style.dominantBaseline) element.setAttribute("dominant-baseline", style.dominantBaseline);
970
+ }
971
+ function applyTransform(element, matrix) {
972
+ const [a, b, c, d, e, f] = [
973
+ matrix[0],
974
+ matrix[3],
975
+ matrix[1],
976
+ matrix[4],
977
+ matrix[2],
978
+ matrix[5]
979
+ ];
980
+ if (a === 1 && b === 0 && c === 0 && d === 1 && e === 0 && f === 0) {
981
+ return;
982
+ }
983
+ element.setAttribute("transform", `matrix(${a},${b},${c},${d},${e},${f})`);
984
+ }
985
+ function styleToString(style) {
986
+ const parts = [];
987
+ if (style.fill) parts.push(`fill="${style.fill}"`);
988
+ if (style.fillOpacity !== void 0) parts.push(`fill-opacity="${style.fillOpacity}"`);
989
+ if (style.stroke) parts.push(`stroke="${style.stroke}"`);
990
+ if (style.strokeWidth !== void 0) parts.push(`stroke-width="${style.strokeWidth}"`);
991
+ if (style.strokeOpacity !== void 0) parts.push(`stroke-opacity="${style.strokeOpacity}"`);
992
+ if (style.strokeDasharray) parts.push(`stroke-dasharray="${style.strokeDasharray}"`);
993
+ if (style.strokeLinecap) parts.push(`stroke-linecap="${style.strokeLinecap}"`);
994
+ if (style.strokeLinejoin) parts.push(`stroke-linejoin="${style.strokeLinejoin}"`);
995
+ if (style.opacity !== void 0) parts.push(`opacity="${style.opacity}"`);
996
+ return parts.join(" ");
997
+ }
998
+ function textStyleToString(style) {
999
+ const parts = [];
1000
+ if (style.fontSize) parts.push(`font-size="${style.fontSize}"`);
1001
+ if (style.fontFamily) parts.push(`font-family="${style.fontFamily}"`);
1002
+ if (style.fontWeight) parts.push(`font-weight="${style.fontWeight}"`);
1003
+ if (style.textAnchor) parts.push(`text-anchor="${style.textAnchor}"`);
1004
+ if (style.dominantBaseline) parts.push(`dominant-baseline="${style.dominantBaseline}"`);
1005
+ return parts.join(" ");
1006
+ }
1007
+ function transformToString(matrix) {
1008
+ const [a, b, c, d, e, f] = [
1009
+ matrix[0],
1010
+ matrix[3],
1011
+ matrix[1],
1012
+ matrix[4],
1013
+ matrix[2],
1014
+ matrix[5]
1015
+ ];
1016
+ if (a === 1 && b === 0 && c === 0 && d === 1 && e === 0 && f === 0) {
1017
+ return "";
1018
+ }
1019
+ return `matrix(${a},${b},${c},${d},${e},${f})`;
1020
+ }
1021
+ function commandsToPath(commands) {
1022
+ return commands.map((cmd) => {
1023
+ switch (cmd.type) {
1024
+ case "M":
1025
+ return `M${cmd.x},${cmd.y}`;
1026
+ case "L":
1027
+ return `L${cmd.x},${cmd.y}`;
1028
+ case "H":
1029
+ return `H${cmd.x}`;
1030
+ case "V":
1031
+ return `V${cmd.y}`;
1032
+ case "C":
1033
+ return `C${cmd.x1},${cmd.y1} ${cmd.x2},${cmd.y2} ${cmd.x},${cmd.y}`;
1034
+ case "S":
1035
+ return `S${cmd.x2},${cmd.y2} ${cmd.x},${cmd.y}`;
1036
+ case "Q":
1037
+ return `Q${cmd.x1},${cmd.y1} ${cmd.x},${cmd.y}`;
1038
+ case "T":
1039
+ return `T${cmd.x},${cmd.y}`;
1040
+ case "A":
1041
+ return `A${cmd.rx},${cmd.ry} ${cmd.angle} ${cmd.largeArc ? 1 : 0},${cmd.sweep ? 1 : 0} ${cmd.x},${cmd.y}`;
1042
+ case "Z":
1043
+ return "Z";
1044
+ }
1045
+ }).join(" ");
1046
+ }
1047
+ function arcToPath(cx, cy, r, startAngle, endAngle) {
1048
+ const startX = cx + r * Math.cos(startAngle);
1049
+ const startY = cy + r * Math.sin(startAngle);
1050
+ const endX = cx + r * Math.cos(endAngle);
1051
+ const endY = cy + r * Math.sin(endAngle);
1052
+ const largeArc = Math.abs(endAngle - startAngle) > Math.PI ? 1 : 0;
1053
+ const sweep = endAngle > startAngle ? 1 : 0;
1054
+ return `M${startX},${startY} A${r},${r} 0 ${largeArc},${sweep} ${endX},${endY}`;
1055
+ }
1056
+ function escapeXML(str) {
1057
+ return str.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#39;");
1058
+ }
1059
+
1060
+ // src/core/render-rough.ts
1061
+ import rough from "roughjs";
1062
+ var SVG_NS2 = "http://www.w3.org/2000/svg";
1063
+ function renderToRough(diagram, container, options = {}) {
1064
+ const {
1065
+ width = 800,
1066
+ height = 600,
1067
+ background,
1068
+ roughness = 1,
1069
+ bowing = 1,
1070
+ seed,
1071
+ fillStyle = "hachure",
1072
+ fillWeight,
1073
+ hachureAngle,
1074
+ hachureGap
1075
+ } = options;
1076
+ let svg;
1077
+ if (container instanceof SVGSVGElement) {
1078
+ svg = container;
1079
+ } else {
1080
+ svg = document.createElementNS(SVG_NS2, "svg");
1081
+ container.appendChild(svg);
1082
+ }
1083
+ svg.setAttribute("width", String(width));
1084
+ svg.setAttribute("height", String(height));
1085
+ svg.setAttribute("viewBox", `0 0 ${width} ${height}`);
1086
+ while (svg.firstChild) {
1087
+ svg.removeChild(svg.firstChild);
1088
+ }
1089
+ if (background) {
1090
+ const rect2 = document.createElementNS(SVG_NS2, "rect");
1091
+ rect2.setAttribute("width", "100%");
1092
+ rect2.setAttribute("height", "100%");
1093
+ rect2.setAttribute("fill", background);
1094
+ svg.appendChild(rect2);
1095
+ }
1096
+ const rc = rough.svg(svg);
1097
+ const defaultRoughOptions = Object.fromEntries(
1098
+ Object.entries({
1099
+ roughness,
1100
+ bowing,
1101
+ seed,
1102
+ fillStyle,
1103
+ fillWeight,
1104
+ hachureAngle,
1105
+ hachureGap
1106
+ }).filter(([_, v]) => v !== void 0)
1107
+ );
1108
+ renderShapeRough(diagram.shape, svg, rc, defaultRoughOptions);
1109
+ return svg;
1110
+ }
1111
+ function renderShapeRough(shape, svg, rc, defaultOptions) {
1112
+ const g = document.createElementNS(SVG_NS2, "g");
1113
+ g.setAttribute("id", shape.id);
1114
+ applyTransform2(g, shape.transform);
1115
+ svg.appendChild(g);
1116
+ const roughOptions = styleToRoughOptions(shape.style, defaultOptions);
1117
+ switch (shape.type) {
1118
+ case "rect":
1119
+ const rectNode = rc.rectangle(
1120
+ shape.x,
1121
+ shape.y,
1122
+ shape.width,
1123
+ shape.height,
1124
+ roughOptions
1125
+ );
1126
+ g.appendChild(rectNode);
1127
+ break;
1128
+ case "circle":
1129
+ const circleNode = rc.circle(
1130
+ shape.cx,
1131
+ shape.cy,
1132
+ shape.r * 2,
1133
+ roughOptions
1134
+ );
1135
+ g.appendChild(circleNode);
1136
+ break;
1137
+ case "ellipse":
1138
+ const ellipseNode = rc.ellipse(
1139
+ shape.cx,
1140
+ shape.cy,
1141
+ shape.rx * 2,
1142
+ shape.ry * 2,
1143
+ roughOptions
1144
+ );
1145
+ g.appendChild(ellipseNode);
1146
+ break;
1147
+ case "line":
1148
+ const lineNode = rc.line(
1149
+ shape.x1,
1150
+ shape.y1,
1151
+ shape.x2,
1152
+ shape.y2,
1153
+ roughOptions
1154
+ );
1155
+ g.appendChild(lineNode);
1156
+ break;
1157
+ case "polygon":
1158
+ const polygonNode = rc.polygon(
1159
+ shape.points,
1160
+ roughOptions
1161
+ );
1162
+ g.appendChild(polygonNode);
1163
+ break;
1164
+ case "polyline":
1165
+ const polylineNode = rc.linearPath(
1166
+ shape.points,
1167
+ roughOptions
1168
+ );
1169
+ g.appendChild(polylineNode);
1170
+ break;
1171
+ case "path":
1172
+ const pathD = commandsToPath2(shape.commands);
1173
+ const pathNode = rc.path(pathD, roughOptions);
1174
+ g.appendChild(pathNode);
1175
+ break;
1176
+ case "arc":
1177
+ const arcNode = rc.arc(
1178
+ shape.cx,
1179
+ shape.cy,
1180
+ shape.r * 2,
1181
+ shape.r * 2,
1182
+ shape.startAngle,
1183
+ shape.endAngle,
1184
+ false,
1185
+ roughOptions
1186
+ );
1187
+ g.appendChild(arcNode);
1188
+ break;
1189
+ case "text":
1190
+ const textNode = document.createElementNS(SVG_NS2, "text");
1191
+ textNode.setAttribute("x", String(shape.x));
1192
+ textNode.setAttribute("y", String(shape.y));
1193
+ textNode.textContent = shape.content;
1194
+ applyTextStyle2(textNode, shape.style);
1195
+ g.appendChild(textNode);
1196
+ break;
1197
+ case "group":
1198
+ for (const child of shape.children) {
1199
+ renderShapeRough(child, svg, rc, defaultOptions);
1200
+ }
1201
+ if (!g.hasChildNodes()) {
1202
+ svg.removeChild(g);
1203
+ }
1204
+ break;
1205
+ }
1206
+ }
1207
+ function styleToRoughOptions(style, defaults) {
1208
+ const options = __spreadValues({}, defaults);
1209
+ if (style.fill && style.fill !== "none") {
1210
+ options.fill = style.fill;
1211
+ }
1212
+ if (style.stroke && style.stroke !== "none") {
1213
+ options.stroke = style.stroke;
1214
+ } else if (!style.fill || style.fill === "none") {
1215
+ options.stroke = "#374151";
1216
+ }
1217
+ if (style.strokeWidth !== void 0) {
1218
+ options.strokeWidth = style.strokeWidth;
1219
+ }
1220
+ if (style.fillOpacity !== void 0) {
1221
+ options.fillWeight = (options.fillWeight || 1) * style.fillOpacity;
1222
+ }
1223
+ return options;
1224
+ }
1225
+ function applyTransform2(element, matrix) {
1226
+ const [a, b, c, d, e, f] = [
1227
+ matrix[0],
1228
+ matrix[3],
1229
+ matrix[1],
1230
+ matrix[4],
1231
+ matrix[2],
1232
+ matrix[5]
1233
+ ];
1234
+ if (a === 1 && b === 0 && c === 0 && d === 1 && e === 0 && f === 0) {
1235
+ return;
1236
+ }
1237
+ element.setAttribute("transform", `matrix(${a},${b},${c},${d},${e},${f})`);
1238
+ }
1239
+ function applyTextStyle2(element, style) {
1240
+ if (style.fill) element.setAttribute("fill", style.fill);
1241
+ if (style.fontSize) element.setAttribute("font-size", String(style.fontSize));
1242
+ if (style.fontFamily) element.setAttribute("font-family", style.fontFamily);
1243
+ if (style.fontWeight) element.setAttribute("font-weight", String(style.fontWeight));
1244
+ if (style.textAnchor) element.setAttribute("text-anchor", style.textAnchor);
1245
+ if (style.dominantBaseline) element.setAttribute("dominant-baseline", style.dominantBaseline);
1246
+ }
1247
+ function commandsToPath2(commands) {
1248
+ return commands.map((cmd) => {
1249
+ switch (cmd.type) {
1250
+ case "M":
1251
+ return `M${cmd.x},${cmd.y}`;
1252
+ case "L":
1253
+ return `L${cmd.x},${cmd.y}`;
1254
+ case "H":
1255
+ return `H${cmd.x}`;
1256
+ case "V":
1257
+ return `V${cmd.y}`;
1258
+ case "C":
1259
+ return `C${cmd.x1},${cmd.y1} ${cmd.x2},${cmd.y2} ${cmd.x},${cmd.y}`;
1260
+ case "S":
1261
+ return `S${cmd.x2},${cmd.y2} ${cmd.x},${cmd.y}`;
1262
+ case "Q":
1263
+ return `Q${cmd.x1},${cmd.y1} ${cmd.x},${cmd.y}`;
1264
+ case "T":
1265
+ return `T${cmd.x},${cmd.y}`;
1266
+ case "A":
1267
+ return `A${cmd.rx},${cmd.ry} ${cmd.angle} ${cmd.largeArc ? 1 : 0},${cmd.sweep ? 1 : 0} ${cmd.x},${cmd.y}`;
1268
+ case "Z":
1269
+ return "Z";
1270
+ }
1271
+ }).join(" ");
1272
+ }
1273
+ var roughPresets = {
1274
+ /** 默认手绘风格 */
1275
+ default: {
1276
+ roughness: 1,
1277
+ bowing: 1,
1278
+ fillStyle: "hachure"
1279
+ },
1280
+ /** 粉笔风格 */
1281
+ chalk: {
1282
+ roughness: 2,
1283
+ bowing: 1.5,
1284
+ fillStyle: "zigzag",
1285
+ fillWeight: 0.5
1286
+ },
1287
+ /** 钢笔风格 */
1288
+ pen: {
1289
+ roughness: 0.5,
1290
+ bowing: 0.5,
1291
+ fillStyle: "cross-hatch"
1292
+ },
1293
+ /** 铅笔风格 */
1294
+ pencil: {
1295
+ roughness: 1.5,
1296
+ bowing: 1,
1297
+ fillStyle: "hachure",
1298
+ fillWeight: 0.3
1299
+ },
1300
+ /** 马克笔风格 */
1301
+ marker: {
1302
+ roughness: 0.8,
1303
+ bowing: 0.3,
1304
+ fillStyle: "solid",
1305
+ strokeWidth: 3
1306
+ },
1307
+ /** 涂鸦风格 */
1308
+ doodle: {
1309
+ roughness: 3,
1310
+ bowing: 2,
1311
+ fillStyle: "zigzag-line"
1312
+ }
1313
+ };
1314
+
1315
+ // src/animate/types.ts
1316
+ var ValueTracker = class {
1317
+ constructor(initialValue = 0) {
1318
+ this.listeners = /* @__PURE__ */ new Set();
1319
+ this._value = initialValue;
1320
+ }
1321
+ get value() {
1322
+ return this._value;
1323
+ }
1324
+ set value(newValue) {
1325
+ this._value = newValue;
1326
+ this.listeners.forEach((listener) => listener(newValue));
1327
+ }
1328
+ /** 添加变化监听器 */
1329
+ addListener(listener) {
1330
+ this.listeners.add(listener);
1331
+ return () => this.listeners.delete(listener);
1332
+ }
1333
+ /** 创建动画目标对象 */
1334
+ animate(targetValue) {
1335
+ return { value: targetValue };
1336
+ }
1337
+ /** 获取当前值的普通对象(用于 GSAP) */
1338
+ toObject() {
1339
+ return { value: this._value };
1340
+ }
1341
+ };
1342
+
1343
+ // src/animate/scene.ts
1344
+ var Scene = class {
1345
+ constructor(container, config = {}) {
1346
+ this.objects = /* @__PURE__ */ new Map();
1347
+ this.currentTime = 0;
1348
+ var _a, _b, _c, _d, _e;
1349
+ this.container = container;
1350
+ this.config = {
1351
+ width: (_a = config.width) != null ? _a : 800,
1352
+ height: (_b = config.height) != null ? _b : 600,
1353
+ background: (_c = config.background) != null ? _c : "#1a1a2e",
1354
+ fps: (_d = config.fps) != null ? _d : 60,
1355
+ rough: (_e = config.rough) != null ? _e : false
1356
+ };
1357
+ this.svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
1358
+ this.svg.setAttribute("width", String(this.config.width));
1359
+ this.svg.setAttribute("height", String(this.config.height));
1360
+ this.svg.setAttribute("viewBox", `0 0 ${this.config.width} ${this.config.height}`);
1361
+ this.svg.style.background = this.config.background;
1362
+ this.container.appendChild(this.svg);
1363
+ this.timeline = createTimeline();
1364
+ }
1365
+ /**
1366
+ * 添加图形到场景(不带动画)
1367
+ */
1368
+ add(...diagrams) {
1369
+ for (const diagram of diagrams) {
1370
+ this.objects.set(diagram.shape.id, diagram);
1371
+ this.renderDiagram(diagram);
1372
+ }
1373
+ }
1374
+ /**
1375
+ * 从场景移除图形
1376
+ */
1377
+ remove(...diagrams) {
1378
+ for (const diagram of diagrams) {
1379
+ this.objects.delete(diagram.shape.id);
1380
+ const element = this.svg.getElementById(diagram.shape.id);
1381
+ if (element) {
1382
+ element.remove();
1383
+ }
1384
+ }
1385
+ }
1386
+ /**
1387
+ * 播放动画
1388
+ *
1389
+ * @param animations - 要播放的动画
1390
+ * @param config - 动画配置
1391
+ */
1392
+ play(...args) {
1393
+ const animations = [];
1394
+ let config = {};
1395
+ for (const arg of args) {
1396
+ if ("execute" in arg) {
1397
+ animations.push(arg);
1398
+ } else {
1399
+ config = __spreadValues(__spreadValues({}, config), arg);
1400
+ }
1401
+ }
1402
+ const { lagRatio = 0, runTime } = config;
1403
+ if (animations.length === 0) return;
1404
+ for (let i = 0; i < animations.length; i++) {
1405
+ const animation = animations[i];
1406
+ const delay = i * lagRatio * (runTime || animation.duration);
1407
+ animation.execute(this, this.timeline, this.currentTime + delay);
1408
+ }
1409
+ const maxDuration = Math.max(...animations.map((a) => a.duration));
1410
+ this.currentTime += maxDuration + lagRatio * maxDuration * (animations.length - 1);
1411
+ }
1412
+ /**
1413
+ * 等待指定时间
1414
+ */
1415
+ wait(seconds = 1) {
1416
+ this.currentTime += seconds;
1417
+ }
1418
+ /**
1419
+ * 运行场景
1420
+ */
1421
+ async render() {
1422
+ this.construct();
1423
+ this.timeline.play();
1424
+ await this.timeline.finished();
1425
+ }
1426
+ /**
1427
+ * 渲染单个图形到 SVG
1428
+ */
1429
+ renderDiagram(diagram) {
1430
+ const tempSvg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
1431
+ renderToSVG(diagram, tempSvg, {
1432
+ width: this.config.width,
1433
+ height: this.config.height
1434
+ });
1435
+ const element = tempSvg.querySelector(`#${diagram.shape.id}`);
1436
+ if (element) {
1437
+ this.svg.appendChild(element.cloneNode(true));
1438
+ return this.svg.getElementById(diagram.shape.id);
1439
+ }
1440
+ return null;
1441
+ }
1442
+ /**
1443
+ * 获取图形对应的 SVG 元素
1444
+ */
1445
+ getElement(diagram) {
1446
+ return this.svg.getElementById(diagram.shape.id);
1447
+ }
1448
+ /**
1449
+ * 获取或创建图形元素
1450
+ */
1451
+ getOrCreateElement(diagram) {
1452
+ let element = this.getElement(diagram);
1453
+ if (!element) {
1454
+ element = this.renderDiagram(diagram);
1455
+ }
1456
+ return element;
1457
+ }
1458
+ /**
1459
+ * 获取 SVG 容器
1460
+ */
1461
+ getSVG() {
1462
+ return this.svg;
1463
+ }
1464
+ /**
1465
+ * 获取配置
1466
+ */
1467
+ getConfig() {
1468
+ return this.config;
1469
+ }
1470
+ /**
1471
+ * 导出为 SVG 字符串
1472
+ */
1473
+ toSVGString() {
1474
+ return this.svg.outerHTML;
1475
+ }
1476
+ /**
1477
+ * 暂停
1478
+ */
1479
+ pause() {
1480
+ this.timeline.pause();
1481
+ }
1482
+ /**
1483
+ * 恢复
1484
+ */
1485
+ resume() {
1486
+ this.timeline.resume();
1487
+ }
1488
+ /**
1489
+ * 重新开始
1490
+ */
1491
+ restart() {
1492
+ this.timeline.restart();
1493
+ }
1494
+ /**
1495
+ * 销毁场景
1496
+ */
1497
+ destroy() {
1498
+ this.timeline.kill();
1499
+ this.svg.remove();
1500
+ this.objects.clear();
1501
+ }
1502
+ };
1503
+ function createScene(container, buildFn, config) {
1504
+ const scene = new SimpleScene(container, buildFn, config);
1505
+ return scene;
1506
+ }
1507
+ var SimpleScene = class extends Scene {
1508
+ constructor(container, buildFn, config) {
1509
+ super(container, config);
1510
+ this.buildFn = buildFn;
1511
+ }
1512
+ construct() {
1513
+ this.buildFn(this);
1514
+ }
1515
+ };
1516
+
1517
+ // src/animate/animations/create.ts
1518
+ import { gsap } from "gsap";
1519
+ function Create(target, options = {}) {
1520
+ const { duration = 1, easing: easing2 = "easeInOut", delay = 0 } = options;
1521
+ return {
1522
+ duration,
1523
+ target,
1524
+ execute(scene, timeline, startTime) {
1525
+ const element = scene.getOrCreateElement(target);
1526
+ if (!element) return;
1527
+ const paths = element.querySelectorAll("path, line, polyline, polygon, circle, ellipse, rect");
1528
+ paths.forEach((path2) => {
1529
+ if (path2 instanceof SVGGeometryElement) {
1530
+ const length2 = path2.getTotalLength();
1531
+ gsap.set(path2, {
1532
+ strokeDasharray: length2,
1533
+ strokeDashoffset: length2,
1534
+ fillOpacity: 0
1535
+ });
1536
+ timeline.add(path2, {
1537
+ strokeDashoffset: 0,
1538
+ duration,
1539
+ ease: getGSAPEasing(easing2),
1540
+ delay
1541
+ }, startTime);
1542
+ const fill = path2.getAttribute("fill");
1543
+ if (fill && fill !== "none") {
1544
+ timeline.add(path2, {
1545
+ fillOpacity: 1,
1546
+ duration: duration * 0.3,
1547
+ ease: "power2.out"
1548
+ }, startTime + duration);
1549
+ }
1550
+ }
1551
+ });
1552
+ const texts = element.querySelectorAll("text");
1553
+ texts.forEach((text2) => {
1554
+ gsap.set(text2, { opacity: 0 });
1555
+ timeline.add(text2, {
1556
+ opacity: 1,
1557
+ duration: duration * 0.5,
1558
+ ease: "power2.out"
1559
+ }, startTime + duration * 0.5);
1560
+ });
1561
+ }
1562
+ };
1563
+ }
1564
+ function Write(target, options = {}) {
1565
+ const { duration = 1, easing: easing2 = "easeOut", delay = 0 } = options;
1566
+ return {
1567
+ duration,
1568
+ target,
1569
+ execute(scene, timeline, startTime) {
1570
+ const element = scene.getOrCreateElement(target);
1571
+ if (!element) return;
1572
+ const texts = element.querySelectorAll("text");
1573
+ if (texts.length > 0) {
1574
+ texts.forEach((text2) => {
1575
+ const content = text2.textContent || "";
1576
+ const chars = content.split("");
1577
+ text2.textContent = "";
1578
+ chars.forEach((char, i) => {
1579
+ const tspan = document.createElementNS("http://www.w3.org/2000/svg", "tspan");
1580
+ tspan.textContent = char;
1581
+ gsap.set(tspan, { opacity: 0 });
1582
+ text2.appendChild(tspan);
1583
+ const charDelay = i / chars.length * duration;
1584
+ timeline.add(tspan, {
1585
+ opacity: 1,
1586
+ duration: duration / chars.length,
1587
+ ease: getGSAPEasing(easing2)
1588
+ }, startTime + delay + charDelay);
1589
+ });
1590
+ });
1591
+ } else {
1592
+ return Create(target, options).execute(scene, timeline, startTime);
1593
+ }
1594
+ }
1595
+ };
1596
+ }
1597
+ function DrawBorderThenFill(target, options = {}) {
1598
+ const { duration = 1.5, easing: easing2 = "easeInOut", delay = 0 } = options;
1599
+ return {
1600
+ duration,
1601
+ target,
1602
+ execute(scene, timeline, startTime) {
1603
+ const element = scene.getOrCreateElement(target);
1604
+ if (!element) return;
1605
+ const paths = element.querySelectorAll("path, line, polyline, polygon, circle, ellipse, rect");
1606
+ paths.forEach((path2) => {
1607
+ if (path2 instanceof SVGGeometryElement) {
1608
+ const length2 = path2.getTotalLength();
1609
+ const originalFill = path2.getAttribute("fill") || "none";
1610
+ const originalStroke = path2.getAttribute("stroke") || "#374151";
1611
+ gsap.set(path2, {
1612
+ strokeDasharray: length2,
1613
+ strokeDashoffset: length2,
1614
+ fill: "none",
1615
+ stroke: originalStroke,
1616
+ strokeWidth: path2.getAttribute("stroke-width") || 2
1617
+ });
1618
+ const borderDuration = duration * 0.6;
1619
+ timeline.add(path2, {
1620
+ strokeDashoffset: 0,
1621
+ duration: borderDuration,
1622
+ ease: getGSAPEasing(easing2)
1623
+ }, startTime + delay);
1624
+ if (originalFill && originalFill !== "none") {
1625
+ const fillDuration = duration * 0.4;
1626
+ timeline.add(path2, {
1627
+ fill: originalFill,
1628
+ fillOpacity: 1,
1629
+ duration: fillDuration,
1630
+ ease: "power2.out"
1631
+ }, startTime + delay + borderDuration);
1632
+ }
1633
+ }
1634
+ });
1635
+ }
1636
+ };
1637
+ }
1638
+ function GrowFromCenter(target, options = {}) {
1639
+ const { duration = 0.5, easing: easing2 = "easeOutBack", delay = 0 } = options;
1640
+ return {
1641
+ duration,
1642
+ target,
1643
+ execute(scene, timeline, startTime) {
1644
+ var _a;
1645
+ const element = scene.getOrCreateElement(target);
1646
+ if (!element) return;
1647
+ const bbox = ((_a = element.getBBox) == null ? void 0 : _a.call(element)) || { x: 0, y: 0, width: 0, height: 0 };
1648
+ const cx = bbox.x + bbox.width / 2;
1649
+ const cy = bbox.y + bbox.height / 2;
1650
+ gsap.set(element, {
1651
+ transformOrigin: `${cx}px ${cy}px`,
1652
+ scale: 0,
1653
+ opacity: 0
1654
+ });
1655
+ timeline.add(element, {
1656
+ scale: 1,
1657
+ opacity: 1,
1658
+ duration,
1659
+ ease: getGSAPEasing(easing2),
1660
+ delay
1661
+ }, startTime);
1662
+ }
1663
+ };
1664
+ }
1665
+ function GrowFromPoint(target, point, options = {}) {
1666
+ const { duration = 0.5, easing: easing2 = "easeOutBack", delay = 0 } = options;
1667
+ return {
1668
+ duration,
1669
+ target,
1670
+ execute(scene, timeline, startTime) {
1671
+ const element = scene.getOrCreateElement(target);
1672
+ if (!element) return;
1673
+ gsap.set(element, {
1674
+ transformOrigin: `${point[0]}px ${point[1]}px`,
1675
+ scale: 0,
1676
+ opacity: 0
1677
+ });
1678
+ timeline.add(element, {
1679
+ scale: 1,
1680
+ opacity: 1,
1681
+ duration,
1682
+ ease: getGSAPEasing(easing2),
1683
+ delay
1684
+ }, startTime);
1685
+ }
1686
+ };
1687
+ }
1688
+ function GrowFromEdge(target, edge = "LEFT", options = {}) {
1689
+ const { duration = 0.5, easing: easing2 = "easeOut", delay = 0 } = options;
1690
+ return {
1691
+ duration,
1692
+ target,
1693
+ execute(scene, timeline, startTime) {
1694
+ var _a;
1695
+ const element = scene.getOrCreateElement(target);
1696
+ if (!element) return;
1697
+ const bbox = ((_a = element.getBBox) == null ? void 0 : _a.call(element)) || { x: 0, y: 0, width: 0, height: 0 };
1698
+ let origin;
1699
+ let scaleFrom;
1700
+ switch (edge) {
1701
+ case "LEFT":
1702
+ origin = `${bbox.x}px ${bbox.y + bbox.height / 2}px`;
1703
+ scaleFrom = { scaleX: 0 };
1704
+ break;
1705
+ case "RIGHT":
1706
+ origin = `${bbox.x + bbox.width}px ${bbox.y + bbox.height / 2}px`;
1707
+ scaleFrom = { scaleX: 0 };
1708
+ break;
1709
+ case "TOP":
1710
+ origin = `${bbox.x + bbox.width / 2}px ${bbox.y}px`;
1711
+ scaleFrom = { scaleY: 0 };
1712
+ break;
1713
+ case "BOTTOM":
1714
+ origin = `${bbox.x + bbox.width / 2}px ${bbox.y + bbox.height}px`;
1715
+ scaleFrom = { scaleY: 0 };
1716
+ break;
1717
+ }
1718
+ gsap.set(element, __spreadProps(__spreadValues({
1719
+ transformOrigin: origin
1720
+ }, scaleFrom), {
1721
+ opacity: 0
1722
+ }));
1723
+ timeline.add(element, {
1724
+ scaleX: 1,
1725
+ scaleY: 1,
1726
+ opacity: 1,
1727
+ duration,
1728
+ ease: getGSAPEasing(easing2),
1729
+ delay
1730
+ }, startTime);
1731
+ }
1732
+ };
1733
+ }
1734
+ function SpinInFromNothing(target, options = {}) {
1735
+ const { duration = 0.8, easing: easing2 = "easeOut", delay = 0 } = options;
1736
+ return {
1737
+ duration,
1738
+ target,
1739
+ execute(scene, timeline, startTime) {
1740
+ var _a;
1741
+ const element = scene.getOrCreateElement(target);
1742
+ if (!element) return;
1743
+ const bbox = ((_a = element.getBBox) == null ? void 0 : _a.call(element)) || { x: 0, y: 0, width: 0, height: 0 };
1744
+ const cx = bbox.x + bbox.width / 2;
1745
+ const cy = bbox.y + bbox.height / 2;
1746
+ gsap.set(element, {
1747
+ transformOrigin: `${cx}px ${cy}px`,
1748
+ scale: 0,
1749
+ rotation: -360,
1750
+ opacity: 0
1751
+ });
1752
+ timeline.add(element, {
1753
+ scale: 1,
1754
+ rotation: 0,
1755
+ opacity: 1,
1756
+ duration,
1757
+ ease: getGSAPEasing(easing2),
1758
+ delay
1759
+ }, startTime);
1760
+ }
1761
+ };
1762
+ }
1763
+
1764
+ // src/animate/animations/fade.ts
1765
+ import { gsap as gsap2 } from "gsap";
1766
+ function directionToVector(direction) {
1767
+ if (!direction) return void 0;
1768
+ if (Array.isArray(direction)) return direction;
1769
+ switch (direction) {
1770
+ case "UP":
1771
+ return UP;
1772
+ case "DOWN":
1773
+ return DOWN;
1774
+ case "LEFT":
1775
+ return LEFT;
1776
+ case "RIGHT":
1777
+ return RIGHT;
1778
+ }
1779
+ }
1780
+ function FadeIn(target, options = {}) {
1781
+ const { duration = 0.5, easing: easing2 = "easeOut", delay = 0, direction, shift = 50 } = options;
1782
+ const dir = directionToVector(direction);
1783
+ return {
1784
+ duration,
1785
+ target,
1786
+ execute(scene, timeline, startTime) {
1787
+ const element = scene.getOrCreateElement(target);
1788
+ if (!element) return;
1789
+ const initialState = { opacity: 0 };
1790
+ if (dir) {
1791
+ initialState.x = -dir[0] * shift;
1792
+ initialState.y = -dir[1] * shift;
1793
+ }
1794
+ gsap2.set(element, initialState);
1795
+ timeline.add(element, {
1796
+ opacity: 1,
1797
+ x: 0,
1798
+ y: 0,
1799
+ duration,
1800
+ ease: getGSAPEasing(easing2),
1801
+ delay
1802
+ }, startTime);
1803
+ }
1804
+ };
1805
+ }
1806
+ function FadeOut(target, options = {}) {
1807
+ const { duration = 0.5, easing: easing2 = "easeIn", delay = 0, direction, shift = 50 } = options;
1808
+ const dir = directionToVector(direction);
1809
+ return {
1810
+ duration,
1811
+ target,
1812
+ execute(scene, timeline, startTime) {
1813
+ const element = scene.getElement(target);
1814
+ if (!element) return;
1815
+ const targetState = {
1816
+ opacity: 0,
1817
+ duration,
1818
+ ease: getGSAPEasing(easing2),
1819
+ delay,
1820
+ onComplete: () => {
1821
+ element.remove();
1822
+ }
1823
+ };
1824
+ if (dir) {
1825
+ targetState.x = dir[0] * shift;
1826
+ targetState.y = dir[1] * shift;
1827
+ }
1828
+ timeline.add(element, targetState, startTime);
1829
+ }
1830
+ };
1831
+ }
1832
+ function FadeInFrom(target, direction, options = {}) {
1833
+ return FadeIn(target, __spreadProps(__spreadValues({}, options), { direction }));
1834
+ }
1835
+ function FadeOutTo(target, direction, options = {}) {
1836
+ return FadeOut(target, __spreadProps(__spreadValues({}, options), { direction }));
1837
+ }
1838
+ function FadeInFromDown(target, options = {}) {
1839
+ return FadeIn(target, __spreadProps(__spreadValues({}, options), { direction: "DOWN" }));
1840
+ }
1841
+ function FadeInFromUp(target, options = {}) {
1842
+ return FadeIn(target, __spreadProps(__spreadValues({}, options), { direction: "UP" }));
1843
+ }
1844
+ function FadeInFromLeft(target, options = {}) {
1845
+ return FadeIn(target, __spreadProps(__spreadValues({}, options), { direction: "LEFT" }));
1846
+ }
1847
+ function FadeInFromRight(target, options = {}) {
1848
+ return FadeIn(target, __spreadProps(__spreadValues({}, options), { direction: "RIGHT" }));
1849
+ }
1850
+ function FadeTransform(source, target, options = {}) {
1851
+ const { duration = 0.5, easing: easing2 = "easeInOut", delay = 0 } = options;
1852
+ return {
1853
+ duration,
1854
+ target: source,
1855
+ execute(scene, timeline, startTime) {
1856
+ const sourceElement = scene.getElement(source);
1857
+ const targetElement = scene.getOrCreateElement(target);
1858
+ if (!sourceElement || !targetElement) return;
1859
+ gsap2.set(targetElement, { opacity: 0 });
1860
+ timeline.add(sourceElement, {
1861
+ opacity: 0,
1862
+ duration,
1863
+ ease: getGSAPEasing(easing2),
1864
+ delay,
1865
+ onComplete: () => {
1866
+ sourceElement.remove();
1867
+ }
1868
+ }, startTime);
1869
+ timeline.add(targetElement, {
1870
+ opacity: 1,
1871
+ duration,
1872
+ ease: getGSAPEasing(easing2),
1873
+ delay
1874
+ }, startTime);
1875
+ }
1876
+ };
1877
+ }
1878
+
1879
+ // src/animate/animations/move.ts
1880
+ import { gsap as gsap3 } from "gsap";
1881
+ import { MotionPathPlugin } from "gsap/MotionPathPlugin";
1882
+ if (typeof window !== "undefined") {
1883
+ gsap3.registerPlugin(MotionPathPlugin);
1884
+ }
1885
+ function Shift(target, offset, options = {}) {
1886
+ const { duration = 0.5, easing: easing2 = "easeInOut", delay = 0 } = options;
1887
+ return {
1888
+ duration,
1889
+ target,
1890
+ execute(scene, timeline, startTime) {
1891
+ const element = scene.getElement(target);
1892
+ if (!element) return;
1893
+ timeline.add(element, {
1894
+ x: `+=${offset[0]}`,
1895
+ y: `+=${offset[1]}`,
1896
+ duration,
1897
+ ease: getGSAPEasing(easing2),
1898
+ delay
1899
+ }, startTime);
1900
+ }
1901
+ };
1902
+ }
1903
+ function MoveTo(target, position, options = {}) {
1904
+ const { duration = 0.5, easing: easing2 = "easeInOut", delay = 0 } = options;
1905
+ return {
1906
+ duration,
1907
+ target,
1908
+ execute(scene, timeline, startTime) {
1909
+ var _a;
1910
+ const element = scene.getElement(target);
1911
+ if (!element) return;
1912
+ const bbox = ((_a = element.getBBox) == null ? void 0 : _a.call(element)) || { x: 0, y: 0, width: 0, height: 0 };
1913
+ const currentCenter = [bbox.x + bbox.width / 2, bbox.y + bbox.height / 2];
1914
+ const offsetX = position[0] - currentCenter[0];
1915
+ const offsetY = position[1] - currentCenter[1];
1916
+ timeline.add(element, {
1917
+ x: `+=${offsetX}`,
1918
+ y: `+=${offsetY}`,
1919
+ duration,
1920
+ ease: getGSAPEasing(easing2),
1921
+ delay
1922
+ }, startTime);
1923
+ }
1924
+ };
1925
+ }
1926
+ function MoveAlongPath(target, path2, options = {}) {
1927
+ const { duration = 2, easing: easing2 = "linear", delay = 0, rotateAlongPath = false } = options;
1928
+ return {
1929
+ duration,
1930
+ target,
1931
+ execute(scene, timeline, startTime) {
1932
+ const element = scene.getElement(target);
1933
+ if (!element) return;
1934
+ let pathData;
1935
+ if (typeof path2 === "string") {
1936
+ pathData = path2;
1937
+ } else {
1938
+ const pathElement = scene.getOrCreateElement(path2);
1939
+ const pathNode = pathElement.querySelector("path") || pathElement.querySelector("circle") || pathElement.querySelector("ellipse") || pathElement;
1940
+ if (pathNode instanceof SVGGeometryElement) {
1941
+ if (pathNode instanceof SVGCircleElement) {
1942
+ const cx = parseFloat(pathNode.getAttribute("cx") || "0");
1943
+ const cy = parseFloat(pathNode.getAttribute("cy") || "0");
1944
+ const r = parseFloat(pathNode.getAttribute("r") || "0");
1945
+ pathData = circleToPath(cx, cy, r);
1946
+ } else if (pathNode instanceof SVGEllipseElement) {
1947
+ const cx = parseFloat(pathNode.getAttribute("cx") || "0");
1948
+ const cy = parseFloat(pathNode.getAttribute("cy") || "0");
1949
+ const rx = parseFloat(pathNode.getAttribute("rx") || "0");
1950
+ const ry = parseFloat(pathNode.getAttribute("ry") || "0");
1951
+ pathData = ellipseToPath(cx, cy, rx, ry);
1952
+ } else {
1953
+ pathData = pathNode.getAttribute("d") || "";
1954
+ }
1955
+ } else {
1956
+ console.warn("MoveAlongPath: \u65E0\u6CD5\u83B7\u53D6\u8DEF\u5F84\u6570\u636E");
1957
+ return;
1958
+ }
1959
+ gsap3.set(pathElement, { opacity: 0 });
1960
+ }
1961
+ timeline.add(element, {
1962
+ motionPath: {
1963
+ path: pathData,
1964
+ align: "self",
1965
+ autoRotate: rotateAlongPath,
1966
+ alignOrigin: [0.5, 0.5]
1967
+ },
1968
+ duration,
1969
+ ease: getGSAPEasing(easing2),
1970
+ delay
1971
+ }, startTime);
1972
+ }
1973
+ };
1974
+ }
1975
+ function Rotate(target, angle2, options = {}) {
1976
+ const { duration = 0.5, easing: easing2 = "easeInOut", delay = 0, aboutPoint } = options;
1977
+ return {
1978
+ duration,
1979
+ target,
1980
+ execute(scene, timeline, startTime) {
1981
+ var _a;
1982
+ const element = scene.getElement(target);
1983
+ if (!element) return;
1984
+ if (aboutPoint) {
1985
+ gsap3.set(element, {
1986
+ transformOrigin: `${aboutPoint[0]}px ${aboutPoint[1]}px`
1987
+ });
1988
+ } else {
1989
+ const bbox = ((_a = element.getBBox) == null ? void 0 : _a.call(element)) || { x: 0, y: 0, width: 0, height: 0 };
1990
+ gsap3.set(element, {
1991
+ transformOrigin: `${bbox.x + bbox.width / 2}px ${bbox.y + bbox.height / 2}px`
1992
+ });
1993
+ }
1994
+ const degrees = angle2 * (180 / Math.PI);
1995
+ timeline.add(element, {
1996
+ rotation: `+=${degrees}`,
1997
+ duration,
1998
+ ease: getGSAPEasing(easing2),
1999
+ delay
2000
+ }, startTime);
2001
+ }
2002
+ };
2003
+ }
2004
+ function Rotating(target, options = {}) {
2005
+ const {
2006
+ duration = 2,
2007
+ easing: easing2 = "linear",
2008
+ delay = 0,
2009
+ angularVelocity = Math.PI,
2010
+ aboutPoint
2011
+ } = options;
2012
+ const totalAngle = angularVelocity * duration;
2013
+ const rotateOptions = { duration, easing: easing2, delay };
2014
+ if (aboutPoint) rotateOptions.aboutPoint = aboutPoint;
2015
+ return Rotate(target, totalAngle, rotateOptions);
2016
+ }
2017
+ function Scale(target, factor, options = {}) {
2018
+ const { duration = 0.5, easing: easing2 = "easeInOut", delay = 0, aboutPoint } = options;
2019
+ const [scaleX, scaleY] = Array.isArray(factor) ? factor : [factor, factor];
2020
+ return {
2021
+ duration,
2022
+ target,
2023
+ execute(scene, timeline, startTime) {
2024
+ var _a;
2025
+ const element = scene.getElement(target);
2026
+ if (!element) return;
2027
+ if (aboutPoint) {
2028
+ gsap3.set(element, {
2029
+ transformOrigin: `${aboutPoint[0]}px ${aboutPoint[1]}px`
2030
+ });
2031
+ } else {
2032
+ const bbox = ((_a = element.getBBox) == null ? void 0 : _a.call(element)) || { x: 0, y: 0, width: 0, height: 0 };
2033
+ gsap3.set(element, {
2034
+ transformOrigin: `${bbox.x + bbox.width / 2}px ${bbox.y + bbox.height / 2}px`
2035
+ });
2036
+ }
2037
+ timeline.add(element, {
2038
+ scaleX,
2039
+ scaleY,
2040
+ duration,
2041
+ ease: getGSAPEasing(easing2),
2042
+ delay
2043
+ }, startTime);
2044
+ }
2045
+ };
2046
+ }
2047
+ function ScaleInPlace(target, factor, options = {}) {
2048
+ return Scale(target, factor, options);
2049
+ }
2050
+ function circleToPath(cx, cy, r) {
2051
+ return `M ${cx - r},${cy} A ${r},${r} 0 1,0 ${cx + r},${cy} A ${r},${r} 0 1,0 ${cx - r},${cy}`;
2052
+ }
2053
+ function ellipseToPath(cx, cy, rx, ry) {
2054
+ return `M ${cx - rx},${cy} A ${rx},${ry} 0 1,0 ${cx + rx},${cy} A ${rx},${ry} 0 1,0 ${cx - rx},${cy}`;
2055
+ }
2056
+
2057
+ // src/animate/animations/indicate.ts
2058
+ import { gsap as gsap4 } from "gsap";
2059
+ function Indicate(target, options = {}) {
2060
+ const {
2061
+ duration = 0.5,
2062
+ easing: easing2 = "easeInOut",
2063
+ delay = 0,
2064
+ color = "#FBBF24",
2065
+ // amber-400
2066
+ scaleFactor = 1.2
2067
+ } = options;
2068
+ return {
2069
+ duration,
2070
+ target,
2071
+ execute(scene, timeline, startTime) {
2072
+ var _a, _b, _c;
2073
+ const element = scene.getElement(target);
2074
+ if (!element) return;
2075
+ const originalFill = (_a = element.getAttribute("fill")) != null ? _a : "";
2076
+ const originalStroke = (_b = element.getAttribute("stroke")) != null ? _b : "";
2077
+ const bbox = ((_c = element.getBBox) == null ? void 0 : _c.call(element)) || { x: 0, y: 0, width: 0, height: 0 };
2078
+ gsap4.set(element, {
2079
+ transformOrigin: `${bbox.x + bbox.width / 2}px ${bbox.y + bbox.height / 2}px`
2080
+ });
2081
+ timeline.add(element, {
2082
+ scale: scaleFactor,
2083
+ fill: color,
2084
+ stroke: color,
2085
+ duration: duration / 2,
2086
+ ease: getGSAPEasing(easing2),
2087
+ delay
2088
+ }, startTime);
2089
+ timeline.add(element, {
2090
+ scale: 1,
2091
+ fill: originalFill,
2092
+ stroke: originalStroke,
2093
+ duration: duration / 2,
2094
+ ease: getGSAPEasing(easing2)
2095
+ }, startTime + duration / 2);
2096
+ }
2097
+ };
2098
+ }
2099
+ function Circumscribe(target, options = {}) {
2100
+ const {
2101
+ duration = 1,
2102
+ easing: easing2 = "easeInOut",
2103
+ delay = 0,
2104
+ shape = "rectangle",
2105
+ color = "#EA580C",
2106
+ strokeWidth = 3,
2107
+ fill = false,
2108
+ fillOpacity = 0.2
2109
+ } = options;
2110
+ return {
2111
+ duration,
2112
+ target,
2113
+ execute(scene, timeline, startTime) {
2114
+ var _a;
2115
+ const element = scene.getElement(target);
2116
+ if (!element) return;
2117
+ const svg = scene.getSVG();
2118
+ const bbox = ((_a = element.getBBox) == null ? void 0 : _a.call(element)) || { x: 0, y: 0, width: 0, height: 0 };
2119
+ const padding = 10;
2120
+ let circumscribeElement;
2121
+ if (shape === "circle") {
2122
+ const cx = bbox.x + bbox.width / 2;
2123
+ const cy = bbox.y + bbox.height / 2;
2124
+ const r = Math.max(bbox.width, bbox.height) / 2 + padding;
2125
+ circumscribeElement = document.createElementNS("http://www.w3.org/2000/svg", "circle");
2126
+ circumscribeElement.setAttribute("cx", String(cx));
2127
+ circumscribeElement.setAttribute("cy", String(cy));
2128
+ circumscribeElement.setAttribute("r", String(r));
2129
+ } else {
2130
+ circumscribeElement = document.createElementNS("http://www.w3.org/2000/svg", "rect");
2131
+ circumscribeElement.setAttribute("x", String(bbox.x - padding));
2132
+ circumscribeElement.setAttribute("y", String(bbox.y - padding));
2133
+ circumscribeElement.setAttribute("width", String(bbox.width + padding * 2));
2134
+ circumscribeElement.setAttribute("height", String(bbox.height + padding * 2));
2135
+ circumscribeElement.setAttribute("rx", "4");
2136
+ }
2137
+ circumscribeElement.setAttribute("fill", fill ? color : "none");
2138
+ circumscribeElement.setAttribute("fill-opacity", String(fillOpacity));
2139
+ circumscribeElement.setAttribute("stroke", color);
2140
+ circumscribeElement.setAttribute("stroke-width", String(strokeWidth));
2141
+ const length2 = circumscribeElement instanceof SVGGeometryElement ? circumscribeElement.getTotalLength() : shape === "circle" ? Math.PI * 2 * parseFloat(circumscribeElement.getAttribute("r") || "0") : (bbox.width + bbox.height + padding * 4) * 2;
2142
+ gsap4.set(circumscribeElement, {
2143
+ strokeDasharray: length2,
2144
+ strokeDashoffset: length2,
2145
+ opacity: 0
2146
+ });
2147
+ svg.appendChild(circumscribeElement);
2148
+ timeline.add(circumscribeElement, {
2149
+ opacity: 1,
2150
+ strokeDashoffset: 0,
2151
+ duration: duration * 0.6,
2152
+ ease: getGSAPEasing(easing2),
2153
+ delay
2154
+ }, startTime);
2155
+ timeline.add(circumscribeElement, {
2156
+ opacity: 0,
2157
+ duration: duration * 0.4,
2158
+ ease: "power2.in",
2159
+ onComplete: () => {
2160
+ circumscribeElement.remove();
2161
+ }
2162
+ }, startTime + duration * 0.6);
2163
+ }
2164
+ };
2165
+ }
2166
+ function Wiggle(target, options = {}) {
2167
+ const {
2168
+ duration = 0.5,
2169
+ delay = 0,
2170
+ nWiggles = 6,
2171
+ scaleValue = 1.1,
2172
+ rotationAngle = 0.02 * Math.PI
2173
+ } = options;
2174
+ return {
2175
+ duration,
2176
+ target,
2177
+ execute(scene, timeline, startTime) {
2178
+ var _a;
2179
+ const element = scene.getElement(target);
2180
+ if (!element) return;
2181
+ const bbox = ((_a = element.getBBox) == null ? void 0 : _a.call(element)) || { x: 0, y: 0, width: 0, height: 0 };
2182
+ gsap4.set(element, {
2183
+ transformOrigin: `${bbox.x + bbox.width / 2}px ${bbox.y + bbox.height / 2}px`
2184
+ });
2185
+ const wiggleDuration = duration / nWiggles;
2186
+ const rotationDegrees = rotationAngle * (180 / Math.PI);
2187
+ for (let i = 0; i < nWiggles; i++) {
2188
+ const direction = i % 2 === 0 ? 1 : -1;
2189
+ const progress = i / nWiggles;
2190
+ const dampening = 1 - progress * 0.5;
2191
+ timeline.add(element, {
2192
+ rotation: rotationDegrees * direction * dampening,
2193
+ scale: 1 + (scaleValue - 1) * dampening * 0.5,
2194
+ duration: wiggleDuration,
2195
+ ease: "sine.inOut"
2196
+ }, startTime + delay + i * wiggleDuration);
2197
+ }
2198
+ timeline.add(element, {
2199
+ rotation: 0,
2200
+ scale: 1,
2201
+ duration: wiggleDuration,
2202
+ ease: "sine.out"
2203
+ }, startTime + delay + duration);
2204
+ }
2205
+ };
2206
+ }
2207
+ function Flash(target, options = {}) {
2208
+ const {
2209
+ duration = 0.5,
2210
+ delay = 0,
2211
+ color = "#FBBF24",
2212
+ lineLength = 30,
2213
+ numLines = 12
2214
+ } = options;
2215
+ return {
2216
+ duration,
2217
+ target,
2218
+ execute(scene, timeline, startTime) {
2219
+ var _a;
2220
+ const element = scene.getElement(target);
2221
+ if (!element) return;
2222
+ const svg = scene.getSVG();
2223
+ const bbox = ((_a = element.getBBox) == null ? void 0 : _a.call(element)) || { x: 0, y: 0, width: 0, height: 0 };
2224
+ const cx = bbox.x + bbox.width / 2;
2225
+ const cy = bbox.y + bbox.height / 2;
2226
+ const innerRadius = Math.max(bbox.width, bbox.height) / 2 + 5;
2227
+ const flashGroup = document.createElementNS("http://www.w3.org/2000/svg", "g");
2228
+ flashGroup.setAttribute("id", `flash_${Date.now()}`);
2229
+ svg.appendChild(flashGroup);
2230
+ for (let i = 0; i < numLines; i++) {
2231
+ const angle2 = i / numLines * Math.PI * 2;
2232
+ const x1 = cx + innerRadius * Math.cos(angle2);
2233
+ const y1 = cy + innerRadius * Math.sin(angle2);
2234
+ const x2 = cx + (innerRadius + lineLength) * Math.cos(angle2);
2235
+ const y2 = cy + (innerRadius + lineLength) * Math.sin(angle2);
2236
+ const line2 = document.createElementNS("http://www.w3.org/2000/svg", "line");
2237
+ line2.setAttribute("x1", String(x1));
2238
+ line2.setAttribute("y1", String(y1));
2239
+ line2.setAttribute("x2", String(x1));
2240
+ line2.setAttribute("y2", String(y1));
2241
+ line2.setAttribute("stroke", color);
2242
+ line2.setAttribute("stroke-width", "2");
2243
+ line2.setAttribute("stroke-linecap", "round");
2244
+ gsap4.set(line2, { opacity: 0 });
2245
+ flashGroup.appendChild(line2);
2246
+ timeline.add(line2, {
2247
+ attr: { x2, y2 },
2248
+ opacity: 1,
2249
+ duration: duration * 0.4,
2250
+ ease: "power2.out",
2251
+ delay: delay + i / numLines * duration * 0.1
2252
+ }, startTime);
2253
+ timeline.add(line2, {
2254
+ opacity: 0,
2255
+ duration: duration * 0.4,
2256
+ ease: "power2.in"
2257
+ }, startTime + duration * 0.5);
2258
+ }
2259
+ timeline.call(() => {
2260
+ flashGroup.remove();
2261
+ }, startTime + duration);
2262
+ }
2263
+ };
2264
+ }
2265
+ function ShowPassingFlash(target, options = {}) {
2266
+ const {
2267
+ duration = 1,
2268
+ easing: easing2 = "easeInOut",
2269
+ delay = 0,
2270
+ color = "#FBBF24"
2271
+ } = options;
2272
+ return {
2273
+ duration,
2274
+ target,
2275
+ execute(scene, timeline, startTime) {
2276
+ const element = scene.getElement(target);
2277
+ if (!element) return;
2278
+ const paths = element.querySelectorAll("path, line, polyline, polygon");
2279
+ paths.forEach((path2) => {
2280
+ var _a;
2281
+ if (path2 instanceof SVGGeometryElement) {
2282
+ const length2 = path2.getTotalLength();
2283
+ const svg = scene.getSVG();
2284
+ const defs = svg.querySelector("defs") || svg.insertBefore(
2285
+ document.createElementNS("http://www.w3.org/2000/svg", "defs"),
2286
+ svg.firstChild
2287
+ );
2288
+ const gradientId = `flash_gradient_${Date.now()}`;
2289
+ const gradient = document.createElementNS("http://www.w3.org/2000/svg", "linearGradient");
2290
+ gradient.setAttribute("id", gradientId);
2291
+ const stop1 = document.createElementNS("http://www.w3.org/2000/svg", "stop");
2292
+ stop1.setAttribute("offset", "0%");
2293
+ stop1.setAttribute("stop-color", "transparent");
2294
+ const stop2 = document.createElementNS("http://www.w3.org/2000/svg", "stop");
2295
+ stop2.setAttribute("offset", "50%");
2296
+ stop2.setAttribute("stop-color", color);
2297
+ const stop3 = document.createElementNS("http://www.w3.org/2000/svg", "stop");
2298
+ stop3.setAttribute("offset", "100%");
2299
+ stop3.setAttribute("stop-color", "transparent");
2300
+ gradient.appendChild(stop1);
2301
+ gradient.appendChild(stop2);
2302
+ gradient.appendChild(stop3);
2303
+ defs.appendChild(gradient);
2304
+ const flashPath = path2.cloneNode();
2305
+ flashPath.setAttribute("stroke", `url(#${gradientId})`);
2306
+ flashPath.setAttribute("fill", "none");
2307
+ flashPath.setAttribute("stroke-width", "4");
2308
+ gsap4.set(flashPath, {
2309
+ strokeDasharray: `${length2 * 0.1} ${length2 * 0.9}`,
2310
+ strokeDashoffset: length2
2311
+ });
2312
+ (_a = path2.parentNode) == null ? void 0 : _a.insertBefore(flashPath, path2.nextSibling);
2313
+ timeline.add(flashPath, {
2314
+ strokeDashoffset: -length2 * 0.1,
2315
+ duration,
2316
+ ease: getGSAPEasing(easing2),
2317
+ delay,
2318
+ onComplete: () => {
2319
+ flashPath.remove();
2320
+ gradient.remove();
2321
+ }
2322
+ }, startTime);
2323
+ }
2324
+ });
2325
+ }
2326
+ };
2327
+ }
2328
+ function Blink(target, options = {}) {
2329
+ const {
2330
+ duration = 1,
2331
+ delay = 0,
2332
+ times = 3
2333
+ } = options;
2334
+ return {
2335
+ duration,
2336
+ target,
2337
+ execute(scene, timeline, startTime) {
2338
+ const element = scene.getElement(target);
2339
+ if (!element) return;
2340
+ const blinkDuration = duration / (times * 2);
2341
+ for (let i = 0; i < times; i++) {
2342
+ timeline.add(element, {
2343
+ opacity: 0,
2344
+ duration: blinkDuration,
2345
+ ease: "power2.in"
2346
+ }, startTime + delay + i * blinkDuration * 2);
2347
+ timeline.add(element, {
2348
+ opacity: 1,
2349
+ duration: blinkDuration,
2350
+ ease: "power2.out"
2351
+ }, startTime + delay + i * blinkDuration * 2 + blinkDuration);
2352
+ }
2353
+ }
2354
+ };
2355
+ }
2356
+
2357
+ // src/animate/animations/composition.ts
2358
+ function AnimationGroup(animations, options = {}) {
2359
+ var _a, _b;
2360
+ const { lagRatio = 0 } = options;
2361
+ const maxDuration = animations.length > 0 ? Math.max(...animations.map((a, i) => a.duration + i * lagRatio * a.duration)) : 0;
2362
+ return {
2363
+ duration: maxDuration,
2364
+ target: (_b = (_a = animations[0]) == null ? void 0 : _a.target) != null ? _b : null,
2365
+ execute(scene, timeline, startTime) {
2366
+ animations.forEach((animation, index) => {
2367
+ const delay = index * lagRatio * animation.duration;
2368
+ animation.execute(scene, timeline, startTime + delay);
2369
+ });
2370
+ }
2371
+ };
2372
+ }
2373
+ function Succession(animations, options = {}) {
2374
+ var _a, _b;
2375
+ const { delay = 0 } = options;
2376
+ const totalDuration = animations.reduce((sum, a) => sum + a.duration, 0);
2377
+ return {
2378
+ duration: totalDuration,
2379
+ target: (_b = (_a = animations[0]) == null ? void 0 : _a.target) != null ? _b : null,
2380
+ execute(scene, timeline, startTime) {
2381
+ let currentTime = startTime + delay;
2382
+ animations.forEach((animation) => {
2383
+ animation.execute(scene, timeline, currentTime);
2384
+ currentTime += animation.duration;
2385
+ });
2386
+ }
2387
+ };
2388
+ }
2389
+ function LaggedStart(animations, options = {}) {
2390
+ var _a;
2391
+ const { lagRatio = 0.05, duration, delay = 0 } = options;
2392
+ let effectiveLagRatio = lagRatio;
2393
+ if (duration && animations.length > 1) {
2394
+ const baseDuration = ((_a = animations[0]) == null ? void 0 : _a.duration) || 1;
2395
+ effectiveLagRatio = (duration - baseDuration) / (baseDuration * (animations.length - 1));
2396
+ }
2397
+ return AnimationGroup(animations, { lagRatio: effectiveLagRatio, delay });
2398
+ }
2399
+ function LaggedStartMap(animationFn, targets, options = {}) {
2400
+ const _a = options, { animationOptions } = _a, groupOptions = __objRest(_a, ["animationOptions"]);
2401
+ const animations = targets.map((target) => animationFn(target, animationOptions));
2402
+ return LaggedStart(animations, groupOptions);
2403
+ }
2404
+ function Wait(duration = 1) {
2405
+ return {
2406
+ duration,
2407
+ target: null,
2408
+ execute() {
2409
+ }
2410
+ };
2411
+ }
2412
+ function ApplyMethod(target, method, options = {}) {
2413
+ const { duration = 0.5, easing: easing2 = "easeInOut", delay = 0 } = options;
2414
+ const targetDiagram = method(target);
2415
+ return {
2416
+ duration,
2417
+ target,
2418
+ execute(scene, timeline, startTime) {
2419
+ import("./transform-TMK5SL54.mjs").then(({ Transform: Transform2 }) => {
2420
+ Transform2(target, targetDiagram, { duration, easing: easing2, delay }).execute(scene, timeline, startTime);
2421
+ });
2422
+ }
2423
+ };
2424
+ }
2425
+ function UpdateFromFunc(target, updateFn, options = {}) {
2426
+ const { duration = 1, delay = 0 } = options;
2427
+ return {
2428
+ duration,
2429
+ target,
2430
+ execute(scene, timeline, startTime) {
2431
+ const element = scene.getElement(target);
2432
+ if (!element) return;
2433
+ const proxy = { t: 0 };
2434
+ timeline.add(proxy, {
2435
+ t: 1,
2436
+ duration,
2437
+ delay,
2438
+ ease: "none",
2439
+ onUpdate: () => {
2440
+ updateFn(target, proxy.t);
2441
+ }
2442
+ }, startTime);
2443
+ }
2444
+ };
2445
+ }
2446
+ function UpdateFromAlphaFunc(target, updateFn, options = {}) {
2447
+ return UpdateFromFunc(target, updateFn, options);
2448
+ }
2449
+ function Homotopy(target, homotopyFn, options = {}) {
2450
+ const { duration = 1, delay = 0 } = options;
2451
+ return {
2452
+ duration,
2453
+ target,
2454
+ execute(scene, timeline, startTime) {
2455
+ const element = scene.getElement(target);
2456
+ if (!element) return;
2457
+ const paths = element.querySelectorAll("path");
2458
+ paths.forEach((path2) => {
2459
+ const originalD = path2.getAttribute("d") || "";
2460
+ const proxy = { t: 0 };
2461
+ timeline.add(proxy, {
2462
+ t: 1,
2463
+ duration,
2464
+ delay,
2465
+ ease: "none",
2466
+ onUpdate: () => {
2467
+ const newD = transformPathByHomotopy(originalD, homotopyFn, proxy.t);
2468
+ path2.setAttribute("d", newD);
2469
+ }
2470
+ }, startTime);
2471
+ });
2472
+ }
2473
+ };
2474
+ }
2475
+ function transformPathByHomotopy(d, homotopyFn, t) {
2476
+ return d.replace(
2477
+ /([ML])\s*([\d.-]+)[,\s]+([\d.-]+)/g,
2478
+ (_match, cmd, x, y) => {
2479
+ const [newX, newY] = homotopyFn(parseFloat(x), parseFloat(y), t);
2480
+ return `${cmd}${newX},${newY}`;
2481
+ }
2482
+ );
2483
+ }
2484
+
2485
+ // src/geometry/axes.ts
2486
+ var Axes = class {
2487
+ constructor(config = {}) {
2488
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k;
2489
+ this.config = {
2490
+ xRange: (_a = config.xRange) != null ? _a : [-5, 5, 1],
2491
+ yRange: (_b = config.yRange) != null ? _b : [-5, 5, 1],
2492
+ xLength: (_c = config.xLength) != null ? _c : 400,
2493
+ yLength: (_d = config.yLength) != null ? _d : 400,
2494
+ origin: (_e = config.origin) != null ? _e : [400, 300],
2495
+ showTicks: (_f = config.showTicks) != null ? _f : true,
2496
+ showLabels: (_g = config.showLabels) != null ? _g : true,
2497
+ showGrid: (_h = config.showGrid) != null ? _h : false,
2498
+ axisColor: (_i = config.axisColor) != null ? _i : "#374151",
2499
+ gridColor: (_j = config.gridColor) != null ? _j : "#E5E7EB",
2500
+ labelSize: (_k = config.labelSize) != null ? _k : 12
2501
+ };
2502
+ this.diagram = this.build();
2503
+ }
2504
+ /** 构建坐标系图形 */
2505
+ build() {
2506
+ const diagrams = [];
2507
+ const {
2508
+ xRange,
2509
+ yRange,
2510
+ xLength,
2511
+ yLength,
2512
+ origin,
2513
+ showTicks,
2514
+ showLabels,
2515
+ showGrid,
2516
+ axisColor,
2517
+ gridColor,
2518
+ labelSize
2519
+ } = this.config;
2520
+ const [ox, oy] = origin;
2521
+ const xMin = xRange[0], xMax = xRange[1], xStep = xRange[2] || 1;
2522
+ const yMin = yRange[0], yMax = yRange[1], yStep = yRange[2] || 1;
2523
+ const xScale = xLength / (xMax - xMin);
2524
+ const yScale = yLength / (yMax - yMin);
2525
+ if (showGrid) {
2526
+ for (let x = xMin; x <= xMax; x += xStep) {
2527
+ const px = ox + x * xScale;
2528
+ diagrams.push(
2529
+ line([px, oy + yMin * yScale], [px, oy + yMax * yScale]).stroke(gridColor).strokeWidth(0.5)
2530
+ );
2531
+ }
2532
+ for (let y = yMin; y <= yMax; y += yStep) {
2533
+ const py = oy - y * yScale;
2534
+ diagrams.push(
2535
+ line([ox + xMin * xScale, py], [ox + xMax * xScale, py]).stroke(gridColor).strokeWidth(0.5)
2536
+ );
2537
+ }
2538
+ }
2539
+ const xAxisStart = [ox + xMin * xScale, oy];
2540
+ const xAxisEnd = [ox + xMax * xScale, oy];
2541
+ diagrams.push(arrow(xAxisStart, xAxisEnd).stroke(axisColor));
2542
+ const yAxisStart = [ox, oy - yMin * yScale];
2543
+ const yAxisEnd = [ox, oy - yMax * yScale];
2544
+ diagrams.push(arrow(yAxisStart, yAxisEnd).stroke(axisColor));
2545
+ if (showTicks || showLabels) {
2546
+ const tickSize = 5;
2547
+ for (let x = xMin; x <= xMax; x += xStep) {
2548
+ if (x === 0) continue;
2549
+ const px = ox + x * xScale;
2550
+ if (showTicks) {
2551
+ diagrams.push(
2552
+ line([px, oy - tickSize], [px, oy + tickSize]).stroke(axisColor).strokeWidth(1)
2553
+ );
2554
+ }
2555
+ if (showLabels) {
2556
+ diagrams.push(
2557
+ text(String(x), { fontSize: labelSize }).position(px, oy + tickSize + labelSize)
2558
+ );
2559
+ }
2560
+ }
2561
+ for (let y = yMin; y <= yMax; y += yStep) {
2562
+ if (y === 0) continue;
2563
+ const py = oy - y * yScale;
2564
+ if (showTicks) {
2565
+ diagrams.push(
2566
+ line([ox - tickSize, py], [ox + tickSize, py]).stroke(axisColor).strokeWidth(1)
2567
+ );
2568
+ }
2569
+ if (showLabels) {
2570
+ diagrams.push(
2571
+ text(String(y), { fontSize: labelSize, anchor: "end" }).position(ox - tickSize - 5, py)
2572
+ );
2573
+ }
2574
+ }
2575
+ if (showLabels) {
2576
+ diagrams.push(
2577
+ text("O", { fontSize: labelSize }).position(ox - tickSize - 5, oy + tickSize + labelSize)
2578
+ );
2579
+ }
2580
+ }
2581
+ return combine(...diagrams);
2582
+ }
2583
+ c2p(xOrPoint, y) {
2584
+ const [x, yVal] = typeof xOrPoint === "number" ? [xOrPoint, y] : xOrPoint;
2585
+ const { xRange, yRange, xLength, yLength, origin } = this.config;
2586
+ const xScale = xLength / (xRange[1] - xRange[0]);
2587
+ const yScale = yLength / (yRange[1] - yRange[0]);
2588
+ return [
2589
+ origin[0] + x * xScale,
2590
+ origin[1] - yVal * yScale
2591
+ // Y 轴向上为正
2592
+ ];
2593
+ }
2594
+ p2c(pxOrPoint, py) {
2595
+ const [px, pyVal] = typeof pxOrPoint === "number" ? [pxOrPoint, py] : pxOrPoint;
2596
+ const { xRange, yRange, xLength, yLength, origin } = this.config;
2597
+ const xScale = xLength / (xRange[1] - xRange[0]);
2598
+ const yScale = yLength / (yRange[1] - yRange[0]);
2599
+ return [
2600
+ (px - origin[0]) / xScale,
2601
+ -(pyVal - origin[1]) / yScale
2602
+ ];
2603
+ }
2604
+ /** 绑制函数图像 */
2605
+ plot(fn, options = {}) {
2606
+ const {
2607
+ xRange = [this.config.xRange[0], this.config.xRange[1]],
2608
+ color = "#EA580C",
2609
+ strokeWidth = 2,
2610
+ samples = 200
2611
+ } = options;
2612
+ const points = [];
2613
+ const step = (xRange[1] - xRange[0]) / samples;
2614
+ for (let x = xRange[0]; x <= xRange[1]; x += step) {
2615
+ const y = fn(x);
2616
+ if (isFinite(y)) {
2617
+ points.push(this.c2p(x, y));
2618
+ }
2619
+ }
2620
+ return polyline(...points).stroke(color).strokeWidth(strokeWidth).fill("none");
2621
+ }
2622
+ /** 绘制参数曲线 */
2623
+ plotParametric(fn, options = {}) {
2624
+ const {
2625
+ tRange = [0, 1],
2626
+ color = "#3B82F6",
2627
+ strokeWidth = 2,
2628
+ samples = 200
2629
+ } = options;
2630
+ const coordPoints = sampleParametric(fn, tRange[0], tRange[1], samples);
2631
+ const pixelPoints = coordPoints.map((p) => this.c2p(p));
2632
+ return polyline(...pixelPoints).stroke(color).strokeWidth(strokeWidth).fill("none");
2633
+ }
2634
+ /** 获取函数图像下方区域 */
2635
+ getArea(graph, options = {}) {
2636
+ const {
2637
+ xRange = [this.config.xRange[0], this.config.xRange[1]],
2638
+ color = "#EA580C",
2639
+ opacity = 0.3
2640
+ } = options;
2641
+ void xRange;
2642
+ return graph.clone().fill(color).opacity(opacity);
2643
+ }
2644
+ /** 获取图形标签 */
2645
+ getGraphLabel(graph, label, options = {}) {
2646
+ const {
2647
+ position = "end",
2648
+ direction = [1, 0],
2649
+ fontSize = 14
2650
+ } = options;
2651
+ const bounds = graph.bounds();
2652
+ let labelPos;
2653
+ switch (position) {
2654
+ case "start":
2655
+ labelPos = [bounds.x, bounds.y + bounds.height / 2];
2656
+ break;
2657
+ case "center":
2658
+ labelPos = [bounds.x + bounds.width / 2, bounds.y + bounds.height / 2];
2659
+ break;
2660
+ case "end":
2661
+ default:
2662
+ labelPos = [bounds.x + bounds.width, bounds.y + bounds.height / 2];
2663
+ }
2664
+ return text(label, { fontSize }).position(labelPos[0] + direction[0] * 20, labelPos[1] + direction[1] * 20);
2665
+ }
2666
+ /** 获取 Diagram */
2667
+ toDiagram() {
2668
+ return this.diagram;
2669
+ }
2670
+ };
2671
+ var NumberLine = class {
2672
+ constructor(config = {}) {
2673
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k;
2674
+ this.config = {
2675
+ range: [(_b = (_a = config.range) == null ? void 0 : _a[0]) != null ? _b : -5, (_d = (_c = config.range) == null ? void 0 : _c[1]) != null ? _d : 5, (_f = (_e = config.range) == null ? void 0 : _e[2]) != null ? _f : 1],
2676
+ length: (_g = config.length) != null ? _g : 400,
2677
+ origin: (_h = config.origin) != null ? _h : [400, 300],
2678
+ showTicks: (_i = config.showTicks) != null ? _i : true,
2679
+ showLabels: (_j = config.showLabels) != null ? _j : true,
2680
+ color: (_k = config.color) != null ? _k : "#374151"
2681
+ };
2682
+ this.diagram = this.build();
2683
+ }
2684
+ build() {
2685
+ const { range, length: length2, origin, showTicks, showLabels, color } = this.config;
2686
+ const [min, max, step] = range;
2687
+ const scale = length2 / (max - min);
2688
+ const diagrams = [];
2689
+ const start = [origin[0] + min * scale, origin[1]];
2690
+ const end = [origin[0] + max * scale, origin[1]];
2691
+ diagrams.push(arrow(start, end).stroke(color));
2692
+ if (showTicks || showLabels) {
2693
+ for (let x = min; x <= max; x += step) {
2694
+ const px = origin[0] + x * scale;
2695
+ if (showTicks) {
2696
+ diagrams.push(
2697
+ line([px, origin[1] - 5], [px, origin[1] + 5]).stroke(color).strokeWidth(1)
2698
+ );
2699
+ }
2700
+ if (showLabels) {
2701
+ diagrams.push(
2702
+ text(String(x), { fontSize: 12 }).position(px, origin[1] + 20)
2703
+ );
2704
+ }
2705
+ }
2706
+ }
2707
+ return combine(...diagrams);
2708
+ }
2709
+ n2p(n) {
2710
+ const { range, length: length2, origin } = this.config;
2711
+ const scale = length2 / (range[1] - range[0]);
2712
+ return [origin[0] + n * scale, origin[1]];
2713
+ }
2714
+ p2n(p) {
2715
+ const { range, length: length2, origin } = this.config;
2716
+ const scale = length2 / (range[1] - range[0]);
2717
+ return (p[0] - origin[0]) / scale;
2718
+ }
2719
+ toDiagram() {
2720
+ return this.diagram;
2721
+ }
2722
+ };
2723
+ function NumberPlane(config = {}) {
2724
+ return new Axes(__spreadProps(__spreadValues({}, config), {
2725
+ showGrid: true
2726
+ }));
2727
+ }
2728
+ function PolarAxes(config = {}) {
2729
+ const {
2730
+ maxRadius = 200,
2731
+ origin = [400, 300],
2732
+ divisions = 8,
2733
+ color = "#374151"
2734
+ } = config;
2735
+ const diagrams = [];
2736
+ const [ox, oy] = origin;
2737
+ for (let r = maxRadius / 4; r <= maxRadius; r += maxRadius / 4) {
2738
+ const points = [];
2739
+ for (let angle2 = 0; angle2 <= 2 * PI; angle2 += PI / 36) {
2740
+ points.push([ox + r * Math.cos(angle2), oy + r * Math.sin(angle2)]);
2741
+ }
2742
+ diagrams.push(polyline(...points).stroke("#E5E7EB").strokeWidth(0.5));
2743
+ }
2744
+ for (let i = 0; i < divisions; i++) {
2745
+ const angle2 = i / divisions * 2 * PI;
2746
+ diagrams.push(
2747
+ line([ox, oy], [ox + maxRadius * Math.cos(angle2), oy + maxRadius * Math.sin(angle2)]).stroke("#E5E7EB").strokeWidth(0.5)
2748
+ );
2749
+ }
2750
+ diagrams.push(
2751
+ arrow([ox - maxRadius, oy], [ox + maxRadius + 20, oy]).stroke(color),
2752
+ arrow([ox, oy + maxRadius], [ox, oy - maxRadius - 20]).stroke(color)
2753
+ );
2754
+ return combine(...diagrams);
2755
+ }
2756
+
2757
+ // src/geometry/construct.ts
2758
+ function midpoint2(a, b) {
2759
+ return midpoint(a, b);
2760
+ }
2761
+ function perpendicularBisector(a, b, length2 = 100) {
2762
+ const mid = midpoint2(a, b);
2763
+ const direction = normalize(perpendicular(sub(b, a)));
2764
+ const start = add(mid, mul(direction, -length2 / 2));
2765
+ const end = add(mid, mul(direction, length2 / 2));
2766
+ return line(start, end);
2767
+ }
2768
+ function perpendicularLine(point, lineStart, lineEnd, length2 = 100) {
2769
+ const lineDir = normalize(sub(lineEnd, lineStart));
2770
+ const perpDir = perpendicular(lineDir);
2771
+ const start = add(point, mul(perpDir, -length2 / 2));
2772
+ const end = add(point, mul(perpDir, length2 / 2));
2773
+ return line(start, end);
2774
+ }
2775
+ function footOfPerpendicular(point, lineStart, lineEnd) {
2776
+ const lineDir = sub(lineEnd, lineStart);
2777
+ const pointDir = sub(point, lineStart);
2778
+ const lineLenSq = lineDir[0] ** 2 + lineDir[1] ** 2;
2779
+ const t = (pointDir[0] * lineDir[0] + pointDir[1] * lineDir[1]) / lineLenSq;
2780
+ return add(lineStart, mul(lineDir, t));
2781
+ }
2782
+ function parallelLine(point, lineStart, lineEnd, length2 = 100) {
2783
+ const lineDir = normalize(sub(lineEnd, lineStart));
2784
+ const start = add(point, mul(lineDir, -length2 / 2));
2785
+ const end = add(point, mul(lineDir, length2 / 2));
2786
+ return line(start, end);
2787
+ }
2788
+ function angleMarker(vertex, a, b, options = {}) {
2789
+ const { radius = 30, color = "#EA580C", label } = options;
2790
+ const dirA = normalize(sub(a, vertex));
2791
+ const dirB = normalize(sub(b, vertex));
2792
+ const angleA = Math.atan2(dirA[1], dirA[0]);
2793
+ const angleB = Math.atan2(dirB[1], dirB[0]);
2794
+ let startAngle = angleA;
2795
+ let endAngle = angleB;
2796
+ if (endAngle < startAngle) {
2797
+ endAngle += 2 * PI;
2798
+ }
2799
+ const diagrams = [];
2800
+ diagrams.push(
2801
+ arc(radius, startAngle, endAngle).translate(vertex[0], vertex[1]).stroke(color).strokeWidth(2)
2802
+ );
2803
+ if (label) {
2804
+ const midAngle = (startAngle + endAngle) / 2;
2805
+ const labelPos = [
2806
+ vertex[0] + (radius + 15) * Math.cos(midAngle),
2807
+ vertex[1] + (radius + 15) * Math.sin(midAngle)
2808
+ ];
2809
+ diagrams.push(text(label, { fontSize: 14 }).position(labelPos[0], labelPos[1]));
2810
+ }
2811
+ return combine(...diagrams);
2812
+ }
2813
+ function rightAngleMarker(vertex, a, b, size = 15) {
2814
+ const dirA = normalize(sub(a, vertex));
2815
+ const dirB = normalize(sub(b, vertex));
2816
+ const p1 = add(vertex, mul(dirA, size));
2817
+ const p2 = add(add(vertex, mul(dirA, size)), mul(dirB, size));
2818
+ const p3 = add(vertex, mul(dirB, size));
2819
+ return polygon(vertex, p1, p2, p3).fill("none").stroke("#374151").strokeWidth(1.5);
2820
+ }
2821
+ function circumscribedCircle(a, b, c) {
2822
+ const midAB = midpoint2(a, b);
2823
+ const midBC = midpoint2(b, c);
2824
+ const dirAB = perpendicular(sub(b, a));
2825
+ const dirBC = perpendicular(sub(c, b));
2826
+ const center = lineIntersection(
2827
+ midAB,
2828
+ add(midAB, dirAB),
2829
+ midBC,
2830
+ add(midBC, dirBC)
2831
+ );
2832
+ if (!center) {
2833
+ throw new Error("\u4E09\u70B9\u5171\u7EBF\uFF0C\u65E0\u6CD5\u786E\u5B9A\u5706");
2834
+ }
2835
+ const radius = distance(center, a);
2836
+ return {
2837
+ center,
2838
+ radius,
2839
+ diagram: circle(radius).translate(center[0], center[1]).fill("none").stroke("#EA580C")
2840
+ };
2841
+ }
2842
+ function inscribedCircle(a, b, c) {
2843
+ const ab = distance(a, b);
2844
+ const bc = distance(b, c);
2845
+ const ca = distance(c, a);
2846
+ const perimeter = ab + bc + ca;
2847
+ const center = [
2848
+ (bc * a[0] + ca * b[0] + ab * c[0]) / perimeter,
2849
+ (bc * a[1] + ca * b[1] + ab * c[1]) / perimeter
2850
+ ];
2851
+ const s = perimeter / 2;
2852
+ const area = Math.sqrt(s * (s - ab) * (s - bc) * (s - ca));
2853
+ const radius = area / s;
2854
+ return {
2855
+ center,
2856
+ radius,
2857
+ diagram: circle(radius).translate(center[0], center[1]).fill("none").stroke("#3B82F6")
2858
+ };
2859
+ }
2860
+ function circleIntersections(c1, r1, c2, r2) {
2861
+ const d = distance(c1, c2);
2862
+ if (d > r1 + r2 || d < Math.abs(r1 - r2)) {
2863
+ return [];
2864
+ }
2865
+ if (d === 0 && r1 === r2) {
2866
+ return [];
2867
+ }
2868
+ const a = (r1 * r1 - r2 * r2 + d * d) / (2 * d);
2869
+ const h = Math.sqrt(r1 * r1 - a * a);
2870
+ const p2 = [
2871
+ c1[0] + a * (c2[0] - c1[0]) / d,
2872
+ c1[1] + a * (c2[1] - c1[1]) / d
2873
+ ];
2874
+ if (h === 0) {
2875
+ return [p2];
2876
+ }
2877
+ const intersection1 = [
2878
+ p2[0] + h * (c2[1] - c1[1]) / d,
2879
+ p2[1] - h * (c2[0] - c1[0]) / d
2880
+ ];
2881
+ const intersection2 = [
2882
+ p2[0] - h * (c2[1] - c1[1]) / d,
2883
+ p2[1] + h * (c2[0] - c1[0]) / d
2884
+ ];
2885
+ return [intersection1, intersection2];
2886
+ }
2887
+ function centroid(a, b, c) {
2888
+ return [(a[0] + b[0] + c[0]) / 3, (a[1] + b[1] + c[1]) / 3];
2889
+ }
2890
+ function orthocenter(a, b, c) {
2891
+ const altitudeA = footOfPerpendicular(a, b, c);
2892
+ const altitudeB = footOfPerpendicular(b, a, c);
2893
+ return lineIntersection(a, altitudeA, b, altitudeB) || centroid(a, b, c);
2894
+ }
2895
+ function median(vertex, opposite1, opposite2) {
2896
+ const mid = midpoint2(opposite1, opposite2);
2897
+ return line(vertex, mid);
2898
+ }
2899
+ function angleBisector(vertex, a, b, length2 = 100) {
2900
+ const dirA = normalize(sub(a, vertex));
2901
+ const dirB = normalize(sub(b, vertex));
2902
+ const bisectorDir = normalize(add(dirA, dirB));
2903
+ const end = add(vertex, mul(bisectorDir, length2));
2904
+ return line(vertex, end);
2905
+ }
2906
+ function altitude(vertex, opposite1, opposite2) {
2907
+ const foot = footOfPerpendicular(vertex, opposite1, opposite2);
2908
+ return line(vertex, foot);
2909
+ }
2910
+ function reflectPoint(point, center) {
2911
+ return [2 * center[0] - point[0], 2 * center[1] - point[1]];
2912
+ }
2913
+ function reflectPointOverLine(point, lineStart, lineEnd) {
2914
+ const foot = footOfPerpendicular(point, lineStart, lineEnd);
2915
+ return [2 * foot[0] - point[0], 2 * foot[1] - point[1]];
2916
+ }
2917
+ function reflectOverPoint(diagram, center) {
2918
+ return diagram.translate(-center[0], -center[1]).scale(-1, -1).translate(center[0], center[1]);
2919
+ }
2920
+ function lineIntersection(l1Start, l1End, l2Start, l2End) {
2921
+ const x1 = l1Start[0], y1 = l1Start[1];
2922
+ const x2 = l1End[0], y2 = l1End[1];
2923
+ const x3 = l2Start[0], y3 = l2Start[1];
2924
+ const x4 = l2End[0], y4 = l2End[1];
2925
+ const denom = (x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4);
2926
+ if (Math.abs(denom) < 1e-10) {
2927
+ return null;
2928
+ }
2929
+ const t = ((x1 - x3) * (y3 - y4) - (y1 - y3) * (x3 - x4)) / denom;
2930
+ return [
2931
+ x1 + t * (x2 - x1),
2932
+ y1 + t * (y2 - y1)
2933
+ ];
2934
+ }
2935
+
2936
+ // src/interactive/interactive.ts
2937
+ var Interactive = class {
2938
+ constructor(container, options = {}) {
2939
+ this.values = {};
2940
+ this.controls = /* @__PURE__ */ new Map();
2941
+ this.locators = /* @__PURE__ */ new Map();
2942
+ this.drawFn = null;
2943
+ this.animationId = null;
2944
+ this.playingSliders = /* @__PURE__ */ new Map();
2945
+ var _a, _b, _c, _d, _e, _f;
2946
+ this.container = container;
2947
+ const rect2 = container.getBoundingClientRect();
2948
+ const autoWidth = rect2.width > 0 ? rect2.width : 400;
2949
+ const autoHeight = rect2.height > 0 ? Math.min(rect2.height - 80, 300) : 300;
2950
+ this.options = {
2951
+ width: (_a = options.width) != null ? _a : autoWidth,
2952
+ height: (_b = options.height) != null ? _b : autoHeight,
2953
+ background: (_c = options.background) != null ? _c : "#ffffff",
2954
+ controlsPosition: (_d = options.controlsPosition) != null ? _d : "bottom",
2955
+ controlsStyle: (_e = options.controlsStyle) != null ? _e : {},
2956
+ rough: (_f = options.rough) != null ? _f : false
2957
+ };
2958
+ this.setupLayout();
2959
+ this.svg = this.createSVG();
2960
+ this.startAnimationLoop();
2961
+ }
2962
+ /** 设置布局 */
2963
+ setupLayout() {
2964
+ this.container.style.display = "flex";
2965
+ this.container.style.flexDirection = "column";
2966
+ this.container.style.height = "100%";
2967
+ this.container.style.background = "#ffffff";
2968
+ this.svgContainer = document.createElement("div");
2969
+ this.svgContainer.style.flex = "1";
2970
+ this.svgContainer.style.display = "flex";
2971
+ this.svgContainer.style.alignItems = "center";
2972
+ this.svgContainer.style.justifyContent = "center";
2973
+ this.svgContainer.style.position = "relative";
2974
+ this.svgContainer.style.minHeight = "280px";
2975
+ this.svgContainer.style.overflow = "hidden";
2976
+ this.container.appendChild(this.svgContainer);
2977
+ this.controlsContainer = document.createElement("div");
2978
+ this.controlsContainer.style.padding = "12px 16px";
2979
+ this.controlsContainer.style.display = "flex";
2980
+ this.controlsContainer.style.flexWrap = "wrap";
2981
+ this.controlsContainer.style.gap = "16px";
2982
+ this.controlsContainer.style.alignItems = "center";
2983
+ this.controlsContainer.style.justifyContent = "center";
2984
+ this.controlsContainer.style.backgroundColor = "#f9fafb";
2985
+ this.controlsContainer.style.borderTop = "1px solid #e5e7eb";
2986
+ this.controlsContainer.style.flexShrink = "0";
2987
+ Object.assign(this.controlsContainer.style, this.options.controlsStyle);
2988
+ this.container.appendChild(this.controlsContainer);
2989
+ }
2990
+ /** 创建 SVG */
2991
+ createSVG() {
2992
+ const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
2993
+ svg.setAttribute("width", String(this.options.width));
2994
+ svg.setAttribute("height", String(this.options.height));
2995
+ svg.setAttribute("viewBox", `0 0 ${this.options.width} ${this.options.height}`);
2996
+ svg.style.background = this.options.background || "#ffffff";
2997
+ this.svgContainer.appendChild(svg);
2998
+ return svg;
2999
+ }
3000
+ // ========== 控件方法 ==========
3001
+ /** 添加滑块控件 */
3002
+ slider(name, config) {
3003
+ const {
3004
+ min,
3005
+ max,
3006
+ value = min,
3007
+ step = (max - min) / 100,
3008
+ label = name,
3009
+ showPlayButton = false,
3010
+ playDuration = 2,
3011
+ loop = false
3012
+ } = config;
3013
+ this.values[name] = value;
3014
+ const wrapper = document.createElement("div");
3015
+ wrapper.style.display = "flex";
3016
+ wrapper.style.flexDirection = "column";
3017
+ wrapper.style.gap = "4px";
3018
+ wrapper.style.minWidth = "150px";
3019
+ const labelRow = document.createElement("div");
3020
+ labelRow.style.display = "flex";
3021
+ labelRow.style.justifyContent = "space-between";
3022
+ labelRow.style.fontSize = "14px";
3023
+ labelRow.style.color = "#374151";
3024
+ const labelEl = document.createElement("span");
3025
+ labelEl.textContent = label;
3026
+ const valueEl = document.createElement("span");
3027
+ valueEl.textContent = String(value);
3028
+ valueEl.style.fontFamily = "monospace";
3029
+ labelRow.appendChild(labelEl);
3030
+ labelRow.appendChild(valueEl);
3031
+ wrapper.appendChild(labelRow);
3032
+ const sliderRow = document.createElement("div");
3033
+ sliderRow.style.display = "flex";
3034
+ sliderRow.style.gap = "8px";
3035
+ sliderRow.style.alignItems = "center";
3036
+ const slider = document.createElement("input");
3037
+ slider.type = "range";
3038
+ slider.min = String(min);
3039
+ slider.max = String(max);
3040
+ slider.step = String(step);
3041
+ slider.value = String(value);
3042
+ slider.style.flex = "1";
3043
+ slider.style.accentColor = "#EA580C";
3044
+ slider.addEventListener("input", () => {
3045
+ const newValue = parseFloat(slider.value);
3046
+ this.values[name] = newValue;
3047
+ valueEl.textContent = newValue.toFixed(2);
3048
+ this.redraw();
3049
+ });
3050
+ sliderRow.appendChild(slider);
3051
+ if (showPlayButton) {
3052
+ const playBtn = document.createElement("button");
3053
+ playBtn.textContent = "\u25B6";
3054
+ playBtn.style.padding = "4px 8px";
3055
+ playBtn.style.border = "none";
3056
+ playBtn.style.borderRadius = "4px";
3057
+ playBtn.style.backgroundColor = "#EA580C";
3058
+ playBtn.style.color = "white";
3059
+ playBtn.style.cursor = "pointer";
3060
+ playBtn.addEventListener("click", () => {
3061
+ if (this.playingSliders.has(name)) {
3062
+ this.playingSliders.delete(name);
3063
+ playBtn.textContent = "\u25B6";
3064
+ } else {
3065
+ this.playingSliders.set(name, {
3066
+ startTime: performance.now(),
3067
+ startValue: this.values[name],
3068
+ config: { min, max, value, step, label, showPlayButton, playDuration, loop }
3069
+ });
3070
+ playBtn.textContent = "\u23F8";
3071
+ }
3072
+ });
3073
+ sliderRow.appendChild(playBtn);
3074
+ }
3075
+ wrapper.appendChild(sliderRow);
3076
+ this.controlsContainer.appendChild(wrapper);
3077
+ this.controls.set(name, wrapper);
3078
+ return this;
3079
+ }
3080
+ /** 添加可拖拽点 */
3081
+ locator(name, config) {
3082
+ const {
3083
+ x,
3084
+ y,
3085
+ radius = 8,
3086
+ color = "#EA580C",
3087
+ constraint
3088
+ } = config;
3089
+ this.values[name] = V2(x, y);
3090
+ const circle2 = document.createElementNS("http://www.w3.org/2000/svg", "circle");
3091
+ circle2.setAttribute("cx", String(x));
3092
+ circle2.setAttribute("cy", String(y));
3093
+ circle2.setAttribute("r", String(radius));
3094
+ circle2.setAttribute("fill", color);
3095
+ circle2.setAttribute("stroke", "white");
3096
+ circle2.setAttribute("stroke-width", "2");
3097
+ circle2.style.cursor = "grab";
3098
+ let isDragging = false;
3099
+ const onMouseDown = (e) => {
3100
+ isDragging = true;
3101
+ circle2.style.cursor = "grabbing";
3102
+ e.preventDefault();
3103
+ };
3104
+ const onMouseMove = (e) => {
3105
+ var _a, _b, _c, _d;
3106
+ if (!isDragging) return;
3107
+ const rect2 = this.svg.getBoundingClientRect();
3108
+ const clientX = "touches" in e ? (_b = (_a = e.touches[0]) == null ? void 0 : _a.clientX) != null ? _b : 0 : e.clientX;
3109
+ const clientY = "touches" in e ? (_d = (_c = e.touches[0]) == null ? void 0 : _c.clientY) != null ? _d : 0 : e.clientY;
3110
+ let newX = (clientX - rect2.left) * (this.options.width / rect2.width);
3111
+ let newY = (clientY - rect2.top) * (this.options.height / rect2.height);
3112
+ if (constraint) {
3113
+ [newX, newY] = constraint([newX, newY]);
3114
+ }
3115
+ circle2.setAttribute("cx", String(newX));
3116
+ circle2.setAttribute("cy", String(newY));
3117
+ this.values[name] = V2(newX, newY);
3118
+ this.redraw();
3119
+ };
3120
+ const onMouseUp = () => {
3121
+ isDragging = false;
3122
+ circle2.style.cursor = "grab";
3123
+ };
3124
+ circle2.addEventListener("mousedown", onMouseDown);
3125
+ circle2.addEventListener("touchstart", onMouseDown);
3126
+ document.addEventListener("mousemove", onMouseMove);
3127
+ document.addEventListener("touchmove", onMouseMove);
3128
+ document.addEventListener("mouseup", onMouseUp);
3129
+ document.addEventListener("touchend", onMouseUp);
3130
+ this.svg.appendChild(circle2);
3131
+ this.locators.set(name, circle2);
3132
+ return this;
3133
+ }
3134
+ /** 添加按钮 */
3135
+ button(config) {
3136
+ const { label, onClick } = config;
3137
+ const button = document.createElement("button");
3138
+ button.textContent = label;
3139
+ button.style.padding = "8px 16px";
3140
+ button.style.border = "none";
3141
+ button.style.borderRadius = "6px";
3142
+ button.style.backgroundColor = "#EA580C";
3143
+ button.style.color = "white";
3144
+ button.style.fontSize = "14px";
3145
+ button.style.cursor = "pointer";
3146
+ button.style.transition = "background-color 0.2s";
3147
+ button.addEventListener("mouseenter", () => {
3148
+ button.style.backgroundColor = "#DC4E08";
3149
+ });
3150
+ button.addEventListener("mouseleave", () => {
3151
+ button.style.backgroundColor = "#EA580C";
3152
+ });
3153
+ button.addEventListener("click", onClick);
3154
+ this.controlsContainer.appendChild(button);
3155
+ return this;
3156
+ }
3157
+ /** 添加复选框 */
3158
+ checkbox(name, config = {}) {
3159
+ const { label = name, value = false } = config;
3160
+ this.values[name] = value;
3161
+ const wrapper = document.createElement("label");
3162
+ wrapper.style.display = "flex";
3163
+ wrapper.style.alignItems = "center";
3164
+ wrapper.style.gap = "8px";
3165
+ wrapper.style.cursor = "pointer";
3166
+ const checkbox = document.createElement("input");
3167
+ checkbox.type = "checkbox";
3168
+ checkbox.checked = value;
3169
+ checkbox.style.accentColor = "#EA580C";
3170
+ checkbox.addEventListener("change", () => {
3171
+ this.values[name] = checkbox.checked;
3172
+ this.redraw();
3173
+ });
3174
+ const labelEl = document.createElement("span");
3175
+ labelEl.textContent = label;
3176
+ labelEl.style.fontSize = "14px";
3177
+ labelEl.style.color = "#374151";
3178
+ wrapper.appendChild(checkbox);
3179
+ wrapper.appendChild(labelEl);
3180
+ this.controlsContainer.appendChild(wrapper);
3181
+ return this;
3182
+ }
3183
+ // ========== 绘制方法 ==========
3184
+ /** 设置绘制函数 */
3185
+ draw(fn) {
3186
+ this.drawFn = fn;
3187
+ this.redraw();
3188
+ return this;
3189
+ }
3190
+ /** 重新绘制 */
3191
+ redraw() {
3192
+ if (!this.drawFn) return;
3193
+ const savedLocators = [];
3194
+ this.locators.forEach((element, name) => {
3195
+ savedLocators.push({ name, element });
3196
+ });
3197
+ while (this.svg.firstChild) {
3198
+ this.svg.removeChild(this.svg.firstChild);
3199
+ }
3200
+ const diagram = this.drawFn(this.values);
3201
+ renderToSVG(diagram, this.svg, {
3202
+ width: this.options.width,
3203
+ height: this.options.height,
3204
+ background: this.options.background
3205
+ });
3206
+ savedLocators.forEach(({ name, element }) => {
3207
+ this.svg.appendChild(element);
3208
+ this.locators.set(name, element);
3209
+ });
3210
+ }
3211
+ // ========== 动画循环 ==========
3212
+ /** 启动动画循环 */
3213
+ startAnimationLoop() {
3214
+ const animate = () => {
3215
+ this.animationId = requestAnimationFrame(animate);
3216
+ const now = performance.now();
3217
+ let needsRedraw = false;
3218
+ this.playingSliders.forEach((state, name) => {
3219
+ const elapsed = (now - state.startTime) / 1e3;
3220
+ const progress = elapsed / state.config.playDuration;
3221
+ if (progress >= 1) {
3222
+ if (state.config.loop) {
3223
+ state.startTime = now;
3224
+ this.values[name] = state.config.min;
3225
+ } else {
3226
+ this.values[name] = state.config.max;
3227
+ this.playingSliders.delete(name);
3228
+ }
3229
+ } else {
3230
+ const range = state.config.max - state.config.min;
3231
+ this.values[name] = state.config.min + range * progress;
3232
+ }
3233
+ const control = this.controls.get(name);
3234
+ if (control) {
3235
+ const slider = control.querySelector('input[type="range"]');
3236
+ const valueEl = control.querySelector("span:last-child");
3237
+ if (slider) slider.value = String(this.values[name]);
3238
+ if (valueEl) valueEl.textContent = this.values[name].toFixed(2);
3239
+ }
3240
+ needsRedraw = true;
3241
+ });
3242
+ if (needsRedraw) {
3243
+ this.redraw();
3244
+ }
3245
+ };
3246
+ animate();
3247
+ }
3248
+ // ========== 工具方法 ==========
3249
+ /** 获取当前值 */
3250
+ getValue(name) {
3251
+ return this.values[name];
3252
+ }
3253
+ /** 设置值 */
3254
+ setValue(name, value) {
3255
+ this.values[name] = value;
3256
+ if (Array.isArray(value) && this.locators.has(name)) {
3257
+ const circle2 = this.locators.get(name);
3258
+ circle2.setAttribute("cx", String(value[0]));
3259
+ circle2.setAttribute("cy", String(value[1]));
3260
+ }
3261
+ if (typeof value === "number" && this.controls.has(name)) {
3262
+ const control = this.controls.get(name);
3263
+ const slider = control.querySelector('input[type="range"]');
3264
+ if (slider) slider.value = String(value);
3265
+ }
3266
+ this.redraw();
3267
+ return this;
3268
+ }
3269
+ /** 销毁 */
3270
+ destroy() {
3271
+ if (this.animationId) {
3272
+ cancelAnimationFrame(this.animationId);
3273
+ }
3274
+ this.container.innerHTML = "";
3275
+ }
3276
+ };
3277
+ function createInteractive(container, options) {
3278
+ return new Interactive(container, options);
3279
+ }
3280
+
3281
+ // src/interactive/index.ts
3282
+ function circleConstraint(cx, cy, radius) {
3283
+ return (p) => {
3284
+ const dx = p[0] - cx;
3285
+ const dy = p[1] - cy;
3286
+ const len = Math.sqrt(dx * dx + dy * dy);
3287
+ if (len === 0) return [cx + radius, cy];
3288
+ return [cx + dx / len * radius, cy + dy / len * radius];
3289
+ };
3290
+ }
3291
+ function lineConstraint(x1, y1, x2, y2) {
3292
+ return (p) => {
3293
+ const dx = x2 - x1;
3294
+ const dy = y2 - y1;
3295
+ const lenSq = dx * dx + dy * dy;
3296
+ if (lenSq === 0) return [x1, y1];
3297
+ let t = ((p[0] - x1) * dx + (p[1] - y1) * dy) / lenSq;
3298
+ t = Math.max(0, Math.min(1, t));
3299
+ return [x1 + t * dx, y1 + t * dy];
3300
+ };
3301
+ }
3302
+ function rectConstraint(x, y, width, height) {
3303
+ return (p) => {
3304
+ return [
3305
+ Math.max(x, Math.min(x + width, p[0])),
3306
+ Math.max(y, Math.min(y + height, p[1]))
3307
+ ];
3308
+ };
3309
+ }
3310
+ function gridConstraint(gridSize, offsetX = 0, offsetY = 0) {
3311
+ return (p) => {
3312
+ return [
3313
+ Math.round((p[0] - offsetX) / gridSize) * gridSize + offsetX,
3314
+ Math.round((p[1] - offsetY) / gridSize) * gridSize + offsetY
3315
+ ];
3316
+ };
3317
+ }
3318
+ function polarConstraint(cx, cy, minRadius, maxRadius) {
3319
+ return (p) => {
3320
+ const dx = p[0] - cx;
3321
+ const dy = p[1] - cy;
3322
+ const len = Math.sqrt(dx * dx + dy * dy);
3323
+ if (len === 0) return [cx + minRadius, cy];
3324
+ const constrainedLen = Math.max(minRadius, Math.min(maxRadius, len));
3325
+ return [cx + dx / len * constrainedLen, cy + dy / len * constrainedLen];
3326
+ };
3327
+ }
3328
+ function functionConstraint(fn, minX, maxX) {
3329
+ return (p) => {
3330
+ const x = Math.max(minX, Math.min(maxX, p[0]));
3331
+ return [x, fn(x)];
3332
+ };
3333
+ }
3334
+ export {
3335
+ AnimationGroup,
3336
+ ApplyMethod,
3337
+ Axes,
3338
+ Blink,
3339
+ Circumscribe,
3340
+ Create,
3341
+ DEGREES,
3342
+ DL,
3343
+ DOWN,
3344
+ DR,
3345
+ Diagram,
3346
+ DrawBorderThenFill,
3347
+ FadeIn,
3348
+ FadeInFrom,
3349
+ FadeInFromDown,
3350
+ FadeInFromLeft,
3351
+ FadeInFromRight,
3352
+ FadeInFromUp,
3353
+ FadeOut,
3354
+ FadeOutTo,
3355
+ FadeTransform,
3356
+ Flash,
3357
+ GrowFromCenter,
3358
+ GrowFromEdge,
3359
+ GrowFromPoint,
3360
+ Homotopy,
3361
+ IDENTITY,
3362
+ Indicate,
3363
+ Interactive,
3364
+ LEFT,
3365
+ LaggedStart,
3366
+ LaggedStartMap,
3367
+ Morphing,
3368
+ MoveAlongPath,
3369
+ MoveTo,
3370
+ MoveToTarget,
3371
+ NumberLine,
3372
+ NumberPlane,
3373
+ ORIGIN,
3374
+ PI,
3375
+ PolarAxes,
3376
+ RIGHT,
3377
+ ReplacementTransform,
3378
+ Rotate,
3379
+ Rotating,
3380
+ Scale,
3381
+ ScaleInPlace,
3382
+ Scene,
3383
+ Shift,
3384
+ ShowPassingFlash,
3385
+ SpinInFromNothing,
3386
+ Succession,
3387
+ TAU,
3388
+ Timeline,
3389
+ Transform,
3390
+ TransformMatchingShapes,
3391
+ UL,
3392
+ UP,
3393
+ UR,
3394
+ UpdateFromAlphaFunc,
3395
+ UpdateFromFunc,
3396
+ V2,
3397
+ V3,
3398
+ ValueTracker,
3399
+ Wait,
3400
+ Wiggle,
3401
+ Write,
3402
+ add,
3403
+ altitude,
3404
+ angle,
3405
+ angleBetween,
3406
+ angleBisector,
3407
+ angleMarker,
3408
+ applyMatrix,
3409
+ arc,
3410
+ arrow,
3411
+ centroid,
3412
+ circle,
3413
+ circleConstraint,
3414
+ circleIntersections,
3415
+ circumscribedCircle,
3416
+ clamp,
3417
+ combine,
3418
+ createInteractive,
3419
+ createScene,
3420
+ createTimeline,
3421
+ cross,
3422
+ cubicBezier,
3423
+ degToRad,
3424
+ distance,
3425
+ div,
3426
+ dot2 as dot,
3427
+ doubleArrow,
3428
+ easing,
3429
+ easingMap,
3430
+ ellipse,
3431
+ equilateralTriangle,
3432
+ footOfPerpendicular,
3433
+ functionConstraint,
3434
+ getGSAPEasing,
3435
+ gridConstraint,
3436
+ group,
3437
+ inscribedCircle,
3438
+ length,
3439
+ lerp,
3440
+ lerpNumber,
3441
+ line,
3442
+ lineConstraint,
3443
+ lineIntersection,
3444
+ mapRange,
3445
+ matrixMultiply,
3446
+ median,
3447
+ midpoint,
3448
+ mul,
3449
+ normalize,
3450
+ orthocenter,
3451
+ parallelLine,
3452
+ path,
3453
+ pathFromString,
3454
+ perpendicular,
3455
+ perpendicularBisector,
3456
+ perpendicularLine,
3457
+ polarConstraint,
3458
+ polygon,
3459
+ polyline,
3460
+ quadraticBezier,
3461
+ radToDeg,
3462
+ rect,
3463
+ rectConstraint,
3464
+ reflect,
3465
+ reflectOverPoint,
3466
+ reflectPoint,
3467
+ reflectPointOverLine,
3468
+ regularPolygon,
3469
+ renderToRough,
3470
+ renderToSVG,
3471
+ rightAngleMarker,
3472
+ rotate,
3473
+ rotationMatrix,
3474
+ roughPresets,
3475
+ sampleParametric,
3476
+ scaleMatrix,
3477
+ sector,
3478
+ square,
3479
+ star,
3480
+ sub,
3481
+ tex,
3482
+ text,
3483
+ toSVGString,
3484
+ translationMatrix,
3485
+ triangle,
3486
+ dot as vectorDot
3487
+ };