@pixodesk/svg-animator-web 1.0.17 → 1.0.19
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 +27 -0
- package/dist/index.cjs +710 -67
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +269 -28
- package/dist/index.d.ts +269 -28
- package/dist/index.js +702 -66
- 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 +702 -66
- package/dist/index.umd.js.map +1 -1
- package/dist/index.umd.min.js +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -7,6 +7,7 @@ var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
|
7
7
|
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
|
|
8
8
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
9
9
|
var __propIsEnum = Object.prototype.propertyIsEnumerable;
|
|
10
|
+
var __pow = Math.pow;
|
|
10
11
|
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
11
12
|
var __spreadValues = (a, b) => {
|
|
12
13
|
for (var prop in b || (b = {}))
|
|
@@ -82,7 +83,8 @@ __export(index_exports, {
|
|
|
82
83
|
PxRetimeEffectSchema: () => PxRetimeEffectSchema,
|
|
83
84
|
PxStrokeGradientEffectSchema: () => PxStrokeGradientEffectSchema,
|
|
84
85
|
PxSvgNodeExtra: () => PxSvgNodeExtra,
|
|
85
|
-
|
|
86
|
+
PxTextEffectSchema: () => PxTextEffectSchema,
|
|
87
|
+
PxTextPathEffectSchema: () => PxTextPathEffectSchema,
|
|
86
88
|
PxTransformPartsSchema: () => PxTransformPartsSchema,
|
|
87
89
|
PxTransformValueSchema: () => PxTransformValueSchema,
|
|
88
90
|
PxTransformationEffectSchema: () => PxTransformationEffectSchema,
|
|
@@ -102,6 +104,7 @@ __export(index_exports, {
|
|
|
102
104
|
describeSchema: () => describeSchema,
|
|
103
105
|
diffInEffect: () => diffInEffect,
|
|
104
106
|
evaluateMotionPathSegment: () => evaluateMotionPathSegment,
|
|
107
|
+
extendedPathForBrowser: () => extendedPathForBrowser,
|
|
105
108
|
generateNewIds: () => generateNewIds,
|
|
106
109
|
getAnimatorConfig: () => getAnimatorConfig,
|
|
107
110
|
getBindings: () => getBindings,
|
|
@@ -110,9 +113,13 @@ __export(index_exports, {
|
|
|
110
113
|
getNormalizedProps: () => getNormalizedProps,
|
|
111
114
|
isPxElementFileFormat: () => isPxElementFileFormat,
|
|
112
115
|
isPxElementFileFormatDeep: () => isPxElementFileFormatDeep,
|
|
116
|
+
jsonElementFactory: () => jsonElementFactory,
|
|
113
117
|
loadTagAnimators: () => loadTagAnimators,
|
|
114
118
|
materialiseAllInTree: () => materialiseAllInTree,
|
|
115
119
|
materialiseAnimatedUseInstances: () => materialiseAnimatedUseInstances,
|
|
120
|
+
materialiseGlyphText: () => materialiseGlyphText,
|
|
121
|
+
materialiseGlyphTextAlongPath: () => materialiseGlyphTextAlongPath,
|
|
122
|
+
materialiseGlyphTextHorizontal: () => materialiseGlyphTextHorizontal,
|
|
116
123
|
materialiseInternalLoopsInPropAnim: () => materialiseInternalLoopsInPropAnim,
|
|
117
124
|
materialiseInternalLoopsInTree: () => materialiseInternalLoopsInTree,
|
|
118
125
|
materialiseMotionPathInPropAnim: () => materialiseMotionPathInPropAnim,
|
|
@@ -123,6 +130,7 @@ __export(index_exports, {
|
|
|
123
130
|
renderNode: () => renderNode,
|
|
124
131
|
schemaKeys: () => schemaKeys,
|
|
125
132
|
setupAnimationTriggers: () => setupAnimationTriggers,
|
|
133
|
+
shiftAnimatable: () => shiftAnimatable,
|
|
126
134
|
toRGBA: () => toRGBA,
|
|
127
135
|
validateNodeEffects: () => validateNodeEffects,
|
|
128
136
|
visualModelAt: () => visualModelAt
|
|
@@ -1005,10 +1013,22 @@ var PxTriggerSchema = implementsInterface()(px.object({
|
|
|
1005
1013
|
outAction: px.enum(["continue", "pause", "reset", "reverse"]).optional(),
|
|
1006
1014
|
scrollIntoViewThreshold: px.number().optional()
|
|
1007
1015
|
}));
|
|
1016
|
+
var PxGlyphSchema = implementsInterface()(px.object({
|
|
1017
|
+
width: px.number(),
|
|
1018
|
+
d: px.string()
|
|
1019
|
+
}));
|
|
1020
|
+
var PxGlyphFontSchema = implementsInterface()(px.object({
|
|
1021
|
+
fFamily: px.string(),
|
|
1022
|
+
style: px.string(),
|
|
1023
|
+
ascent: px.number(),
|
|
1024
|
+
unitsPerEm: px.number(),
|
|
1025
|
+
glyphs: px.record(PxGlyphSchema)
|
|
1026
|
+
}));
|
|
1008
1027
|
var PxDefsSchema = implementsInterface()(px.object({
|
|
1009
1028
|
easings: px.record(px.tuple([px.number(), px.number(), px.number(), px.number()])).optional(),
|
|
1010
1029
|
animations: px.record(PxAnimationDefinitionSchema).optional(),
|
|
1011
|
-
styles: px.record(px.any()).optional()
|
|
1030
|
+
styles: px.record(px.any()).optional(),
|
|
1031
|
+
glyphs: px.record(PxGlyphFontSchema).optional()
|
|
1012
1032
|
}));
|
|
1013
1033
|
var PxAnimatorConfigSchema = implementsInterface()(px.object({
|
|
1014
1034
|
mode: px.enum([PxAnimatorMode.auto, PxAnimatorMode.webapi, PxAnimatorMode.frames]).optional(),
|
|
@@ -1121,14 +1141,18 @@ var PxFillGradientEffectSchema = implementsInterface()(px.object({
|
|
|
1121
1141
|
gradientTransform: px.string().optional()
|
|
1122
1142
|
}));
|
|
1123
1143
|
var PxStrokeGradientEffectSchema = PxFillGradientEffectSchema;
|
|
1124
|
-
var
|
|
1125
|
-
|
|
1144
|
+
var PxTextPathEffectSchema = implementsInterface()(px.object({
|
|
1145
|
+
path: px.string(),
|
|
1146
|
+
pathOverflow: px.string().optional(),
|
|
1126
1147
|
lengthAdjust: px.string().optional(),
|
|
1127
1148
|
method: px.string().optional(),
|
|
1128
1149
|
spacing: px.string().optional(),
|
|
1129
1150
|
startOffset: PxAnimatableNumberSchema.optional(),
|
|
1130
1151
|
textLength: PxAnimatableNumberSchema.optional()
|
|
1131
1152
|
}));
|
|
1153
|
+
var PxTextEffectSchema = implementsInterface()(px.object({
|
|
1154
|
+
useGlyphs: px.boolean().optional()
|
|
1155
|
+
}));
|
|
1132
1156
|
var PxEffectsSchema = implementsInterface()(px.object({
|
|
1133
1157
|
transformation: PxTransformationEffectSchema.optional(),
|
|
1134
1158
|
repeater: PxRepeaterEffectSchema.optional(),
|
|
@@ -1138,7 +1162,8 @@ var PxEffectsSchema = implementsInterface()(px.object({
|
|
|
1138
1162
|
isCombinedShape: px.boolean().optional(),
|
|
1139
1163
|
fillGradient: PxFillGradientEffectSchema.optional(),
|
|
1140
1164
|
strokeGradient: PxStrokeGradientEffectSchema.optional(),
|
|
1141
|
-
|
|
1165
|
+
textPath: PxTextPathEffectSchema.optional(),
|
|
1166
|
+
text: PxTextEffectSchema.optional()
|
|
1142
1167
|
}));
|
|
1143
1168
|
function validateNodeEffects(root, opts) {
|
|
1144
1169
|
const warnings = [];
|
|
@@ -2010,48 +2035,6 @@ function remapKeyframeTimesOnly(node, start, stretch) {
|
|
|
2010
2035
|
}
|
|
2011
2036
|
}
|
|
2012
2037
|
|
|
2013
|
-
// src/effects/textAlongPathEffect.ts
|
|
2014
|
-
function applyTextAlongPathEffect(node, fx, _ctx) {
|
|
2015
|
-
var _a;
|
|
2016
|
-
if (!fx) return node;
|
|
2017
|
-
const href = typeof fx.href === "string" && !fx.href.startsWith("#") ? "#" + fx.href : fx.href;
|
|
2018
|
-
const textPath = {
|
|
2019
|
-
type: "textPath",
|
|
2020
|
-
href,
|
|
2021
|
-
children: (_a = node.children) != null ? _a : []
|
|
2022
|
-
};
|
|
2023
|
-
if (fx.lengthAdjust !== void 0) textPath.lengthAdjust = fx.lengthAdjust;
|
|
2024
|
-
if (fx.method !== void 0) textPath.method = fx.method;
|
|
2025
|
-
if (fx.spacing !== void 0) textPath.spacing = fx.spacing;
|
|
2026
|
-
applyAnimatableNumber(textPath, "startOffset", fx.startOffset);
|
|
2027
|
-
applyAnimatableNumber(textPath, "textLength", fx.textLength);
|
|
2028
|
-
node.children = [textPath];
|
|
2029
|
-
return node;
|
|
2030
|
-
}
|
|
2031
|
-
function applyAnimatableNumber(node, attrName, raw) {
|
|
2032
|
-
if (raw === void 0 || raw === null) return;
|
|
2033
|
-
if (typeof raw === "number") {
|
|
2034
|
-
node[attrName] = String(raw);
|
|
2035
|
-
return;
|
|
2036
|
-
}
|
|
2037
|
-
if (typeof raw === "object" && raw !== null) {
|
|
2038
|
-
const obj = raw;
|
|
2039
|
-
if (Array.isArray(obj.keyframes)) {
|
|
2040
|
-
const prevAnimate = node.animate && typeof node.animate === "object" && !Array.isArray(node.animate) ? node.animate : void 0;
|
|
2041
|
-
const animate = __spreadValues({}, prevAnimate || {});
|
|
2042
|
-
const block = { keyframes: obj.keyframes };
|
|
2043
|
-
if (obj.loop !== void 0) block.loop = obj.loop;
|
|
2044
|
-
animate[attrName] = block;
|
|
2045
|
-
node.animate = animate;
|
|
2046
|
-
return;
|
|
2047
|
-
}
|
|
2048
|
-
if (typeof obj.value === "number") {
|
|
2049
|
-
node[attrName] = String(obj.value);
|
|
2050
|
-
return;
|
|
2051
|
-
}
|
|
2052
|
-
}
|
|
2053
|
-
}
|
|
2054
|
-
|
|
2055
2038
|
// src/PxAnimatorUtil.ts
|
|
2056
2039
|
function bezierToSvgPath(path) {
|
|
2057
2040
|
var _a, _b, _c, _d;
|
|
@@ -2424,6 +2407,24 @@ function bezier2D_arcLengthLUT(P0, P1, P2, P3, steps = 100) {
|
|
|
2424
2407
|
}
|
|
2425
2408
|
return { ts, ds };
|
|
2426
2409
|
}
|
|
2410
|
+
function bezier2D_tForDistance(lut, distance) {
|
|
2411
|
+
const { ts, ds } = lut;
|
|
2412
|
+
const last = ds.length - 1;
|
|
2413
|
+
if (distance <= 0) return ts[0];
|
|
2414
|
+
if (distance >= ds[last]) return ts[last];
|
|
2415
|
+
let lo = 1;
|
|
2416
|
+
let hi = last;
|
|
2417
|
+
while (lo < hi) {
|
|
2418
|
+
const mid = lo + hi >>> 1;
|
|
2419
|
+
if (ds[mid] < distance) lo = mid + 1;
|
|
2420
|
+
else hi = mid;
|
|
2421
|
+
}
|
|
2422
|
+
const dPrev = ds[hi - 1];
|
|
2423
|
+
const dCur = ds[hi];
|
|
2424
|
+
const span = dCur - dPrev;
|
|
2425
|
+
const frac = span > 0 ? (distance - dPrev) / span : 0;
|
|
2426
|
+
return ts[hi - 1] + frac * (ts[hi] - ts[hi - 1]);
|
|
2427
|
+
}
|
|
2427
2428
|
function bezier2D_arcAtT(lut, t) {
|
|
2428
2429
|
const { ts, ds } = lut;
|
|
2429
2430
|
const last = ts.length - 1;
|
|
@@ -2446,6 +2447,623 @@ function invertEasing(easing) {
|
|
|
2446
2447
|
return cubicBezier(flipped);
|
|
2447
2448
|
}
|
|
2448
2449
|
|
|
2450
|
+
// src/effects/pathSampler.ts
|
|
2451
|
+
var LUT_STEPS = 48;
|
|
2452
|
+
var CMD_RE = /[MmLlHhVvCcSsQqTtAaZz]/;
|
|
2453
|
+
function tokenize(d) {
|
|
2454
|
+
const tokens = [];
|
|
2455
|
+
const re = /([MmLlHhVvCcSsQqTtAaZz])|(-?\d*\.?\d+(?:[eE][-+]?\d+)?)/g;
|
|
2456
|
+
let m;
|
|
2457
|
+
while ((m = re.exec(d)) !== null) tokens.push(m[0]);
|
|
2458
|
+
return tokens;
|
|
2459
|
+
}
|
|
2460
|
+
function quadToCubic(P0, Qc, P3) {
|
|
2461
|
+
return {
|
|
2462
|
+
P1: [P0[0] + 2 / 3 * (Qc[0] - P0[0]), P0[1] + 2 / 3 * (Qc[1] - P0[1])],
|
|
2463
|
+
P2: [P3[0] + 2 / 3 * (Qc[0] - P3[0]), P3[1] + 2 / 3 * (Qc[1] - P3[1])]
|
|
2464
|
+
};
|
|
2465
|
+
}
|
|
2466
|
+
function parseCubics(d) {
|
|
2467
|
+
const tokens = tokenize(d);
|
|
2468
|
+
const segs = [];
|
|
2469
|
+
let i = 0;
|
|
2470
|
+
let cx = 0, cy = 0;
|
|
2471
|
+
let sx = 0, sy = 0;
|
|
2472
|
+
let pcx = 0, pcy = 0;
|
|
2473
|
+
let pqx = 0, pqy = 0;
|
|
2474
|
+
let prevCmd = "";
|
|
2475
|
+
const num2 = () => parseFloat(tokens[i++]);
|
|
2476
|
+
const push = (P1, P2, P3) => {
|
|
2477
|
+
const P0 = [cx, cy];
|
|
2478
|
+
const lut = bezier2D_arcLengthLUT(P0, P1, P2, P3, LUT_STEPS);
|
|
2479
|
+
segs.push({ P0, P1, P2, P3, lut, len: lut.ds[lut.ds.length - 1] });
|
|
2480
|
+
cx = P3[0];
|
|
2481
|
+
cy = P3[1];
|
|
2482
|
+
};
|
|
2483
|
+
const pushLine = (x, y) => {
|
|
2484
|
+
push(
|
|
2485
|
+
[cx + (x - cx) / 3, cy + (y - cy) / 3],
|
|
2486
|
+
[cx + 2 * (x - cx) / 3, cy + 2 * (y - cy) / 3],
|
|
2487
|
+
[x, y]
|
|
2488
|
+
);
|
|
2489
|
+
};
|
|
2490
|
+
while (i < tokens.length) {
|
|
2491
|
+
let cmd = tokens[i];
|
|
2492
|
+
if (CMD_RE.test(cmd)) i++;
|
|
2493
|
+
else cmd = prevCmd === "M" ? "L" : prevCmd === "m" ? "l" : prevCmd;
|
|
2494
|
+
const rel = cmd >= "a";
|
|
2495
|
+
const U = cmd.toUpperCase();
|
|
2496
|
+
if (U === "Z") {
|
|
2497
|
+
pushLine(sx, sy);
|
|
2498
|
+
cx = sx;
|
|
2499
|
+
cy = sy;
|
|
2500
|
+
prevCmd = cmd;
|
|
2501
|
+
continue;
|
|
2502
|
+
}
|
|
2503
|
+
if (U === "M") {
|
|
2504
|
+
const x = num2() + (rel ? cx : 0), y = num2() + (rel ? cy : 0);
|
|
2505
|
+
cx = x;
|
|
2506
|
+
cy = y;
|
|
2507
|
+
sx = x;
|
|
2508
|
+
sy = y;
|
|
2509
|
+
prevCmd = cmd;
|
|
2510
|
+
continue;
|
|
2511
|
+
}
|
|
2512
|
+
if (U === "L") {
|
|
2513
|
+
pushLine(num2() + (rel ? cx : 0), num2() + (rel ? cy : 0));
|
|
2514
|
+
} else if (U === "H") {
|
|
2515
|
+
pushLine(num2() + (rel ? cx : 0), cy);
|
|
2516
|
+
} else if (U === "V") {
|
|
2517
|
+
pushLine(cx, num2() + (rel ? cy : 0));
|
|
2518
|
+
} else if (U === "C") {
|
|
2519
|
+
const p1 = [num2() + (rel ? cx : 0), num2() + (rel ? cy : 0)];
|
|
2520
|
+
const p2 = [num2() + (rel ? cx : 0), num2() + (rel ? cy : 0)];
|
|
2521
|
+
const p3 = [num2() + (rel ? cx : 0), num2() + (rel ? cy : 0)];
|
|
2522
|
+
pcx = p2[0];
|
|
2523
|
+
pcy = p2[1];
|
|
2524
|
+
push(p1, p2, p3);
|
|
2525
|
+
} else if (U === "S") {
|
|
2526
|
+
const smooth = prevCmd.toUpperCase() === "C" || prevCmd.toUpperCase() === "S";
|
|
2527
|
+
const p1 = smooth ? [2 * cx - pcx, 2 * cy - pcy] : [cx, cy];
|
|
2528
|
+
const p2 = [num2() + (rel ? cx : 0), num2() + (rel ? cy : 0)];
|
|
2529
|
+
const p3 = [num2() + (rel ? cx : 0), num2() + (rel ? cy : 0)];
|
|
2530
|
+
pcx = p2[0];
|
|
2531
|
+
pcy = p2[1];
|
|
2532
|
+
push(p1, p2, p3);
|
|
2533
|
+
} else if (U === "Q") {
|
|
2534
|
+
const qc = [num2() + (rel ? cx : 0), num2() + (rel ? cy : 0)];
|
|
2535
|
+
const p3 = [num2() + (rel ? cx : 0), num2() + (rel ? cy : 0)];
|
|
2536
|
+
pqx = qc[0];
|
|
2537
|
+
pqy = qc[1];
|
|
2538
|
+
const { P1, P2 } = quadToCubic([cx, cy], qc, p3);
|
|
2539
|
+
push(P1, P2, p3);
|
|
2540
|
+
} else if (U === "T") {
|
|
2541
|
+
const smooth = prevCmd.toUpperCase() === "Q" || prevCmd.toUpperCase() === "T";
|
|
2542
|
+
const qc = smooth ? [2 * cx - pqx, 2 * cy - pqy] : [cx, cy];
|
|
2543
|
+
const p3 = [num2() + (rel ? cx : 0), num2() + (rel ? cy : 0)];
|
|
2544
|
+
pqx = qc[0];
|
|
2545
|
+
pqy = qc[1];
|
|
2546
|
+
const { P1, P2 } = quadToCubic([cx, cy], qc, p3);
|
|
2547
|
+
push(P1, P2, p3);
|
|
2548
|
+
} else if (U === "A") {
|
|
2549
|
+
i += 5;
|
|
2550
|
+
pushLine(num2() + (rel ? cx : 0), num2() + (rel ? cy : 0));
|
|
2551
|
+
} else {
|
|
2552
|
+
i++;
|
|
2553
|
+
continue;
|
|
2554
|
+
}
|
|
2555
|
+
prevCmd = cmd;
|
|
2556
|
+
}
|
|
2557
|
+
return segs.length ? segs : null;
|
|
2558
|
+
}
|
|
2559
|
+
function clamp2(v, lo, hi) {
|
|
2560
|
+
return v < lo ? lo : v > hi ? hi : v;
|
|
2561
|
+
}
|
|
2562
|
+
function createPathSampler(d) {
|
|
2563
|
+
const segs = parseCubics(d);
|
|
2564
|
+
if (!segs) return null;
|
|
2565
|
+
const cum = new Float64Array(segs.length + 1);
|
|
2566
|
+
for (let k = 0; k < segs.length; k++) cum[k + 1] = cum[k] + segs[k].len;
|
|
2567
|
+
const totalLength = cum[segs.length];
|
|
2568
|
+
const start = segs[0].P0, end = segs[segs.length - 1].P3;
|
|
2569
|
+
const closed = Math.hypot(end[0] - start[0], end[1] - start[1]) < 1e-3;
|
|
2570
|
+
const sampleOn = (dist) => {
|
|
2571
|
+
let k = 0;
|
|
2572
|
+
while (k < segs.length - 1 && dist > cum[k + 1]) k++;
|
|
2573
|
+
const seg = segs[k];
|
|
2574
|
+
const local = dist - cum[k];
|
|
2575
|
+
const t = seg.len > 0 ? bezier2D_tForDistance(seg.lut, local) : 0;
|
|
2576
|
+
const [x, y] = bezier2D_pointAt(seg.P0, seg.P1, seg.P2, seg.P3, t);
|
|
2577
|
+
const [dx, dy] = bezier2D_derivativeAt(seg.P0, seg.P1, seg.P2, seg.P3, t);
|
|
2578
|
+
return { x, y, angle: Math.atan2(dy, dx) };
|
|
2579
|
+
};
|
|
2580
|
+
return {
|
|
2581
|
+
totalLength,
|
|
2582
|
+
closed,
|
|
2583
|
+
sampleAtDistance(dist) {
|
|
2584
|
+
if (!closed && (dist < 0 || dist > totalLength)) {
|
|
2585
|
+
const edge = dist < 0 ? 0 : totalLength;
|
|
2586
|
+
const p = sampleOn(edge);
|
|
2587
|
+
const over = dist - edge;
|
|
2588
|
+
return { x: p.x + Math.cos(p.angle) * over, y: p.y + Math.sin(p.angle) * over, angle: p.angle };
|
|
2589
|
+
}
|
|
2590
|
+
return sampleOn(clamp2(dist, 0, totalLength));
|
|
2591
|
+
}
|
|
2592
|
+
};
|
|
2593
|
+
}
|
|
2594
|
+
|
|
2595
|
+
// src/effects/textPathEffect.ts
|
|
2596
|
+
var EXTEND_MARGIN_FRAC = 0.15;
|
|
2597
|
+
function numRange(v) {
|
|
2598
|
+
if (typeof v === "number") return { min: v, max: v };
|
|
2599
|
+
if (v && typeof v === "object") {
|
|
2600
|
+
const o = v;
|
|
2601
|
+
if (typeof o.value === "number") return { min: o.value, max: o.value };
|
|
2602
|
+
if (Array.isArray(o.keyframes) && o.keyframes.length) {
|
|
2603
|
+
const vals = o.keyframes.map((k) => Number(k.value) || 0);
|
|
2604
|
+
return { min: Math.min(...vals), max: Math.max(...vals) };
|
|
2605
|
+
}
|
|
2606
|
+
}
|
|
2607
|
+
return { min: 0, max: 0 };
|
|
2608
|
+
}
|
|
2609
|
+
function estimateTextAdvance(node) {
|
|
2610
|
+
let chars = 0, maxFont = 16;
|
|
2611
|
+
const walk = (el) => {
|
|
2612
|
+
var _a, _b;
|
|
2613
|
+
const fs = parseFloat(String((_a = el.fontSize) != null ? _a : "")) || 0;
|
|
2614
|
+
if (fs) maxFont = Math.max(maxFont, fs);
|
|
2615
|
+
const t = (_b = el.text) != null ? _b : el.textContent;
|
|
2616
|
+
if (typeof t === "string") chars += t.length;
|
|
2617
|
+
if (el.children) for (const c of el.children) walk(c);
|
|
2618
|
+
};
|
|
2619
|
+
walk(node);
|
|
2620
|
+
return chars * maxFont;
|
|
2621
|
+
}
|
|
2622
|
+
var r3 = (n) => Math.round(n * 1e3) / 1e3;
|
|
2623
|
+
function shiftAnimatable(v, by) {
|
|
2624
|
+
if (!by || v === void 0 || v === null) return v;
|
|
2625
|
+
if (typeof v === "number") return v + by;
|
|
2626
|
+
const o = v;
|
|
2627
|
+
if (typeof o.value === "number") return __spreadProps(__spreadValues({}, o), { value: o.value + by });
|
|
2628
|
+
if (Array.isArray(o.keyframes)) return __spreadProps(__spreadValues({}, o), { keyframes: o.keyframes.map((k) => __spreadProps(__spreadValues({}, k), { value: (Number(k.value) || 0) + by })) });
|
|
2629
|
+
return v;
|
|
2630
|
+
}
|
|
2631
|
+
function extendedPathForBrowser(pathD, opts) {
|
|
2632
|
+
var _a;
|
|
2633
|
+
if (opts.pathOverflow === "clip") return { d: pathD, startShift: 0 };
|
|
2634
|
+
const sampler = createPathSampler(pathD);
|
|
2635
|
+
if (!sampler || sampler.closed || sampler.totalLength <= 0) return { d: pathD, startShift: 0 };
|
|
2636
|
+
const L = sampler.totalLength;
|
|
2637
|
+
const margin = EXTEND_MARGIN_FRAC * L;
|
|
2638
|
+
const so = numRange(opts.startOffset);
|
|
2639
|
+
const runWidth = numRange(opts.textLength).max || ((_a = opts.advance) != null ? _a : 0);
|
|
2640
|
+
const startOverflow = Math.max(0, -so.min);
|
|
2641
|
+
const endOverflow = Math.max(0, so.max + runWidth - L);
|
|
2642
|
+
const startExt = startOverflow > 0 ? startOverflow + margin : 0;
|
|
2643
|
+
const endExt = endOverflow > 0 ? endOverflow + margin : 0;
|
|
2644
|
+
if (endExt <= 0 && startExt <= 0) return { d: pathD, startShift: 0 };
|
|
2645
|
+
const s = sampler.sampleAtDistance(0);
|
|
2646
|
+
const e = sampler.sampleAtDistance(L);
|
|
2647
|
+
let d = pathD;
|
|
2648
|
+
if (startExt > 0) {
|
|
2649
|
+
const sx = s.x - Math.cos(s.angle) * startExt, sy = s.y - Math.sin(s.angle) * startExt;
|
|
2650
|
+
const rest = pathD.replace(/^\s*[Mm]\s*-?[\d.]+[\s,]+-?[\d.]+/, "");
|
|
2651
|
+
d = "M" + r3(sx) + "," + r3(sy) + "L" + r3(s.x) + "," + r3(s.y) + rest;
|
|
2652
|
+
}
|
|
2653
|
+
if (endExt > 0) {
|
|
2654
|
+
const ex = e.x + Math.cos(e.angle) * endExt, ey = e.y + Math.sin(e.angle) * endExt;
|
|
2655
|
+
d += "L" + r3(ex) + "," + r3(ey);
|
|
2656
|
+
}
|
|
2657
|
+
return { d, startShift: startExt };
|
|
2658
|
+
}
|
|
2659
|
+
function applyTextPathEffect(node, fx, ctx) {
|
|
2660
|
+
var _a;
|
|
2661
|
+
if (!fx || typeof fx.path !== "string" || !fx.path) return node;
|
|
2662
|
+
const pathId = genId(ctx, "tpath");
|
|
2663
|
+
const { d, startShift } = extendedPathForBrowser(fx.path, {
|
|
2664
|
+
pathOverflow: fx.pathOverflow,
|
|
2665
|
+
startOffset: fx.startOffset,
|
|
2666
|
+
textLength: fx.textLength,
|
|
2667
|
+
advance: estimateTextAdvance(node)
|
|
2668
|
+
});
|
|
2669
|
+
ctx.defs.push({ type: "path", id: pathId, d });
|
|
2670
|
+
const textPath = {
|
|
2671
|
+
type: "textPath",
|
|
2672
|
+
href: "#" + pathId,
|
|
2673
|
+
children: (_a = node.children) != null ? _a : []
|
|
2674
|
+
};
|
|
2675
|
+
if (fx.lengthAdjust !== void 0) textPath.lengthAdjust = fx.lengthAdjust;
|
|
2676
|
+
if (fx.method !== void 0) textPath.method = fx.method;
|
|
2677
|
+
if (fx.spacing !== void 0) textPath.spacing = fx.spacing;
|
|
2678
|
+
applyAnimatableNumber(textPath, "startOffset", shiftAnimatable(fx.startOffset, startShift));
|
|
2679
|
+
applyAnimatableNumber(textPath, "textLength", fx.textLength);
|
|
2680
|
+
node.children = [textPath];
|
|
2681
|
+
return node;
|
|
2682
|
+
}
|
|
2683
|
+
function applyAnimatableNumber(node, attrName, raw) {
|
|
2684
|
+
if (raw === void 0 || raw === null) return;
|
|
2685
|
+
if (typeof raw === "number") {
|
|
2686
|
+
node[attrName] = String(raw);
|
|
2687
|
+
return;
|
|
2688
|
+
}
|
|
2689
|
+
if (typeof raw === "object" && raw !== null) {
|
|
2690
|
+
const obj = raw;
|
|
2691
|
+
if (Array.isArray(obj.keyframes)) {
|
|
2692
|
+
const prevAnimate = node.animate && typeof node.animate === "object" && !Array.isArray(node.animate) ? node.animate : void 0;
|
|
2693
|
+
const animate = __spreadValues({}, prevAnimate || {});
|
|
2694
|
+
const block = { keyframes: obj.keyframes };
|
|
2695
|
+
if (obj.loop !== void 0) block.loop = obj.loop;
|
|
2696
|
+
animate[attrName] = block;
|
|
2697
|
+
node.animate = animate;
|
|
2698
|
+
return;
|
|
2699
|
+
}
|
|
2700
|
+
if (typeof obj.value === "number") {
|
|
2701
|
+
node[attrName] = String(obj.value);
|
|
2702
|
+
return;
|
|
2703
|
+
}
|
|
2704
|
+
}
|
|
2705
|
+
}
|
|
2706
|
+
|
|
2707
|
+
// src/effects/elementFactory.ts
|
|
2708
|
+
var jsonElementFactory = (type, props, children) => {
|
|
2709
|
+
const node = { type };
|
|
2710
|
+
for (const k in props) if (props[k] !== void 0) node[k] = props[k];
|
|
2711
|
+
const arr = Array.isArray(children) ? children.filter((c) => c != null) : children != null ? [children] : [];
|
|
2712
|
+
if (arr.length) node.children = arr;
|
|
2713
|
+
return node;
|
|
2714
|
+
};
|
|
2715
|
+
|
|
2716
|
+
// src/effects/glyphPathBake.ts
|
|
2717
|
+
function fmt(v, decimals) {
|
|
2718
|
+
return Math.round(v) === v ? "" + Math.round(v) : v.toFixed(decimals);
|
|
2719
|
+
}
|
|
2720
|
+
function pack(nums, decimals) {
|
|
2721
|
+
let s = "";
|
|
2722
|
+
for (let i = 0; i < nums.length; i++) {
|
|
2723
|
+
const str2 = fmt(nums[i], decimals);
|
|
2724
|
+
if (i > 0 && str2.charCodeAt(0) !== 45) s += " ";
|
|
2725
|
+
s += str2;
|
|
2726
|
+
}
|
|
2727
|
+
return s;
|
|
2728
|
+
}
|
|
2729
|
+
function apply(m, x, y) {
|
|
2730
|
+
return [m[0] * x + m[2] * y + m[4], m[1] * x + m[3] * y + m[5]];
|
|
2731
|
+
}
|
|
2732
|
+
var TOKEN_RE = /([MLCQZ])|(-?\d*\.?\d+(?:e[-+]?\d+)?)/gi;
|
|
2733
|
+
function transformPathData(d, m, decimals = 2) {
|
|
2734
|
+
const tokens = [];
|
|
2735
|
+
let match;
|
|
2736
|
+
TOKEN_RE.lastIndex = 0;
|
|
2737
|
+
while ((match = TOKEN_RE.exec(d)) !== null) tokens.push(match[0]);
|
|
2738
|
+
let out = "";
|
|
2739
|
+
let i = 0;
|
|
2740
|
+
const num2 = () => parseFloat(tokens[i++]);
|
|
2741
|
+
while (i < tokens.length) {
|
|
2742
|
+
const cmd = tokens[i++];
|
|
2743
|
+
if (cmd === "M" || cmd === "L") {
|
|
2744
|
+
const [x, y] = apply(m, num2(), num2());
|
|
2745
|
+
out += cmd + pack([x, y], decimals);
|
|
2746
|
+
} else if (cmd === "C") {
|
|
2747
|
+
const [x1, y1] = apply(m, num2(), num2());
|
|
2748
|
+
const [x2, y2] = apply(m, num2(), num2());
|
|
2749
|
+
const [x, y] = apply(m, num2(), num2());
|
|
2750
|
+
out += "C" + pack([x1, y1, x2, y2, x, y], decimals);
|
|
2751
|
+
} else if (cmd === "Q") {
|
|
2752
|
+
const [x1, y1] = apply(m, num2(), num2());
|
|
2753
|
+
const [x, y] = apply(m, num2(), num2());
|
|
2754
|
+
out += "Q" + pack([x1, y1, x, y], decimals);
|
|
2755
|
+
} else if (cmd === "Z" || cmd === "z") {
|
|
2756
|
+
out += "Z";
|
|
2757
|
+
}
|
|
2758
|
+
}
|
|
2759
|
+
return out;
|
|
2760
|
+
}
|
|
2761
|
+
|
|
2762
|
+
// src/effects/textGlyphsEffect.ts
|
|
2763
|
+
var DEFAULT_FONT_SIZE = 16;
|
|
2764
|
+
var TEXT_ATTR_KEYS = [
|
|
2765
|
+
"fontFamily",
|
|
2766
|
+
"fontSize",
|
|
2767
|
+
"fontWeight",
|
|
2768
|
+
"fontStyle",
|
|
2769
|
+
"textAnchor",
|
|
2770
|
+
"letterSpacing",
|
|
2771
|
+
"wordSpacing",
|
|
2772
|
+
"textDecoration",
|
|
2773
|
+
"textTransform",
|
|
2774
|
+
"whiteSpace",
|
|
2775
|
+
"x",
|
|
2776
|
+
"y",
|
|
2777
|
+
"dx",
|
|
2778
|
+
"dy",
|
|
2779
|
+
"lengthAdjust",
|
|
2780
|
+
"fill",
|
|
2781
|
+
"stroke",
|
|
2782
|
+
"strokeWidth",
|
|
2783
|
+
"effects",
|
|
2784
|
+
TEXT_ATTR,
|
|
2785
|
+
TEXT_CONTENT_ATTR,
|
|
2786
|
+
"xml:space"
|
|
2787
|
+
];
|
|
2788
|
+
function parseLen(v) {
|
|
2789
|
+
if (typeof v === "number") return v;
|
|
2790
|
+
if (typeof v === "string") {
|
|
2791
|
+
const n = parseFloat(v);
|
|
2792
|
+
return isNaN(n) ? void 0 : n;
|
|
2793
|
+
}
|
|
2794
|
+
return void 0;
|
|
2795
|
+
}
|
|
2796
|
+
function str(v) {
|
|
2797
|
+
return typeof v === "string" ? v : void 0;
|
|
2798
|
+
}
|
|
2799
|
+
function resolveStyle(node, parent) {
|
|
2800
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
2801
|
+
return {
|
|
2802
|
+
fontFamily: (_a = str(node.fontFamily)) != null ? _a : parent.fontFamily,
|
|
2803
|
+
fontSize: (_b = parseLen(node.fontSize)) != null ? _b : parent.fontSize,
|
|
2804
|
+
fill: (_c = node.fill) != null ? _c : parent.fill,
|
|
2805
|
+
stroke: (_d = node.stroke) != null ? _d : parent.stroke,
|
|
2806
|
+
strokeWidth: (_e = node.strokeWidth) != null ? _e : parent.strokeWidth,
|
|
2807
|
+
letterSpacing: (_f = parseLen(node.letterSpacing)) != null ? _f : parent.letterSpacing,
|
|
2808
|
+
wordSpacing: (_g = parseLen(node.wordSpacing)) != null ? _g : parent.wordSpacing
|
|
2809
|
+
};
|
|
2810
|
+
}
|
|
2811
|
+
function rootStyleOf(node) {
|
|
2812
|
+
var _a, _b, _c;
|
|
2813
|
+
return {
|
|
2814
|
+
fontFamily: str(node.fontFamily),
|
|
2815
|
+
fontSize: (_a = parseLen(node.fontSize)) != null ? _a : DEFAULT_FONT_SIZE,
|
|
2816
|
+
fill: node.fill,
|
|
2817
|
+
stroke: node.stroke,
|
|
2818
|
+
strokeWidth: node.strokeWidth,
|
|
2819
|
+
letterSpacing: (_b = parseLen(node.letterSpacing)) != null ? _b : 0,
|
|
2820
|
+
wordSpacing: (_c = parseLen(node.wordSpacing)) != null ? _c : 0
|
|
2821
|
+
};
|
|
2822
|
+
}
|
|
2823
|
+
function paintOf(s) {
|
|
2824
|
+
const p = {};
|
|
2825
|
+
if (s.fill !== void 0) p.fill = s.fill;
|
|
2826
|
+
if (s.stroke !== void 0) p.stroke = s.stroke;
|
|
2827
|
+
if (s.strokeWidth !== void 0) p.strokeWidth = s.strokeWidth;
|
|
2828
|
+
return p;
|
|
2829
|
+
}
|
|
2830
|
+
function glyphFontFor(s, glyphs, soleFont, warnings) {
|
|
2831
|
+
var _a;
|
|
2832
|
+
const gf = s.fontFamily ? glyphs[s.fontFamily] : soleFont;
|
|
2833
|
+
if (!gf) warnings == null ? void 0 : warnings.push('textGlyphs: no glyphs for font "' + ((_a = s.fontFamily) != null ? _a : "") + '"');
|
|
2834
|
+
return gf;
|
|
2835
|
+
}
|
|
2836
|
+
function soleFontOf(glyphs) {
|
|
2837
|
+
const names = Object.keys(glyphs);
|
|
2838
|
+
return names.length === 1 ? glyphs[names[0]] : void 0;
|
|
2839
|
+
}
|
|
2840
|
+
function materialiseGlyphTextHorizontal(node, opts) {
|
|
2841
|
+
var _a, _b, _c, _d;
|
|
2842
|
+
const { glyphs, create = jsonElementFactory, warnings } = opts;
|
|
2843
|
+
const soleFont = soleFontOf(glyphs);
|
|
2844
|
+
const pen = { x: (_a = parseLen(node.x)) != null ? _a : 0, y: (_b = parseLen(node.y)) != null ? _b : 0 };
|
|
2845
|
+
const placements = [];
|
|
2846
|
+
const lines = [{ start: pen.x, end: pen.x }];
|
|
2847
|
+
let line = 0;
|
|
2848
|
+
const renderChars = (content, s) => {
|
|
2849
|
+
const gf = glyphFontFor(s, glyphs, soleFont, warnings);
|
|
2850
|
+
if (!gf) return;
|
|
2851
|
+
const scale = s.fontSize / gf.unitsPerEm;
|
|
2852
|
+
const paint = paintOf(s);
|
|
2853
|
+
for (let i = 0; i < content.length; i++) {
|
|
2854
|
+
const ch = content.charAt(i);
|
|
2855
|
+
const g = gf.glyphs[ch];
|
|
2856
|
+
if (g && g.d) placements.push({ glyphD: g.d, m: [scale, 0, 0, scale, pen.x, pen.y], paint, line, x: pen.x, y: pen.y, scale });
|
|
2857
|
+
pen.x += (g ? g.width : 0) * scale + s.letterSpacing + (ch === " " ? s.wordSpacing : 0);
|
|
2858
|
+
lines[line].end = pen.x;
|
|
2859
|
+
}
|
|
2860
|
+
};
|
|
2861
|
+
const walk = (el, parentStyle) => {
|
|
2862
|
+
var _a2, _b2, _c2, _d2;
|
|
2863
|
+
const s = resolveStyle(el, parentStyle);
|
|
2864
|
+
const x = parseLen(el.x);
|
|
2865
|
+
const y = parseLen(el.y);
|
|
2866
|
+
if (x !== void 0) {
|
|
2867
|
+
pen.x = x;
|
|
2868
|
+
line = lines.length;
|
|
2869
|
+
lines.push({ start: pen.x, end: pen.x });
|
|
2870
|
+
}
|
|
2871
|
+
if (y !== void 0) pen.y = y;
|
|
2872
|
+
pen.x += (_a2 = parseLen(el.dx)) != null ? _a2 : 0;
|
|
2873
|
+
pen.y += (_b2 = parseLen(el.dy)) != null ? _b2 : 0;
|
|
2874
|
+
const content = (_c2 = str(el[TEXT_ATTR])) != null ? _c2 : str(el[TEXT_CONTENT_ATTR]);
|
|
2875
|
+
if (content && !((_d2 = el.children) == null ? void 0 : _d2.length)) renderChars(content, s);
|
|
2876
|
+
if (el.children) for (const ch of el.children) walk(ch, s);
|
|
2877
|
+
};
|
|
2878
|
+
const rootStyle = rootStyleOf(node);
|
|
2879
|
+
if (node.children) for (const ch of node.children) walk(ch, rootStyle);
|
|
2880
|
+
const rootContent = (_c = str(node[TEXT_ATTR])) != null ? _c : str(node[TEXT_CONTENT_ATTR]);
|
|
2881
|
+
if (rootContent && !((_d = node.children) == null ? void 0 : _d.length)) renderChars(rootContent, rootStyle);
|
|
2882
|
+
const anchor = str(node.textAnchor);
|
|
2883
|
+
if (anchor === "middle" || anchor === "end") {
|
|
2884
|
+
for (const p of placements) {
|
|
2885
|
+
const w = lines[p.line].end - lines[p.line].start;
|
|
2886
|
+
const shift = anchor === "middle" ? -w / 2 : -w;
|
|
2887
|
+
p.m = [p.scale, 0, 0, p.scale, p.x + shift, p.y];
|
|
2888
|
+
}
|
|
2889
|
+
}
|
|
2890
|
+
return toGroup(node, buildPaths(placements, create, warnings), create);
|
|
2891
|
+
}
|
|
2892
|
+
function collectAlongPathCells(node, glyphs, soleFont, warnings) {
|
|
2893
|
+
const cells = [];
|
|
2894
|
+
let adv = 0;
|
|
2895
|
+
const walk = (el, parentStyle) => {
|
|
2896
|
+
var _a, _b;
|
|
2897
|
+
const s = resolveStyle(el, parentStyle);
|
|
2898
|
+
const content = (_a = str(el[TEXT_ATTR])) != null ? _a : str(el[TEXT_CONTENT_ATTR]);
|
|
2899
|
+
if (content && !((_b = el.children) == null ? void 0 : _b.length)) {
|
|
2900
|
+
const gf = glyphFontFor(s, glyphs, soleFont, warnings);
|
|
2901
|
+
if (gf) {
|
|
2902
|
+
const scale = s.fontSize / gf.unitsPerEm;
|
|
2903
|
+
const paint = paintOf(s);
|
|
2904
|
+
for (let i = 0; i < content.length; i++) {
|
|
2905
|
+
const ch = content.charAt(i);
|
|
2906
|
+
const g = gf.glyphs[ch];
|
|
2907
|
+
const glyphAdv = (g ? g.width : 0) * scale;
|
|
2908
|
+
if (g && g.d) cells.push({ glyphD: g.d, widthEm: g.width, scale, paint, midBase: adv + glyphAdv / 2 });
|
|
2909
|
+
adv += glyphAdv + s.letterSpacing + (ch === " " ? s.wordSpacing : 0);
|
|
2910
|
+
}
|
|
2911
|
+
}
|
|
2912
|
+
}
|
|
2913
|
+
if (el.children) for (const ch of el.children) walk(ch, s);
|
|
2914
|
+
};
|
|
2915
|
+
walk(node, rootStyleOf(node));
|
|
2916
|
+
return { cells, width: adv };
|
|
2917
|
+
}
|
|
2918
|
+
function alongAffine(sampler, dist, scale, widthEm) {
|
|
2919
|
+
const { x, y, angle } = sampler.sampleAtDistance(dist);
|
|
2920
|
+
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];
|
|
2922
|
+
}
|
|
2923
|
+
function materialiseGlyphTextAlongPath(node, pathD, startOffset, opts, textLength, pathOverflow) {
|
|
2924
|
+
var _a;
|
|
2925
|
+
const { glyphs, create = jsonElementFactory, warnings } = opts;
|
|
2926
|
+
const sampler = pathD ? createPathSampler(pathD) : null;
|
|
2927
|
+
if (!sampler) {
|
|
2928
|
+
warnings == null ? void 0 : warnings.push("textGlyphs: unparsable along-path geometry");
|
|
2929
|
+
return null;
|
|
2930
|
+
}
|
|
2931
|
+
const soleFont = soleFontOf(glyphs);
|
|
2932
|
+
const { cells, width } = collectAlongPathCells(node, glyphs, soleFont, warnings);
|
|
2933
|
+
if (!cells.length) return toGroup(node, [], create);
|
|
2934
|
+
if (textLength && textLength > 0 && width > 0) {
|
|
2935
|
+
const k = textLength / width;
|
|
2936
|
+
for (const c of cells) c.midBase *= k;
|
|
2937
|
+
}
|
|
2938
|
+
const isClip = pathOverflow === "clip" && !sampler.closed;
|
|
2939
|
+
const so = readAnimatable(startOffset);
|
|
2940
|
+
if (so.kind === "animated" /* Animated */ && so.keyframes.length >= 2) {
|
|
2941
|
+
return toGroup(node, buildAnimatedAlongPath(cells, sampler, so.keyframes, so.loop, create, isClip), create);
|
|
2942
|
+
}
|
|
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;
|
|
2944
|
+
const placeCells = isClip ? cells.filter((c) => {
|
|
2945
|
+
const d = base + c.midBase;
|
|
2946
|
+
return d >= 0 && d <= sampler.totalLength;
|
|
2947
|
+
}) : cells;
|
|
2948
|
+
const placements = placeCells.map((c) => ({
|
|
2949
|
+
glyphD: c.glyphD,
|
|
2950
|
+
paint: c.paint,
|
|
2951
|
+
m: alongAffine(sampler, base + c.midBase, c.scale, c.widthEm)
|
|
2952
|
+
}));
|
|
2953
|
+
return toGroup(node, buildPaths(placements, create, warnings), create);
|
|
2954
|
+
}
|
|
2955
|
+
var ALONG_PATH_MAX_STEPS = 48;
|
|
2956
|
+
var ALONG_PATH_MAX_STEPS_PER_SEGMENT = 64;
|
|
2957
|
+
function roundN(v, n) {
|
|
2958
|
+
const f = __pow(10, n);
|
|
2959
|
+
return Math.round(v * f) / f;
|
|
2960
|
+
}
|
|
2961
|
+
function buildAnimatedAlongPath(cells, sampler, sokfs, loop, create, isClip) {
|
|
2962
|
+
const step = Math.max(sampler.totalLength / ALONG_PATH_MAX_STEPS, 0.5);
|
|
2963
|
+
const timeOf = (kf) => Number(kf.time) || 0;
|
|
2964
|
+
const offOf = (kf) => Number(kf.value) || 0;
|
|
2965
|
+
const onPath = (dist) => dist >= 0 && dist <= sampler.totalLength;
|
|
2966
|
+
const out = [];
|
|
2967
|
+
for (const c of cells) {
|
|
2968
|
+
const centred = [c.scale, 0, 0, c.scale, -c.scale * (c.widthEm / 2), 0];
|
|
2969
|
+
const d = transformPathData(c.glyphD, centred);
|
|
2970
|
+
const sampleKf = (dist, time) => {
|
|
2971
|
+
const { x, y, angle } = sampler.sampleAtDistance(dist);
|
|
2972
|
+
return {
|
|
2973
|
+
time,
|
|
2974
|
+
value: {
|
|
2975
|
+
["translate" /* Translate */]: [roundN(x, 3), roundN(y, 3)],
|
|
2976
|
+
["rotate" /* Rotate */]: roundN(angle * 180 / Math.PI, 3)
|
|
2977
|
+
}
|
|
2978
|
+
};
|
|
2979
|
+
};
|
|
2980
|
+
const kfs = [];
|
|
2981
|
+
const opKfs = [];
|
|
2982
|
+
const pushKf = (dist, time) => {
|
|
2983
|
+
kfs.push(sampleKf(dist, time));
|
|
2984
|
+
if (isClip) opKfs.push({ time, value: onPath(dist) ? 1 : 0 });
|
|
2985
|
+
};
|
|
2986
|
+
pushKf(offOf(sokfs[0]) + c.midBase, timeOf(sokfs[0]));
|
|
2987
|
+
for (let k = 1; k < sokfs.length; k++) {
|
|
2988
|
+
const t0 = timeOf(sokfs[k - 1]), t1 = timeOf(sokfs[k]);
|
|
2989
|
+
const o0 = offOf(sokfs[k - 1]), o1 = offOf(sokfs[k]);
|
|
2990
|
+
const n = Math.min(ALONG_PATH_MAX_STEPS_PER_SEGMENT, Math.max(1, Math.ceil(Math.abs(o1 - o0) / step)));
|
|
2991
|
+
for (let s = 1; s <= n; s++) {
|
|
2992
|
+
const f = s / n;
|
|
2993
|
+
pushKf(o0 + f * (o1 - o0) + c.midBase, t0 + f * (t1 - t0));
|
|
2994
|
+
}
|
|
2995
|
+
}
|
|
2996
|
+
const transform = { keyframes: kfs };
|
|
2997
|
+
if (loop !== void 0) transform.loop = loop;
|
|
2998
|
+
const animate = { transform };
|
|
2999
|
+
if (isClip && opKfs.some((k) => k.value === 0)) {
|
|
3000
|
+
const op = { keyframes: opKfs };
|
|
3001
|
+
if (loop !== void 0) op.loop = loop;
|
|
3002
|
+
animate.opacity = op;
|
|
3003
|
+
}
|
|
3004
|
+
out.push(create("path", __spreadProps(__spreadValues({ d }, paintProps(c.paint)), { animate }), []));
|
|
3005
|
+
}
|
|
3006
|
+
return out;
|
|
3007
|
+
}
|
|
3008
|
+
function paintProps(paint) {
|
|
3009
|
+
const p = {};
|
|
3010
|
+
if (paint.fill !== void 0) p.fill = paint.fill;
|
|
3011
|
+
if (paint.stroke !== void 0) p.stroke = paint.stroke;
|
|
3012
|
+
if (paint.strokeWidth !== void 0) p.strokeWidth = paint.strokeWidth;
|
|
3013
|
+
return p;
|
|
3014
|
+
}
|
|
3015
|
+
function buildPaths(placements, create, warnings) {
|
|
3016
|
+
var _a, _b, _c;
|
|
3017
|
+
if (!placements.length) {
|
|
3018
|
+
warnings == null ? void 0 : warnings.push("textGlyphs: nothing to render");
|
|
3019
|
+
return [];
|
|
3020
|
+
}
|
|
3021
|
+
const byPaint = /* @__PURE__ */ new Map();
|
|
3022
|
+
for (const p of placements) {
|
|
3023
|
+
const key = JSON.stringify([(_a = p.paint.fill) != null ? _a : null, (_b = p.paint.stroke) != null ? _b : null, (_c = p.paint.strokeWidth) != null ? _c : null]);
|
|
3024
|
+
const baked = transformPathData(p.glyphD, p.m);
|
|
3025
|
+
const entry = byPaint.get(key);
|
|
3026
|
+
if (entry) entry.d += baked;
|
|
3027
|
+
else byPaint.set(key, { paint: p.paint, d: baked });
|
|
3028
|
+
}
|
|
3029
|
+
const out = [];
|
|
3030
|
+
for (const { paint, d } of byPaint.values()) out.push(create("path", __spreadValues({ d }, paintProps(paint)), []));
|
|
3031
|
+
return out;
|
|
3032
|
+
}
|
|
3033
|
+
function toGroup(node, children, create) {
|
|
3034
|
+
const gProps = {};
|
|
3035
|
+
for (const k of Object.keys(node)) {
|
|
3036
|
+
if (k === "type" || k === "children" || TEXT_ATTR_KEYS.indexOf(k) !== -1) continue;
|
|
3037
|
+
gProps[k] = node[k];
|
|
3038
|
+
}
|
|
3039
|
+
if (gProps.style && typeof gProps.style === "object") {
|
|
3040
|
+
const style = __spreadValues({}, gProps.style);
|
|
3041
|
+
delete style["white-space"];
|
|
3042
|
+
if (Object.keys(style).length) gProps.style = style;
|
|
3043
|
+
else delete gProps.style;
|
|
3044
|
+
}
|
|
3045
|
+
return create("g", gProps, children);
|
|
3046
|
+
}
|
|
3047
|
+
function materialiseGlyphText(node, opts) {
|
|
3048
|
+
if (opts.alongPath) return materialiseGlyphTextAlongPath(node, opts.alongPath.pathD, opts.alongPath.startOffset, opts, opts.alongPath.textLength, opts.alongPath.pathOverflow);
|
|
3049
|
+
return materialiseGlyphTextHorizontal(node, opts);
|
|
3050
|
+
}
|
|
3051
|
+
function applyTextGlyphsEffect(node, fx, ctx) {
|
|
3052
|
+
if (!(fx == null ? void 0 : fx.useGlyphs)) return node;
|
|
3053
|
+
if (!ctx.glyphs) {
|
|
3054
|
+
ctx.warnings.push("textGlyphs: no definitions.glyphs \u2014 left as native <text>");
|
|
3055
|
+
return node;
|
|
3056
|
+
}
|
|
3057
|
+
return materialiseGlyphTextHorizontal(node, { glyphs: ctx.glyphs, warnings: ctx.warnings });
|
|
3058
|
+
}
|
|
3059
|
+
function applyTextGlyphsAlongPath(node, ctx, pathD, startOffset, textLength, pathOverflow) {
|
|
3060
|
+
if (!ctx.glyphs) {
|
|
3061
|
+
ctx.warnings.push("textGlyphs: no definitions.glyphs");
|
|
3062
|
+
return null;
|
|
3063
|
+
}
|
|
3064
|
+
return materialiseGlyphTextAlongPath(node, pathD, startOffset, { glyphs: ctx.glyphs, warnings: ctx.warnings }, textLength, pathOverflow);
|
|
3065
|
+
}
|
|
3066
|
+
|
|
2449
3067
|
// src/PxMotionPath.ts
|
|
2450
3068
|
function getKfTranslate(kf) {
|
|
2451
3069
|
var _a;
|
|
@@ -2889,12 +3507,12 @@ function parseSvgPathToBezier(d) {
|
|
|
2889
3507
|
}
|
|
2890
3508
|
return res;
|
|
2891
3509
|
}
|
|
2892
|
-
function extractPathData(
|
|
2893
|
-
if (
|
|
2894
|
-
return
|
|
3510
|
+
function extractPathData(str2) {
|
|
3511
|
+
if (str2.startsWith("path(") && str2.endsWith(")")) {
|
|
3512
|
+
return str2.slice(5, -1);
|
|
2895
3513
|
}
|
|
2896
|
-
if (/^[MmZzLlHhVvCcSsQqTtAa]/.test(
|
|
2897
|
-
return
|
|
3514
|
+
if (/^[MmZzLlHhVvCcSsQqTtAa]/.test(str2)) {
|
|
3515
|
+
return str2;
|
|
2898
3516
|
}
|
|
2899
3517
|
return void 0;
|
|
2900
3518
|
}
|
|
@@ -3819,7 +4437,7 @@ function rectToPathD(node) {
|
|
|
3819
4437
|
|
|
3820
4438
|
// src/effects/PlayerEffectsUtil.ts
|
|
3821
4439
|
function applyPlayerEffects(root) {
|
|
3822
|
-
var _a;
|
|
4440
|
+
var _a, _b;
|
|
3823
4441
|
const ctx = {
|
|
3824
4442
|
defs: [],
|
|
3825
4443
|
warnings: [],
|
|
@@ -3830,7 +4448,8 @@ function applyPlayerEffects(root) {
|
|
|
3830
4448
|
maskAncestorChains: /* @__PURE__ */ new Map(),
|
|
3831
4449
|
// Resolved engine: `frames` ONLY when explicitly set; auto/webapi/unset →
|
|
3832
4450
|
// webapi (we're not 100% sure it's frames, and CSS/WAAPI need the inline form).
|
|
3833
|
-
engine: ((_a = getAnimatorConfig(root)) == null ? void 0 : _a.mode) === PxAnimatorMode.frames ? PxAnimatorEngine.frames : PxAnimatorEngine.webapi
|
|
4451
|
+
engine: ((_a = getAnimatorConfig(root)) == null ? void 0 : _a.mode) === PxAnimatorMode.frames ? PxAnimatorEngine.frames : PxAnimatorEngine.webapi,
|
|
4452
|
+
glyphs: (_b = getDefs(root)) == null ? void 0 : _b.glyphs
|
|
3834
4453
|
};
|
|
3835
4454
|
const working = clone(root);
|
|
3836
4455
|
indexById(working, ctx.idMap);
|
|
@@ -3842,16 +4461,33 @@ function applyPlayerEffects(root) {
|
|
|
3842
4461
|
return { root: out, defs: ctx.defs, warnings: ctx.warnings, errors: ctx.errors };
|
|
3843
4462
|
}
|
|
3844
4463
|
function applyPlayerEffects_exceptRetime(node, ctx) {
|
|
4464
|
+
var _a;
|
|
3845
4465
|
if (node.children) node.children = node.children.map((child) => applyPlayerEffects_exceptRetime(child, ctx));
|
|
3846
4466
|
const fx = node.effects;
|
|
3847
4467
|
const originalId = typeof node.id === "string" ? node.id : void 0;
|
|
3848
4468
|
const innerIdForContentRef = originalId ? ctx.contentRefInnerIds.get(originalId) : void 0;
|
|
3849
4469
|
if (!fx && !innerIdForContentRef) return node;
|
|
3850
|
-
const { transformation, repeater, maskedBy, trimPath, clone: cloneFx, fillGradient, strokeGradient,
|
|
4470
|
+
const { transformation, repeater, maskedBy, trimPath, clone: cloneFx, fillGradient, strokeGradient, textPath, text } = fx != null ? fx : {};
|
|
3851
4471
|
const isCombinedShape = fx == null ? void 0 : fx.isCombinedShape;
|
|
3852
4472
|
if (fx) delete node.effects;
|
|
3853
4473
|
let n = node;
|
|
3854
|
-
|
|
4474
|
+
let consumedByGlyphs = false;
|
|
4475
|
+
if (text == null ? void 0 : text.useGlyphs) {
|
|
4476
|
+
if (textPath) {
|
|
4477
|
+
const pathD = typeof textPath.path === "string" ? textPath.path : void 0;
|
|
4478
|
+
const rawTL = textPath.textLength;
|
|
4479
|
+
const textLength = typeof rawTL === "number" ? rawTL : rawTL && typeof rawTL === "object" ? typeof rawTL.value === "number" ? rawTL.value : Array.isArray(rawTL.keyframes) && rawTL.keyframes.length ? Number((_a = rawTL.keyframes[0]) == null ? void 0 : _a.value) : void 0 : void 0;
|
|
4480
|
+
const glyphed = applyTextGlyphsAlongPath(n, ctx, pathD, textPath.startOffset, textLength, textPath.pathOverflow);
|
|
4481
|
+
if (glyphed) {
|
|
4482
|
+
n = glyphed;
|
|
4483
|
+
consumedByGlyphs = true;
|
|
4484
|
+
}
|
|
4485
|
+
} else {
|
|
4486
|
+
n = applyTextGlyphsEffect(n, text, ctx);
|
|
4487
|
+
consumedByGlyphs = true;
|
|
4488
|
+
}
|
|
4489
|
+
}
|
|
4490
|
+
if (!consumedByGlyphs) n = applyTextPathEffect(n, textPath, ctx);
|
|
3855
4491
|
n = applyFillGradientEffect(n, fillGradient, ctx);
|
|
3856
4492
|
n = applyStrokeGradientEffect(n, strokeGradient, ctx);
|
|
3857
4493
|
n = applyTrimPathEffect(n, trimPath, isCombinedShape, ctx);
|
|
@@ -4094,8 +4730,8 @@ var DATA_RASTER_IMAGE_RE = /^data:image\/(?:png|jpe?g|gif|webp|bmp);base64,/i;
|
|
|
4094
4730
|
var DATA_SVG_IMAGE_RE = /^data:image\/svg\+xml(?:;[^,]*)?,/i;
|
|
4095
4731
|
var DATA_IMAGE_BASE64_PAYLOAD_RE = /^data:image\/[^;,]*;base64,([A-Za-z0-9+/]{8})/i;
|
|
4096
4732
|
var BASE64_RASTER_MAGICS = ["iVBORw0K", "/9j/", "R0lGOD", "UklGR", "Qk"];
|
|
4097
|
-
function isContentSniffedRasterImage(
|
|
4098
|
-
const m = DATA_IMAGE_BASE64_PAYLOAD_RE.exec(
|
|
4733
|
+
function isContentSniffedRasterImage(str2) {
|
|
4734
|
+
const m = DATA_IMAGE_BASE64_PAYLOAD_RE.exec(str2);
|
|
4099
4735
|
return !!m && BASE64_RASTER_MAGICS.some((magic) => m[1].startsWith(magic));
|
|
4100
4736
|
}
|
|
4101
4737
|
function isDangerousAttrName(nameLower) {
|
|
@@ -4109,18 +4745,18 @@ function sanitiseAttributeValue(name, value) {
|
|
|
4109
4745
|
return void 0;
|
|
4110
4746
|
}
|
|
4111
4747
|
if (nameLower === "fill" || nameLower === "stroke" || nameLower === "stopcolor") {
|
|
4112
|
-
const
|
|
4113
|
-
if (
|
|
4748
|
+
const str2 = String(value);
|
|
4749
|
+
if (str2.includes("url(") && !/^url\(#[^)]+\)$/.test(str2)) {
|
|
4114
4750
|
console.warn('Attribute "' + nameLower + '" blocked: url() must be internal url(#id), got:', value);
|
|
4115
4751
|
return void 0;
|
|
4116
4752
|
}
|
|
4117
4753
|
return value;
|
|
4118
4754
|
}
|
|
4119
4755
|
if (URL_VALUE_ATTRS_LOWER.has(nameLower)) {
|
|
4120
|
-
const
|
|
4121
|
-
if (
|
|
4122
|
-
if (/^url\(#[^)]+\)$/.test(
|
|
4123
|
-
if (IMAGE_REF_ATTRS_LOWER.has(nameLower) && (DATA_RASTER_IMAGE_RE.test(
|
|
4756
|
+
const str2 = String(value);
|
|
4757
|
+
if (str2.startsWith("#")) return value;
|
|
4758
|
+
if (/^url\(#[^)]+\)$/.test(str2)) return value;
|
|
4759
|
+
if (IMAGE_REF_ATTRS_LOWER.has(nameLower) && (DATA_RASTER_IMAGE_RE.test(str2) || DATA_SVG_IMAGE_RE.test(str2) || isContentSniffedRasterImage(str2))) return value;
|
|
4124
4760
|
console.warn('Attribute "' + nameLower + '" blocked: must be #id, url(#id), or data:image/\u2026 URI, got:', value);
|
|
4125
4761
|
return void 0;
|
|
4126
4762
|
}
|
|
@@ -4150,7 +4786,7 @@ function createElement(tagName, normalisedProps, style, children, textContent) {
|
|
|
4150
4786
|
if (textContent) element.textContent = textContent;
|
|
4151
4787
|
return element;
|
|
4152
4788
|
}
|
|
4153
|
-
function
|
|
4789
|
+
function resolveStyle2(style, defs) {
|
|
4154
4790
|
var _a;
|
|
4155
4791
|
if (!style) return void 0;
|
|
4156
4792
|
if (typeof style === "string") {
|
|
@@ -4186,7 +4822,7 @@ function renderNode(node, defs) {
|
|
|
4186
4822
|
if (!node) return null;
|
|
4187
4823
|
const _a = node, { type, children, style } = _a, props = __objRest(_a, ["type", "children", "style"]);
|
|
4188
4824
|
const nodeDefs = getDefs(node) || defs;
|
|
4189
|
-
const resolvedStyle =
|
|
4825
|
+
const resolvedStyle = resolveStyle2(style, nodeDefs);
|
|
4190
4826
|
let childElements;
|
|
4191
4827
|
if (children) {
|
|
4192
4828
|
for (const ch of children) {
|
|
@@ -5239,7 +5875,8 @@ function subtractMultiset(a, b) {
|
|
|
5239
5875
|
PxRetimeEffectSchema,
|
|
5240
5876
|
PxStrokeGradientEffectSchema,
|
|
5241
5877
|
PxSvgNodeExtra,
|
|
5242
|
-
|
|
5878
|
+
PxTextEffectSchema,
|
|
5879
|
+
PxTextPathEffectSchema,
|
|
5243
5880
|
PxTransformPartsSchema,
|
|
5244
5881
|
PxTransformValueSchema,
|
|
5245
5882
|
PxTransformationEffectSchema,
|
|
@@ -5259,6 +5896,7 @@ function subtractMultiset(a, b) {
|
|
|
5259
5896
|
describeSchema,
|
|
5260
5897
|
diffInEffect,
|
|
5261
5898
|
evaluateMotionPathSegment,
|
|
5899
|
+
extendedPathForBrowser,
|
|
5262
5900
|
generateNewIds,
|
|
5263
5901
|
getAnimatorConfig,
|
|
5264
5902
|
getBindings,
|
|
@@ -5267,9 +5905,13 @@ function subtractMultiset(a, b) {
|
|
|
5267
5905
|
getNormalizedProps,
|
|
5268
5906
|
isPxElementFileFormat,
|
|
5269
5907
|
isPxElementFileFormatDeep,
|
|
5908
|
+
jsonElementFactory,
|
|
5270
5909
|
loadTagAnimators,
|
|
5271
5910
|
materialiseAllInTree,
|
|
5272
5911
|
materialiseAnimatedUseInstances,
|
|
5912
|
+
materialiseGlyphText,
|
|
5913
|
+
materialiseGlyphTextAlongPath,
|
|
5914
|
+
materialiseGlyphTextHorizontal,
|
|
5273
5915
|
materialiseInternalLoopsInPropAnim,
|
|
5274
5916
|
materialiseInternalLoopsInTree,
|
|
5275
5917
|
materialiseMotionPathInPropAnim,
|
|
@@ -5280,6 +5922,7 @@ function subtractMultiset(a, b) {
|
|
|
5280
5922
|
renderNode,
|
|
5281
5923
|
schemaKeys,
|
|
5282
5924
|
setupAnimationTriggers,
|
|
5925
|
+
shiftAnimatable,
|
|
5283
5926
|
toRGBA,
|
|
5284
5927
|
validateNodeEffects,
|
|
5285
5928
|
visualModelAt
|