@pixodesk/svg-animator-web 1.0.19 → 1.0.20
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/README.md +31 -14
- package/dist/index.cjs +363 -65
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +285 -4
- package/dist/index.d.ts +285 -4
- package/dist/index.js +361 -65
- package/dist/index.js.map +1 -1
- package/dist/index.min.cjs +1 -1
- package/dist/index.min.js +1 -1
- package/dist/index.umd.js +361 -65
- package/dist/index.umd.js.map +1 -1
- package/dist/index.umd.min.js +1 -1
- package/package.json +2 -1
package/dist/index.cjs
CHANGED
|
@@ -100,6 +100,7 @@ __export(index_exports, {
|
|
|
100
100
|
createAnimatorImpl: () => createAnimatorImpl,
|
|
101
101
|
createBasicFrameLoopAnimator: () => createBasicFrameLoopAnimator,
|
|
102
102
|
createFrameLoopAnimator: () => createFrameLoopAnimator,
|
|
103
|
+
createPathSampler: () => createPathSampler,
|
|
103
104
|
createWebApiAnimator: () => createWebApiAnimator,
|
|
104
105
|
describeSchema: () => describeSchema,
|
|
105
106
|
diffInEffect: () => diffInEffect,
|
|
@@ -114,6 +115,7 @@ __export(index_exports, {
|
|
|
114
115
|
isPxElementFileFormat: () => isPxElementFileFormat,
|
|
115
116
|
isPxElementFileFormatDeep: () => isPxElementFileFormatDeep,
|
|
116
117
|
jsonElementFactory: () => jsonElementFactory,
|
|
118
|
+
layoutGlyphTextChars: () => layoutGlyphTextChars,
|
|
117
119
|
loadTagAnimators: () => loadTagAnimators,
|
|
118
120
|
materialiseAllInTree: () => materialiseAllInTree,
|
|
119
121
|
materialiseAnimatedUseInstances: () => materialiseAnimatedUseInstances,
|
|
@@ -1090,6 +1092,10 @@ var PxMaskedByEffectSchema = implementsInterface()(px.object({
|
|
|
1090
1092
|
maskUnits: px.string().optional(),
|
|
1091
1093
|
maskContentUnits: px.string().optional()
|
|
1092
1094
|
}));
|
|
1095
|
+
var PxClipPathEffectSchema = implementsInterface()(px.object({
|
|
1096
|
+
d: px.string().optional(),
|
|
1097
|
+
animate: PxPropertyAnimationSchema.optional()
|
|
1098
|
+
}));
|
|
1093
1099
|
var PxTrimPathEffectSchema = implementsInterface()(px.object({
|
|
1094
1100
|
offset: PxAnimatableNumberSchema.optional(),
|
|
1095
1101
|
range: PxAnimatableVec2Schema.optional(),
|
|
@@ -1157,6 +1163,7 @@ var PxEffectsSchema = implementsInterface()(px.object({
|
|
|
1157
1163
|
transformation: PxTransformationEffectSchema.optional(),
|
|
1158
1164
|
repeater: PxRepeaterEffectSchema.optional(),
|
|
1159
1165
|
maskedBy: PxMaskedByEffectSchema.optional(),
|
|
1166
|
+
clipPath: PxClipPathEffectSchema.optional(),
|
|
1160
1167
|
trimPath: PxTrimPathEffectSchema.optional(),
|
|
1161
1168
|
clone: PxCloneEffectSchema.optional(),
|
|
1162
1169
|
isCombinedShape: px.boolean().optional(),
|
|
@@ -1463,6 +1470,17 @@ function formatOffset(o) {
|
|
|
1463
1470
|
return pct + "%";
|
|
1464
1471
|
}
|
|
1465
1472
|
|
|
1473
|
+
// src/effects/clipPathEffect.ts
|
|
1474
|
+
function applyClipPathEffect(node, fx, ctx) {
|
|
1475
|
+
if (!fx || !fx.d && !fx.animate) return node;
|
|
1476
|
+
const clipId = genId(ctx, "clip");
|
|
1477
|
+
const pathChild = { type: "path", d: fx.d };
|
|
1478
|
+
if (fx.animate) pathChild.animate = { d: fx.animate };
|
|
1479
|
+
ctx.defs.push({ type: "clipPath", id: clipId, children: [pathChild] });
|
|
1480
|
+
node.clipPath = "url(#" + clipId + ")";
|
|
1481
|
+
return node;
|
|
1482
|
+
}
|
|
1483
|
+
|
|
1466
1484
|
// src/effects/maskedByEffect.ts
|
|
1467
1485
|
function applyMaskedByEffect(node, fx, transformation, ctx) {
|
|
1468
1486
|
if (!fx) return node;
|
|
@@ -1905,6 +1923,9 @@ function synthesiseScale(raw, i) {
|
|
|
1905
1923
|
var RETIME_MATERIALISATION_MODE_INLINE_G = false;
|
|
1906
1924
|
function asRetime(r) {
|
|
1907
1925
|
var _a, _b;
|
|
1926
|
+
if (r.timeCrop) {
|
|
1927
|
+
console.warn("retime: `timeCrop` is not supported yet and will be ignored");
|
|
1928
|
+
}
|
|
1908
1929
|
return { start: (_a = r.start) != null ? _a : 0, stretch: (_b = r.stretch) != null ? _b : 1 };
|
|
1909
1930
|
}
|
|
1910
1931
|
function concatRetime(child, parent) {
|
|
@@ -2323,6 +2344,8 @@ var SVG_CAMEL_CASE_ATTRS = /* @__PURE__ */ new Set([
|
|
|
2323
2344
|
// Filter
|
|
2324
2345
|
"filterUnits",
|
|
2325
2346
|
"primitiveUnits",
|
|
2347
|
+
"tableValues",
|
|
2348
|
+
// feFuncR/G/B/A transfer table (type="table")
|
|
2326
2349
|
"stdDeviation",
|
|
2327
2350
|
"baseFrequency",
|
|
2328
2351
|
"numOctaves",
|
|
@@ -2581,6 +2604,9 @@ function createPathSampler(d) {
|
|
|
2581
2604
|
totalLength,
|
|
2582
2605
|
closed,
|
|
2583
2606
|
sampleAtDistance(dist) {
|
|
2607
|
+
if (closed && totalLength > 0 && (dist < 0 || dist > totalLength)) {
|
|
2608
|
+
return sampleOn((dist % totalLength + totalLength) % totalLength);
|
|
2609
|
+
}
|
|
2584
2610
|
if (!closed && (dist < 0 || dist > totalLength)) {
|
|
2585
2611
|
const edge = dist < 0 ? 0 : totalLength;
|
|
2586
2612
|
const p = sampleOn(edge);
|
|
@@ -2837,6 +2863,19 @@ function soleFontOf(glyphs) {
|
|
|
2837
2863
|
const names = Object.keys(glyphs);
|
|
2838
2864
|
return names.length === 1 ? glyphs[names[0]] : void 0;
|
|
2839
2865
|
}
|
|
2866
|
+
var MISSING_GLYPH_ADVANCE_EM = 0.6;
|
|
2867
|
+
function missingGlyphBoxEm(advanceEm, ascentEm) {
|
|
2868
|
+
if (advanceEm <= 0 || ascentEm <= 0) return "";
|
|
2869
|
+
const inset = 0.08;
|
|
2870
|
+
const x0 = advanceEm * inset, x1 = advanceEm * (1 - inset);
|
|
2871
|
+
const y1 = -ascentEm * (1 - inset);
|
|
2872
|
+
const bw = x1 - x0, bh = -y1;
|
|
2873
|
+
const t = Math.max(1, Math.min(bw, bh) * 0.12);
|
|
2874
|
+
const outer = "M" + x0 + " 0L" + x1 + " 0L" + x1 + " " + y1 + "L" + x0 + " " + y1 + "Z";
|
|
2875
|
+
if (bw <= 2 * t || bh <= 2 * t) return outer;
|
|
2876
|
+
const ix0 = x0 + t, ix1 = x1 - t, iyb = -t, iyt = y1 + t;
|
|
2877
|
+
return outer + "M" + ix0 + " " + iyb + "L" + ix0 + " " + iyt + "L" + ix1 + " " + iyt + "L" + ix1 + " " + iyb + "Z";
|
|
2878
|
+
}
|
|
2840
2879
|
function materialiseGlyphTextHorizontal(node, opts) {
|
|
2841
2880
|
var _a, _b, _c, _d;
|
|
2842
2881
|
const { glyphs, create = jsonElementFactory, warnings } = opts;
|
|
@@ -2846,15 +2885,26 @@ function materialiseGlyphTextHorizontal(node, opts) {
|
|
|
2846
2885
|
const lines = [{ start: pen.x, end: pen.x }];
|
|
2847
2886
|
let line = 0;
|
|
2848
2887
|
const renderChars = (content, s) => {
|
|
2888
|
+
var _a2;
|
|
2849
2889
|
const gf = glyphFontFor(s, glyphs, soleFont, warnings);
|
|
2850
|
-
|
|
2851
|
-
const scale = s.fontSize /
|
|
2890
|
+
const upm = (gf == null ? void 0 : gf.unitsPerEm) || 1e3;
|
|
2891
|
+
const scale = s.fontSize / upm;
|
|
2892
|
+
const ascentEm = (_a2 = gf == null ? void 0 : gf.ascent) != null ? _a2 : 0.9 * upm;
|
|
2852
2893
|
const paint = paintOf(s);
|
|
2853
2894
|
for (let i = 0; i < content.length; i++) {
|
|
2854
2895
|
const ch = content.charAt(i);
|
|
2855
|
-
const g = gf.glyphs[ch];
|
|
2856
|
-
if (g && g.d)
|
|
2857
|
-
|
|
2896
|
+
const g = gf == null ? void 0 : gf.glyphs[ch];
|
|
2897
|
+
if (g && g.d) {
|
|
2898
|
+
placements.push({ glyphD: g.d, m: [scale, 0, 0, scale, pen.x, pen.y], paint, line, x: pen.x, y: pen.y, scale });
|
|
2899
|
+
pen.x += g.width * scale;
|
|
2900
|
+
} else if (/\S/.test(ch)) {
|
|
2901
|
+
const advEm = g && g.width > 0 ? g.width : MISSING_GLYPH_ADVANCE_EM * upm;
|
|
2902
|
+
placements.push({ glyphD: missingGlyphBoxEm(advEm, ascentEm), m: [scale, 0, 0, scale, pen.x, pen.y], paint, line, x: pen.x, y: pen.y, scale });
|
|
2903
|
+
pen.x += advEm * scale;
|
|
2904
|
+
} else {
|
|
2905
|
+
pen.x += (g ? g.width : 0) * scale;
|
|
2906
|
+
}
|
|
2907
|
+
pen.x += s.letterSpacing + (ch === " " ? s.wordSpacing : 0);
|
|
2858
2908
|
lines[line].end = pen.x;
|
|
2859
2909
|
}
|
|
2860
2910
|
};
|
|
@@ -2889,24 +2939,152 @@ function materialiseGlyphTextHorizontal(node, opts) {
|
|
|
2889
2939
|
}
|
|
2890
2940
|
return toGroup(node, buildPaths(placements, create, warnings), create);
|
|
2891
2941
|
}
|
|
2942
|
+
function layoutGlyphTextChars(node, opts) {
|
|
2943
|
+
var _a, _b, _c, _d, _e;
|
|
2944
|
+
if ((_a = opts.alongPath) == null ? void 0 : _a.pathD) return layoutGlyphTextCharsAlongPath(node, opts.alongPath.pathD, opts);
|
|
2945
|
+
const { glyphs, warnings } = opts;
|
|
2946
|
+
const soleFont = soleFontOf(glyphs);
|
|
2947
|
+
const pen = { x: (_b = parseLen(node.x)) != null ? _b : 0, y: (_c = parseLen(node.y)) != null ? _c : 0 };
|
|
2948
|
+
const boxes = [];
|
|
2949
|
+
const lines = [{ start: pen.x, end: pen.x }];
|
|
2950
|
+
let line = 0;
|
|
2951
|
+
const renderChars = (content, s) => {
|
|
2952
|
+
var _a2;
|
|
2953
|
+
const gf = glyphFontFor(s, glyphs, soleFont, warnings);
|
|
2954
|
+
const upm = (gf == null ? void 0 : gf.unitsPerEm) || 1e3;
|
|
2955
|
+
const scale = s.fontSize / upm;
|
|
2956
|
+
const ascent = ((_a2 = gf == null ? void 0 : gf.ascent) != null ? _a2 : 0.9 * upm) * scale;
|
|
2957
|
+
for (let i = 0; i < content.length; i++) {
|
|
2958
|
+
const ch = content.charAt(i);
|
|
2959
|
+
const g = gf == null ? void 0 : gf.glyphs[ch];
|
|
2960
|
+
const advance = (g ? g.width : 0) * scale + s.letterSpacing + (ch === " " ? s.wordSpacing : 0);
|
|
2961
|
+
boxes.push({ x: pen.x, y: pen.y, width: advance, ascent, fontSize: s.fontSize, line });
|
|
2962
|
+
pen.x += advance;
|
|
2963
|
+
lines[line].end = pen.x;
|
|
2964
|
+
}
|
|
2965
|
+
};
|
|
2966
|
+
const walk = (el, parentStyle) => {
|
|
2967
|
+
var _a2, _b2, _c2, _d2;
|
|
2968
|
+
const s = resolveStyle(el, parentStyle);
|
|
2969
|
+
const x = parseLen(el.x);
|
|
2970
|
+
const y = parseLen(el.y);
|
|
2971
|
+
if (x !== void 0) {
|
|
2972
|
+
pen.x = x;
|
|
2973
|
+
line = lines.length;
|
|
2974
|
+
lines.push({ start: pen.x, end: pen.x });
|
|
2975
|
+
}
|
|
2976
|
+
if (y !== void 0) pen.y = y;
|
|
2977
|
+
pen.x += (_a2 = parseLen(el.dx)) != null ? _a2 : 0;
|
|
2978
|
+
pen.y += (_b2 = parseLen(el.dy)) != null ? _b2 : 0;
|
|
2979
|
+
const content = (_c2 = str(el[TEXT_ATTR])) != null ? _c2 : str(el[TEXT_CONTENT_ATTR]);
|
|
2980
|
+
if (content && !((_d2 = el.children) == null ? void 0 : _d2.length)) renderChars(content, s);
|
|
2981
|
+
if (el.children) for (const ch of el.children) walk(ch, s);
|
|
2982
|
+
};
|
|
2983
|
+
const rootStyle = rootStyleOf(node);
|
|
2984
|
+
if (node.children) for (const ch of node.children) walk(ch, rootStyle);
|
|
2985
|
+
const rootContent = (_d = str(node[TEXT_ATTR])) != null ? _d : str(node[TEXT_CONTENT_ATTR]);
|
|
2986
|
+
if (rootContent && !((_e = node.children) == null ? void 0 : _e.length)) renderChars(rootContent, rootStyle);
|
|
2987
|
+
const anchor = str(node.textAnchor);
|
|
2988
|
+
if (anchor === "middle" || anchor === "end") {
|
|
2989
|
+
for (const b of boxes) {
|
|
2990
|
+
const w = lines[b.line].end - lines[b.line].start;
|
|
2991
|
+
b.x += anchor === "middle" ? -w / 2 : -w;
|
|
2992
|
+
}
|
|
2993
|
+
}
|
|
2994
|
+
return boxes.map((_f) => {
|
|
2995
|
+
var _g = _f, { line: _l } = _g, b = __objRest(_g, ["line"]);
|
|
2996
|
+
return b;
|
|
2997
|
+
});
|
|
2998
|
+
}
|
|
2999
|
+
function layoutGlyphTextCharsAlongPath(node, pathD, opts) {
|
|
3000
|
+
var _a;
|
|
3001
|
+
const { glyphs, warnings, alongPath } = opts;
|
|
3002
|
+
const sampler = createPathSampler(pathD);
|
|
3003
|
+
if (!sampler) {
|
|
3004
|
+
warnings == null ? void 0 : warnings.push("textGlyphs: unparsable along-path geometry (caret)");
|
|
3005
|
+
return [];
|
|
3006
|
+
}
|
|
3007
|
+
const soleFont = soleFontOf(glyphs);
|
|
3008
|
+
const chars = [];
|
|
3009
|
+
let adv = 0;
|
|
3010
|
+
const walk = (el, parentStyle) => {
|
|
3011
|
+
var _a2, _b, _c;
|
|
3012
|
+
const s = resolveStyle(el, parentStyle);
|
|
3013
|
+
const content = (_a2 = str(el[TEXT_ATTR])) != null ? _a2 : str(el[TEXT_CONTENT_ATTR]);
|
|
3014
|
+
if (content && !((_b = el.children) == null ? void 0 : _b.length)) {
|
|
3015
|
+
const gf = glyphFontFor(s, glyphs, soleFont, warnings);
|
|
3016
|
+
const upm = (gf == null ? void 0 : gf.unitsPerEm) || 1e3;
|
|
3017
|
+
const scale = s.fontSize / upm;
|
|
3018
|
+
const ascent = ((_c = gf == null ? void 0 : gf.ascent) != null ? _c : 0.9 * upm) * scale;
|
|
3019
|
+
for (let i = 0; i < content.length; i++) {
|
|
3020
|
+
const ch = content.charAt(i);
|
|
3021
|
+
const g = gf == null ? void 0 : gf.glyphs[ch];
|
|
3022
|
+
const glyphW = (g ? g.width : 0) * scale;
|
|
3023
|
+
const advance = glyphW + s.letterSpacing + (ch === " " ? s.wordSpacing : 0);
|
|
3024
|
+
chars.push({ advStart: adv, advEnd: adv + advance, glyphW, ascent, fontSize: s.fontSize });
|
|
3025
|
+
adv += advance;
|
|
3026
|
+
}
|
|
3027
|
+
}
|
|
3028
|
+
if (el.children) for (const ch of el.children) walk(ch, s);
|
|
3029
|
+
};
|
|
3030
|
+
walk(node, rootStyleOf(node));
|
|
3031
|
+
const width = adv;
|
|
3032
|
+
const k = (alongPath == null ? void 0 : alongPath.textLength) && alongPath.textLength > 0 && width > 0 ? alongPath.textLength / width : 1;
|
|
3033
|
+
const so = readAnimatable(alongPath == null ? void 0 : alongPath.startOffset);
|
|
3034
|
+
const { along: alongOffset, perp } = alongPathNodeOffsets(node);
|
|
3035
|
+
const base = alongOffset + (so.kind === "animated" /* Animated */ ? Number((_a = so.keyframes[0]) == null ? void 0 : _a.value) || 0 : so.kind === "static" /* Static */ ? Number(so.value) || 0 : 0);
|
|
3036
|
+
const withPerp = (p) => ({
|
|
3037
|
+
x: p.x - perp * Math.sin(p.angle),
|
|
3038
|
+
y: p.y + perp * Math.cos(p.angle),
|
|
3039
|
+
angle: p.angle
|
|
3040
|
+
});
|
|
3041
|
+
return chars.map((c) => {
|
|
3042
|
+
const dStart = base + c.advStart * k;
|
|
3043
|
+
const dEnd = base + c.advEnd * k;
|
|
3044
|
+
const p0 = withPerp(sampler.sampleAtDistance(dStart));
|
|
3045
|
+
const p1 = withPerp(sampler.sampleAtDistance(dEnd));
|
|
3046
|
+
const glyphMid = sampler.sampleAtDistance(base + (c.advStart + c.glyphW / 2) * k);
|
|
3047
|
+
return {
|
|
3048
|
+
x: p0.x,
|
|
3049
|
+
y: p0.y,
|
|
3050
|
+
width: c.advEnd - c.advStart,
|
|
3051
|
+
ascent: c.ascent,
|
|
3052
|
+
fontSize: c.fontSize,
|
|
3053
|
+
endX: p1.x,
|
|
3054
|
+
endY: p1.y,
|
|
3055
|
+
rotation: glyphMid.angle * 180 / Math.PI
|
|
3056
|
+
};
|
|
3057
|
+
});
|
|
3058
|
+
}
|
|
2892
3059
|
function collectAlongPathCells(node, glyphs, soleFont, warnings) {
|
|
2893
3060
|
const cells = [];
|
|
2894
3061
|
let adv = 0;
|
|
2895
3062
|
const walk = (el, parentStyle) => {
|
|
2896
|
-
var _a, _b;
|
|
3063
|
+
var _a, _b, _c;
|
|
2897
3064
|
const s = resolveStyle(el, parentStyle);
|
|
2898
3065
|
const content = (_a = str(el[TEXT_ATTR])) != null ? _a : str(el[TEXT_CONTENT_ATTR]);
|
|
2899
3066
|
if (content && !((_b = el.children) == null ? void 0 : _b.length)) {
|
|
2900
3067
|
const gf = glyphFontFor(s, glyphs, soleFont, warnings);
|
|
2901
3068
|
if (gf) {
|
|
2902
3069
|
const scale = s.fontSize / gf.unitsPerEm;
|
|
3070
|
+
const ascentEm = (_c = gf.ascent) != null ? _c : 0.9 * gf.unitsPerEm;
|
|
2903
3071
|
const paint = paintOf(s);
|
|
2904
3072
|
for (let i = 0; i < content.length; i++) {
|
|
2905
3073
|
const ch = content.charAt(i);
|
|
2906
3074
|
const g = gf.glyphs[ch];
|
|
2907
|
-
|
|
2908
|
-
|
|
2909
|
-
|
|
3075
|
+
if (g && g.d) {
|
|
3076
|
+
const glyphAdv = g.width * scale;
|
|
3077
|
+
cells.push({ glyphD: g.d, widthEm: g.width, scale, paint, midBase: adv + glyphAdv / 2 });
|
|
3078
|
+
adv += glyphAdv;
|
|
3079
|
+
} else if (/\S/.test(ch)) {
|
|
3080
|
+
const wEm = g && g.width > 0 ? g.width : MISSING_GLYPH_ADVANCE_EM * gf.unitsPerEm;
|
|
3081
|
+
const boxAdv = wEm * scale;
|
|
3082
|
+
cells.push({ glyphD: missingGlyphBoxEm(wEm, ascentEm), widthEm: wEm, scale, paint, midBase: adv + boxAdv / 2 });
|
|
3083
|
+
adv += boxAdv;
|
|
3084
|
+
} else {
|
|
3085
|
+
adv += (g ? g.width : 0) * scale;
|
|
3086
|
+
}
|
|
3087
|
+
adv += s.letterSpacing + (ch === " " ? s.wordSpacing : 0);
|
|
2910
3088
|
}
|
|
2911
3089
|
}
|
|
2912
3090
|
}
|
|
@@ -2915,10 +3093,17 @@ function collectAlongPathCells(node, glyphs, soleFont, warnings) {
|
|
|
2915
3093
|
walk(node, rootStyleOf(node));
|
|
2916
3094
|
return { cells, width: adv };
|
|
2917
3095
|
}
|
|
2918
|
-
function alongAffine(sampler, dist, scale, widthEm) {
|
|
3096
|
+
function alongAffine(sampler, dist, scale, widthEm, perp = 0) {
|
|
2919
3097
|
const { x, y, angle } = sampler.sampleAtDistance(dist);
|
|
2920
3098
|
const cos = Math.cos(angle), sin = Math.sin(angle), hw = widthEm / 2;
|
|
2921
|
-
return [scale * cos, scale * sin, -scale * sin, scale * cos, x - scale * cos * hw, y - scale * sin * hw];
|
|
3099
|
+
return [scale * cos, scale * sin, -scale * sin, scale * cos, x - scale * cos * hw - perp * sin, y - scale * sin * hw + perp * cos];
|
|
3100
|
+
}
|
|
3101
|
+
function alongPathNodeOffsets(node) {
|
|
3102
|
+
var _a, _b, _c;
|
|
3103
|
+
return {
|
|
3104
|
+
along: ((_a = parseLen(node.x)) != null ? _a : 0) + ((_b = parseLen(node.dx)) != null ? _b : 0),
|
|
3105
|
+
perp: (_c = parseLen(node.dy)) != null ? _c : 0
|
|
3106
|
+
};
|
|
2922
3107
|
}
|
|
2923
3108
|
function materialiseGlyphTextAlongPath(node, pathD, startOffset, opts, textLength, pathOverflow) {
|
|
2924
3109
|
var _a;
|
|
@@ -2931,6 +3116,7 @@ function materialiseGlyphTextAlongPath(node, pathD, startOffset, opts, textLengt
|
|
|
2931
3116
|
const soleFont = soleFontOf(glyphs);
|
|
2932
3117
|
const { cells, width } = collectAlongPathCells(node, glyphs, soleFont, warnings);
|
|
2933
3118
|
if (!cells.length) return toGroup(node, [], create);
|
|
3119
|
+
const { along: alongOffset, perp } = alongPathNodeOffsets(node);
|
|
2934
3120
|
if (textLength && textLength > 0 && width > 0) {
|
|
2935
3121
|
const k = textLength / width;
|
|
2936
3122
|
for (const c of cells) c.midBase *= k;
|
|
@@ -2938,9 +3124,9 @@ function materialiseGlyphTextAlongPath(node, pathD, startOffset, opts, textLengt
|
|
|
2938
3124
|
const isClip = pathOverflow === "clip" && !sampler.closed;
|
|
2939
3125
|
const so = readAnimatable(startOffset);
|
|
2940
3126
|
if (so.kind === "animated" /* Animated */ && so.keyframes.length >= 2) {
|
|
2941
|
-
return toGroup(node, buildAnimatedAlongPath(cells, sampler, so.keyframes, so.loop, create, isClip), create);
|
|
3127
|
+
return toGroup(node, buildAnimatedAlongPath(cells, sampler, so.keyframes, so.loop, create, isClip, alongOffset, perp), create);
|
|
2942
3128
|
}
|
|
2943
|
-
const base = so.kind === "animated" /* Animated */ ? Number((_a = so.keyframes[0]) == null ? void 0 : _a.value) || 0 : so.kind === "static" /* Static */ ? Number(so.value) || 0 : 0;
|
|
3129
|
+
const base = alongOffset + (so.kind === "animated" /* Animated */ ? Number((_a = so.keyframes[0]) == null ? void 0 : _a.value) || 0 : so.kind === "static" /* Static */ ? Number(so.value) || 0 : 0);
|
|
2944
3130
|
const placeCells = isClip ? cells.filter((c) => {
|
|
2945
3131
|
const d = base + c.midBase;
|
|
2946
3132
|
return d >= 0 && d <= sampler.totalLength;
|
|
@@ -2948,7 +3134,7 @@ function materialiseGlyphTextAlongPath(node, pathD, startOffset, opts, textLengt
|
|
|
2948
3134
|
const placements = placeCells.map((c) => ({
|
|
2949
3135
|
glyphD: c.glyphD,
|
|
2950
3136
|
paint: c.paint,
|
|
2951
|
-
m: alongAffine(sampler, base + c.midBase, c.scale, c.widthEm)
|
|
3137
|
+
m: alongAffine(sampler, base + c.midBase, c.scale, c.widthEm, perp)
|
|
2952
3138
|
}));
|
|
2953
3139
|
return toGroup(node, buildPaths(placements, create, warnings), create);
|
|
2954
3140
|
}
|
|
@@ -2958,10 +3144,10 @@ function roundN(v, n) {
|
|
|
2958
3144
|
const f = __pow(10, n);
|
|
2959
3145
|
return Math.round(v * f) / f;
|
|
2960
3146
|
}
|
|
2961
|
-
function buildAnimatedAlongPath(cells, sampler, sokfs, loop, create, isClip) {
|
|
3147
|
+
function buildAnimatedAlongPath(cells, sampler, sokfs, loop, create, isClip, alongOffset = 0, perp = 0) {
|
|
2962
3148
|
const step = Math.max(sampler.totalLength / ALONG_PATH_MAX_STEPS, 0.5);
|
|
2963
3149
|
const timeOf = (kf) => Number(kf.time) || 0;
|
|
2964
|
-
const offOf = (kf) => Number(kf.value) || 0;
|
|
3150
|
+
const offOf = (kf) => alongOffset + (Number(kf.value) || 0);
|
|
2965
3151
|
const onPath = (dist) => dist >= 0 && dist <= sampler.totalLength;
|
|
2966
3152
|
const out = [];
|
|
2967
3153
|
for (const c of cells) {
|
|
@@ -2969,10 +3155,11 @@ function buildAnimatedAlongPath(cells, sampler, sokfs, loop, create, isClip) {
|
|
|
2969
3155
|
const d = transformPathData(c.glyphD, centred);
|
|
2970
3156
|
const sampleKf = (dist, time) => {
|
|
2971
3157
|
const { x, y, angle } = sampler.sampleAtDistance(dist);
|
|
3158
|
+
const cos = Math.cos(angle), sin = Math.sin(angle);
|
|
2972
3159
|
return {
|
|
2973
3160
|
time,
|
|
2974
3161
|
value: {
|
|
2975
|
-
["translate" /* Translate */]: [roundN(x, 3), roundN(y, 3)],
|
|
3162
|
+
["translate" /* Translate */]: [roundN(x - perp * sin, 3), roundN(y + perp * cos, 3)],
|
|
2976
3163
|
["rotate" /* Rotate */]: roundN(angle * 180 / Math.PI, 3)
|
|
2977
3164
|
}
|
|
2978
3165
|
};
|
|
@@ -3242,9 +3429,18 @@ function buildOutKfValue(prevV, nextV, p, translate, rotateDegFromAutoOrient, au
|
|
|
3242
3429
|
if (pv === void 0 && nv === void 0) continue;
|
|
3243
3430
|
value[k] = interpolatePart(pv, nv, p);
|
|
3244
3431
|
}
|
|
3245
|
-
if (rotateDegFromAutoOrient !== void 0)
|
|
3432
|
+
if (rotateDegFromAutoOrient !== void 0) {
|
|
3433
|
+
value.rotate = rotateDegFromAutoOrient + explicitRotateAt(prevV, nextV, p);
|
|
3434
|
+
}
|
|
3246
3435
|
return value;
|
|
3247
3436
|
}
|
|
3437
|
+
function explicitRotateAt(prevV, nextV, p) {
|
|
3438
|
+
const pv = typeof (prevV == null ? void 0 : prevV.rotate) === "number" ? prevV.rotate : void 0;
|
|
3439
|
+
const nv = typeof (nextV == null ? void 0 : nextV.rotate) === "number" ? nextV.rotate : void 0;
|
|
3440
|
+
if (pv === void 0 && nv === void 0) return 0;
|
|
3441
|
+
const r = interpolatePart(pv, nv, p);
|
|
3442
|
+
return typeof r === "number" ? r : 0;
|
|
3443
|
+
}
|
|
3248
3444
|
function derivAngleForFirstKf(kf0, kf1) {
|
|
3249
3445
|
const p0 = getKfTranslate(kf0);
|
|
3250
3446
|
const p1 = getKfTranslate(kf1);
|
|
@@ -3265,10 +3461,12 @@ function insertSharpCornerStepKfIfNeeded(out, prevKf, nextKf, prevPos, nextPos,
|
|
|
3265
3461
|
const lastV = (_a = lastKf.v) != null ? _a : lastKf.value;
|
|
3266
3462
|
const prevExit = lastV == null ? void 0 : lastV.rotate;
|
|
3267
3463
|
if (typeof prevExit !== "number") return;
|
|
3464
|
+
const boundaryV = getKfValueParts(prevKf);
|
|
3465
|
+
const prevExitTangent = prevExit - explicitRotateAt(boundaryV, boundaryV, 0);
|
|
3268
3466
|
const seg = getSegmentCache(prevKf, nextKf, prevPos, nextPos);
|
|
3269
3467
|
const tanAtStart = bezier2D_derivativeAt(seg.P0, seg.P1, seg.P2, seg.P3, 0);
|
|
3270
3468
|
const nextEntry = Math.atan2(tanAtStart[1], tanAtStart[0]) * 180 / Math.PI;
|
|
3271
|
-
const delta = wrappedAngleDelta(nextEntry,
|
|
3469
|
+
const delta = wrappedAngleDelta(nextEntry, prevExitTangent);
|
|
3272
3470
|
if (Math.abs(delta) <= rotationTol) return;
|
|
3273
3471
|
const dupValue = buildOutKfValue(
|
|
3274
3472
|
getKfValueParts(prevKf),
|
|
@@ -4467,7 +4665,7 @@ function applyPlayerEffects_exceptRetime(node, ctx) {
|
|
|
4467
4665
|
const originalId = typeof node.id === "string" ? node.id : void 0;
|
|
4468
4666
|
const innerIdForContentRef = originalId ? ctx.contentRefInnerIds.get(originalId) : void 0;
|
|
4469
4667
|
if (!fx && !innerIdForContentRef) return node;
|
|
4470
|
-
const { transformation, repeater, maskedBy, trimPath, clone: cloneFx, fillGradient, strokeGradient, textPath, text } = fx != null ? fx : {};
|
|
4668
|
+
const { transformation, repeater, maskedBy, clipPath, trimPath, clone: cloneFx, fillGradient, strokeGradient, textPath, text } = fx != null ? fx : {};
|
|
4471
4669
|
const isCombinedShape = fx == null ? void 0 : fx.isCombinedShape;
|
|
4472
4670
|
if (fx) delete node.effects;
|
|
4473
4671
|
let n = node;
|
|
@@ -4493,6 +4691,7 @@ function applyPlayerEffects_exceptRetime(node, ctx) {
|
|
|
4493
4691
|
n = applyTrimPathEffect(n, trimPath, isCombinedShape, ctx);
|
|
4494
4692
|
n = applyRepeaterEffect(n, repeater, ctx);
|
|
4495
4693
|
n = applyMaskedByEffect(n, maskedBy, transformation, ctx);
|
|
4694
|
+
n = applyClipPathEffect(n, clipPath, ctx);
|
|
4496
4695
|
if (innerIdForContentRef) {
|
|
4497
4696
|
applyRefHref(n, cloneFx, ctx);
|
|
4498
4697
|
n = splitForContentRef(n, transformation, originalId, innerIdForContentRef, ctx);
|
|
@@ -4821,6 +5020,8 @@ function getNormalizedProps(props) {
|
|
|
4821
5020
|
function renderNode(node, defs) {
|
|
4822
5021
|
if (!node) return null;
|
|
4823
5022
|
const _a = node, { type, children, style } = _a, props = __objRest(_a, ["type", "children", "style"]);
|
|
5023
|
+
const feFuncType = props.funcType;
|
|
5024
|
+
if (feFuncType !== void 0) delete props.funcType;
|
|
4824
5025
|
const nodeDefs = getDefs(node) || defs;
|
|
4825
5026
|
const resolvedStyle = resolveStyle2(style, nodeDefs);
|
|
4826
5027
|
let childElements;
|
|
@@ -4833,13 +5034,15 @@ function renderNode(node, defs) {
|
|
|
4833
5034
|
}
|
|
4834
5035
|
}
|
|
4835
5036
|
}
|
|
4836
|
-
|
|
5037
|
+
const element = createElement(
|
|
4837
5038
|
type || "g",
|
|
4838
5039
|
getNormalizedProps(props),
|
|
4839
5040
|
resolvedStyle,
|
|
4840
5041
|
childElements,
|
|
4841
5042
|
props[TEXT_ATTR] || props[TEXT_CONTENT_ATTR]
|
|
4842
5043
|
);
|
|
5044
|
+
if (element && feFuncType !== void 0) element.setAttribute("type", feFuncType);
|
|
5045
|
+
return element;
|
|
4843
5046
|
}
|
|
4844
5047
|
|
|
4845
5048
|
// src/PxAnimatorTriggers.ts
|
|
@@ -4850,7 +5053,12 @@ function setupAnimationTriggers(api, config) {
|
|
|
4850
5053
|
console.warn("setupAnimationTriggers: No root element found for animation.");
|
|
4851
5054
|
return api;
|
|
4852
5055
|
}
|
|
5056
|
+
let reversed = false;
|
|
4853
5057
|
const start = () => {
|
|
5058
|
+
if (reversed) {
|
|
5059
|
+
reversed = false;
|
|
5060
|
+
api.setPlaybackRate(1);
|
|
5061
|
+
}
|
|
4854
5062
|
api.play();
|
|
4855
5063
|
};
|
|
4856
5064
|
const handleEndAction = () => {
|
|
@@ -4862,6 +5070,8 @@ function setupAnimationTriggers(api, config) {
|
|
|
4862
5070
|
api.cancel();
|
|
4863
5071
|
break;
|
|
4864
5072
|
case "reverse":
|
|
5073
|
+
reversed = true;
|
|
5074
|
+
api.setPlaybackRate(-1);
|
|
4865
5075
|
api.play();
|
|
4866
5076
|
break;
|
|
4867
5077
|
case "continue":
|
|
@@ -4924,6 +5134,7 @@ function getSelector(id) {
|
|
|
4924
5134
|
return "#" + id;
|
|
4925
5135
|
}
|
|
4926
5136
|
function createBasicFrameLoopAnimator(doc, adapter, callbacks) {
|
|
5137
|
+
var _a;
|
|
4927
5138
|
const config = getAnimatorConfig(doc) || {};
|
|
4928
5139
|
const bindings = getNormalisedBindings(doc, PxAnimatorEngine.frames);
|
|
4929
5140
|
const _iterations = config.iterations;
|
|
@@ -4934,18 +5145,24 @@ function createBasicFrameLoopAnimator(doc, adapter, callbacks) {
|
|
|
4934
5145
|
const duration = +(config.duration || DEFAULT_DURATION_MS);
|
|
4935
5146
|
const totalDuration = duration && iterations ? duration * (iterations === Infinity ? Infinity : iterations) : duration ? (iterations != null ? iterations : 1) * duration : 0;
|
|
4936
5147
|
const direction = config.direction || "normal";
|
|
5148
|
+
const fill = (_a = config.fill) != null ? _a : "forwards";
|
|
5149
|
+
const fillsForwards = fill === "forwards" || fill === "both";
|
|
5150
|
+
const fillsBackwards = fill === "backwards" || fill === "both";
|
|
4937
5151
|
let timerId = null;
|
|
4938
5152
|
let playing = false;
|
|
4939
|
-
let timeBeforeLastStartMs = config.delay || 0;
|
|
5153
|
+
let timeBeforeLastStartMs = -(config.delay || 0);
|
|
4940
5154
|
let lastStartedTs = 0;
|
|
4941
5155
|
let playbackRate = 1;
|
|
4942
5156
|
let finishCalled = false;
|
|
4943
5157
|
const frameRate = config.frameRate;
|
|
4944
5158
|
const minFrameIntervalMs = frameRate && frameRate > 0 ? 1e3 / frameRate : 0;
|
|
4945
5159
|
let lastRenderTs = 0;
|
|
4946
|
-
const
|
|
5160
|
+
const getRawAnimTime = () => {
|
|
4947
5161
|
const runningElapsed = lastStartedTs ? (Date.now() - lastStartedTs) * playbackRate : 0;
|
|
4948
|
-
|
|
5162
|
+
return timeBeforeLastStartMs + runningElapsed;
|
|
5163
|
+
};
|
|
5164
|
+
const getAnimCurrentTime = () => {
|
|
5165
|
+
let time = getRawAnimTime();
|
|
4949
5166
|
if (Number.isFinite(totalDuration) && time > totalDuration) time = totalDuration;
|
|
4950
5167
|
if (time < 0) time = 0;
|
|
4951
5168
|
return time;
|
|
@@ -4990,40 +5207,59 @@ function createBasicFrameLoopAnimator(doc, adapter, callbacks) {
|
|
|
4990
5207
|
}
|
|
4991
5208
|
}
|
|
4992
5209
|
const tick = () => {
|
|
4993
|
-
var
|
|
5210
|
+
var _a2, _b;
|
|
4994
5211
|
if (!adapter.isConnected()) {
|
|
4995
5212
|
pauseAnim();
|
|
4996
5213
|
return;
|
|
4997
5214
|
}
|
|
4998
5215
|
const currentTime = getAnimCurrentTime();
|
|
4999
|
-
|
|
5000
|
-
|
|
5001
|
-
if (
|
|
5002
|
-
|
|
5003
|
-
}
|
|
5004
|
-
lastRenderTs = now;
|
|
5005
|
-
}
|
|
5006
|
-
if (duration <= 0) {
|
|
5216
|
+
const rawTime = getRawAnimTime();
|
|
5217
|
+
if (rawTime < 0 && playbackRate > 0) {
|
|
5218
|
+
if (fillsBackwards) renderFrame(0);
|
|
5219
|
+
return;
|
|
5007
5220
|
}
|
|
5008
|
-
if (
|
|
5009
|
-
|
|
5221
|
+
if (playbackRate < 0 && rawTime <= 0) {
|
|
5222
|
+
pauseAnim();
|
|
5223
|
+
renderFrame(0);
|
|
5010
5224
|
if (!finishCalled) {
|
|
5011
5225
|
finishCalled = true;
|
|
5012
|
-
(
|
|
5226
|
+
(_a2 = callbacks == null ? void 0 : callbacks.onFinish) == null ? void 0 : _a2.call(callbacks);
|
|
5013
5227
|
}
|
|
5228
|
+
return;
|
|
5229
|
+
}
|
|
5230
|
+
if (playbackRate > 0 && totalDuration && Number.isFinite(totalDuration) && currentTime >= totalDuration) {
|
|
5014
5231
|
pauseAnim();
|
|
5232
|
+
renderFrame(fillsForwards ? totalDuration : 0);
|
|
5233
|
+
if (!finishCalled) {
|
|
5234
|
+
finishCalled = true;
|
|
5235
|
+
(_b = callbacks == null ? void 0 : callbacks.onFinish) == null ? void 0 : _b.call(callbacks);
|
|
5236
|
+
}
|
|
5015
5237
|
return;
|
|
5016
5238
|
}
|
|
5239
|
+
if (minFrameIntervalMs > 0) {
|
|
5240
|
+
const now = Date.now();
|
|
5241
|
+
if (lastRenderTs && now - lastRenderTs < minFrameIntervalMs) {
|
|
5242
|
+
return;
|
|
5243
|
+
}
|
|
5244
|
+
lastRenderTs = now;
|
|
5245
|
+
}
|
|
5017
5246
|
renderFrame(currentTime);
|
|
5018
5247
|
};
|
|
5019
5248
|
if (config.delay) {
|
|
5020
|
-
|
|
5249
|
+
if (config.delay < 0) {
|
|
5250
|
+
renderFrame(getAnimCurrentTime());
|
|
5251
|
+
} else if (fillsBackwards) {
|
|
5252
|
+
renderFrame(0);
|
|
5253
|
+
}
|
|
5021
5254
|
}
|
|
5022
5255
|
const _isPlaying = () => {
|
|
5023
5256
|
if (!playing) return false;
|
|
5024
5257
|
if (!adapter.isConnected()) {
|
|
5025
5258
|
return false;
|
|
5026
5259
|
}
|
|
5260
|
+
if (playbackRate < 0) {
|
|
5261
|
+
return getRawAnimTime() > 0;
|
|
5262
|
+
}
|
|
5027
5263
|
if (Number.isFinite(totalDuration) && getAnimCurrentTime() >= totalDuration) return false;
|
|
5028
5264
|
return true;
|
|
5029
5265
|
};
|
|
@@ -5043,37 +5279,53 @@ function createBasicFrameLoopAnimator(doc, adapter, callbacks) {
|
|
|
5043
5279
|
};
|
|
5044
5280
|
const startAnim = () => {
|
|
5045
5281
|
if (playing) return;
|
|
5046
|
-
if (
|
|
5047
|
-
timeBeforeLastStartMs
|
|
5048
|
-
|
|
5282
|
+
if (playbackRate >= 0) {
|
|
5283
|
+
if (Number.isFinite(totalDuration) && timeBeforeLastStartMs >= totalDuration) {
|
|
5284
|
+
timeBeforeLastStartMs = 0;
|
|
5285
|
+
}
|
|
5286
|
+
} else {
|
|
5287
|
+
if (timeBeforeLastStartMs <= 0) {
|
|
5288
|
+
if (!Number.isFinite(totalDuration)) {
|
|
5289
|
+
console.warn("play: cannot start reverse playback of an infinite animation from time 0");
|
|
5290
|
+
return;
|
|
5291
|
+
}
|
|
5292
|
+
timeBeforeLastStartMs = totalDuration;
|
|
5293
|
+
}
|
|
5049
5294
|
}
|
|
5295
|
+
finishCalled = false;
|
|
5050
5296
|
playing = true;
|
|
5051
5297
|
lastStartedTs = Date.now();
|
|
5052
5298
|
loopAnim(true);
|
|
5053
5299
|
};
|
|
5054
5300
|
const pauseAnim = () => {
|
|
5055
5301
|
if (!playing) return;
|
|
5056
|
-
|
|
5302
|
+
let raw = getRawAnimTime();
|
|
5303
|
+
if (Number.isFinite(totalDuration) && raw > totalDuration) raw = totalDuration;
|
|
5304
|
+
timeBeforeLastStartMs = raw;
|
|
5057
5305
|
lastStartedTs = 0;
|
|
5058
5306
|
playing = false;
|
|
5059
5307
|
if (timerId !== null) {
|
|
5060
5308
|
cancelAnimationFrame(timerId);
|
|
5061
5309
|
timerId = null;
|
|
5062
5310
|
}
|
|
5063
|
-
|
|
5311
|
+
if (raw >= 0) {
|
|
5312
|
+
renderFrame(raw);
|
|
5313
|
+
} else if (fillsBackwards) {
|
|
5314
|
+
renderFrame(0);
|
|
5315
|
+
}
|
|
5064
5316
|
};
|
|
5065
5317
|
const cancelAnim = () => {
|
|
5066
|
-
var
|
|
5318
|
+
var _a2;
|
|
5067
5319
|
pauseAnim();
|
|
5068
5320
|
timeBeforeLastStartMs = 0;
|
|
5069
5321
|
lastStartedTs = 0;
|
|
5070
5322
|
playing = false;
|
|
5071
5323
|
finishCalled = false;
|
|
5072
5324
|
renderFrame(timeBeforeLastStartMs);
|
|
5073
|
-
(
|
|
5325
|
+
(_a2 = callbacks == null ? void 0 : callbacks.onCancel) == null ? void 0 : _a2.call(callbacks);
|
|
5074
5326
|
};
|
|
5075
5327
|
const finishAnim = (callOnFinish = true) => {
|
|
5076
|
-
var
|
|
5328
|
+
var _a2;
|
|
5077
5329
|
if (Number.isFinite(totalDuration)) {
|
|
5078
5330
|
timeBeforeLastStartMs = totalDuration;
|
|
5079
5331
|
} else {
|
|
@@ -5081,10 +5333,14 @@ function createBasicFrameLoopAnimator(doc, adapter, callbacks) {
|
|
|
5081
5333
|
}
|
|
5082
5334
|
lastStartedTs = 0;
|
|
5083
5335
|
playing = false;
|
|
5084
|
-
|
|
5336
|
+
if (timerId !== null) {
|
|
5337
|
+
cancelAnimationFrame(timerId);
|
|
5338
|
+
timerId = null;
|
|
5339
|
+
}
|
|
5340
|
+
renderFrame(fillsForwards ? timeBeforeLastStartMs : 0);
|
|
5085
5341
|
if (callOnFinish && !finishCalled) {
|
|
5086
5342
|
finishCalled = true;
|
|
5087
|
-
(
|
|
5343
|
+
(_a2 = callbacks == null ? void 0 : callbacks.onFinish) == null ? void 0 : _a2.call(callbacks);
|
|
5088
5344
|
}
|
|
5089
5345
|
};
|
|
5090
5346
|
const api = {
|
|
@@ -5094,14 +5350,14 @@ function createBasicFrameLoopAnimator(doc, adapter, callbacks) {
|
|
|
5094
5350
|
return _isPlaying();
|
|
5095
5351
|
},
|
|
5096
5352
|
"play": () => {
|
|
5097
|
-
var
|
|
5353
|
+
var _a2;
|
|
5098
5354
|
startAnim();
|
|
5099
|
-
(
|
|
5355
|
+
(_a2 = callbacks == null ? void 0 : callbacks.onPlay) == null ? void 0 : _a2.call(callbacks);
|
|
5100
5356
|
},
|
|
5101
5357
|
"pause": () => {
|
|
5102
|
-
var
|
|
5358
|
+
var _a2;
|
|
5103
5359
|
pauseAnim();
|
|
5104
|
-
(
|
|
5360
|
+
(_a2 = callbacks == null ? void 0 : callbacks.onPause) == null ? void 0 : _a2.call(callbacks);
|
|
5105
5361
|
},
|
|
5106
5362
|
"cancel": () => {
|
|
5107
5363
|
cancelAnim();
|
|
@@ -5114,7 +5370,9 @@ function createBasicFrameLoopAnimator(doc, adapter, callbacks) {
|
|
|
5114
5370
|
console.warn("setPlaybackRate: rate must be finite and non-zero");
|
|
5115
5371
|
return;
|
|
5116
5372
|
}
|
|
5117
|
-
|
|
5373
|
+
let current = getRawAnimTime();
|
|
5374
|
+
if (Number.isFinite(totalDuration) && current > totalDuration) current = totalDuration;
|
|
5375
|
+
if (rate < 0 !== playbackRate < 0) finishCalled = false;
|
|
5118
5376
|
playbackRate = rate;
|
|
5119
5377
|
timeBeforeLastStartMs = current;
|
|
5120
5378
|
if (playing) lastStartedTs = Date.now();
|
|
@@ -5127,10 +5385,13 @@ function createBasicFrameLoopAnimator(doc, adapter, callbacks) {
|
|
|
5127
5385
|
if (Number.isFinite(totalDuration) && newTime > totalDuration) newTime = totalDuration;
|
|
5128
5386
|
timeBeforeLastStartMs = newTime;
|
|
5129
5387
|
if (playing) lastStartedTs = Date.now();
|
|
5388
|
+
if (!Number.isFinite(totalDuration) || newTime < totalDuration) finishCalled = false;
|
|
5130
5389
|
renderFrame(getAnimCurrentTime());
|
|
5131
5390
|
},
|
|
5132
5391
|
"destroy": () => {
|
|
5392
|
+
var _a2;
|
|
5133
5393
|
api.cancel();
|
|
5394
|
+
(_a2 = callbacks == null ? void 0 : callbacks.onRemove) == null ? void 0 : _a2.call(callbacks);
|
|
5134
5395
|
}
|
|
5135
5396
|
};
|
|
5136
5397
|
return api;
|
|
@@ -5295,6 +5556,8 @@ function createWebApiAnimator(doc, callbacks, rootElement, forceEvenIfHasUnsuppo
|
|
|
5295
5556
|
if (typeof _iterations === "number") iterations = _iterations;
|
|
5296
5557
|
if (_iterations === "infinite") iterations = Infinity;
|
|
5297
5558
|
const unsupportedSet = /* @__PURE__ */ new Set();
|
|
5559
|
+
let finishNotified = false;
|
|
5560
|
+
let removeCalled = false;
|
|
5298
5561
|
if (!(bindings == null ? void 0 : bindings.length)) {
|
|
5299
5562
|
console.warn("createWebApiAnimator: No animation bindings defined");
|
|
5300
5563
|
}
|
|
@@ -5311,7 +5574,11 @@ function createWebApiAnimator(doc, callbacks, rootElement, forceEvenIfHasUnsuppo
|
|
|
5311
5574
|
}
|
|
5312
5575
|
const keyframesMap = convertToWebApiKeyframes(animDef, unsupportedSet, config);
|
|
5313
5576
|
const positiveDelay = config.delay && config.delay > 0 ? config.delay : void 0;
|
|
5314
|
-
|
|
5577
|
+
let seekPosition;
|
|
5578
|
+
if (config.delay && config.delay < 0 && config.duration) {
|
|
5579
|
+
const rawSeek = -config.delay;
|
|
5580
|
+
seekPosition = iterations === Infinity ? rawSeek % config.duration : Math.min(rawSeek, config.duration * (iterations != null ? iterations : 1));
|
|
5581
|
+
}
|
|
5315
5582
|
const effectOptions = {
|
|
5316
5583
|
duration: config.duration,
|
|
5317
5584
|
delay: positiveDelay,
|
|
@@ -5332,13 +5599,17 @@ function createWebApiAnimator(doc, callbacks, rootElement, forceEvenIfHasUnsuppo
|
|
|
5332
5599
|
const anim = new Animation(effect, document.timeline);
|
|
5333
5600
|
if (callbacks == null ? void 0 : callbacks.onFinish) anim.onfinish = () => {
|
|
5334
5601
|
var _a2;
|
|
5335
|
-
|
|
5602
|
+
if (finishNotified) return;
|
|
5603
|
+
finishNotified = true;
|
|
5604
|
+
(_a2 = callbacks.onFinish) == null ? void 0 : _a2.call(callbacks);
|
|
5336
5605
|
};
|
|
5337
5606
|
if (callbacks == null ? void 0 : callbacks.onRemove) anim.onremove = () => {
|
|
5338
5607
|
var _a2;
|
|
5339
|
-
|
|
5608
|
+
if (removeCalled) return;
|
|
5609
|
+
removeCalled = true;
|
|
5610
|
+
(_a2 = callbacks.onRemove) == null ? void 0 : _a2.call(callbacks);
|
|
5340
5611
|
};
|
|
5341
|
-
if (seekPosition) {
|
|
5612
|
+
if (seekPosition !== void 0) {
|
|
5342
5613
|
anim.currentTime = seekPosition;
|
|
5343
5614
|
}
|
|
5344
5615
|
animations.push(anim);
|
|
@@ -5362,6 +5633,7 @@ function createWebApiAnimator(doc, callbacks, rootElement, forceEvenIfHasUnsuppo
|
|
|
5362
5633
|
},
|
|
5363
5634
|
"play": () => {
|
|
5364
5635
|
var _a2;
|
|
5636
|
+
finishNotified = false;
|
|
5365
5637
|
animations.forEach((a) => a.play());
|
|
5366
5638
|
(_a2 = callbacks == null ? void 0 : callbacks.onPlay) == null ? void 0 : _a2.call(callbacks);
|
|
5367
5639
|
},
|
|
@@ -5372,6 +5644,7 @@ function createWebApiAnimator(doc, callbacks, rootElement, forceEvenIfHasUnsuppo
|
|
|
5372
5644
|
},
|
|
5373
5645
|
"cancel": () => {
|
|
5374
5646
|
var _a2;
|
|
5647
|
+
finishNotified = false;
|
|
5375
5648
|
animations.forEach((a) => a.cancel());
|
|
5376
5649
|
(_a2 = callbacks == null ? void 0 : callbacks.onCancel) == null ? void 0 : _a2.call(callbacks);
|
|
5377
5650
|
},
|
|
@@ -5401,13 +5674,19 @@ function createWebApiAnimator(doc, callbacks, rootElement, forceEvenIfHasUnsuppo
|
|
|
5401
5674
|
return res !== null ? +res : null;
|
|
5402
5675
|
},
|
|
5403
5676
|
"setCurrentTime": (time) => {
|
|
5677
|
+
finishNotified = false;
|
|
5404
5678
|
animations.forEach((a) => {
|
|
5405
5679
|
a.currentTime = time;
|
|
5406
5680
|
});
|
|
5407
5681
|
},
|
|
5408
5682
|
"destroy": () => {
|
|
5683
|
+
var _a2;
|
|
5409
5684
|
api.cancel();
|
|
5410
5685
|
animations.splice(0, animations.length);
|
|
5686
|
+
if (!removeCalled) {
|
|
5687
|
+
removeCalled = true;
|
|
5688
|
+
(_a2 = callbacks == null ? void 0 : callbacks.onRemove) == null ? void 0 : _a2.call(callbacks);
|
|
5689
|
+
}
|
|
5411
5690
|
}
|
|
5412
5691
|
};
|
|
5413
5692
|
if (config.trigger) {
|
|
@@ -5551,7 +5830,6 @@ function createAnimatorImpl(doc, adapter, callbacks, containerElement) {
|
|
|
5551
5830
|
const effectsWarnings = validateNodeEffects(doc);
|
|
5552
5831
|
for (const w of effectsWarnings) console.warn("[PxAnimator] effects shape warning:", w);
|
|
5553
5832
|
const animatorConfig = getAnimatorConfig(doc) || {};
|
|
5554
|
-
animatorConfig.debug = true;
|
|
5555
5833
|
const engine = animatorConfig.mode === PxAnimatorMode.frames ? PxAnimatorEngine.frames : PxAnimatorEngine.webapi;
|
|
5556
5834
|
doc = materialiseAllInTree(doc, engine);
|
|
5557
5835
|
let rootElement = null;
|
|
@@ -5580,37 +5858,55 @@ function createAnimator(options) {
|
|
|
5580
5858
|
return createAnimatorImpl(data, adapter, callbacks, container);
|
|
5581
5859
|
}
|
|
5582
5860
|
let animator = null;
|
|
5861
|
+
let pending = [];
|
|
5862
|
+
let destroyed = false;
|
|
5863
|
+
const enqueue = (call) => {
|
|
5864
|
+
if (animator) {
|
|
5865
|
+
call(animator);
|
|
5866
|
+
} else if (pending) {
|
|
5867
|
+
pending.push(call);
|
|
5868
|
+
}
|
|
5869
|
+
};
|
|
5583
5870
|
fetch(src).then((res) => res.json()).then((json) => {
|
|
5871
|
+
if (destroyed) return;
|
|
5584
5872
|
if (isPxElementFileFormat(json)) {
|
|
5585
5873
|
animator = createAnimatorImpl(json, adapter, callbacks, container);
|
|
5874
|
+
const queued = pending;
|
|
5875
|
+
pending = null;
|
|
5876
|
+
queued == null ? void 0 : queued.forEach((call) => call(animator));
|
|
5586
5877
|
} else {
|
|
5587
|
-
console.error(
|
|
5878
|
+
console.error('createAnimator: invalid animation document format at "' + src + '"');
|
|
5588
5879
|
}
|
|
5880
|
+
}).catch((err) => {
|
|
5881
|
+
pending = null;
|
|
5882
|
+
console.error('createAnimator: failed to load "' + src + '"', err);
|
|
5589
5883
|
});
|
|
5590
5884
|
return {
|
|
5591
5885
|
"isReady": () => !!animator,
|
|
5592
5886
|
"getRootElement": () => animator ? animator.getRootElement() : null,
|
|
5593
5887
|
"isPlaying": () => (animator == null ? void 0 : animator.isPlaying()) || false,
|
|
5594
5888
|
"play": () => {
|
|
5595
|
-
|
|
5889
|
+
enqueue((api) => api.play());
|
|
5596
5890
|
},
|
|
5597
5891
|
"pause": () => {
|
|
5598
|
-
|
|
5892
|
+
enqueue((api) => api.pause());
|
|
5599
5893
|
},
|
|
5600
5894
|
"cancel": () => {
|
|
5601
|
-
|
|
5895
|
+
enqueue((api) => api.cancel());
|
|
5602
5896
|
},
|
|
5603
5897
|
"finish": () => {
|
|
5604
|
-
|
|
5898
|
+
enqueue((api) => api.finish());
|
|
5605
5899
|
},
|
|
5606
5900
|
"setPlaybackRate": (rate) => {
|
|
5607
|
-
|
|
5901
|
+
enqueue((api) => api.setPlaybackRate(rate));
|
|
5608
5902
|
},
|
|
5609
|
-
"getCurrentTime": () =>
|
|
5903
|
+
"getCurrentTime": () => animator ? animator.getCurrentTime() : null,
|
|
5610
5904
|
"setCurrentTime": (time) => {
|
|
5611
|
-
|
|
5905
|
+
enqueue((api) => api.setCurrentTime(time));
|
|
5612
5906
|
},
|
|
5613
5907
|
"destroy": () => {
|
|
5908
|
+
destroyed = true;
|
|
5909
|
+
pending = null;
|
|
5614
5910
|
animator == null ? void 0 : animator.destroy();
|
|
5615
5911
|
}
|
|
5616
5912
|
};
|
|
@@ -5892,6 +6188,7 @@ function subtractMultiset(a, b) {
|
|
|
5892
6188
|
createAnimatorImpl,
|
|
5893
6189
|
createBasicFrameLoopAnimator,
|
|
5894
6190
|
createFrameLoopAnimator,
|
|
6191
|
+
createPathSampler,
|
|
5895
6192
|
createWebApiAnimator,
|
|
5896
6193
|
describeSchema,
|
|
5897
6194
|
diffInEffect,
|
|
@@ -5906,6 +6203,7 @@ function subtractMultiset(a, b) {
|
|
|
5906
6203
|
isPxElementFileFormat,
|
|
5907
6204
|
isPxElementFileFormatDeep,
|
|
5908
6205
|
jsonElementFactory,
|
|
6206
|
+
layoutGlyphTextChars,
|
|
5909
6207
|
loadTagAnimators,
|
|
5910
6208
|
materialiseAllInTree,
|
|
5911
6209
|
materialiseAnimatedUseInstances,
|