@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.js
CHANGED
|
@@ -4,6 +4,7 @@ var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
|
|
|
4
4
|
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
|
|
5
5
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
6
|
var __propIsEnum = Object.prototype.propertyIsEnumerable;
|
|
7
|
+
var __pow = Math.pow;
|
|
7
8
|
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
8
9
|
var __spreadValues = (a, b) => {
|
|
9
10
|
for (var prop in b || (b = {}))
|
|
@@ -906,10 +907,22 @@ var PxTriggerSchema = implementsInterface()(px.object({
|
|
|
906
907
|
outAction: px.enum(["continue", "pause", "reset", "reverse"]).optional(),
|
|
907
908
|
scrollIntoViewThreshold: px.number().optional()
|
|
908
909
|
}));
|
|
910
|
+
var PxGlyphSchema = implementsInterface()(px.object({
|
|
911
|
+
width: px.number(),
|
|
912
|
+
d: px.string()
|
|
913
|
+
}));
|
|
914
|
+
var PxGlyphFontSchema = implementsInterface()(px.object({
|
|
915
|
+
fFamily: px.string(),
|
|
916
|
+
style: px.string(),
|
|
917
|
+
ascent: px.number(),
|
|
918
|
+
unitsPerEm: px.number(),
|
|
919
|
+
glyphs: px.record(PxGlyphSchema)
|
|
920
|
+
}));
|
|
909
921
|
var PxDefsSchema = implementsInterface()(px.object({
|
|
910
922
|
easings: px.record(px.tuple([px.number(), px.number(), px.number(), px.number()])).optional(),
|
|
911
923
|
animations: px.record(PxAnimationDefinitionSchema).optional(),
|
|
912
|
-
styles: px.record(px.any()).optional()
|
|
924
|
+
styles: px.record(px.any()).optional(),
|
|
925
|
+
glyphs: px.record(PxGlyphFontSchema).optional()
|
|
913
926
|
}));
|
|
914
927
|
var PxAnimatorConfigSchema = implementsInterface()(px.object({
|
|
915
928
|
mode: px.enum([PxAnimatorMode.auto, PxAnimatorMode.webapi, PxAnimatorMode.frames]).optional(),
|
|
@@ -1022,14 +1035,18 @@ var PxFillGradientEffectSchema = implementsInterface()(px.object({
|
|
|
1022
1035
|
gradientTransform: px.string().optional()
|
|
1023
1036
|
}));
|
|
1024
1037
|
var PxStrokeGradientEffectSchema = PxFillGradientEffectSchema;
|
|
1025
|
-
var
|
|
1026
|
-
|
|
1038
|
+
var PxTextPathEffectSchema = implementsInterface()(px.object({
|
|
1039
|
+
path: px.string(),
|
|
1040
|
+
pathOverflow: px.string().optional(),
|
|
1027
1041
|
lengthAdjust: px.string().optional(),
|
|
1028
1042
|
method: px.string().optional(),
|
|
1029
1043
|
spacing: px.string().optional(),
|
|
1030
1044
|
startOffset: PxAnimatableNumberSchema.optional(),
|
|
1031
1045
|
textLength: PxAnimatableNumberSchema.optional()
|
|
1032
1046
|
}));
|
|
1047
|
+
var PxTextEffectSchema = implementsInterface()(px.object({
|
|
1048
|
+
useGlyphs: px.boolean().optional()
|
|
1049
|
+
}));
|
|
1033
1050
|
var PxEffectsSchema = implementsInterface()(px.object({
|
|
1034
1051
|
transformation: PxTransformationEffectSchema.optional(),
|
|
1035
1052
|
repeater: PxRepeaterEffectSchema.optional(),
|
|
@@ -1039,7 +1056,8 @@ var PxEffectsSchema = implementsInterface()(px.object({
|
|
|
1039
1056
|
isCombinedShape: px.boolean().optional(),
|
|
1040
1057
|
fillGradient: PxFillGradientEffectSchema.optional(),
|
|
1041
1058
|
strokeGradient: PxStrokeGradientEffectSchema.optional(),
|
|
1042
|
-
|
|
1059
|
+
textPath: PxTextPathEffectSchema.optional(),
|
|
1060
|
+
text: PxTextEffectSchema.optional()
|
|
1043
1061
|
}));
|
|
1044
1062
|
function validateNodeEffects(root, opts) {
|
|
1045
1063
|
const warnings = [];
|
|
@@ -1911,48 +1929,6 @@ function remapKeyframeTimesOnly(node, start, stretch) {
|
|
|
1911
1929
|
}
|
|
1912
1930
|
}
|
|
1913
1931
|
|
|
1914
|
-
// src/effects/textAlongPathEffect.ts
|
|
1915
|
-
function applyTextAlongPathEffect(node, fx, _ctx) {
|
|
1916
|
-
var _a;
|
|
1917
|
-
if (!fx) return node;
|
|
1918
|
-
const href = typeof fx.href === "string" && !fx.href.startsWith("#") ? "#" + fx.href : fx.href;
|
|
1919
|
-
const textPath = {
|
|
1920
|
-
type: "textPath",
|
|
1921
|
-
href,
|
|
1922
|
-
children: (_a = node.children) != null ? _a : []
|
|
1923
|
-
};
|
|
1924
|
-
if (fx.lengthAdjust !== void 0) textPath.lengthAdjust = fx.lengthAdjust;
|
|
1925
|
-
if (fx.method !== void 0) textPath.method = fx.method;
|
|
1926
|
-
if (fx.spacing !== void 0) textPath.spacing = fx.spacing;
|
|
1927
|
-
applyAnimatableNumber(textPath, "startOffset", fx.startOffset);
|
|
1928
|
-
applyAnimatableNumber(textPath, "textLength", fx.textLength);
|
|
1929
|
-
node.children = [textPath];
|
|
1930
|
-
return node;
|
|
1931
|
-
}
|
|
1932
|
-
function applyAnimatableNumber(node, attrName, raw) {
|
|
1933
|
-
if (raw === void 0 || raw === null) return;
|
|
1934
|
-
if (typeof raw === "number") {
|
|
1935
|
-
node[attrName] = String(raw);
|
|
1936
|
-
return;
|
|
1937
|
-
}
|
|
1938
|
-
if (typeof raw === "object" && raw !== null) {
|
|
1939
|
-
const obj = raw;
|
|
1940
|
-
if (Array.isArray(obj.keyframes)) {
|
|
1941
|
-
const prevAnimate = node.animate && typeof node.animate === "object" && !Array.isArray(node.animate) ? node.animate : void 0;
|
|
1942
|
-
const animate = __spreadValues({}, prevAnimate || {});
|
|
1943
|
-
const block = { keyframes: obj.keyframes };
|
|
1944
|
-
if (obj.loop !== void 0) block.loop = obj.loop;
|
|
1945
|
-
animate[attrName] = block;
|
|
1946
|
-
node.animate = animate;
|
|
1947
|
-
return;
|
|
1948
|
-
}
|
|
1949
|
-
if (typeof obj.value === "number") {
|
|
1950
|
-
node[attrName] = String(obj.value);
|
|
1951
|
-
return;
|
|
1952
|
-
}
|
|
1953
|
-
}
|
|
1954
|
-
}
|
|
1955
|
-
|
|
1956
1932
|
// src/PxAnimatorUtil.ts
|
|
1957
1933
|
function bezierToSvgPath(path) {
|
|
1958
1934
|
var _a, _b, _c, _d;
|
|
@@ -2325,6 +2301,24 @@ function bezier2D_arcLengthLUT(P0, P1, P2, P3, steps = 100) {
|
|
|
2325
2301
|
}
|
|
2326
2302
|
return { ts, ds };
|
|
2327
2303
|
}
|
|
2304
|
+
function bezier2D_tForDistance(lut, distance) {
|
|
2305
|
+
const { ts, ds } = lut;
|
|
2306
|
+
const last = ds.length - 1;
|
|
2307
|
+
if (distance <= 0) return ts[0];
|
|
2308
|
+
if (distance >= ds[last]) return ts[last];
|
|
2309
|
+
let lo = 1;
|
|
2310
|
+
let hi = last;
|
|
2311
|
+
while (lo < hi) {
|
|
2312
|
+
const mid = lo + hi >>> 1;
|
|
2313
|
+
if (ds[mid] < distance) lo = mid + 1;
|
|
2314
|
+
else hi = mid;
|
|
2315
|
+
}
|
|
2316
|
+
const dPrev = ds[hi - 1];
|
|
2317
|
+
const dCur = ds[hi];
|
|
2318
|
+
const span = dCur - dPrev;
|
|
2319
|
+
const frac = span > 0 ? (distance - dPrev) / span : 0;
|
|
2320
|
+
return ts[hi - 1] + frac * (ts[hi] - ts[hi - 1]);
|
|
2321
|
+
}
|
|
2328
2322
|
function bezier2D_arcAtT(lut, t) {
|
|
2329
2323
|
const { ts, ds } = lut;
|
|
2330
2324
|
const last = ts.length - 1;
|
|
@@ -2347,6 +2341,623 @@ function invertEasing(easing) {
|
|
|
2347
2341
|
return cubicBezier(flipped);
|
|
2348
2342
|
}
|
|
2349
2343
|
|
|
2344
|
+
// src/effects/pathSampler.ts
|
|
2345
|
+
var LUT_STEPS = 48;
|
|
2346
|
+
var CMD_RE = /[MmLlHhVvCcSsQqTtAaZz]/;
|
|
2347
|
+
function tokenize(d) {
|
|
2348
|
+
const tokens = [];
|
|
2349
|
+
const re = /([MmLlHhVvCcSsQqTtAaZz])|(-?\d*\.?\d+(?:[eE][-+]?\d+)?)/g;
|
|
2350
|
+
let m;
|
|
2351
|
+
while ((m = re.exec(d)) !== null) tokens.push(m[0]);
|
|
2352
|
+
return tokens;
|
|
2353
|
+
}
|
|
2354
|
+
function quadToCubic(P0, Qc, P3) {
|
|
2355
|
+
return {
|
|
2356
|
+
P1: [P0[0] + 2 / 3 * (Qc[0] - P0[0]), P0[1] + 2 / 3 * (Qc[1] - P0[1])],
|
|
2357
|
+
P2: [P3[0] + 2 / 3 * (Qc[0] - P3[0]), P3[1] + 2 / 3 * (Qc[1] - P3[1])]
|
|
2358
|
+
};
|
|
2359
|
+
}
|
|
2360
|
+
function parseCubics(d) {
|
|
2361
|
+
const tokens = tokenize(d);
|
|
2362
|
+
const segs = [];
|
|
2363
|
+
let i = 0;
|
|
2364
|
+
let cx = 0, cy = 0;
|
|
2365
|
+
let sx = 0, sy = 0;
|
|
2366
|
+
let pcx = 0, pcy = 0;
|
|
2367
|
+
let pqx = 0, pqy = 0;
|
|
2368
|
+
let prevCmd = "";
|
|
2369
|
+
const num2 = () => parseFloat(tokens[i++]);
|
|
2370
|
+
const push = (P1, P2, P3) => {
|
|
2371
|
+
const P0 = [cx, cy];
|
|
2372
|
+
const lut = bezier2D_arcLengthLUT(P0, P1, P2, P3, LUT_STEPS);
|
|
2373
|
+
segs.push({ P0, P1, P2, P3, lut, len: lut.ds[lut.ds.length - 1] });
|
|
2374
|
+
cx = P3[0];
|
|
2375
|
+
cy = P3[1];
|
|
2376
|
+
};
|
|
2377
|
+
const pushLine = (x, y) => {
|
|
2378
|
+
push(
|
|
2379
|
+
[cx + (x - cx) / 3, cy + (y - cy) / 3],
|
|
2380
|
+
[cx + 2 * (x - cx) / 3, cy + 2 * (y - cy) / 3],
|
|
2381
|
+
[x, y]
|
|
2382
|
+
);
|
|
2383
|
+
};
|
|
2384
|
+
while (i < tokens.length) {
|
|
2385
|
+
let cmd = tokens[i];
|
|
2386
|
+
if (CMD_RE.test(cmd)) i++;
|
|
2387
|
+
else cmd = prevCmd === "M" ? "L" : prevCmd === "m" ? "l" : prevCmd;
|
|
2388
|
+
const rel = cmd >= "a";
|
|
2389
|
+
const U = cmd.toUpperCase();
|
|
2390
|
+
if (U === "Z") {
|
|
2391
|
+
pushLine(sx, sy);
|
|
2392
|
+
cx = sx;
|
|
2393
|
+
cy = sy;
|
|
2394
|
+
prevCmd = cmd;
|
|
2395
|
+
continue;
|
|
2396
|
+
}
|
|
2397
|
+
if (U === "M") {
|
|
2398
|
+
const x = num2() + (rel ? cx : 0), y = num2() + (rel ? cy : 0);
|
|
2399
|
+
cx = x;
|
|
2400
|
+
cy = y;
|
|
2401
|
+
sx = x;
|
|
2402
|
+
sy = y;
|
|
2403
|
+
prevCmd = cmd;
|
|
2404
|
+
continue;
|
|
2405
|
+
}
|
|
2406
|
+
if (U === "L") {
|
|
2407
|
+
pushLine(num2() + (rel ? cx : 0), num2() + (rel ? cy : 0));
|
|
2408
|
+
} else if (U === "H") {
|
|
2409
|
+
pushLine(num2() + (rel ? cx : 0), cy);
|
|
2410
|
+
} else if (U === "V") {
|
|
2411
|
+
pushLine(cx, num2() + (rel ? cy : 0));
|
|
2412
|
+
} else if (U === "C") {
|
|
2413
|
+
const p1 = [num2() + (rel ? cx : 0), num2() + (rel ? cy : 0)];
|
|
2414
|
+
const p2 = [num2() + (rel ? cx : 0), num2() + (rel ? cy : 0)];
|
|
2415
|
+
const p3 = [num2() + (rel ? cx : 0), num2() + (rel ? cy : 0)];
|
|
2416
|
+
pcx = p2[0];
|
|
2417
|
+
pcy = p2[1];
|
|
2418
|
+
push(p1, p2, p3);
|
|
2419
|
+
} else if (U === "S") {
|
|
2420
|
+
const smooth = prevCmd.toUpperCase() === "C" || prevCmd.toUpperCase() === "S";
|
|
2421
|
+
const p1 = smooth ? [2 * cx - pcx, 2 * cy - pcy] : [cx, cy];
|
|
2422
|
+
const p2 = [num2() + (rel ? cx : 0), num2() + (rel ? cy : 0)];
|
|
2423
|
+
const p3 = [num2() + (rel ? cx : 0), num2() + (rel ? cy : 0)];
|
|
2424
|
+
pcx = p2[0];
|
|
2425
|
+
pcy = p2[1];
|
|
2426
|
+
push(p1, p2, p3);
|
|
2427
|
+
} else if (U === "Q") {
|
|
2428
|
+
const qc = [num2() + (rel ? cx : 0), num2() + (rel ? cy : 0)];
|
|
2429
|
+
const p3 = [num2() + (rel ? cx : 0), num2() + (rel ? cy : 0)];
|
|
2430
|
+
pqx = qc[0];
|
|
2431
|
+
pqy = qc[1];
|
|
2432
|
+
const { P1, P2 } = quadToCubic([cx, cy], qc, p3);
|
|
2433
|
+
push(P1, P2, p3);
|
|
2434
|
+
} else if (U === "T") {
|
|
2435
|
+
const smooth = prevCmd.toUpperCase() === "Q" || prevCmd.toUpperCase() === "T";
|
|
2436
|
+
const qc = smooth ? [2 * cx - pqx, 2 * cy - pqy] : [cx, cy];
|
|
2437
|
+
const p3 = [num2() + (rel ? cx : 0), num2() + (rel ? cy : 0)];
|
|
2438
|
+
pqx = qc[0];
|
|
2439
|
+
pqy = qc[1];
|
|
2440
|
+
const { P1, P2 } = quadToCubic([cx, cy], qc, p3);
|
|
2441
|
+
push(P1, P2, p3);
|
|
2442
|
+
} else if (U === "A") {
|
|
2443
|
+
i += 5;
|
|
2444
|
+
pushLine(num2() + (rel ? cx : 0), num2() + (rel ? cy : 0));
|
|
2445
|
+
} else {
|
|
2446
|
+
i++;
|
|
2447
|
+
continue;
|
|
2448
|
+
}
|
|
2449
|
+
prevCmd = cmd;
|
|
2450
|
+
}
|
|
2451
|
+
return segs.length ? segs : null;
|
|
2452
|
+
}
|
|
2453
|
+
function clamp2(v, lo, hi) {
|
|
2454
|
+
return v < lo ? lo : v > hi ? hi : v;
|
|
2455
|
+
}
|
|
2456
|
+
function createPathSampler(d) {
|
|
2457
|
+
const segs = parseCubics(d);
|
|
2458
|
+
if (!segs) return null;
|
|
2459
|
+
const cum = new Float64Array(segs.length + 1);
|
|
2460
|
+
for (let k = 0; k < segs.length; k++) cum[k + 1] = cum[k] + segs[k].len;
|
|
2461
|
+
const totalLength = cum[segs.length];
|
|
2462
|
+
const start = segs[0].P0, end = segs[segs.length - 1].P3;
|
|
2463
|
+
const closed = Math.hypot(end[0] - start[0], end[1] - start[1]) < 1e-3;
|
|
2464
|
+
const sampleOn = (dist) => {
|
|
2465
|
+
let k = 0;
|
|
2466
|
+
while (k < segs.length - 1 && dist > cum[k + 1]) k++;
|
|
2467
|
+
const seg = segs[k];
|
|
2468
|
+
const local = dist - cum[k];
|
|
2469
|
+
const t = seg.len > 0 ? bezier2D_tForDistance(seg.lut, local) : 0;
|
|
2470
|
+
const [x, y] = bezier2D_pointAt(seg.P0, seg.P1, seg.P2, seg.P3, t);
|
|
2471
|
+
const [dx, dy] = bezier2D_derivativeAt(seg.P0, seg.P1, seg.P2, seg.P3, t);
|
|
2472
|
+
return { x, y, angle: Math.atan2(dy, dx) };
|
|
2473
|
+
};
|
|
2474
|
+
return {
|
|
2475
|
+
totalLength,
|
|
2476
|
+
closed,
|
|
2477
|
+
sampleAtDistance(dist) {
|
|
2478
|
+
if (!closed && (dist < 0 || dist > totalLength)) {
|
|
2479
|
+
const edge = dist < 0 ? 0 : totalLength;
|
|
2480
|
+
const p = sampleOn(edge);
|
|
2481
|
+
const over = dist - edge;
|
|
2482
|
+
return { x: p.x + Math.cos(p.angle) * over, y: p.y + Math.sin(p.angle) * over, angle: p.angle };
|
|
2483
|
+
}
|
|
2484
|
+
return sampleOn(clamp2(dist, 0, totalLength));
|
|
2485
|
+
}
|
|
2486
|
+
};
|
|
2487
|
+
}
|
|
2488
|
+
|
|
2489
|
+
// src/effects/textPathEffect.ts
|
|
2490
|
+
var EXTEND_MARGIN_FRAC = 0.15;
|
|
2491
|
+
function numRange(v) {
|
|
2492
|
+
if (typeof v === "number") return { min: v, max: v };
|
|
2493
|
+
if (v && typeof v === "object") {
|
|
2494
|
+
const o = v;
|
|
2495
|
+
if (typeof o.value === "number") return { min: o.value, max: o.value };
|
|
2496
|
+
if (Array.isArray(o.keyframes) && o.keyframes.length) {
|
|
2497
|
+
const vals = o.keyframes.map((k) => Number(k.value) || 0);
|
|
2498
|
+
return { min: Math.min(...vals), max: Math.max(...vals) };
|
|
2499
|
+
}
|
|
2500
|
+
}
|
|
2501
|
+
return { min: 0, max: 0 };
|
|
2502
|
+
}
|
|
2503
|
+
function estimateTextAdvance(node) {
|
|
2504
|
+
let chars = 0, maxFont = 16;
|
|
2505
|
+
const walk = (el) => {
|
|
2506
|
+
var _a, _b;
|
|
2507
|
+
const fs = parseFloat(String((_a = el.fontSize) != null ? _a : "")) || 0;
|
|
2508
|
+
if (fs) maxFont = Math.max(maxFont, fs);
|
|
2509
|
+
const t = (_b = el.text) != null ? _b : el.textContent;
|
|
2510
|
+
if (typeof t === "string") chars += t.length;
|
|
2511
|
+
if (el.children) for (const c of el.children) walk(c);
|
|
2512
|
+
};
|
|
2513
|
+
walk(node);
|
|
2514
|
+
return chars * maxFont;
|
|
2515
|
+
}
|
|
2516
|
+
var r3 = (n) => Math.round(n * 1e3) / 1e3;
|
|
2517
|
+
function shiftAnimatable(v, by) {
|
|
2518
|
+
if (!by || v === void 0 || v === null) return v;
|
|
2519
|
+
if (typeof v === "number") return v + by;
|
|
2520
|
+
const o = v;
|
|
2521
|
+
if (typeof o.value === "number") return __spreadProps(__spreadValues({}, o), { value: o.value + by });
|
|
2522
|
+
if (Array.isArray(o.keyframes)) return __spreadProps(__spreadValues({}, o), { keyframes: o.keyframes.map((k) => __spreadProps(__spreadValues({}, k), { value: (Number(k.value) || 0) + by })) });
|
|
2523
|
+
return v;
|
|
2524
|
+
}
|
|
2525
|
+
function extendedPathForBrowser(pathD, opts) {
|
|
2526
|
+
var _a;
|
|
2527
|
+
if (opts.pathOverflow === "clip") return { d: pathD, startShift: 0 };
|
|
2528
|
+
const sampler = createPathSampler(pathD);
|
|
2529
|
+
if (!sampler || sampler.closed || sampler.totalLength <= 0) return { d: pathD, startShift: 0 };
|
|
2530
|
+
const L = sampler.totalLength;
|
|
2531
|
+
const margin = EXTEND_MARGIN_FRAC * L;
|
|
2532
|
+
const so = numRange(opts.startOffset);
|
|
2533
|
+
const runWidth = numRange(opts.textLength).max || ((_a = opts.advance) != null ? _a : 0);
|
|
2534
|
+
const startOverflow = Math.max(0, -so.min);
|
|
2535
|
+
const endOverflow = Math.max(0, so.max + runWidth - L);
|
|
2536
|
+
const startExt = startOverflow > 0 ? startOverflow + margin : 0;
|
|
2537
|
+
const endExt = endOverflow > 0 ? endOverflow + margin : 0;
|
|
2538
|
+
if (endExt <= 0 && startExt <= 0) return { d: pathD, startShift: 0 };
|
|
2539
|
+
const s = sampler.sampleAtDistance(0);
|
|
2540
|
+
const e = sampler.sampleAtDistance(L);
|
|
2541
|
+
let d = pathD;
|
|
2542
|
+
if (startExt > 0) {
|
|
2543
|
+
const sx = s.x - Math.cos(s.angle) * startExt, sy = s.y - Math.sin(s.angle) * startExt;
|
|
2544
|
+
const rest = pathD.replace(/^\s*[Mm]\s*-?[\d.]+[\s,]+-?[\d.]+/, "");
|
|
2545
|
+
d = "M" + r3(sx) + "," + r3(sy) + "L" + r3(s.x) + "," + r3(s.y) + rest;
|
|
2546
|
+
}
|
|
2547
|
+
if (endExt > 0) {
|
|
2548
|
+
const ex = e.x + Math.cos(e.angle) * endExt, ey = e.y + Math.sin(e.angle) * endExt;
|
|
2549
|
+
d += "L" + r3(ex) + "," + r3(ey);
|
|
2550
|
+
}
|
|
2551
|
+
return { d, startShift: startExt };
|
|
2552
|
+
}
|
|
2553
|
+
function applyTextPathEffect(node, fx, ctx) {
|
|
2554
|
+
var _a;
|
|
2555
|
+
if (!fx || typeof fx.path !== "string" || !fx.path) return node;
|
|
2556
|
+
const pathId = genId(ctx, "tpath");
|
|
2557
|
+
const { d, startShift } = extendedPathForBrowser(fx.path, {
|
|
2558
|
+
pathOverflow: fx.pathOverflow,
|
|
2559
|
+
startOffset: fx.startOffset,
|
|
2560
|
+
textLength: fx.textLength,
|
|
2561
|
+
advance: estimateTextAdvance(node)
|
|
2562
|
+
});
|
|
2563
|
+
ctx.defs.push({ type: "path", id: pathId, d });
|
|
2564
|
+
const textPath = {
|
|
2565
|
+
type: "textPath",
|
|
2566
|
+
href: "#" + pathId,
|
|
2567
|
+
children: (_a = node.children) != null ? _a : []
|
|
2568
|
+
};
|
|
2569
|
+
if (fx.lengthAdjust !== void 0) textPath.lengthAdjust = fx.lengthAdjust;
|
|
2570
|
+
if (fx.method !== void 0) textPath.method = fx.method;
|
|
2571
|
+
if (fx.spacing !== void 0) textPath.spacing = fx.spacing;
|
|
2572
|
+
applyAnimatableNumber(textPath, "startOffset", shiftAnimatable(fx.startOffset, startShift));
|
|
2573
|
+
applyAnimatableNumber(textPath, "textLength", fx.textLength);
|
|
2574
|
+
node.children = [textPath];
|
|
2575
|
+
return node;
|
|
2576
|
+
}
|
|
2577
|
+
function applyAnimatableNumber(node, attrName, raw) {
|
|
2578
|
+
if (raw === void 0 || raw === null) return;
|
|
2579
|
+
if (typeof raw === "number") {
|
|
2580
|
+
node[attrName] = String(raw);
|
|
2581
|
+
return;
|
|
2582
|
+
}
|
|
2583
|
+
if (typeof raw === "object" && raw !== null) {
|
|
2584
|
+
const obj = raw;
|
|
2585
|
+
if (Array.isArray(obj.keyframes)) {
|
|
2586
|
+
const prevAnimate = node.animate && typeof node.animate === "object" && !Array.isArray(node.animate) ? node.animate : void 0;
|
|
2587
|
+
const animate = __spreadValues({}, prevAnimate || {});
|
|
2588
|
+
const block = { keyframes: obj.keyframes };
|
|
2589
|
+
if (obj.loop !== void 0) block.loop = obj.loop;
|
|
2590
|
+
animate[attrName] = block;
|
|
2591
|
+
node.animate = animate;
|
|
2592
|
+
return;
|
|
2593
|
+
}
|
|
2594
|
+
if (typeof obj.value === "number") {
|
|
2595
|
+
node[attrName] = String(obj.value);
|
|
2596
|
+
return;
|
|
2597
|
+
}
|
|
2598
|
+
}
|
|
2599
|
+
}
|
|
2600
|
+
|
|
2601
|
+
// src/effects/elementFactory.ts
|
|
2602
|
+
var jsonElementFactory = (type, props, children) => {
|
|
2603
|
+
const node = { type };
|
|
2604
|
+
for (const k in props) if (props[k] !== void 0) node[k] = props[k];
|
|
2605
|
+
const arr = Array.isArray(children) ? children.filter((c) => c != null) : children != null ? [children] : [];
|
|
2606
|
+
if (arr.length) node.children = arr;
|
|
2607
|
+
return node;
|
|
2608
|
+
};
|
|
2609
|
+
|
|
2610
|
+
// src/effects/glyphPathBake.ts
|
|
2611
|
+
function fmt(v, decimals) {
|
|
2612
|
+
return Math.round(v) === v ? "" + Math.round(v) : v.toFixed(decimals);
|
|
2613
|
+
}
|
|
2614
|
+
function pack(nums, decimals) {
|
|
2615
|
+
let s = "";
|
|
2616
|
+
for (let i = 0; i < nums.length; i++) {
|
|
2617
|
+
const str2 = fmt(nums[i], decimals);
|
|
2618
|
+
if (i > 0 && str2.charCodeAt(0) !== 45) s += " ";
|
|
2619
|
+
s += str2;
|
|
2620
|
+
}
|
|
2621
|
+
return s;
|
|
2622
|
+
}
|
|
2623
|
+
function apply(m, x, y) {
|
|
2624
|
+
return [m[0] * x + m[2] * y + m[4], m[1] * x + m[3] * y + m[5]];
|
|
2625
|
+
}
|
|
2626
|
+
var TOKEN_RE = /([MLCQZ])|(-?\d*\.?\d+(?:e[-+]?\d+)?)/gi;
|
|
2627
|
+
function transformPathData(d, m, decimals = 2) {
|
|
2628
|
+
const tokens = [];
|
|
2629
|
+
let match;
|
|
2630
|
+
TOKEN_RE.lastIndex = 0;
|
|
2631
|
+
while ((match = TOKEN_RE.exec(d)) !== null) tokens.push(match[0]);
|
|
2632
|
+
let out = "";
|
|
2633
|
+
let i = 0;
|
|
2634
|
+
const num2 = () => parseFloat(tokens[i++]);
|
|
2635
|
+
while (i < tokens.length) {
|
|
2636
|
+
const cmd = tokens[i++];
|
|
2637
|
+
if (cmd === "M" || cmd === "L") {
|
|
2638
|
+
const [x, y] = apply(m, num2(), num2());
|
|
2639
|
+
out += cmd + pack([x, y], decimals);
|
|
2640
|
+
} else if (cmd === "C") {
|
|
2641
|
+
const [x1, y1] = apply(m, num2(), num2());
|
|
2642
|
+
const [x2, y2] = apply(m, num2(), num2());
|
|
2643
|
+
const [x, y] = apply(m, num2(), num2());
|
|
2644
|
+
out += "C" + pack([x1, y1, x2, y2, x, y], decimals);
|
|
2645
|
+
} else if (cmd === "Q") {
|
|
2646
|
+
const [x1, y1] = apply(m, num2(), num2());
|
|
2647
|
+
const [x, y] = apply(m, num2(), num2());
|
|
2648
|
+
out += "Q" + pack([x1, y1, x, y], decimals);
|
|
2649
|
+
} else if (cmd === "Z" || cmd === "z") {
|
|
2650
|
+
out += "Z";
|
|
2651
|
+
}
|
|
2652
|
+
}
|
|
2653
|
+
return out;
|
|
2654
|
+
}
|
|
2655
|
+
|
|
2656
|
+
// src/effects/textGlyphsEffect.ts
|
|
2657
|
+
var DEFAULT_FONT_SIZE = 16;
|
|
2658
|
+
var TEXT_ATTR_KEYS = [
|
|
2659
|
+
"fontFamily",
|
|
2660
|
+
"fontSize",
|
|
2661
|
+
"fontWeight",
|
|
2662
|
+
"fontStyle",
|
|
2663
|
+
"textAnchor",
|
|
2664
|
+
"letterSpacing",
|
|
2665
|
+
"wordSpacing",
|
|
2666
|
+
"textDecoration",
|
|
2667
|
+
"textTransform",
|
|
2668
|
+
"whiteSpace",
|
|
2669
|
+
"x",
|
|
2670
|
+
"y",
|
|
2671
|
+
"dx",
|
|
2672
|
+
"dy",
|
|
2673
|
+
"lengthAdjust",
|
|
2674
|
+
"fill",
|
|
2675
|
+
"stroke",
|
|
2676
|
+
"strokeWidth",
|
|
2677
|
+
"effects",
|
|
2678
|
+
TEXT_ATTR,
|
|
2679
|
+
TEXT_CONTENT_ATTR,
|
|
2680
|
+
"xml:space"
|
|
2681
|
+
];
|
|
2682
|
+
function parseLen(v) {
|
|
2683
|
+
if (typeof v === "number") return v;
|
|
2684
|
+
if (typeof v === "string") {
|
|
2685
|
+
const n = parseFloat(v);
|
|
2686
|
+
return isNaN(n) ? void 0 : n;
|
|
2687
|
+
}
|
|
2688
|
+
return void 0;
|
|
2689
|
+
}
|
|
2690
|
+
function str(v) {
|
|
2691
|
+
return typeof v === "string" ? v : void 0;
|
|
2692
|
+
}
|
|
2693
|
+
function resolveStyle(node, parent) {
|
|
2694
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
2695
|
+
return {
|
|
2696
|
+
fontFamily: (_a = str(node.fontFamily)) != null ? _a : parent.fontFamily,
|
|
2697
|
+
fontSize: (_b = parseLen(node.fontSize)) != null ? _b : parent.fontSize,
|
|
2698
|
+
fill: (_c = node.fill) != null ? _c : parent.fill,
|
|
2699
|
+
stroke: (_d = node.stroke) != null ? _d : parent.stroke,
|
|
2700
|
+
strokeWidth: (_e = node.strokeWidth) != null ? _e : parent.strokeWidth,
|
|
2701
|
+
letterSpacing: (_f = parseLen(node.letterSpacing)) != null ? _f : parent.letterSpacing,
|
|
2702
|
+
wordSpacing: (_g = parseLen(node.wordSpacing)) != null ? _g : parent.wordSpacing
|
|
2703
|
+
};
|
|
2704
|
+
}
|
|
2705
|
+
function rootStyleOf(node) {
|
|
2706
|
+
var _a, _b, _c;
|
|
2707
|
+
return {
|
|
2708
|
+
fontFamily: str(node.fontFamily),
|
|
2709
|
+
fontSize: (_a = parseLen(node.fontSize)) != null ? _a : DEFAULT_FONT_SIZE,
|
|
2710
|
+
fill: node.fill,
|
|
2711
|
+
stroke: node.stroke,
|
|
2712
|
+
strokeWidth: node.strokeWidth,
|
|
2713
|
+
letterSpacing: (_b = parseLen(node.letterSpacing)) != null ? _b : 0,
|
|
2714
|
+
wordSpacing: (_c = parseLen(node.wordSpacing)) != null ? _c : 0
|
|
2715
|
+
};
|
|
2716
|
+
}
|
|
2717
|
+
function paintOf(s) {
|
|
2718
|
+
const p = {};
|
|
2719
|
+
if (s.fill !== void 0) p.fill = s.fill;
|
|
2720
|
+
if (s.stroke !== void 0) p.stroke = s.stroke;
|
|
2721
|
+
if (s.strokeWidth !== void 0) p.strokeWidth = s.strokeWidth;
|
|
2722
|
+
return p;
|
|
2723
|
+
}
|
|
2724
|
+
function glyphFontFor(s, glyphs, soleFont, warnings) {
|
|
2725
|
+
var _a;
|
|
2726
|
+
const gf = s.fontFamily ? glyphs[s.fontFamily] : soleFont;
|
|
2727
|
+
if (!gf) warnings == null ? void 0 : warnings.push('textGlyphs: no glyphs for font "' + ((_a = s.fontFamily) != null ? _a : "") + '"');
|
|
2728
|
+
return gf;
|
|
2729
|
+
}
|
|
2730
|
+
function soleFontOf(glyphs) {
|
|
2731
|
+
const names = Object.keys(glyphs);
|
|
2732
|
+
return names.length === 1 ? glyphs[names[0]] : void 0;
|
|
2733
|
+
}
|
|
2734
|
+
function materialiseGlyphTextHorizontal(node, opts) {
|
|
2735
|
+
var _a, _b, _c, _d;
|
|
2736
|
+
const { glyphs, create = jsonElementFactory, warnings } = opts;
|
|
2737
|
+
const soleFont = soleFontOf(glyphs);
|
|
2738
|
+
const pen = { x: (_a = parseLen(node.x)) != null ? _a : 0, y: (_b = parseLen(node.y)) != null ? _b : 0 };
|
|
2739
|
+
const placements = [];
|
|
2740
|
+
const lines = [{ start: pen.x, end: pen.x }];
|
|
2741
|
+
let line = 0;
|
|
2742
|
+
const renderChars = (content, s) => {
|
|
2743
|
+
const gf = glyphFontFor(s, glyphs, soleFont, warnings);
|
|
2744
|
+
if (!gf) return;
|
|
2745
|
+
const scale = s.fontSize / gf.unitsPerEm;
|
|
2746
|
+
const paint = paintOf(s);
|
|
2747
|
+
for (let i = 0; i < content.length; i++) {
|
|
2748
|
+
const ch = content.charAt(i);
|
|
2749
|
+
const g = gf.glyphs[ch];
|
|
2750
|
+
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 });
|
|
2751
|
+
pen.x += (g ? g.width : 0) * scale + s.letterSpacing + (ch === " " ? s.wordSpacing : 0);
|
|
2752
|
+
lines[line].end = pen.x;
|
|
2753
|
+
}
|
|
2754
|
+
};
|
|
2755
|
+
const walk = (el, parentStyle) => {
|
|
2756
|
+
var _a2, _b2, _c2, _d2;
|
|
2757
|
+
const s = resolveStyle(el, parentStyle);
|
|
2758
|
+
const x = parseLen(el.x);
|
|
2759
|
+
const y = parseLen(el.y);
|
|
2760
|
+
if (x !== void 0) {
|
|
2761
|
+
pen.x = x;
|
|
2762
|
+
line = lines.length;
|
|
2763
|
+
lines.push({ start: pen.x, end: pen.x });
|
|
2764
|
+
}
|
|
2765
|
+
if (y !== void 0) pen.y = y;
|
|
2766
|
+
pen.x += (_a2 = parseLen(el.dx)) != null ? _a2 : 0;
|
|
2767
|
+
pen.y += (_b2 = parseLen(el.dy)) != null ? _b2 : 0;
|
|
2768
|
+
const content = (_c2 = str(el[TEXT_ATTR])) != null ? _c2 : str(el[TEXT_CONTENT_ATTR]);
|
|
2769
|
+
if (content && !((_d2 = el.children) == null ? void 0 : _d2.length)) renderChars(content, s);
|
|
2770
|
+
if (el.children) for (const ch of el.children) walk(ch, s);
|
|
2771
|
+
};
|
|
2772
|
+
const rootStyle = rootStyleOf(node);
|
|
2773
|
+
if (node.children) for (const ch of node.children) walk(ch, rootStyle);
|
|
2774
|
+
const rootContent = (_c = str(node[TEXT_ATTR])) != null ? _c : str(node[TEXT_CONTENT_ATTR]);
|
|
2775
|
+
if (rootContent && !((_d = node.children) == null ? void 0 : _d.length)) renderChars(rootContent, rootStyle);
|
|
2776
|
+
const anchor = str(node.textAnchor);
|
|
2777
|
+
if (anchor === "middle" || anchor === "end") {
|
|
2778
|
+
for (const p of placements) {
|
|
2779
|
+
const w = lines[p.line].end - lines[p.line].start;
|
|
2780
|
+
const shift = anchor === "middle" ? -w / 2 : -w;
|
|
2781
|
+
p.m = [p.scale, 0, 0, p.scale, p.x + shift, p.y];
|
|
2782
|
+
}
|
|
2783
|
+
}
|
|
2784
|
+
return toGroup(node, buildPaths(placements, create, warnings), create);
|
|
2785
|
+
}
|
|
2786
|
+
function collectAlongPathCells(node, glyphs, soleFont, warnings) {
|
|
2787
|
+
const cells = [];
|
|
2788
|
+
let adv = 0;
|
|
2789
|
+
const walk = (el, parentStyle) => {
|
|
2790
|
+
var _a, _b;
|
|
2791
|
+
const s = resolveStyle(el, parentStyle);
|
|
2792
|
+
const content = (_a = str(el[TEXT_ATTR])) != null ? _a : str(el[TEXT_CONTENT_ATTR]);
|
|
2793
|
+
if (content && !((_b = el.children) == null ? void 0 : _b.length)) {
|
|
2794
|
+
const gf = glyphFontFor(s, glyphs, soleFont, warnings);
|
|
2795
|
+
if (gf) {
|
|
2796
|
+
const scale = s.fontSize / gf.unitsPerEm;
|
|
2797
|
+
const paint = paintOf(s);
|
|
2798
|
+
for (let i = 0; i < content.length; i++) {
|
|
2799
|
+
const ch = content.charAt(i);
|
|
2800
|
+
const g = gf.glyphs[ch];
|
|
2801
|
+
const glyphAdv = (g ? g.width : 0) * scale;
|
|
2802
|
+
if (g && g.d) cells.push({ glyphD: g.d, widthEm: g.width, scale, paint, midBase: adv + glyphAdv / 2 });
|
|
2803
|
+
adv += glyphAdv + s.letterSpacing + (ch === " " ? s.wordSpacing : 0);
|
|
2804
|
+
}
|
|
2805
|
+
}
|
|
2806
|
+
}
|
|
2807
|
+
if (el.children) for (const ch of el.children) walk(ch, s);
|
|
2808
|
+
};
|
|
2809
|
+
walk(node, rootStyleOf(node));
|
|
2810
|
+
return { cells, width: adv };
|
|
2811
|
+
}
|
|
2812
|
+
function alongAffine(sampler, dist, scale, widthEm) {
|
|
2813
|
+
const { x, y, angle } = sampler.sampleAtDistance(dist);
|
|
2814
|
+
const cos = Math.cos(angle), sin = Math.sin(angle), hw = widthEm / 2;
|
|
2815
|
+
return [scale * cos, scale * sin, -scale * sin, scale * cos, x - scale * cos * hw, y - scale * sin * hw];
|
|
2816
|
+
}
|
|
2817
|
+
function materialiseGlyphTextAlongPath(node, pathD, startOffset, opts, textLength, pathOverflow) {
|
|
2818
|
+
var _a;
|
|
2819
|
+
const { glyphs, create = jsonElementFactory, warnings } = opts;
|
|
2820
|
+
const sampler = pathD ? createPathSampler(pathD) : null;
|
|
2821
|
+
if (!sampler) {
|
|
2822
|
+
warnings == null ? void 0 : warnings.push("textGlyphs: unparsable along-path geometry");
|
|
2823
|
+
return null;
|
|
2824
|
+
}
|
|
2825
|
+
const soleFont = soleFontOf(glyphs);
|
|
2826
|
+
const { cells, width } = collectAlongPathCells(node, glyphs, soleFont, warnings);
|
|
2827
|
+
if (!cells.length) return toGroup(node, [], create);
|
|
2828
|
+
if (textLength && textLength > 0 && width > 0) {
|
|
2829
|
+
const k = textLength / width;
|
|
2830
|
+
for (const c of cells) c.midBase *= k;
|
|
2831
|
+
}
|
|
2832
|
+
const isClip = pathOverflow === "clip" && !sampler.closed;
|
|
2833
|
+
const so = readAnimatable(startOffset);
|
|
2834
|
+
if (so.kind === "animated" /* Animated */ && so.keyframes.length >= 2) {
|
|
2835
|
+
return toGroup(node, buildAnimatedAlongPath(cells, sampler, so.keyframes, so.loop, create, isClip), create);
|
|
2836
|
+
}
|
|
2837
|
+
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;
|
|
2838
|
+
const placeCells = isClip ? cells.filter((c) => {
|
|
2839
|
+
const d = base + c.midBase;
|
|
2840
|
+
return d >= 0 && d <= sampler.totalLength;
|
|
2841
|
+
}) : cells;
|
|
2842
|
+
const placements = placeCells.map((c) => ({
|
|
2843
|
+
glyphD: c.glyphD,
|
|
2844
|
+
paint: c.paint,
|
|
2845
|
+
m: alongAffine(sampler, base + c.midBase, c.scale, c.widthEm)
|
|
2846
|
+
}));
|
|
2847
|
+
return toGroup(node, buildPaths(placements, create, warnings), create);
|
|
2848
|
+
}
|
|
2849
|
+
var ALONG_PATH_MAX_STEPS = 48;
|
|
2850
|
+
var ALONG_PATH_MAX_STEPS_PER_SEGMENT = 64;
|
|
2851
|
+
function roundN(v, n) {
|
|
2852
|
+
const f = __pow(10, n);
|
|
2853
|
+
return Math.round(v * f) / f;
|
|
2854
|
+
}
|
|
2855
|
+
function buildAnimatedAlongPath(cells, sampler, sokfs, loop, create, isClip) {
|
|
2856
|
+
const step = Math.max(sampler.totalLength / ALONG_PATH_MAX_STEPS, 0.5);
|
|
2857
|
+
const timeOf = (kf) => Number(kf.time) || 0;
|
|
2858
|
+
const offOf = (kf) => Number(kf.value) || 0;
|
|
2859
|
+
const onPath = (dist) => dist >= 0 && dist <= sampler.totalLength;
|
|
2860
|
+
const out = [];
|
|
2861
|
+
for (const c of cells) {
|
|
2862
|
+
const centred = [c.scale, 0, 0, c.scale, -c.scale * (c.widthEm / 2), 0];
|
|
2863
|
+
const d = transformPathData(c.glyphD, centred);
|
|
2864
|
+
const sampleKf = (dist, time) => {
|
|
2865
|
+
const { x, y, angle } = sampler.sampleAtDistance(dist);
|
|
2866
|
+
return {
|
|
2867
|
+
time,
|
|
2868
|
+
value: {
|
|
2869
|
+
["translate" /* Translate */]: [roundN(x, 3), roundN(y, 3)],
|
|
2870
|
+
["rotate" /* Rotate */]: roundN(angle * 180 / Math.PI, 3)
|
|
2871
|
+
}
|
|
2872
|
+
};
|
|
2873
|
+
};
|
|
2874
|
+
const kfs = [];
|
|
2875
|
+
const opKfs = [];
|
|
2876
|
+
const pushKf = (dist, time) => {
|
|
2877
|
+
kfs.push(sampleKf(dist, time));
|
|
2878
|
+
if (isClip) opKfs.push({ time, value: onPath(dist) ? 1 : 0 });
|
|
2879
|
+
};
|
|
2880
|
+
pushKf(offOf(sokfs[0]) + c.midBase, timeOf(sokfs[0]));
|
|
2881
|
+
for (let k = 1; k < sokfs.length; k++) {
|
|
2882
|
+
const t0 = timeOf(sokfs[k - 1]), t1 = timeOf(sokfs[k]);
|
|
2883
|
+
const o0 = offOf(sokfs[k - 1]), o1 = offOf(sokfs[k]);
|
|
2884
|
+
const n = Math.min(ALONG_PATH_MAX_STEPS_PER_SEGMENT, Math.max(1, Math.ceil(Math.abs(o1 - o0) / step)));
|
|
2885
|
+
for (let s = 1; s <= n; s++) {
|
|
2886
|
+
const f = s / n;
|
|
2887
|
+
pushKf(o0 + f * (o1 - o0) + c.midBase, t0 + f * (t1 - t0));
|
|
2888
|
+
}
|
|
2889
|
+
}
|
|
2890
|
+
const transform = { keyframes: kfs };
|
|
2891
|
+
if (loop !== void 0) transform.loop = loop;
|
|
2892
|
+
const animate = { transform };
|
|
2893
|
+
if (isClip && opKfs.some((k) => k.value === 0)) {
|
|
2894
|
+
const op = { keyframes: opKfs };
|
|
2895
|
+
if (loop !== void 0) op.loop = loop;
|
|
2896
|
+
animate.opacity = op;
|
|
2897
|
+
}
|
|
2898
|
+
out.push(create("path", __spreadProps(__spreadValues({ d }, paintProps(c.paint)), { animate }), []));
|
|
2899
|
+
}
|
|
2900
|
+
return out;
|
|
2901
|
+
}
|
|
2902
|
+
function paintProps(paint) {
|
|
2903
|
+
const p = {};
|
|
2904
|
+
if (paint.fill !== void 0) p.fill = paint.fill;
|
|
2905
|
+
if (paint.stroke !== void 0) p.stroke = paint.stroke;
|
|
2906
|
+
if (paint.strokeWidth !== void 0) p.strokeWidth = paint.strokeWidth;
|
|
2907
|
+
return p;
|
|
2908
|
+
}
|
|
2909
|
+
function buildPaths(placements, create, warnings) {
|
|
2910
|
+
var _a, _b, _c;
|
|
2911
|
+
if (!placements.length) {
|
|
2912
|
+
warnings == null ? void 0 : warnings.push("textGlyphs: nothing to render");
|
|
2913
|
+
return [];
|
|
2914
|
+
}
|
|
2915
|
+
const byPaint = /* @__PURE__ */ new Map();
|
|
2916
|
+
for (const p of placements) {
|
|
2917
|
+
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]);
|
|
2918
|
+
const baked = transformPathData(p.glyphD, p.m);
|
|
2919
|
+
const entry = byPaint.get(key);
|
|
2920
|
+
if (entry) entry.d += baked;
|
|
2921
|
+
else byPaint.set(key, { paint: p.paint, d: baked });
|
|
2922
|
+
}
|
|
2923
|
+
const out = [];
|
|
2924
|
+
for (const { paint, d } of byPaint.values()) out.push(create("path", __spreadValues({ d }, paintProps(paint)), []));
|
|
2925
|
+
return out;
|
|
2926
|
+
}
|
|
2927
|
+
function toGroup(node, children, create) {
|
|
2928
|
+
const gProps = {};
|
|
2929
|
+
for (const k of Object.keys(node)) {
|
|
2930
|
+
if (k === "type" || k === "children" || TEXT_ATTR_KEYS.indexOf(k) !== -1) continue;
|
|
2931
|
+
gProps[k] = node[k];
|
|
2932
|
+
}
|
|
2933
|
+
if (gProps.style && typeof gProps.style === "object") {
|
|
2934
|
+
const style = __spreadValues({}, gProps.style);
|
|
2935
|
+
delete style["white-space"];
|
|
2936
|
+
if (Object.keys(style).length) gProps.style = style;
|
|
2937
|
+
else delete gProps.style;
|
|
2938
|
+
}
|
|
2939
|
+
return create("g", gProps, children);
|
|
2940
|
+
}
|
|
2941
|
+
function materialiseGlyphText(node, opts) {
|
|
2942
|
+
if (opts.alongPath) return materialiseGlyphTextAlongPath(node, opts.alongPath.pathD, opts.alongPath.startOffset, opts, opts.alongPath.textLength, opts.alongPath.pathOverflow);
|
|
2943
|
+
return materialiseGlyphTextHorizontal(node, opts);
|
|
2944
|
+
}
|
|
2945
|
+
function applyTextGlyphsEffect(node, fx, ctx) {
|
|
2946
|
+
if (!(fx == null ? void 0 : fx.useGlyphs)) return node;
|
|
2947
|
+
if (!ctx.glyphs) {
|
|
2948
|
+
ctx.warnings.push("textGlyphs: no definitions.glyphs \u2014 left as native <text>");
|
|
2949
|
+
return node;
|
|
2950
|
+
}
|
|
2951
|
+
return materialiseGlyphTextHorizontal(node, { glyphs: ctx.glyphs, warnings: ctx.warnings });
|
|
2952
|
+
}
|
|
2953
|
+
function applyTextGlyphsAlongPath(node, ctx, pathD, startOffset, textLength, pathOverflow) {
|
|
2954
|
+
if (!ctx.glyphs) {
|
|
2955
|
+
ctx.warnings.push("textGlyphs: no definitions.glyphs");
|
|
2956
|
+
return null;
|
|
2957
|
+
}
|
|
2958
|
+
return materialiseGlyphTextAlongPath(node, pathD, startOffset, { glyphs: ctx.glyphs, warnings: ctx.warnings }, textLength, pathOverflow);
|
|
2959
|
+
}
|
|
2960
|
+
|
|
2350
2961
|
// src/PxMotionPath.ts
|
|
2351
2962
|
function getKfTranslate(kf) {
|
|
2352
2963
|
var _a;
|
|
@@ -2790,12 +3401,12 @@ function parseSvgPathToBezier(d) {
|
|
|
2790
3401
|
}
|
|
2791
3402
|
return res;
|
|
2792
3403
|
}
|
|
2793
|
-
function extractPathData(
|
|
2794
|
-
if (
|
|
2795
|
-
return
|
|
3404
|
+
function extractPathData(str2) {
|
|
3405
|
+
if (str2.startsWith("path(") && str2.endsWith(")")) {
|
|
3406
|
+
return str2.slice(5, -1);
|
|
2796
3407
|
}
|
|
2797
|
-
if (/^[MmZzLlHhVvCcSsQqTtAa]/.test(
|
|
2798
|
-
return
|
|
3408
|
+
if (/^[MmZzLlHhVvCcSsQqTtAa]/.test(str2)) {
|
|
3409
|
+
return str2;
|
|
2799
3410
|
}
|
|
2800
3411
|
return void 0;
|
|
2801
3412
|
}
|
|
@@ -3720,7 +4331,7 @@ function rectToPathD(node) {
|
|
|
3720
4331
|
|
|
3721
4332
|
// src/effects/PlayerEffectsUtil.ts
|
|
3722
4333
|
function applyPlayerEffects(root) {
|
|
3723
|
-
var _a;
|
|
4334
|
+
var _a, _b;
|
|
3724
4335
|
const ctx = {
|
|
3725
4336
|
defs: [],
|
|
3726
4337
|
warnings: [],
|
|
@@ -3731,7 +4342,8 @@ function applyPlayerEffects(root) {
|
|
|
3731
4342
|
maskAncestorChains: /* @__PURE__ */ new Map(),
|
|
3732
4343
|
// Resolved engine: `frames` ONLY when explicitly set; auto/webapi/unset →
|
|
3733
4344
|
// webapi (we're not 100% sure it's frames, and CSS/WAAPI need the inline form).
|
|
3734
|
-
engine: ((_a = getAnimatorConfig(root)) == null ? void 0 : _a.mode) === PxAnimatorMode.frames ? PxAnimatorEngine.frames : PxAnimatorEngine.webapi
|
|
4345
|
+
engine: ((_a = getAnimatorConfig(root)) == null ? void 0 : _a.mode) === PxAnimatorMode.frames ? PxAnimatorEngine.frames : PxAnimatorEngine.webapi,
|
|
4346
|
+
glyphs: (_b = getDefs(root)) == null ? void 0 : _b.glyphs
|
|
3735
4347
|
};
|
|
3736
4348
|
const working = clone(root);
|
|
3737
4349
|
indexById(working, ctx.idMap);
|
|
@@ -3743,16 +4355,33 @@ function applyPlayerEffects(root) {
|
|
|
3743
4355
|
return { root: out, defs: ctx.defs, warnings: ctx.warnings, errors: ctx.errors };
|
|
3744
4356
|
}
|
|
3745
4357
|
function applyPlayerEffects_exceptRetime(node, ctx) {
|
|
4358
|
+
var _a;
|
|
3746
4359
|
if (node.children) node.children = node.children.map((child) => applyPlayerEffects_exceptRetime(child, ctx));
|
|
3747
4360
|
const fx = node.effects;
|
|
3748
4361
|
const originalId = typeof node.id === "string" ? node.id : void 0;
|
|
3749
4362
|
const innerIdForContentRef = originalId ? ctx.contentRefInnerIds.get(originalId) : void 0;
|
|
3750
4363
|
if (!fx && !innerIdForContentRef) return node;
|
|
3751
|
-
const { transformation, repeater, maskedBy, trimPath, clone: cloneFx, fillGradient, strokeGradient,
|
|
4364
|
+
const { transformation, repeater, maskedBy, trimPath, clone: cloneFx, fillGradient, strokeGradient, textPath, text } = fx != null ? fx : {};
|
|
3752
4365
|
const isCombinedShape = fx == null ? void 0 : fx.isCombinedShape;
|
|
3753
4366
|
if (fx) delete node.effects;
|
|
3754
4367
|
let n = node;
|
|
3755
|
-
|
|
4368
|
+
let consumedByGlyphs = false;
|
|
4369
|
+
if (text == null ? void 0 : text.useGlyphs) {
|
|
4370
|
+
if (textPath) {
|
|
4371
|
+
const pathD = typeof textPath.path === "string" ? textPath.path : void 0;
|
|
4372
|
+
const rawTL = textPath.textLength;
|
|
4373
|
+
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;
|
|
4374
|
+
const glyphed = applyTextGlyphsAlongPath(n, ctx, pathD, textPath.startOffset, textLength, textPath.pathOverflow);
|
|
4375
|
+
if (glyphed) {
|
|
4376
|
+
n = glyphed;
|
|
4377
|
+
consumedByGlyphs = true;
|
|
4378
|
+
}
|
|
4379
|
+
} else {
|
|
4380
|
+
n = applyTextGlyphsEffect(n, text, ctx);
|
|
4381
|
+
consumedByGlyphs = true;
|
|
4382
|
+
}
|
|
4383
|
+
}
|
|
4384
|
+
if (!consumedByGlyphs) n = applyTextPathEffect(n, textPath, ctx);
|
|
3756
4385
|
n = applyFillGradientEffect(n, fillGradient, ctx);
|
|
3757
4386
|
n = applyStrokeGradientEffect(n, strokeGradient, ctx);
|
|
3758
4387
|
n = applyTrimPathEffect(n, trimPath, isCombinedShape, ctx);
|
|
@@ -3995,8 +4624,8 @@ var DATA_RASTER_IMAGE_RE = /^data:image\/(?:png|jpe?g|gif|webp|bmp);base64,/i;
|
|
|
3995
4624
|
var DATA_SVG_IMAGE_RE = /^data:image\/svg\+xml(?:;[^,]*)?,/i;
|
|
3996
4625
|
var DATA_IMAGE_BASE64_PAYLOAD_RE = /^data:image\/[^;,]*;base64,([A-Za-z0-9+/]{8})/i;
|
|
3997
4626
|
var BASE64_RASTER_MAGICS = ["iVBORw0K", "/9j/", "R0lGOD", "UklGR", "Qk"];
|
|
3998
|
-
function isContentSniffedRasterImage(
|
|
3999
|
-
const m = DATA_IMAGE_BASE64_PAYLOAD_RE.exec(
|
|
4627
|
+
function isContentSniffedRasterImage(str2) {
|
|
4628
|
+
const m = DATA_IMAGE_BASE64_PAYLOAD_RE.exec(str2);
|
|
4000
4629
|
return !!m && BASE64_RASTER_MAGICS.some((magic) => m[1].startsWith(magic));
|
|
4001
4630
|
}
|
|
4002
4631
|
function isDangerousAttrName(nameLower) {
|
|
@@ -4010,18 +4639,18 @@ function sanitiseAttributeValue(name, value) {
|
|
|
4010
4639
|
return void 0;
|
|
4011
4640
|
}
|
|
4012
4641
|
if (nameLower === "fill" || nameLower === "stroke" || nameLower === "stopcolor") {
|
|
4013
|
-
const
|
|
4014
|
-
if (
|
|
4642
|
+
const str2 = String(value);
|
|
4643
|
+
if (str2.includes("url(") && !/^url\(#[^)]+\)$/.test(str2)) {
|
|
4015
4644
|
console.warn('Attribute "' + nameLower + '" blocked: url() must be internal url(#id), got:', value);
|
|
4016
4645
|
return void 0;
|
|
4017
4646
|
}
|
|
4018
4647
|
return value;
|
|
4019
4648
|
}
|
|
4020
4649
|
if (URL_VALUE_ATTRS_LOWER.has(nameLower)) {
|
|
4021
|
-
const
|
|
4022
|
-
if (
|
|
4023
|
-
if (/^url\(#[^)]+\)$/.test(
|
|
4024
|
-
if (IMAGE_REF_ATTRS_LOWER.has(nameLower) && (DATA_RASTER_IMAGE_RE.test(
|
|
4650
|
+
const str2 = String(value);
|
|
4651
|
+
if (str2.startsWith("#")) return value;
|
|
4652
|
+
if (/^url\(#[^)]+\)$/.test(str2)) return value;
|
|
4653
|
+
if (IMAGE_REF_ATTRS_LOWER.has(nameLower) && (DATA_RASTER_IMAGE_RE.test(str2) || DATA_SVG_IMAGE_RE.test(str2) || isContentSniffedRasterImage(str2))) return value;
|
|
4025
4654
|
console.warn('Attribute "' + nameLower + '" blocked: must be #id, url(#id), or data:image/\u2026 URI, got:', value);
|
|
4026
4655
|
return void 0;
|
|
4027
4656
|
}
|
|
@@ -4051,7 +4680,7 @@ function createElement(tagName, normalisedProps, style, children, textContent) {
|
|
|
4051
4680
|
if (textContent) element.textContent = textContent;
|
|
4052
4681
|
return element;
|
|
4053
4682
|
}
|
|
4054
|
-
function
|
|
4683
|
+
function resolveStyle2(style, defs) {
|
|
4055
4684
|
var _a;
|
|
4056
4685
|
if (!style) return void 0;
|
|
4057
4686
|
if (typeof style === "string") {
|
|
@@ -4087,7 +4716,7 @@ function renderNode(node, defs) {
|
|
|
4087
4716
|
if (!node) return null;
|
|
4088
4717
|
const _a = node, { type, children, style } = _a, props = __objRest(_a, ["type", "children", "style"]);
|
|
4089
4718
|
const nodeDefs = getDefs(node) || defs;
|
|
4090
|
-
const resolvedStyle =
|
|
4719
|
+
const resolvedStyle = resolveStyle2(style, nodeDefs);
|
|
4091
4720
|
let childElements;
|
|
4092
4721
|
if (children) {
|
|
4093
4722
|
for (const ch of children) {
|
|
@@ -5139,7 +5768,8 @@ export {
|
|
|
5139
5768
|
PxRetimeEffectSchema,
|
|
5140
5769
|
PxStrokeGradientEffectSchema,
|
|
5141
5770
|
PxSvgNodeExtra,
|
|
5142
|
-
|
|
5771
|
+
PxTextEffectSchema,
|
|
5772
|
+
PxTextPathEffectSchema,
|
|
5143
5773
|
PxTransformPartsSchema,
|
|
5144
5774
|
PxTransformValueSchema,
|
|
5145
5775
|
PxTransformationEffectSchema,
|
|
@@ -5159,6 +5789,7 @@ export {
|
|
|
5159
5789
|
describeSchema,
|
|
5160
5790
|
diffInEffect,
|
|
5161
5791
|
evaluateMotionPathSegment,
|
|
5792
|
+
extendedPathForBrowser,
|
|
5162
5793
|
generateNewIds,
|
|
5163
5794
|
getAnimatorConfig,
|
|
5164
5795
|
getBindings,
|
|
@@ -5167,9 +5798,13 @@ export {
|
|
|
5167
5798
|
getNormalizedProps,
|
|
5168
5799
|
isPxElementFileFormat,
|
|
5169
5800
|
isPxElementFileFormatDeep,
|
|
5801
|
+
jsonElementFactory,
|
|
5170
5802
|
loadTagAnimators,
|
|
5171
5803
|
materialiseAllInTree,
|
|
5172
5804
|
materialiseAnimatedUseInstances,
|
|
5805
|
+
materialiseGlyphText,
|
|
5806
|
+
materialiseGlyphTextAlongPath,
|
|
5807
|
+
materialiseGlyphTextHorizontal,
|
|
5173
5808
|
materialiseInternalLoopsInPropAnim,
|
|
5174
5809
|
materialiseInternalLoopsInTree,
|
|
5175
5810
|
materialiseMotionPathInPropAnim,
|
|
@@ -5180,6 +5815,7 @@ export {
|
|
|
5180
5815
|
renderNode,
|
|
5181
5816
|
schemaKeys,
|
|
5182
5817
|
setupAnimationTriggers,
|
|
5818
|
+
shiftAnimatable,
|
|
5183
5819
|
toRGBA,
|
|
5184
5820
|
validateNodeEffects,
|
|
5185
5821
|
visualModelAt
|