@sarmal/core 0.5.0 → 0.7.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/auto-init.cjs +174 -40
- package/dist/auto-init.cjs.map +1 -1
- package/dist/auto-init.js +174 -40
- package/dist/auto-init.js.map +1 -1
- package/dist/index.cjs +278 -41
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +52 -12
- package/dist/index.d.ts +52 -12
- package/dist/index.js +278 -41
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -42,8 +42,8 @@ var CircularBuffer = class {
|
|
|
42
42
|
return this.count;
|
|
43
43
|
}
|
|
44
44
|
};
|
|
45
|
-
function
|
|
46
|
-
|
|
45
|
+
function resolveCurve(curveDef) {
|
|
46
|
+
return {
|
|
47
47
|
name: curveDef.name,
|
|
48
48
|
fn: curveDef.fn,
|
|
49
49
|
period: curveDef.period ?? TWO_PI,
|
|
@@ -51,15 +51,37 @@ function createEngine(curveDef, trailLength = 120) {
|
|
|
51
51
|
skeleton: curveDef.skeleton,
|
|
52
52
|
skeletonFn: curveDef.skeletonFn
|
|
53
53
|
};
|
|
54
|
+
}
|
|
55
|
+
function createEngine(curveDef, trailLength = 120) {
|
|
56
|
+
let curve = resolveCurve(curveDef);
|
|
54
57
|
const trail = new CircularBuffer(trailLength);
|
|
55
58
|
let t = 0;
|
|
56
59
|
let actualTime = 0;
|
|
60
|
+
let morphCurveB = null;
|
|
61
|
+
let _morphAlpha = null;
|
|
62
|
+
let _morphStrategy = "normalized";
|
|
63
|
+
function sampleSkeleton(c, sampleT) {
|
|
64
|
+
if (c.skeletonFn) {
|
|
65
|
+
return c.skeletonFn(sampleT);
|
|
66
|
+
}
|
|
67
|
+
if (c.skeleton === "live") {
|
|
68
|
+
return c.fn(sampleT, actualTime, {});
|
|
69
|
+
}
|
|
70
|
+
return c.fn(sampleT, 0, {});
|
|
71
|
+
}
|
|
57
72
|
return {
|
|
58
73
|
tick(deltaTime) {
|
|
59
74
|
t = (t + curve.speed * deltaTime) % curve.period;
|
|
60
75
|
actualTime += deltaTime;
|
|
61
|
-
|
|
62
|
-
|
|
76
|
+
if (morphCurveB !== null && _morphAlpha !== null) {
|
|
77
|
+
const a = curve.fn(t, actualTime, {});
|
|
78
|
+
const tB = _morphStrategy === "normalized" ? t / curve.period * morphCurveB.period : t;
|
|
79
|
+
const b = morphCurveB.fn(tB, actualTime, {});
|
|
80
|
+
trail.push(a.x + (b.x - a.x) * _morphAlpha, a.y + (b.y - a.y) * _morphAlpha);
|
|
81
|
+
} else {
|
|
82
|
+
const point = curve.fn(t, actualTime, {});
|
|
83
|
+
trail.push(point.x, point.y);
|
|
84
|
+
}
|
|
63
85
|
return trail.toArray();
|
|
64
86
|
},
|
|
65
87
|
get trailCount() {
|
|
@@ -68,6 +90,9 @@ function createEngine(curveDef, trailLength = 120) {
|
|
|
68
90
|
get isLiveSkeleton() {
|
|
69
91
|
return curve.skeleton === "live";
|
|
70
92
|
},
|
|
93
|
+
get morphAlpha() {
|
|
94
|
+
return _morphAlpha;
|
|
95
|
+
},
|
|
71
96
|
reset() {
|
|
72
97
|
t = 0;
|
|
73
98
|
actualTime = 0;
|
|
@@ -96,24 +121,62 @@ function createEngine(curveDef, trailLength = 120) {
|
|
|
96
121
|
trail.push(point.x, point.y);
|
|
97
122
|
}
|
|
98
123
|
},
|
|
124
|
+
startMorph(target, strategy = "normalized") {
|
|
125
|
+
const resolvedTarget = resolveCurve(target);
|
|
126
|
+
if (morphCurveB !== null && _morphAlpha !== null) {
|
|
127
|
+
const frozenAlpha = _morphAlpha;
|
|
128
|
+
const frozenA = curve;
|
|
129
|
+
const frozenB = morphCurveB;
|
|
130
|
+
const frozenStrategy = _morphStrategy;
|
|
131
|
+
curve = {
|
|
132
|
+
...frozenB,
|
|
133
|
+
fn: (sampleT, time, params) => {
|
|
134
|
+
const a = frozenA.fn(sampleT, time, params);
|
|
135
|
+
const tB = frozenStrategy === "normalized" ? sampleT / frozenA.period * frozenB.period : sampleT;
|
|
136
|
+
const b = frozenB.fn(tB, time, params);
|
|
137
|
+
return {
|
|
138
|
+
x: a.x + (b.x - a.x) * frozenAlpha,
|
|
139
|
+
y: a.y + (b.y - a.y) * frozenAlpha
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
_morphStrategy = strategy;
|
|
145
|
+
morphCurveB = resolvedTarget;
|
|
146
|
+
_morphAlpha = 0;
|
|
147
|
+
},
|
|
148
|
+
setMorphAlpha(alpha) {
|
|
149
|
+
_morphAlpha = alpha;
|
|
150
|
+
},
|
|
151
|
+
completeMorph() {
|
|
152
|
+
if (morphCurveB !== null) {
|
|
153
|
+
if (_morphStrategy === "normalized" && curve.period !== morphCurveB.period) {
|
|
154
|
+
t = t / curve.period * morphCurveB.period;
|
|
155
|
+
}
|
|
156
|
+
curve = morphCurveB;
|
|
157
|
+
}
|
|
158
|
+
morphCurveB = null;
|
|
159
|
+
_morphAlpha = null;
|
|
160
|
+
},
|
|
99
161
|
getSarmalSkeleton() {
|
|
100
162
|
const steps = Math.ceil(curve.period * POINTS_PER_PERIOD_UNIT);
|
|
101
163
|
const points = new Array(steps);
|
|
102
|
-
if (
|
|
164
|
+
if (morphCurveB !== null && _morphAlpha !== null) {
|
|
103
165
|
for (let i = 0; i < steps; i++) {
|
|
104
166
|
const sampleT = i / (steps - 1) * curve.period;
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
} else {
|
|
113
|
-
for (let i = 0; i < steps; i++) {
|
|
114
|
-
const sampleT = i / (steps - 1) * curve.period;
|
|
115
|
-
points[i] = curve.fn(sampleT, 0, {});
|
|
167
|
+
const a = sampleSkeleton(curve, sampleT);
|
|
168
|
+
const tB = _morphStrategy === "normalized" ? sampleT / curve.period * morphCurveB.period : sampleT;
|
|
169
|
+
const b = sampleSkeleton(morphCurveB, tB);
|
|
170
|
+
points[i] = {
|
|
171
|
+
x: a.x + (b.x - a.x) * _morphAlpha,
|
|
172
|
+
y: a.y + (b.y - a.y) * _morphAlpha
|
|
173
|
+
};
|
|
116
174
|
}
|
|
175
|
+
return points;
|
|
176
|
+
}
|
|
177
|
+
for (let i = 0; i < steps; i++) {
|
|
178
|
+
const sampleT = i / (steps - 1) * curve.period;
|
|
179
|
+
points[i] = sampleSkeleton(curve, sampleT);
|
|
117
180
|
}
|
|
118
181
|
return points;
|
|
119
182
|
}
|
|
@@ -121,6 +184,7 @@ function createEngine(curveDef, trailLength = 120) {
|
|
|
121
184
|
}
|
|
122
185
|
|
|
123
186
|
// src/renderer.ts
|
|
187
|
+
var DEFAULT_MORPH_DURATION_MS = 300;
|
|
124
188
|
var DEFAULT_HEAD_RADIUS = 4;
|
|
125
189
|
var DEFAULT_GLOW_SIZE = 20;
|
|
126
190
|
var DEFAULT_SKELETON_COLOR = "#ffffff";
|
|
@@ -163,25 +227,20 @@ function createRenderer(options) {
|
|
|
163
227
|
let offsetY = 0;
|
|
164
228
|
let animationId = null;
|
|
165
229
|
let lastTime = 0;
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
230
|
+
let morphResolve = null;
|
|
231
|
+
let morphDurationMs = DEFAULT_MORPH_DURATION_MS;
|
|
232
|
+
let morphAlpha = 0;
|
|
233
|
+
let morphBoundsA = null;
|
|
234
|
+
let morphBoundsB = null;
|
|
235
|
+
function computeBoundaries(pts) {
|
|
236
|
+
if (pts.length === 0) return null;
|
|
237
|
+
const first = pts[0];
|
|
171
238
|
let minX = first.x, maxX = first.x, minY = first.y, maxY = first.y;
|
|
172
|
-
for (const p of
|
|
173
|
-
if (p.x < minX)
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
if (p.
|
|
177
|
-
maxX = p.x;
|
|
178
|
-
}
|
|
179
|
-
if (p.y < minY) {
|
|
180
|
-
minY = p.y;
|
|
181
|
-
}
|
|
182
|
-
if (p.y > maxY) {
|
|
183
|
-
maxY = p.y;
|
|
184
|
-
}
|
|
239
|
+
for (const p of pts) {
|
|
240
|
+
if (p.x < minX) minX = p.x;
|
|
241
|
+
if (p.x > maxX) maxX = p.x;
|
|
242
|
+
if (p.y < minY) minY = p.y;
|
|
243
|
+
if (p.y > maxY) maxY = p.y;
|
|
185
244
|
}
|
|
186
245
|
const width = maxX - minX;
|
|
187
246
|
const height = maxY - minY;
|
|
@@ -189,11 +248,22 @@ function createRenderer(options) {
|
|
|
189
248
|
const canvasHeight = canvas.height;
|
|
190
249
|
const scaleX = canvasWidth / (width * (1 + FIT_PADDING * 2));
|
|
191
250
|
const scaleY = canvasHeight / (height * (1 + FIT_PADDING * 2));
|
|
192
|
-
|
|
193
|
-
const boundsWidth = width *
|
|
194
|
-
const boundsHeight = height *
|
|
195
|
-
|
|
196
|
-
|
|
251
|
+
const s = Math.min(scaleX, scaleY);
|
|
252
|
+
const boundsWidth = width * s;
|
|
253
|
+
const boundsHeight = height * s;
|
|
254
|
+
return {
|
|
255
|
+
scale: s,
|
|
256
|
+
offsetX: (canvasWidth - boundsWidth) / 2 - minX * s,
|
|
257
|
+
offsetY: (canvasHeight - boundsHeight) / 2 - minY * s
|
|
258
|
+
};
|
|
259
|
+
}
|
|
260
|
+
function calculateBoundaries() {
|
|
261
|
+
const b = computeBoundaries(skeleton);
|
|
262
|
+
if (b) {
|
|
263
|
+
scale = b.scale;
|
|
264
|
+
offsetX = b.offsetX;
|
|
265
|
+
offsetY = b.offsetY;
|
|
266
|
+
}
|
|
197
267
|
}
|
|
198
268
|
function buildSkeletonCanvas() {
|
|
199
269
|
if (skeleton.length < 2) return;
|
|
@@ -210,10 +280,25 @@ function createRenderer(options) {
|
|
|
210
280
|
}
|
|
211
281
|
skeletonCtx.stroke();
|
|
212
282
|
}
|
|
283
|
+
function drawSkeletonPath(pts, opacity) {
|
|
284
|
+
if (pts.length < 2) return;
|
|
285
|
+
ctx.strokeStyle = `rgba(${hexToRgbComponents(opts.skeletonColor)},${opacity})`;
|
|
286
|
+
ctx.lineWidth = 1.5;
|
|
287
|
+
ctx.beginPath();
|
|
288
|
+
ctx.moveTo(pts[0].x * scale + offsetX, pts[0].y * scale + offsetY);
|
|
289
|
+
for (let i = 1; i < pts.length; i++) {
|
|
290
|
+
ctx.lineTo(pts[i].x * scale + offsetX, pts[i].y * scale + offsetY);
|
|
291
|
+
}
|
|
292
|
+
ctx.stroke();
|
|
293
|
+
}
|
|
213
294
|
function drawSkeleton() {
|
|
214
295
|
if (opts.skeletonColor === "transparent") {
|
|
215
296
|
return;
|
|
216
297
|
}
|
|
298
|
+
if (engine.morphAlpha !== null) {
|
|
299
|
+
drawSkeletonPath(engine.getSarmalSkeleton(), DEFAULT_SKELETON_OPACITY);
|
|
300
|
+
return;
|
|
301
|
+
}
|
|
217
302
|
if (engine.isLiveSkeleton) {
|
|
218
303
|
if (skeleton.length < 2) {
|
|
219
304
|
return;
|
|
@@ -280,11 +365,34 @@ function createRenderer(options) {
|
|
|
280
365
|
const now = performance.now();
|
|
281
366
|
const deltaTime = Math.min((now - lastTime) / 1e3, 1 / 30);
|
|
282
367
|
lastTime = now;
|
|
368
|
+
if (engine.morphAlpha !== null) {
|
|
369
|
+
morphAlpha = Math.min(1, morphAlpha + deltaTime / (morphDurationMs / 1e3));
|
|
370
|
+
engine.setMorphAlpha(morphAlpha);
|
|
371
|
+
if (morphBoundsA && morphBoundsB) {
|
|
372
|
+
const a = morphBoundsA;
|
|
373
|
+
const b = morphBoundsB;
|
|
374
|
+
scale = a.scale + (b.scale - a.scale) * morphAlpha;
|
|
375
|
+
offsetX = a.offsetX + (b.offsetX - a.offsetX) * morphAlpha;
|
|
376
|
+
offsetY = a.offsetY + (b.offsetY - a.offsetY) * morphAlpha;
|
|
377
|
+
}
|
|
378
|
+
if (morphAlpha >= 1) {
|
|
379
|
+
engine.completeMorph();
|
|
380
|
+
morphResolve?.();
|
|
381
|
+
morphResolve = null;
|
|
382
|
+
morphAlpha = 0;
|
|
383
|
+
morphBoundsA = null;
|
|
384
|
+
morphBoundsB = null;
|
|
385
|
+
skeleton = engine.getSarmalSkeleton();
|
|
386
|
+
if (!engine.isLiveSkeleton) {
|
|
387
|
+
buildSkeletonCanvas();
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
}
|
|
283
391
|
trail = engine.tick(deltaTime);
|
|
284
392
|
trailCount = engine.trailCount;
|
|
285
393
|
head = trailCount > 0 ? trail[trailCount - 1] : null;
|
|
286
394
|
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
|
287
|
-
if (engine.isLiveSkeleton) {
|
|
395
|
+
if (engine.isLiveSkeleton && engine.morphAlpha === null) {
|
|
288
396
|
skeleton = engine.getSarmalSkeleton();
|
|
289
397
|
calculateBoundaries();
|
|
290
398
|
}
|
|
@@ -329,11 +437,38 @@ function createRenderer(options) {
|
|
|
329
437
|
},
|
|
330
438
|
seekWithTrail(t) {
|
|
331
439
|
engine.seekWithTrail(t);
|
|
440
|
+
},
|
|
441
|
+
morphTo(target, options2) {
|
|
442
|
+
const interruptBounds = morphResolve !== null ? { scale, offsetX, offsetY } : null;
|
|
443
|
+
if (morphResolve !== null) {
|
|
444
|
+
engine.completeMorph();
|
|
445
|
+
morphResolve();
|
|
446
|
+
morphResolve = null;
|
|
447
|
+
morphAlpha = 0;
|
|
448
|
+
morphBoundsA = null;
|
|
449
|
+
morphBoundsB = null;
|
|
450
|
+
}
|
|
451
|
+
morphDurationMs = options2?.duration ?? DEFAULT_MORPH_DURATION_MS;
|
|
452
|
+
morphAlpha = 0;
|
|
453
|
+
morphBoundsA = interruptBounds ?? computeBoundaries(engine.getSarmalSkeleton()) ?? { scale, offsetX, offsetY };
|
|
454
|
+
engine.startMorph(target, options2?.morphStrategy);
|
|
455
|
+
const period = target.period ?? Math.PI * 2;
|
|
456
|
+
const samples = Math.max(50, Math.round(period * 20));
|
|
457
|
+
const skeletonFn = target.skeletonFn ?? ((t) => target.fn(t, 0, {}));
|
|
458
|
+
const skeletonB = Array.from(
|
|
459
|
+
{ length: samples + 1 },
|
|
460
|
+
(_, i) => skeletonFn(i / samples * period)
|
|
461
|
+
);
|
|
462
|
+
morphBoundsB = computeBoundaries(skeletonB) ?? { scale, offsetX, offsetY };
|
|
463
|
+
return new Promise((resolve) => {
|
|
464
|
+
morphResolve = resolve;
|
|
465
|
+
});
|
|
332
466
|
}
|
|
333
467
|
};
|
|
334
468
|
}
|
|
335
469
|
|
|
336
470
|
// src/renderer-svg.ts
|
|
471
|
+
var DEFAULT_MORPH_DURATION_MS2 = 300;
|
|
337
472
|
var TRAIL_BATCH_COUNT = 12;
|
|
338
473
|
var TRAIL_FADE_CURVE2 = 1.5;
|
|
339
474
|
var TRAIL_MAX_OPACITY2 = 0.88;
|
|
@@ -398,6 +533,20 @@ function createSVGRenderer(options) {
|
|
|
398
533
|
skeletonPath.setAttribute("stroke-opacity", String(DEFAULT_SKELETON_OPACITY2));
|
|
399
534
|
skeletonPath.setAttribute("stroke-width", "1.5");
|
|
400
535
|
svg.appendChild(skeletonPath);
|
|
536
|
+
const skeletonPathA = el("path");
|
|
537
|
+
skeletonPathA.setAttribute("fill", "none");
|
|
538
|
+
skeletonPathA.setAttribute("stroke", opts.skeletonColor);
|
|
539
|
+
skeletonPathA.setAttribute("stroke-width", "1.5");
|
|
540
|
+
skeletonPathA.setAttribute("visibility", "hidden");
|
|
541
|
+
svg.appendChild(skeletonPathA);
|
|
542
|
+
const skeletonPathB = el("path");
|
|
543
|
+
skeletonPathB.setAttribute("fill", "none");
|
|
544
|
+
skeletonPathB.setAttribute("stroke", opts.skeletonColor);
|
|
545
|
+
skeletonPathB.setAttribute("stroke-width", "1.5");
|
|
546
|
+
skeletonPathB.setAttribute("visibility", "hidden");
|
|
547
|
+
svg.appendChild(skeletonPathB);
|
|
548
|
+
let morphPathABuilt = "";
|
|
549
|
+
let morphPathBBuilt = "";
|
|
401
550
|
const trailPaths = [];
|
|
402
551
|
for (let i = 0; i < TRAIL_BATCH_COUNT; i++) {
|
|
403
552
|
const path = el("path");
|
|
@@ -513,13 +662,69 @@ function createSVGRenderer(options) {
|
|
|
513
662
|
let animationId = null;
|
|
514
663
|
let lastTime = 0;
|
|
515
664
|
const prefersReducedMotion = typeof window !== "undefined" && window.matchMedia("(prefers-reduced-motion: reduce)").matches;
|
|
665
|
+
let morphResolve = null;
|
|
666
|
+
let morphDurationMs = DEFAULT_MORPH_DURATION_MS2;
|
|
667
|
+
let morphTarget = null;
|
|
668
|
+
let morphAlpha = 0;
|
|
669
|
+
function buildSkeletonPath(target, scale2, offsetX2, offsetY2) {
|
|
670
|
+
const period = target.period ?? Math.PI * 2;
|
|
671
|
+
const samples = Math.max(50, Math.round(period * 20));
|
|
672
|
+
const points = [];
|
|
673
|
+
for (let i = 0; i <= samples; i++) {
|
|
674
|
+
const t = i / samples * period;
|
|
675
|
+
const p = target.fn(t, 0, {});
|
|
676
|
+
points.push(p);
|
|
677
|
+
}
|
|
678
|
+
if (points.length < 2) {
|
|
679
|
+
return "";
|
|
680
|
+
}
|
|
681
|
+
const px2 = (p) => (p.x * scale2 + offsetX2).toFixed(2);
|
|
682
|
+
const py2 = (p) => (p.y * scale2 + offsetY2).toFixed(2);
|
|
683
|
+
let d = `M${px2(points[0])} ${py2(points[0])}`;
|
|
684
|
+
for (let i = 1; i < points.length; i++) {
|
|
685
|
+
d += ` L${px2(points[i])} ${py2(points[i])}`;
|
|
686
|
+
}
|
|
687
|
+
d += " Z";
|
|
688
|
+
return d;
|
|
689
|
+
}
|
|
516
690
|
function renderFrame() {
|
|
517
691
|
const now = performance.now();
|
|
518
692
|
const dt = Math.min((now - lastTime) / 1e3, 1 / 30);
|
|
519
693
|
lastTime = now;
|
|
694
|
+
if (engine.morphAlpha !== null) {
|
|
695
|
+
morphAlpha = Math.min(1, morphAlpha + dt / (morphDurationMs / 1e3));
|
|
696
|
+
engine.setMorphAlpha(morphAlpha);
|
|
697
|
+
if (morphPathABuilt) {
|
|
698
|
+
skeletonPathA.setAttribute("d", morphPathABuilt);
|
|
699
|
+
skeletonPathA.setAttribute("visibility", "visible");
|
|
700
|
+
skeletonPathA.setAttribute(
|
|
701
|
+
"stroke-opacity",
|
|
702
|
+
String((1 - morphAlpha) * DEFAULT_SKELETON_OPACITY2)
|
|
703
|
+
);
|
|
704
|
+
}
|
|
705
|
+
if (morphPathBBuilt) {
|
|
706
|
+
skeletonPathB.setAttribute("d", morphPathBBuilt);
|
|
707
|
+
skeletonPathB.setAttribute("visibility", "visible");
|
|
708
|
+
skeletonPathB.setAttribute("stroke-opacity", String(morphAlpha * DEFAULT_SKELETON_OPACITY2));
|
|
709
|
+
}
|
|
710
|
+
if (morphAlpha >= 1) {
|
|
711
|
+
engine.completeMorph();
|
|
712
|
+
morphResolve?.();
|
|
713
|
+
morphResolve = null;
|
|
714
|
+
morphTarget = null;
|
|
715
|
+
morphAlpha = 0;
|
|
716
|
+
morphPathABuilt = "";
|
|
717
|
+
morphPathBBuilt = "";
|
|
718
|
+
skeletonPathA.setAttribute("visibility", "hidden");
|
|
719
|
+
skeletonPathB.setAttribute("visibility", "hidden");
|
|
720
|
+
const newSkeleton = engine.getSarmalSkeleton();
|
|
721
|
+
calculateBoundaries(newSkeleton);
|
|
722
|
+
updateSkeleton(newSkeleton);
|
|
723
|
+
}
|
|
724
|
+
}
|
|
520
725
|
const trail = engine.tick(dt);
|
|
521
726
|
const trailCount = engine.trailCount;
|
|
522
|
-
if (engine.isLiveSkeleton) {
|
|
727
|
+
if (engine.isLiveSkeleton && engine.morphAlpha === null) {
|
|
523
728
|
const liveSkeleton = engine.getSarmalSkeleton();
|
|
524
729
|
calculateBoundaries(liveSkeleton);
|
|
525
730
|
updateSkeleton(liveSkeleton);
|
|
@@ -560,6 +765,38 @@ function createSVGRenderer(options) {
|
|
|
560
765
|
},
|
|
561
766
|
seekWithTrail(t) {
|
|
562
767
|
engine.seekWithTrail(t);
|
|
768
|
+
},
|
|
769
|
+
morphTo(target, options2) {
|
|
770
|
+
if (morphResolve !== null) {
|
|
771
|
+
engine.completeMorph();
|
|
772
|
+
morphResolve();
|
|
773
|
+
morphResolve = null;
|
|
774
|
+
morphAlpha = 0;
|
|
775
|
+
skeletonPathA.setAttribute("visibility", "hidden");
|
|
776
|
+
skeletonPathB.setAttribute("visibility", "hidden");
|
|
777
|
+
}
|
|
778
|
+
morphDurationMs = options2?.duration ?? DEFAULT_MORPH_DURATION_MS2;
|
|
779
|
+
morphTarget = target;
|
|
780
|
+
morphAlpha = 0;
|
|
781
|
+
const currentSkeleton = engine.getSarmalSkeleton();
|
|
782
|
+
if (currentSkeleton.length >= 2) {
|
|
783
|
+
const px2 = (p) => (p.x * scale + offsetX).toFixed(2);
|
|
784
|
+
const py2 = (p) => (p.y * scale + offsetY).toFixed(2);
|
|
785
|
+
morphPathABuilt = `M${px2(currentSkeleton[0])} ${py2(currentSkeleton[0])}`;
|
|
786
|
+
for (let i = 1; i < currentSkeleton.length; i++) {
|
|
787
|
+
morphPathABuilt += ` L${px2(currentSkeleton[i])} ${py2(currentSkeleton[i])}`;
|
|
788
|
+
}
|
|
789
|
+
morphPathABuilt += " Z";
|
|
790
|
+
} else {
|
|
791
|
+
morphPathABuilt = "";
|
|
792
|
+
}
|
|
793
|
+
engine.startMorph(target, options2?.morphStrategy);
|
|
794
|
+
if (morphTarget) {
|
|
795
|
+
morphPathBBuilt = buildSkeletonPath(morphTarget, scale, offsetX, offsetY);
|
|
796
|
+
}
|
|
797
|
+
return new Promise((resolve) => {
|
|
798
|
+
morphResolve = resolve;
|
|
799
|
+
});
|
|
563
800
|
}
|
|
564
801
|
};
|
|
565
802
|
}
|