@opendata-ai/openchart-vanilla 8.0.0-rc.24 → 8.0.0-rc.26
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-2YWRNRUK.js → chunk-ADWV256V.js} +1242 -1218
- package/dist/chunk-ADWV256V.js.map +1 -0
- package/dist/index.d.ts +40 -19
- package/dist/index.js +31 -96
- package/dist/index.js.map +1 -1
- package/dist/{mount-Dvv8NYIv.d.ts → mount-CL-nA0f-.d.ts} +8 -39
- package/dist/static.d.ts +2 -0
- package/dist/static.js +1 -0
- package/dist/static.js.map +1 -1
- package/dist/story/index.d.ts +24 -9
- package/dist/story/index.js +5 -5
- package/dist/story/index.js.map +1 -1
- package/dist/styles.css.map +1 -1
- package/package.json +3 -3
- package/dist/chunk-2YWRNRUK.js.map +0 -1
|
@@ -526,7 +526,12 @@ function materializeRasterMarkSVG(layout) {
|
|
|
526
526
|
const host = document.createElement("div");
|
|
527
527
|
const svg = renderChartSVG(layout, host, { animate: false });
|
|
528
528
|
const dataUrl = rasterizeMarks(layout);
|
|
529
|
-
if (!dataUrl)
|
|
529
|
+
if (!dataUrl) {
|
|
530
|
+
console.warn(
|
|
531
|
+
"[viz] Canvas raster export unavailable in this environment; exporting all points as vector SVG (larger file)."
|
|
532
|
+
);
|
|
533
|
+
return svg;
|
|
534
|
+
}
|
|
530
535
|
for (const circle of svg.querySelectorAll("circle.oc-mark-point")) {
|
|
531
536
|
circle.remove();
|
|
532
537
|
}
|
|
@@ -566,6 +571,20 @@ function materializeCanvasModeSVG(layout, opts) {
|
|
|
566
571
|
return materializeRasterMarkSVG(layout);
|
|
567
572
|
}
|
|
568
573
|
|
|
574
|
+
// src/motion/easing.ts
|
|
575
|
+
function linear(t) {
|
|
576
|
+
return t;
|
|
577
|
+
}
|
|
578
|
+
function cubicOut(t) {
|
|
579
|
+
const f = 1 - t;
|
|
580
|
+
return 1 - f * f * f;
|
|
581
|
+
}
|
|
582
|
+
function cubicInOut(t) {
|
|
583
|
+
return t < 0.5 ? 4 * t * t * t : 1 - (-2 * t + 2) ** 3 / 2;
|
|
584
|
+
}
|
|
585
|
+
var clamp01 = (t) => Math.min(1, Math.max(0, t));
|
|
586
|
+
var lerp = (a, b, t) => a + (b - a) * t;
|
|
587
|
+
|
|
569
588
|
// src/text-edit-overlay.ts
|
|
570
589
|
function getScale(svg) {
|
|
571
590
|
const viewBox = svg.viewBox?.baseVal;
|
|
@@ -818,14 +837,121 @@ function createTextEditOverlayAtPosition(config) {
|
|
|
818
837
|
return { destroy };
|
|
819
838
|
}
|
|
820
839
|
|
|
821
|
-
// src/transition.ts
|
|
840
|
+
// src/transition/keys.ts
|
|
841
|
+
function annotationKey(a) {
|
|
842
|
+
if (a.id) return `id:${a.id}`;
|
|
843
|
+
return `${a.type}:${a.label?.text ?? ""}`;
|
|
844
|
+
}
|
|
845
|
+
function keyAnnotations(annotations) {
|
|
846
|
+
const seen = /* @__PURE__ */ new Map();
|
|
847
|
+
return annotations.map((a) => {
|
|
848
|
+
const base = annotationKey(a);
|
|
849
|
+
const n = seen.get(base) ?? 0;
|
|
850
|
+
seen.set(base, n + 1);
|
|
851
|
+
return n === 0 ? base : `${base}#${n}`;
|
|
852
|
+
});
|
|
853
|
+
}
|
|
854
|
+
|
|
855
|
+
// src/transition/gate.ts
|
|
856
|
+
var TRANSITIONABLE_MARKS = /* @__PURE__ */ new Set(["bar", "line", "area", "point"]);
|
|
857
|
+
var DEFAULT_UPDATE_MAX_MARKS = 500;
|
|
858
|
+
var CANVAS_DEFAULT_UPDATE_MAX_MARKS = 2e4;
|
|
859
|
+
function canTransitionSpecShape(prevSpec, nextSpec) {
|
|
860
|
+
const prev = prevSpec;
|
|
861
|
+
const next = nextSpec;
|
|
862
|
+
if (!prev || !next || !("mark" in prev) || !("mark" in next)) return false;
|
|
863
|
+
const prevMark = typeof prev.mark === "string" ? prev.mark : prev.mark?.type;
|
|
864
|
+
const nextMark = typeof next.mark === "string" ? next.mark : next.mark?.type;
|
|
865
|
+
if (prevMark !== nextMark) return false;
|
|
866
|
+
if (!TRANSITIONABLE_MARKS.has(prevMark)) return false;
|
|
867
|
+
const prevEnc = prev.encoding;
|
|
868
|
+
const nextEnc = next.encoding;
|
|
869
|
+
if (!prevEnc || !nextEnc) return false;
|
|
870
|
+
return !(prevEnc.x?.field !== nextEnc.x?.field || prevEnc.x?.type !== nextEnc.x?.type || prevEnc.y?.field !== nextEnc.y?.field || prevEnc.y?.type !== nextEnc.y?.type || prevEnc.color?.field !== nextEnc.color?.field);
|
|
871
|
+
}
|
|
872
|
+
function canTransition(args) {
|
|
873
|
+
const { prevLayout, nextLayout, prevSpec, nextSpec, isFirstRender, entranceInFlight } = args;
|
|
874
|
+
if (!prevLayout || !prevSpec || isFirstRender) return false;
|
|
875
|
+
if (!nextLayout.animation?.update) return false;
|
|
876
|
+
if (!canTransitionSpecShape(prevSpec, nextSpec)) return false;
|
|
877
|
+
if (nextLayout.display === "sparkline") return false;
|
|
878
|
+
if (entranceInFlight) return false;
|
|
879
|
+
if (prevLayout.dimensions.width !== nextLayout.dimensions.width || prevLayout.dimensions.height !== nextLayout.dimensions.height) {
|
|
880
|
+
return false;
|
|
881
|
+
}
|
|
882
|
+
const cap = nextLayout.animation.update.maxMarks ?? (nextLayout.markRenderMode === "canvas" ? CANVAS_DEFAULT_UPDATE_MAX_MARKS : DEFAULT_UPDATE_MAX_MARKS);
|
|
883
|
+
if (Math.max(prevLayout.marks.length, nextLayout.marks.length) > cap) return false;
|
|
884
|
+
if (!hasVisibleChange(prevLayout, nextLayout)) return false;
|
|
885
|
+
if (typeof window !== "undefined" && typeof window.matchMedia === "function") {
|
|
886
|
+
try {
|
|
887
|
+
if (window.matchMedia("(prefers-reduced-motion: reduce)").matches) return false;
|
|
888
|
+
} catch {
|
|
889
|
+
}
|
|
890
|
+
}
|
|
891
|
+
return true;
|
|
892
|
+
}
|
|
893
|
+
function hasVisibleChange(prevLayout, nextLayout) {
|
|
894
|
+
return hasGeometryChanged(prevLayout, nextLayout) || hasColorChanged(prevLayout, nextLayout) || hasAnnotationChanged(prevLayout, nextLayout);
|
|
895
|
+
}
|
|
896
|
+
function hasColorChanged(prevLayout, nextLayout) {
|
|
897
|
+
const prevMarks = prevLayout.marks;
|
|
898
|
+
const nextMarks = nextLayout.marks;
|
|
899
|
+
if (prevMarks.length !== nextMarks.length) return true;
|
|
900
|
+
for (let i = 0; i < prevMarks.length; i++) {
|
|
901
|
+
const p = prevMarks[i];
|
|
902
|
+
const n = nextMarks[i];
|
|
903
|
+
if (p.fill !== n.fill || p.stroke !== n.stroke) return true;
|
|
904
|
+
}
|
|
905
|
+
return false;
|
|
906
|
+
}
|
|
907
|
+
function hasAnnotationChanged(prevLayout, nextLayout) {
|
|
908
|
+
const prev = prevLayout.annotations ?? [];
|
|
909
|
+
const next = nextLayout.annotations ?? [];
|
|
910
|
+
if (prev.length !== next.length) return true;
|
|
911
|
+
const prevKeys = keyAnnotations(prev);
|
|
912
|
+
const nextKeys = keyAnnotations(next);
|
|
913
|
+
for (let i = 0; i < prev.length; i++) {
|
|
914
|
+
if (prevKeys[i] !== nextKeys[i]) return true;
|
|
915
|
+
const p = prev[i];
|
|
916
|
+
const n = next[i];
|
|
917
|
+
if (p.label?.x !== n.label?.x || p.label?.y !== n.label?.y) return true;
|
|
918
|
+
if (p.opacity !== n.opacity) return true;
|
|
919
|
+
}
|
|
920
|
+
return false;
|
|
921
|
+
}
|
|
922
|
+
function hasGeometryChanged(prevLayout, nextLayout) {
|
|
923
|
+
const prevMarks = prevLayout.marks;
|
|
924
|
+
const nextMarks = nextLayout.marks;
|
|
925
|
+
if (prevMarks.length !== nextMarks.length) return true;
|
|
926
|
+
for (let i = 0; i < prevMarks.length; i++) {
|
|
927
|
+
const p = prevMarks[i];
|
|
928
|
+
const n = nextMarks[i];
|
|
929
|
+
if (p.type !== n.type || p.key !== n.key) return true;
|
|
930
|
+
if (p.type === "rect" && n.type === "rect") {
|
|
931
|
+
if (p.x !== n.x || p.y !== n.y || p.width !== n.width || p.height !== n.height) return true;
|
|
932
|
+
} else if (p.type === "line" && n.type === "line") {
|
|
933
|
+
if (p.path !== n.path || p.points.length !== n.points.length) return true;
|
|
934
|
+
for (let j = 0; j < p.points.length; j++) {
|
|
935
|
+
if (p.points[j].x !== n.points[j].x || p.points[j].y !== n.points[j].y) return true;
|
|
936
|
+
}
|
|
937
|
+
} else if (p.type === "area" && n.type === "area") {
|
|
938
|
+
if (p.path !== n.path) return true;
|
|
939
|
+
} else if (p.type === "point" && n.type === "point") {
|
|
940
|
+
if (p.cx !== n.cx || p.cy !== n.cy || p.r !== n.r) return true;
|
|
941
|
+
} else if (p.type === "rule" && n.type === "rule") {
|
|
942
|
+
if (p.x1 !== n.x1 || p.y1 !== n.y1 || p.x2 !== n.x2 || p.y2 !== n.y2) return true;
|
|
943
|
+
} else if (p.type === "tick" && n.type === "tick") {
|
|
944
|
+
if (p.x !== n.x || p.y !== n.y) return true;
|
|
945
|
+
} else if (p.type === "textMark" && n.type === "textMark") {
|
|
946
|
+
if (p.x !== n.x || p.y !== n.y) return true;
|
|
947
|
+
}
|
|
948
|
+
}
|
|
949
|
+
return false;
|
|
950
|
+
}
|
|
951
|
+
|
|
952
|
+
// src/transition/driver.ts
|
|
822
953
|
import { isGradientDef } from "@opendata-ai/openchart-core";
|
|
823
|
-
import {
|
|
824
|
-
buildAreaPath,
|
|
825
|
-
buildLinePath,
|
|
826
|
-
EXIT_DEFAULTS,
|
|
827
|
-
serializeKeyValue
|
|
828
|
-
} from "@opendata-ai/openchart-engine";
|
|
954
|
+
import { buildAreaPath as buildAreaPath2, buildLinePath as buildLinePath2, EXIT_DEFAULTS } from "@opendata-ai/openchart-engine";
|
|
829
955
|
|
|
830
956
|
// ../../node_modules/.bun/d3-color@3.1.0/node_modules/d3-color/src/define.js
|
|
831
957
|
function define_default(constructor, factory, prototype) {
|
|
@@ -1201,7 +1327,7 @@ function basisClosed_default(values) {
|
|
|
1201
1327
|
var constant_default = (x) => () => x;
|
|
1202
1328
|
|
|
1203
1329
|
// ../../node_modules/.bun/d3-interpolate@3.0.1/node_modules/d3-interpolate/src/color.js
|
|
1204
|
-
function
|
|
1330
|
+
function linear2(a, d) {
|
|
1205
1331
|
return function(t) {
|
|
1206
1332
|
return a + t * d;
|
|
1207
1333
|
};
|
|
@@ -1218,7 +1344,7 @@ function gamma(y) {
|
|
|
1218
1344
|
}
|
|
1219
1345
|
function nogamma(a, b) {
|
|
1220
1346
|
var d = b - a;
|
|
1221
|
-
return d ?
|
|
1347
|
+
return d ? linear2(a, d) : constant_default(isNaN(a) ? b : a);
|
|
1222
1348
|
}
|
|
1223
1349
|
|
|
1224
1350
|
// ../../node_modules/.bun/d3-interpolate@3.0.1/node_modules/d3-interpolate/src/rgb.js
|
|
@@ -1306,694 +1432,723 @@ var zoom_default = (function zoomRho(rho, rho2, rho4) {
|
|
|
1306
1432
|
return zoom;
|
|
1307
1433
|
})(Math.SQRT2, 2, 4);
|
|
1308
1434
|
|
|
1309
|
-
// src/transition.ts
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
}
|
|
1314
|
-
function
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
const
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
});
|
|
1322
|
-
}
|
|
1323
|
-
function cubicOut(t) {
|
|
1324
|
-
const f = 1 - t;
|
|
1325
|
-
return 1 - f * f * f;
|
|
1435
|
+
// src/transition/canvas-tweens.ts
|
|
1436
|
+
import { serializeKeyValue as serializeKeyValue2 } from "@opendata-ai/openchart-engine";
|
|
1437
|
+
|
|
1438
|
+
// src/transition/chrome-tweens.ts
|
|
1439
|
+
import { serializeKeyValue } from "@opendata-ai/openchart-engine";
|
|
1440
|
+
function markShapeElement(el, attr) {
|
|
1441
|
+
if (el.tagName === "circle" || el.tagName === "rect" || el.tagName === "path") return el;
|
|
1442
|
+
if (attr === "stroke") {
|
|
1443
|
+
const areaTop = el.querySelector(".oc-area-top");
|
|
1444
|
+
if (areaTop) return areaTop;
|
|
1445
|
+
}
|
|
1446
|
+
return el.querySelector("rect, path, circle, line") ?? el;
|
|
1326
1447
|
}
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
var CANVAS_DEFAULT_UPDATE_MAX_MARKS = 2e4;
|
|
1330
|
-
function canTransitionSpecShape(prevSpec, nextSpec) {
|
|
1331
|
-
const prev = prevSpec;
|
|
1332
|
-
const next = nextSpec;
|
|
1333
|
-
if (!prev || !next || !("mark" in prev) || !("mark" in next)) return false;
|
|
1334
|
-
const prevMark = typeof prev.mark === "string" ? prev.mark : prev.mark?.type;
|
|
1335
|
-
const nextMark = typeof next.mark === "string" ? next.mark : next.mark?.type;
|
|
1336
|
-
if (prevMark !== nextMark) return false;
|
|
1337
|
-
if (!TRANSITIONABLE_MARKS.has(prevMark)) return false;
|
|
1338
|
-
const prevEnc = prev.encoding;
|
|
1339
|
-
const nextEnc = next.encoding;
|
|
1340
|
-
if (!prevEnc || !nextEnc) return false;
|
|
1341
|
-
return !(prevEnc.x?.field !== nextEnc.x?.field || prevEnc.x?.type !== nextEnc.x?.type || prevEnc.y?.field !== nextEnc.y?.field || prevEnc.y?.type !== nextEnc.y?.type || prevEnc.color?.field !== nextEnc.color?.field);
|
|
1448
|
+
function isInterpolableColor(v) {
|
|
1449
|
+
return typeof v === "string" && v !== "" && v !== "none" && !v.startsWith("url(");
|
|
1342
1450
|
}
|
|
1343
|
-
function
|
|
1344
|
-
const
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
if (!canTransitionSpecShape(prevSpec, nextSpec)) return false;
|
|
1348
|
-
if (nextLayout.display === "sparkline") return false;
|
|
1349
|
-
if (entranceInFlight) return false;
|
|
1350
|
-
if (prevLayout.dimensions.width !== nextLayout.dimensions.width || prevLayout.dimensions.height !== nextLayout.dimensions.height) {
|
|
1351
|
-
return false;
|
|
1451
|
+
function buildColorTweens(prevLayout, nextLayout, dom, tweens) {
|
|
1452
|
+
const prevByKey = /* @__PURE__ */ new Map();
|
|
1453
|
+
for (const m of prevLayout.marks) {
|
|
1454
|
+
if (m.key) prevByKey.set(m.key, m);
|
|
1352
1455
|
}
|
|
1353
|
-
const
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1456
|
+
for (const next of nextLayout.marks) {
|
|
1457
|
+
if (!next.key) continue;
|
|
1458
|
+
const prev = prevByKey.get(next.key);
|
|
1459
|
+
if (!prev) continue;
|
|
1460
|
+
const group = dom.any(next.key);
|
|
1461
|
+
if (!group) continue;
|
|
1462
|
+
for (const attr of ["fill", "stroke"]) {
|
|
1463
|
+
const from = prev[attr];
|
|
1464
|
+
const to = next[attr];
|
|
1465
|
+
if (from === to) continue;
|
|
1466
|
+
if (!isInterpolableColor(from) || !isInterpolableColor(to)) continue;
|
|
1467
|
+
tweens.push({
|
|
1468
|
+
tweenType: "color",
|
|
1469
|
+
kind: "update",
|
|
1470
|
+
el: markShapeElement(group, attr),
|
|
1471
|
+
attr,
|
|
1472
|
+
from,
|
|
1473
|
+
to
|
|
1474
|
+
});
|
|
1360
1475
|
}
|
|
1361
1476
|
}
|
|
1362
|
-
return true;
|
|
1363
|
-
}
|
|
1364
|
-
function hasVisibleChange(prevLayout, nextLayout) {
|
|
1365
|
-
return hasGeometryChanged(prevLayout, nextLayout) || hasColorChanged(prevLayout, nextLayout) || hasAnnotationChanged(prevLayout, nextLayout);
|
|
1366
|
-
}
|
|
1367
|
-
function hasColorChanged(prevLayout, nextLayout) {
|
|
1368
|
-
const prevMarks = prevLayout.marks;
|
|
1369
|
-
const nextMarks = nextLayout.marks;
|
|
1370
|
-
if (prevMarks.length !== nextMarks.length) return true;
|
|
1371
|
-
for (let i = 0; i < prevMarks.length; i++) {
|
|
1372
|
-
const p = prevMarks[i];
|
|
1373
|
-
const n = nextMarks[i];
|
|
1374
|
-
if (p.fill !== n.fill || p.stroke !== n.stroke) return true;
|
|
1375
|
-
}
|
|
1376
|
-
return false;
|
|
1377
1477
|
}
|
|
1378
|
-
function
|
|
1478
|
+
function buildAnnotationTweens(svg, prevLayout, nextLayout, tweens) {
|
|
1379
1479
|
const prev = prevLayout.annotations ?? [];
|
|
1380
1480
|
const next = nextLayout.annotations ?? [];
|
|
1381
|
-
if (prev.length
|
|
1382
|
-
const
|
|
1481
|
+
if (prev.length === 0 && next.length === 0) return;
|
|
1482
|
+
const container = svg.querySelector(".oc-annotations");
|
|
1483
|
+
if (!container) return;
|
|
1484
|
+
const prevByKey = new Map(keyAnnotations(prev).map((k, i) => [k, prev[i]]));
|
|
1383
1485
|
const nextKeys = keyAnnotations(next);
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
const
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
if (
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
if (p.type !== n.type || p.key !== n.key) return true;
|
|
1401
|
-
if (p.type === "rect" && n.type === "rect") {
|
|
1402
|
-
if (p.x !== n.x || p.y !== n.y || p.width !== n.width || p.height !== n.height) return true;
|
|
1403
|
-
} else if (p.type === "line" && n.type === "line") {
|
|
1404
|
-
if (p.path !== n.path || p.points.length !== n.points.length) return true;
|
|
1405
|
-
for (let j = 0; j < p.points.length; j++) {
|
|
1406
|
-
if (p.points[j].x !== n.points[j].x || p.points[j].y !== n.points[j].y) return true;
|
|
1407
|
-
}
|
|
1408
|
-
} else if (p.type === "area" && n.type === "area") {
|
|
1409
|
-
if (p.path !== n.path) return true;
|
|
1410
|
-
} else if (p.type === "point" && n.type === "point") {
|
|
1411
|
-
if (p.cx !== n.cx || p.cy !== n.cy || p.r !== n.r) return true;
|
|
1412
|
-
} else if (p.type === "rule" && n.type === "rule") {
|
|
1413
|
-
if (p.x1 !== n.x1 || p.y1 !== n.y1 || p.x2 !== n.x2 || p.y2 !== n.y2) return true;
|
|
1414
|
-
} else if (p.type === "tick" && n.type === "tick") {
|
|
1415
|
-
if (p.x !== n.x || p.y !== n.y) return true;
|
|
1416
|
-
} else if (p.type === "textMark" && n.type === "textMark") {
|
|
1417
|
-
if (p.x !== n.x || p.y !== n.y) return true;
|
|
1486
|
+
const els = container.querySelectorAll(".oc-annotation");
|
|
1487
|
+
for (let i = 0; i < next.length; i++) {
|
|
1488
|
+
const el = els[i];
|
|
1489
|
+
if (!el) continue;
|
|
1490
|
+
const before = prevByKey.get(nextKeys[i]);
|
|
1491
|
+
if (!before) {
|
|
1492
|
+
tweens.push({
|
|
1493
|
+
tweenType: "annotation",
|
|
1494
|
+
kind: "enter",
|
|
1495
|
+
el,
|
|
1496
|
+
fromDx: 0,
|
|
1497
|
+
fromDy: 0,
|
|
1498
|
+
fromOpacity: 0,
|
|
1499
|
+
toOpacity: 1
|
|
1500
|
+
});
|
|
1501
|
+
continue;
|
|
1418
1502
|
}
|
|
1503
|
+
const dx = (before.label?.x ?? 0) - (next[i].label?.x ?? 0);
|
|
1504
|
+
const dy = (before.label?.y ?? 0) - (next[i].label?.y ?? 0);
|
|
1505
|
+
if (dx === 0 && dy === 0) continue;
|
|
1506
|
+
tweens.push({
|
|
1507
|
+
tweenType: "annotation",
|
|
1508
|
+
kind: "update",
|
|
1509
|
+
el,
|
|
1510
|
+
fromDx: dx,
|
|
1511
|
+
fromDy: dy
|
|
1512
|
+
});
|
|
1419
1513
|
}
|
|
1420
|
-
return false;
|
|
1421
|
-
}
|
|
1422
|
-
function geomFromMark(m) {
|
|
1423
|
-
return { x: m.x, y: m.y, width: m.width, height: m.height };
|
|
1424
1514
|
}
|
|
1425
|
-
function
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
const sides = mark.cornerRadiusSides;
|
|
1429
|
-
const partialCorners = !!sides && (!sides.tl || !sides.tr || !sides.br || !sides.bl) && !!mark.cornerRadius;
|
|
1430
|
-
if (partialCorners && shapeEl.tagName === "path") {
|
|
1431
|
-
const tempMark = { ...mark, ...geom };
|
|
1432
|
-
shapeEl.setAttribute("d", rectPathWithCorners(tempMark, sides));
|
|
1433
|
-
} else {
|
|
1434
|
-
shapeEl.setAttribute("x", String(geom.x));
|
|
1435
|
-
shapeEl.setAttribute("y", String(geom.y));
|
|
1436
|
-
shapeEl.setAttribute("width", String(geom.width));
|
|
1437
|
-
shapeEl.setAttribute("height", String(geom.height));
|
|
1438
|
-
}
|
|
1515
|
+
function buildAxisTweens(svg, prevLayout, nextLayout, tweens, ghosts) {
|
|
1516
|
+
buildSingleAxisTweens(svg, prevLayout.axes.x, nextLayout.axes.x, "x", nextLayout, tweens, ghosts);
|
|
1517
|
+
buildSingleAxisTweens(svg, prevLayout.axes.y, nextLayout.axes.y, "y", nextLayout, tweens, ghosts);
|
|
1439
1518
|
}
|
|
1440
|
-
function
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1519
|
+
function computeGridlineDeltas(prevAxis, nextAxis) {
|
|
1520
|
+
const byValue = (axis) => {
|
|
1521
|
+
const map = /* @__PURE__ */ new Map();
|
|
1522
|
+
for (const tick of axis.ticks) {
|
|
1523
|
+
const matching = axis.gridlines.find((g) => g.position === tick.position);
|
|
1524
|
+
if (matching) map.set(serializeKeyValue(tick.value), matching.position);
|
|
1525
|
+
}
|
|
1526
|
+
return map;
|
|
1446
1527
|
};
|
|
1528
|
+
return { prevGridByValue: byValue(prevAxis), nextGridByValue: byValue(nextAxis) };
|
|
1447
1529
|
}
|
|
1448
|
-
function
|
|
1449
|
-
|
|
1450
|
-
}
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
const
|
|
1454
|
-
|
|
1455
|
-
|
|
1530
|
+
function buildSingleAxisTweens(svg, prevAxis, nextAxis, orientation, layout, tweens, ghosts) {
|
|
1531
|
+
if (!prevAxis || !nextAxis) return;
|
|
1532
|
+
const axisClass = `oc-axis-${orientation}`;
|
|
1533
|
+
const axisGroup = svg.querySelector(`.${axisClass}`);
|
|
1534
|
+
if (!axisGroup) return;
|
|
1535
|
+
const isRotated = !!(nextAxis.tickAngle && Math.abs(nextAxis.tickAngle) > 10);
|
|
1536
|
+
const prevTickMap = /* @__PURE__ */ new Map();
|
|
1537
|
+
for (const tick of prevAxis.ticks) {
|
|
1538
|
+
prevTickMap.set(serializeKeyValue(tick.value), tick.position);
|
|
1456
1539
|
}
|
|
1457
|
-
const
|
|
1458
|
-
for (
|
|
1459
|
-
|
|
1540
|
+
const nextTickMap = /* @__PURE__ */ new Map();
|
|
1541
|
+
for (const tick of nextAxis.ticks) {
|
|
1542
|
+
nextTickMap.set(serializeKeyValue(tick.value), tick.position);
|
|
1460
1543
|
}
|
|
1461
|
-
const
|
|
1462
|
-
|
|
1463
|
-
|
|
1544
|
+
const posAttr = orientation === "x" ? "x" : "y";
|
|
1545
|
+
const tickLabels = axisGroup.querySelectorAll(".oc-axis-tick[data-tick-key]");
|
|
1546
|
+
const matchedNextKeys = /* @__PURE__ */ new Set();
|
|
1547
|
+
for (const labelEl of tickLabels) {
|
|
1548
|
+
const key = labelEl.getAttribute("data-tick-key");
|
|
1549
|
+
if (!key) continue;
|
|
1550
|
+
const nextPos = nextTickMap.get(key);
|
|
1551
|
+
const prevPos = prevTickMap.get(key);
|
|
1552
|
+
if (prevPos !== void 0 && nextPos !== void 0) {
|
|
1553
|
+
matchedNextKeys.add(key);
|
|
1554
|
+
tweens.push({
|
|
1555
|
+
tweenType: "axisTick",
|
|
1556
|
+
kind: "update",
|
|
1557
|
+
el: labelEl,
|
|
1558
|
+
posAttr,
|
|
1559
|
+
fromPos: prevPos,
|
|
1560
|
+
toPos: nextPos,
|
|
1561
|
+
crossfade: isRotated
|
|
1562
|
+
});
|
|
1563
|
+
} else if (prevPos === void 0 && nextPos !== void 0) {
|
|
1564
|
+
matchedNextKeys.add(key);
|
|
1565
|
+
tweens.push({
|
|
1566
|
+
tweenType: "axisTick",
|
|
1567
|
+
kind: "enter",
|
|
1568
|
+
el: labelEl,
|
|
1569
|
+
posAttr,
|
|
1570
|
+
fromPos: nextPos,
|
|
1571
|
+
toPos: nextPos,
|
|
1572
|
+
crossfade: false,
|
|
1573
|
+
fromOpacity: 0,
|
|
1574
|
+
toOpacity: 1
|
|
1575
|
+
});
|
|
1576
|
+
}
|
|
1464
1577
|
}
|
|
1465
|
-
const
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1578
|
+
for (const [key, prevPos] of prevTickMap) {
|
|
1579
|
+
if (nextTickMap.has(key)) continue;
|
|
1580
|
+
const prevTick = prevAxis.ticks.find((t) => serializeKeyValue(t.value) === key);
|
|
1581
|
+
if (!prevTick) continue;
|
|
1582
|
+
const ghost = document.createElementNS("http://www.w3.org/2000/svg", "text");
|
|
1583
|
+
ghost.setAttribute("class", "oc-axis-tick oc-ghost");
|
|
1584
|
+
ghost.setAttribute("aria-hidden", "true");
|
|
1585
|
+
ghost.setAttribute("pointer-events", "none");
|
|
1586
|
+
ghost.textContent = prevTick.label;
|
|
1587
|
+
const area = layout.area;
|
|
1588
|
+
if (orientation === "x") {
|
|
1589
|
+
ghost.setAttribute("x", String(prevPos));
|
|
1590
|
+
const xLabelPad = nextAxis.labelPadding ?? layout.theme.spacing.xAxisLabelPadding;
|
|
1591
|
+
const fontSize = nextAxis.tickLabelStyle.fontSize;
|
|
1592
|
+
ghost.setAttribute("y", String(area.y + area.height + xLabelPad + fontSize * 0.8));
|
|
1593
|
+
ghost.setAttribute("text-anchor", "middle");
|
|
1594
|
+
} else {
|
|
1595
|
+
const TICK_LABEL_OFFSET = 8;
|
|
1596
|
+
ghost.setAttribute("x", String(area.x - TICK_LABEL_OFFSET));
|
|
1597
|
+
ghost.setAttribute("y", String(prevPos));
|
|
1598
|
+
ghost.setAttribute("text-anchor", "end");
|
|
1599
|
+
ghost.setAttribute("dominant-baseline", "central");
|
|
1600
|
+
}
|
|
1601
|
+
axisGroup.appendChild(ghost);
|
|
1602
|
+
ghosts.push(ghost);
|
|
1603
|
+
tweens.push({
|
|
1604
|
+
tweenType: "axisTick",
|
|
1605
|
+
kind: "exit",
|
|
1606
|
+
el: ghost,
|
|
1607
|
+
posAttr,
|
|
1608
|
+
fromPos: prevPos,
|
|
1609
|
+
toPos: prevPos,
|
|
1610
|
+
crossfade: false,
|
|
1611
|
+
ghost,
|
|
1612
|
+
fromOpacity: 1,
|
|
1613
|
+
toOpacity: 0
|
|
1614
|
+
});
|
|
1469
1615
|
}
|
|
1470
|
-
const
|
|
1471
|
-
const
|
|
1472
|
-
for (const
|
|
1473
|
-
const
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1616
|
+
const { prevGridByValue, nextGridByValue } = computeGridlineDeltas(prevAxis, nextAxis);
|
|
1617
|
+
const gridlines = axisGroup.querySelectorAll(".oc-gridline[data-tick-key]");
|
|
1618
|
+
for (const glEl of gridlines) {
|
|
1619
|
+
const key = glEl.getAttribute("data-tick-key");
|
|
1620
|
+
if (!key) continue;
|
|
1621
|
+
const nextPos = nextGridByValue.get(key);
|
|
1622
|
+
const prevPos = prevGridByValue.get(key);
|
|
1623
|
+
if (prevPos !== void 0 && nextPos !== void 0) {
|
|
1624
|
+
tweens.push({
|
|
1625
|
+
tweenType: "gridline",
|
|
1626
|
+
kind: "update",
|
|
1627
|
+
el: glEl,
|
|
1628
|
+
orientation,
|
|
1629
|
+
fromPos: prevPos,
|
|
1630
|
+
toPos: nextPos
|
|
1631
|
+
});
|
|
1632
|
+
} else if (prevPos === void 0 && nextPos !== void 0) {
|
|
1633
|
+
tweens.push({
|
|
1634
|
+
tweenType: "gridline",
|
|
1635
|
+
kind: "enter",
|
|
1636
|
+
el: glEl,
|
|
1637
|
+
orientation,
|
|
1638
|
+
fromPos: nextPos,
|
|
1639
|
+
toPos: nextPos,
|
|
1640
|
+
fromOpacity: 0,
|
|
1641
|
+
toOpacity: 1
|
|
1642
|
+
});
|
|
1486
1643
|
}
|
|
1487
1644
|
}
|
|
1488
|
-
|
|
1645
|
+
for (const [key, prevPos] of prevGridByValue) {
|
|
1646
|
+
if (nextGridByValue.has(key)) continue;
|
|
1647
|
+
const ghost = document.createElementNS("http://www.w3.org/2000/svg", "line");
|
|
1648
|
+
ghost.setAttribute("class", "oc-gridline oc-ghost");
|
|
1649
|
+
ghost.setAttribute("aria-hidden", "true");
|
|
1650
|
+
ghost.setAttribute("pointer-events", "none");
|
|
1651
|
+
if (orientation === "y") {
|
|
1652
|
+
const area = layout.area;
|
|
1653
|
+
ghost.setAttribute("x1", String(area.x));
|
|
1654
|
+
ghost.setAttribute("y1", String(prevPos));
|
|
1655
|
+
ghost.setAttribute("x2", String(area.x + area.width));
|
|
1656
|
+
ghost.setAttribute("y2", String(prevPos));
|
|
1657
|
+
} else {
|
|
1658
|
+
const area = layout.area;
|
|
1659
|
+
ghost.setAttribute("x1", String(prevPos));
|
|
1660
|
+
ghost.setAttribute("y1", String(area.y));
|
|
1661
|
+
ghost.setAttribute("x2", String(prevPos));
|
|
1662
|
+
ghost.setAttribute("y2", String(area.y + area.height));
|
|
1663
|
+
}
|
|
1664
|
+
axisGroup.appendChild(ghost);
|
|
1665
|
+
ghosts.push(ghost);
|
|
1666
|
+
tweens.push({
|
|
1667
|
+
tweenType: "gridline",
|
|
1668
|
+
kind: "exit",
|
|
1669
|
+
el: ghost,
|
|
1670
|
+
orientation,
|
|
1671
|
+
fromPos: prevPos,
|
|
1672
|
+
toPos: prevPos,
|
|
1673
|
+
ghost,
|
|
1674
|
+
fromOpacity: 1,
|
|
1675
|
+
toOpacity: 0
|
|
1676
|
+
});
|
|
1677
|
+
}
|
|
1489
1678
|
}
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1679
|
+
|
|
1680
|
+
// src/transition/canvas-tweens.ts
|
|
1681
|
+
function buildCanvasPointsTween(prevLayout, nextLayout, layer, tweens, fromSnapshot) {
|
|
1682
|
+
const prevPoints = prevLayout.marks.filter((m) => m.type === "point");
|
|
1683
|
+
const nextPoints = nextLayout.marks.filter((m) => m.type === "point");
|
|
1684
|
+
const prevByKey = /* @__PURE__ */ new Map();
|
|
1685
|
+
for (const m of prevPoints) {
|
|
1686
|
+
if (m.key) prevByKey.set(m.key, m);
|
|
1494
1687
|
}
|
|
1495
|
-
const
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
let ni = 0;
|
|
1503
|
-
while (pi < prevKeys.length && ni < nextKeys.length) {
|
|
1504
|
-
const pk = prevKeys[pi];
|
|
1505
|
-
const nk = nextKeys[ni];
|
|
1506
|
-
if (added.has(pk)) {
|
|
1507
|
-
pi++;
|
|
1508
|
-
continue;
|
|
1509
|
-
}
|
|
1510
|
-
if (added.has(nk)) {
|
|
1511
|
-
ni++;
|
|
1512
|
-
continue;
|
|
1513
|
-
}
|
|
1514
|
-
if (pk === nk) {
|
|
1515
|
-
result.push(pk);
|
|
1516
|
-
added.add(pk);
|
|
1517
|
-
pi++;
|
|
1518
|
-
ni++;
|
|
1519
|
-
} else {
|
|
1520
|
-
const pkInNext = nextIndex.has(pk) && nextIndex.get(pk) >= ni ? nextIndex.get(pk) : -1;
|
|
1521
|
-
const nkInPrev = prevIndex.has(nk) && prevIndex.get(nk) >= pi ? prevIndex.get(nk) : -1;
|
|
1522
|
-
if (pkInNext === -1 && nkInPrev === -1) {
|
|
1523
|
-
result.push(pk);
|
|
1524
|
-
added.add(pk);
|
|
1525
|
-
pi++;
|
|
1526
|
-
} else if (pkInNext === -1) {
|
|
1527
|
-
result.push(pk);
|
|
1528
|
-
added.add(pk);
|
|
1529
|
-
pi++;
|
|
1530
|
-
} else if (nkInPrev === -1) {
|
|
1531
|
-
result.push(nk);
|
|
1532
|
-
added.add(nk);
|
|
1533
|
-
ni++;
|
|
1534
|
-
} else {
|
|
1535
|
-
if (pkInNext <= nkInPrev) {
|
|
1536
|
-
result.push(pk);
|
|
1537
|
-
added.add(pk);
|
|
1538
|
-
pi++;
|
|
1539
|
-
} else {
|
|
1540
|
-
result.push(nk);
|
|
1541
|
-
added.add(nk);
|
|
1542
|
-
ni++;
|
|
1543
|
-
}
|
|
1544
|
-
}
|
|
1545
|
-
}
|
|
1546
|
-
}
|
|
1547
|
-
while (pi < prevKeys.length) {
|
|
1548
|
-
if (!added.has(prevKeys[pi])) {
|
|
1549
|
-
result.push(prevKeys[pi]);
|
|
1550
|
-
added.add(prevKeys[pi]);
|
|
1551
|
-
}
|
|
1552
|
-
pi++;
|
|
1688
|
+
const soa = layer.state.marks;
|
|
1689
|
+
const survivors = [];
|
|
1690
|
+
const enters = [];
|
|
1691
|
+
for (let i = 0; i < soa.n; i++) {
|
|
1692
|
+
const key = soa.keys[i];
|
|
1693
|
+
if (key !== void 0 && prevByKey.has(key)) survivors.push(i);
|
|
1694
|
+
else enters.push(i);
|
|
1553
1695
|
}
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
}
|
|
1559
|
-
ni++;
|
|
1696
|
+
const exits = [];
|
|
1697
|
+
const nextKeys = /* @__PURE__ */ new Set();
|
|
1698
|
+
for (const m of nextPoints) {
|
|
1699
|
+
if (m.key) nextKeys.add(m.key);
|
|
1560
1700
|
}
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
function findInsertionPosition(key, merged, mergedIndex, prevByKey, nextByKey, nextPt) {
|
|
1564
|
-
const idx = mergedIndex.get(key) ?? -1;
|
|
1565
|
-
let beforeKey = null;
|
|
1566
|
-
for (let i = idx - 1; i >= 0; i--) {
|
|
1567
|
-
if (prevByKey.has(merged[i]) && nextByKey.has(merged[i])) {
|
|
1568
|
-
beforeKey = merged[i];
|
|
1569
|
-
break;
|
|
1570
|
-
}
|
|
1701
|
+
for (const [key, prev] of prevByKey) {
|
|
1702
|
+
if (!nextKeys.has(key)) exits.push(prev);
|
|
1571
1703
|
}
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1704
|
+
const sn = survivors.length;
|
|
1705
|
+
const soaIndex = new Uint32Array(sn);
|
|
1706
|
+
const fromCx = new Float32Array(sn);
|
|
1707
|
+
const fromCy = new Float32Array(sn);
|
|
1708
|
+
const fromR = new Float32Array(sn);
|
|
1709
|
+
const toCx = new Float32Array(sn);
|
|
1710
|
+
const toCy = new Float32Array(sn);
|
|
1711
|
+
const toR = new Float32Array(sn);
|
|
1712
|
+
const soaKeys = new Array(sn);
|
|
1713
|
+
for (let s = 0; s < sn; s++) {
|
|
1714
|
+
const i = survivors[s];
|
|
1715
|
+
const key = soa.keys[i];
|
|
1716
|
+
const prev = prevByKey.get(key);
|
|
1717
|
+
let px = prev.cx;
|
|
1718
|
+
let py = prev.cy;
|
|
1719
|
+
let pr = prev.r;
|
|
1720
|
+
const snap = fromSnapshot?.get(key);
|
|
1721
|
+
if (snap && snap.type === "point") {
|
|
1722
|
+
px = snap.cx;
|
|
1723
|
+
py = snap.cy;
|
|
1724
|
+
if (snap.r !== void 0) pr = snap.r;
|
|
1577
1725
|
}
|
|
1726
|
+
soaIndex[s] = i;
|
|
1727
|
+
soaKeys[s] = key;
|
|
1728
|
+
fromCx[s] = px;
|
|
1729
|
+
fromCy[s] = py;
|
|
1730
|
+
fromR[s] = pr;
|
|
1731
|
+
toCx[s] = soa.x[i];
|
|
1732
|
+
toCy[s] = soa.y[i];
|
|
1733
|
+
toR[s] = soa.r[i];
|
|
1578
1734
|
}
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
const
|
|
1582
|
-
const
|
|
1583
|
-
|
|
1584
|
-
const range = afterNext.x - beforeNext.x;
|
|
1585
|
-
const t = range === 0 ? 0.5 : (nextPt.x - beforeNext.x) / range;
|
|
1586
|
-
return lerpPoint(beforePrev, afterPrev, Math.max(0, Math.min(1, t)));
|
|
1587
|
-
}
|
|
1588
|
-
if (beforeKey) {
|
|
1589
|
-
return { ...prevByKey.get(beforeKey) };
|
|
1735
|
+
const enterSoaIndex = Uint32Array.from(enters);
|
|
1736
|
+
if (enters.length > 0) {
|
|
1737
|
+
const alpha = new Float32Array(soa.n).fill(1);
|
|
1738
|
+
for (const i of enters) alpha[i] = 0;
|
|
1739
|
+
layer.state.enterAlpha = alpha;
|
|
1590
1740
|
}
|
|
1591
|
-
|
|
1592
|
-
|
|
1741
|
+
const exitCx = new Float32Array(exits.length);
|
|
1742
|
+
const exitCy = new Float32Array(exits.length);
|
|
1743
|
+
const exitR = new Float32Array(exits.length);
|
|
1744
|
+
const exitFill = new Array(exits.length);
|
|
1745
|
+
for (let x = 0; x < exits.length; x++) {
|
|
1746
|
+
const m = exits[x];
|
|
1747
|
+
exitCx[x] = m.cx;
|
|
1748
|
+
exitCy[x] = m.cy;
|
|
1749
|
+
exitR[x] = m.r;
|
|
1750
|
+
exitFill[x] = flattenFill(m.fill);
|
|
1593
1751
|
}
|
|
1594
|
-
|
|
1752
|
+
const exitState = exits.length > 0 ? { x: exitCx, y: exitCy, r: exitR, fill: exitFill, alpha: 1 } : null;
|
|
1753
|
+
tweens.push({
|
|
1754
|
+
tweenType: "canvasPoints",
|
|
1755
|
+
kind: "update",
|
|
1756
|
+
layer,
|
|
1757
|
+
soaIndex,
|
|
1758
|
+
fromCx,
|
|
1759
|
+
fromCy,
|
|
1760
|
+
fromR,
|
|
1761
|
+
toCx,
|
|
1762
|
+
toCy,
|
|
1763
|
+
toR,
|
|
1764
|
+
soaKeys,
|
|
1765
|
+
enterSoaIndex,
|
|
1766
|
+
exitState
|
|
1767
|
+
});
|
|
1595
1768
|
}
|
|
1596
|
-
function
|
|
1597
|
-
const
|
|
1598
|
-
|
|
1599
|
-
for (let
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1769
|
+
function applyCanvasPointsState(tw, elapsed, update, exit, enterDelay, enterDuration) {
|
|
1770
|
+
const soa = tw.layer.state.marks;
|
|
1771
|
+
const easedUpdate = cubicOut(Math.min(elapsed / update.duration, 1));
|
|
1772
|
+
for (let s = 0; s < tw.soaIndex.length; s++) {
|
|
1773
|
+
const i = tw.soaIndex[s];
|
|
1774
|
+
soa.x[i] = tw.fromCx[s] + (tw.toCx[s] - tw.fromCx[s]) * easedUpdate;
|
|
1775
|
+
soa.y[i] = tw.fromCy[s] + (tw.toCy[s] - tw.fromCy[s]) * easedUpdate;
|
|
1776
|
+
soa.r[i] = tw.fromR[s] + (tw.toR[s] - tw.fromR[s]) * easedUpdate;
|
|
1604
1777
|
}
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1778
|
+
const alpha = tw.layer.state.enterAlpha;
|
|
1779
|
+
if (alpha && tw.enterSoaIndex.length > 0) {
|
|
1780
|
+
const tEnter = elapsed < enterDelay ? 0 : Math.min((elapsed - enterDelay) / enterDuration, 1);
|
|
1781
|
+
const easedEnter = cubicOut(tEnter);
|
|
1782
|
+
for (let e = 0; e < tw.enterSoaIndex.length; e++) {
|
|
1783
|
+
alpha[tw.enterSoaIndex[e]] = easedEnter;
|
|
1610
1784
|
}
|
|
1611
1785
|
}
|
|
1612
|
-
if (
|
|
1613
|
-
const
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
const afterNext = nextByKey.get(afterKey);
|
|
1617
|
-
const range = afterPrev.x - beforePrev.x;
|
|
1618
|
-
const t = range === 0 ? 0.5 : (prevPt.x - beforePrev.x) / range;
|
|
1619
|
-
return lerpPoint(beforeNext, afterNext, Math.max(0, Math.min(1, t)));
|
|
1620
|
-
}
|
|
1621
|
-
if (beforeKey) {
|
|
1622
|
-
return { ...nextByKey.get(beforeKey) };
|
|
1623
|
-
}
|
|
1624
|
-
if (afterKey) {
|
|
1625
|
-
return { ...nextByKey.get(afterKey) };
|
|
1626
|
-
}
|
|
1627
|
-
return prevPt;
|
|
1628
|
-
}
|
|
1629
|
-
function interpolatePoints(fromPts, toPts, t) {
|
|
1630
|
-
const len = Math.min(fromPts.length, toPts.length);
|
|
1631
|
-
const result = new Array(len);
|
|
1632
|
-
for (let i = 0; i < len; i++) {
|
|
1633
|
-
result[i] = lerpPoint(fromPts[i], toPts[i], t);
|
|
1634
|
-
}
|
|
1635
|
-
return result;
|
|
1636
|
-
}
|
|
1637
|
-
function applyLinePath(el, points, interpolate) {
|
|
1638
|
-
const pathEl = el.querySelector("path");
|
|
1639
|
-
if (!pathEl) return;
|
|
1640
|
-
pathEl.setAttribute("d", buildLinePath(points, interpolate));
|
|
1641
|
-
}
|
|
1642
|
-
function applyAreaPaths(el, topPoints, bottomPoints, interpolate, hasStroke) {
|
|
1643
|
-
const paths = el.querySelectorAll("path");
|
|
1644
|
-
if (paths[0]) {
|
|
1645
|
-
paths[0].setAttribute("d", buildAreaPath(topPoints, bottomPoints, interpolate));
|
|
1646
|
-
}
|
|
1647
|
-
if (hasStroke && paths[1]) {
|
|
1648
|
-
paths[1].setAttribute("d", buildLinePath(topPoints, interpolate));
|
|
1786
|
+
if (tw.exitState) {
|
|
1787
|
+
const easedExit = cubicOut(Math.min(elapsed / exit.duration, 1));
|
|
1788
|
+
tw.exitState.alpha = 1 - easedExit;
|
|
1789
|
+
tw.layer.state.exiting = tw.exitState;
|
|
1649
1790
|
}
|
|
1650
1791
|
}
|
|
1651
|
-
function
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1792
|
+
function canvasGridlineAxes(layout) {
|
|
1793
|
+
return [
|
|
1794
|
+
{ axis: layout.axes.y, orient: "y" },
|
|
1795
|
+
{ axis: layout.axes.y2, orient: "y" },
|
|
1796
|
+
{ axis: layout.axes.x, orient: "x" }
|
|
1797
|
+
];
|
|
1655
1798
|
}
|
|
1656
|
-
function
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
paths[0].setAttribute("d", mark.path);
|
|
1660
|
-
}
|
|
1661
|
-
if (paths[1] && mark.topPath) {
|
|
1662
|
-
paths[1].setAttribute("d", mark.topPath);
|
|
1663
|
-
}
|
|
1799
|
+
function axisEmitsGridlines(axis, orient) {
|
|
1800
|
+
if (!axis) return false;
|
|
1801
|
+
return !(orient === "y" && axis.orient === "right");
|
|
1664
1802
|
}
|
|
1665
|
-
function
|
|
1666
|
-
const
|
|
1667
|
-
const
|
|
1668
|
-
const
|
|
1669
|
-
const
|
|
1670
|
-
const
|
|
1671
|
-
const
|
|
1672
|
-
const
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
(m) => "fill" in m && isGradientDef(m.fill)
|
|
1701
|
-
);
|
|
1702
|
-
if (gradientMarks.length > 0) {
|
|
1703
|
-
ghostGradientMap = buildGradientDefs(gradientMarks, defs);
|
|
1803
|
+
function buildCanvasGridlinesTween(prevLayout, nextLayout, layer, tweens) {
|
|
1804
|
+
const live = layer.state.gridlines;
|
|
1805
|
+
const index = [];
|
|
1806
|
+
const fromPos = [];
|
|
1807
|
+
const toPos = [];
|
|
1808
|
+
const fromAlpha = [];
|
|
1809
|
+
const toAlpha = [];
|
|
1810
|
+
const prevAxes = canvasGridlineAxes(prevLayout);
|
|
1811
|
+
const nextAxes = canvasGridlineAxes(nextLayout);
|
|
1812
|
+
let cursor = 0;
|
|
1813
|
+
for (let a = 0; a < nextAxes.length; a++) {
|
|
1814
|
+
const nextAxis = nextAxes[a].axis;
|
|
1815
|
+
const orient = nextAxes[a].orient;
|
|
1816
|
+
if (!axisEmitsGridlines(nextAxis, orient)) continue;
|
|
1817
|
+
const prevAxis = prevAxes[a].axis;
|
|
1818
|
+
const deltas = axisEmitsGridlines(prevAxis, orient) ? computeGridlineDeltas(prevAxis, nextAxis) : null;
|
|
1819
|
+
const valueAtPosition = /* @__PURE__ */ new Map();
|
|
1820
|
+
for (const tick of nextAxis.ticks) {
|
|
1821
|
+
valueAtPosition.set(tick.position, serializeKeyValue2(tick.value));
|
|
1822
|
+
}
|
|
1823
|
+
for (const gridline of nextAxis.gridlines) {
|
|
1824
|
+
const slot = cursor++;
|
|
1825
|
+
if (slot >= live.length) break;
|
|
1826
|
+
const key = valueAtPosition.get(gridline.position);
|
|
1827
|
+
const prevPos = key !== void 0 ? deltas?.prevGridByValue.get(key) : void 0;
|
|
1828
|
+
index.push(slot);
|
|
1829
|
+
toPos.push(gridline.position);
|
|
1830
|
+
toAlpha.push(live[slot].alpha);
|
|
1831
|
+
if (prevPos !== void 0) {
|
|
1832
|
+
fromPos.push(prevPos);
|
|
1833
|
+
fromAlpha.push(live[slot].alpha);
|
|
1834
|
+
} else {
|
|
1835
|
+
fromPos.push(gridline.position);
|
|
1836
|
+
fromAlpha.push(0);
|
|
1837
|
+
}
|
|
1704
1838
|
}
|
|
1705
1839
|
}
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1840
|
+
if (index.length === 0) return;
|
|
1841
|
+
tweens.push({
|
|
1842
|
+
tweenType: "canvasGridlines",
|
|
1843
|
+
kind: "update",
|
|
1844
|
+
layer,
|
|
1845
|
+
index: Uint32Array.from(index),
|
|
1846
|
+
fromPos: Float32Array.from(fromPos),
|
|
1847
|
+
toPos: Float32Array.from(toPos),
|
|
1848
|
+
fromAlpha: Float32Array.from(fromAlpha),
|
|
1849
|
+
toAlpha: Float32Array.from(toAlpha)
|
|
1850
|
+
});
|
|
1851
|
+
}
|
|
1852
|
+
function applyCanvasGridlinesState(tw, elapsed, update, enterDelay, enterDuration) {
|
|
1853
|
+
const live = tw.layer.state.gridlines;
|
|
1854
|
+
const easedUpdate = cubicOut(Math.min(elapsed / update.duration, 1));
|
|
1855
|
+
const tEnter = elapsed < enterDelay ? 0 : Math.min((elapsed - enterDelay) / enterDuration, 1);
|
|
1856
|
+
const easedEnter = cubicOut(tEnter);
|
|
1857
|
+
for (let i = 0; i < tw.index.length; i++) {
|
|
1858
|
+
const g = live[tw.index[i]];
|
|
1859
|
+
g.position = tw.fromPos[i] + (tw.toPos[i] - tw.fromPos[i]) * easedUpdate;
|
|
1860
|
+
const from = tw.fromAlpha[i];
|
|
1861
|
+
const to = tw.toAlpha[i];
|
|
1862
|
+
g.alpha = from === to ? to : from + (to - from) * easedEnter;
|
|
1723
1863
|
}
|
|
1724
|
-
|
|
1725
|
-
|
|
1864
|
+
}
|
|
1865
|
+
function snapCanvasGridlinesToFinal(tw) {
|
|
1866
|
+
const live = tw.layer.state.gridlines;
|
|
1867
|
+
for (let i = 0; i < tw.index.length; i++) {
|
|
1868
|
+
const g = live[tw.index[i]];
|
|
1869
|
+
g.position = tw.toPos[i];
|
|
1870
|
+
g.alpha = tw.toAlpha[i];
|
|
1726
1871
|
}
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
fromSnapshot
|
|
1736
|
-
);
|
|
1872
|
+
}
|
|
1873
|
+
function snapCanvasPointsToFinal(tw) {
|
|
1874
|
+
const soa = tw.layer.state.marks;
|
|
1875
|
+
for (let s = 0; s < tw.soaIndex.length; s++) {
|
|
1876
|
+
const i = tw.soaIndex[s];
|
|
1877
|
+
soa.x[i] = tw.toCx[s];
|
|
1878
|
+
soa.y[i] = tw.toCy[s];
|
|
1879
|
+
soa.r[i] = tw.toR[s];
|
|
1737
1880
|
}
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1881
|
+
tw.layer.state.exiting = null;
|
|
1882
|
+
tw.layer.state.enterAlpha = null;
|
|
1883
|
+
}
|
|
1884
|
+
|
|
1885
|
+
// src/transition/interpolate.ts
|
|
1886
|
+
import { buildAreaPath, buildLinePath } from "@opendata-ai/openchart-engine";
|
|
1887
|
+
function geomFromMark(m) {
|
|
1888
|
+
return { x: m.x, y: m.y, width: m.width, height: m.height };
|
|
1889
|
+
}
|
|
1890
|
+
function applyGeomToElement(el, geom, mark) {
|
|
1891
|
+
const shapeEl = el.querySelector("rect, path");
|
|
1892
|
+
if (!shapeEl) return;
|
|
1893
|
+
const sides = mark.cornerRadiusSides;
|
|
1894
|
+
const partialCorners = !!sides && (!sides.tl || !sides.tr || !sides.br || !sides.bl) && !!mark.cornerRadius;
|
|
1895
|
+
if (partialCorners && shapeEl.tagName === "path") {
|
|
1896
|
+
const tempMark = { ...mark, ...geom };
|
|
1897
|
+
shapeEl.setAttribute("d", rectPathWithCorners(tempMark, sides));
|
|
1898
|
+
} else {
|
|
1899
|
+
shapeEl.setAttribute("x", String(geom.x));
|
|
1900
|
+
shapeEl.setAttribute("y", String(geom.y));
|
|
1901
|
+
shapeEl.setAttribute("width", String(geom.width));
|
|
1902
|
+
shapeEl.setAttribute("height", String(geom.height));
|
|
1752
1903
|
}
|
|
1753
|
-
|
|
1754
|
-
|
|
1904
|
+
}
|
|
1905
|
+
function lerpGeom(from, to, t) {
|
|
1906
|
+
return {
|
|
1907
|
+
x: from.x + (to.x - from.x) * t,
|
|
1908
|
+
y: from.y + (to.y - from.y) * t,
|
|
1909
|
+
width: from.width + (to.width - from.width) * t,
|
|
1910
|
+
height: from.height + (to.height - from.height) * t
|
|
1911
|
+
};
|
|
1912
|
+
}
|
|
1913
|
+
function lerpPoint(a, b, t) {
|
|
1914
|
+
return { x: a.x + (b.x - a.x) * t, y: a.y + (b.y - a.y) * t };
|
|
1915
|
+
}
|
|
1916
|
+
function normalizePointArrays(prevPoints, nextPoints, prevKeys, nextKeys) {
|
|
1917
|
+
const nextKeySet = new Set(nextKeys);
|
|
1918
|
+
const survivors = prevKeys.filter((k) => nextKeySet.has(k));
|
|
1919
|
+
if (survivors.length === 0) {
|
|
1920
|
+
return [prevPoints, nextPoints];
|
|
1755
1921
|
}
|
|
1756
|
-
|
|
1757
|
-
|
|
1922
|
+
const prevByKey = /* @__PURE__ */ new Map();
|
|
1923
|
+
for (let i = 0; i < prevKeys.length; i++) {
|
|
1924
|
+
prevByKey.set(prevKeys[i], prevPoints[i]);
|
|
1758
1925
|
}
|
|
1759
|
-
|
|
1760
|
-
|
|
1926
|
+
const nextByKey = /* @__PURE__ */ new Map();
|
|
1927
|
+
for (let i = 0; i < nextKeys.length; i++) {
|
|
1928
|
+
nextByKey.set(nextKeys[i], nextPoints[i]);
|
|
1761
1929
|
}
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
|
|
1930
|
+
const merged = mergeKeyOrder(prevKeys, nextKeys);
|
|
1931
|
+
const mergedIndex = /* @__PURE__ */ new Map();
|
|
1932
|
+
for (let i = 0; i < merged.length; i++) {
|
|
1933
|
+
mergedIndex.set(merged[i], i);
|
|
1765
1934
|
}
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
const
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1935
|
+
const fromPts = [];
|
|
1936
|
+
const toPts = [];
|
|
1937
|
+
for (const key of merged) {
|
|
1938
|
+
const inPrev = prevByKey.has(key);
|
|
1939
|
+
const inNext = nextByKey.has(key);
|
|
1940
|
+
if (inPrev && inNext) {
|
|
1941
|
+
fromPts.push(prevByKey.get(key));
|
|
1942
|
+
toPts.push(nextByKey.get(key));
|
|
1943
|
+
} else if (inNext && !inPrev) {
|
|
1944
|
+
const nextPt = nextByKey.get(key);
|
|
1945
|
+
toPts.push(nextPt);
|
|
1946
|
+
fromPts.push(findInsertionPosition(key, merged, mergedIndex, prevByKey, nextByKey, nextPt));
|
|
1947
|
+
} else if (inPrev && !inNext) {
|
|
1948
|
+
const prevPt = prevByKey.get(key);
|
|
1949
|
+
fromPts.push(prevPt);
|
|
1950
|
+
toPts.push(findRemovalPosition(key, merged, mergedIndex, prevByKey, nextByKey, prevPt));
|
|
1951
|
+
}
|
|
1772
1952
|
}
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1953
|
+
return [fromPts, toPts];
|
|
1954
|
+
}
|
|
1955
|
+
function mergeKeyOrder(prevKeys, nextKeys) {
|
|
1956
|
+
const nextIndex = /* @__PURE__ */ new Map();
|
|
1957
|
+
for (let i = 0; i < nextKeys.length; i++) {
|
|
1958
|
+
if (!nextIndex.has(nextKeys[i])) nextIndex.set(nextKeys[i], i);
|
|
1777
1959
|
}
|
|
1778
|
-
|
|
1779
|
-
let
|
|
1780
|
-
|
|
1781
|
-
let lastElapsed = 0;
|
|
1782
|
-
const nextLineMarks = nextLayout.marks.filter((m) => m.type === "line");
|
|
1783
|
-
const nextAreaMarks = nextLayout.marks.filter((m) => m.type === "area");
|
|
1784
|
-
function tick(now) {
|
|
1785
|
-
if (!running) return;
|
|
1786
|
-
if (startTime === null) startTime = now;
|
|
1787
|
-
const elapsed = now - startTime;
|
|
1788
|
-
lastElapsed = elapsed;
|
|
1789
|
-
const tGlobal = Math.min(elapsed / totalMs, 1);
|
|
1790
|
-
for (const tw of tweens) {
|
|
1791
|
-
applyTweenState(tw, elapsed, update, exit, enterDelay, enterDuration);
|
|
1792
|
-
}
|
|
1793
|
-
applySecondaryOpacity(secondaryEls, elapsed, enterDelay, enterDuration);
|
|
1794
|
-
canvas?.repaint();
|
|
1795
|
-
if (tGlobal >= 1) {
|
|
1796
|
-
finish();
|
|
1797
|
-
} else {
|
|
1798
|
-
rafId = requestAnimationFrame(tick);
|
|
1799
|
-
}
|
|
1960
|
+
const prevIndex = /* @__PURE__ */ new Map();
|
|
1961
|
+
for (let i = 0; i < prevKeys.length; i++) {
|
|
1962
|
+
if (!prevIndex.has(prevKeys[i])) prevIndex.set(prevKeys[i], i);
|
|
1800
1963
|
}
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
if (
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
snapToFinal();
|
|
1812
|
-
removeGhosts();
|
|
1813
|
-
settleCanvas();
|
|
1814
|
-
for (let i = 0; i < secondaryEls.length; i++) {
|
|
1815
|
-
secondaryEls[i].style.opacity = secondaryOriginalOpacity[i];
|
|
1816
|
-
}
|
|
1817
|
-
onComplete();
|
|
1818
|
-
}
|
|
1819
|
-
function snapToFinal() {
|
|
1820
|
-
for (const tw of tweens) {
|
|
1821
|
-
snapTweenToFinal(tw);
|
|
1964
|
+
const result = [];
|
|
1965
|
+
const added = /* @__PURE__ */ new Set();
|
|
1966
|
+
let pi = 0;
|
|
1967
|
+
let ni = 0;
|
|
1968
|
+
while (pi < prevKeys.length && ni < nextKeys.length) {
|
|
1969
|
+
const pk = prevKeys[pi];
|
|
1970
|
+
const nk = nextKeys[ni];
|
|
1971
|
+
if (added.has(pk)) {
|
|
1972
|
+
pi++;
|
|
1973
|
+
continue;
|
|
1822
1974
|
}
|
|
1823
|
-
|
|
1824
|
-
|
|
1825
|
-
|
|
1826
|
-
if (el) applyFinalLinePath(el, mark);
|
|
1975
|
+
if (added.has(nk)) {
|
|
1976
|
+
ni++;
|
|
1977
|
+
continue;
|
|
1827
1978
|
}
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
1979
|
+
if (pk === nk) {
|
|
1980
|
+
result.push(pk);
|
|
1981
|
+
added.add(pk);
|
|
1982
|
+
pi++;
|
|
1983
|
+
ni++;
|
|
1984
|
+
} else {
|
|
1985
|
+
const pkInNext = nextIndex.has(pk) && nextIndex.get(pk) >= ni ? nextIndex.get(pk) : -1;
|
|
1986
|
+
const nkInPrev = prevIndex.has(nk) && prevIndex.get(nk) >= pi ? prevIndex.get(nk) : -1;
|
|
1987
|
+
if (pkInNext === -1 && nkInPrev === -1) {
|
|
1988
|
+
result.push(pk);
|
|
1989
|
+
added.add(pk);
|
|
1990
|
+
pi++;
|
|
1991
|
+
} else if (pkInNext === -1) {
|
|
1992
|
+
result.push(pk);
|
|
1993
|
+
added.add(pk);
|
|
1994
|
+
pi++;
|
|
1995
|
+
} else if (nkInPrev === -1) {
|
|
1996
|
+
result.push(nk);
|
|
1997
|
+
added.add(nk);
|
|
1998
|
+
ni++;
|
|
1999
|
+
} else {
|
|
2000
|
+
if (pkInNext <= nkInPrev) {
|
|
2001
|
+
result.push(pk);
|
|
2002
|
+
added.add(pk);
|
|
2003
|
+
pi++;
|
|
2004
|
+
} else {
|
|
2005
|
+
result.push(nk);
|
|
2006
|
+
added.add(nk);
|
|
2007
|
+
ni++;
|
|
2008
|
+
}
|
|
2009
|
+
}
|
|
1832
2010
|
}
|
|
1833
2011
|
}
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
2012
|
+
while (pi < prevKeys.length) {
|
|
2013
|
+
if (!added.has(prevKeys[pi])) {
|
|
2014
|
+
result.push(prevKeys[pi]);
|
|
2015
|
+
added.add(prevKeys[pi]);
|
|
1837
2016
|
}
|
|
2017
|
+
pi++;
|
|
1838
2018
|
}
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
for (const tw of tweens) {
|
|
1844
|
-
if (tw.kind !== "update") continue;
|
|
1845
|
-
if (tw.tweenType === "canvasPoints") {
|
|
1846
|
-
for (let s = 0; s < tw.soaIndex.length; s++) {
|
|
1847
|
-
snap.set(tw.soaKeys[s], {
|
|
1848
|
-
type: "point",
|
|
1849
|
-
cx: tw.fromCx[s] + (tw.toCx[s] - tw.fromCx[s]) * easedUpdate,
|
|
1850
|
-
cy: tw.fromCy[s] + (tw.toCy[s] - tw.fromCy[s]) * easedUpdate,
|
|
1851
|
-
r: tw.fromR[s] + (tw.toR[s] - tw.fromR[s]) * easedUpdate
|
|
1852
|
-
});
|
|
1853
|
-
}
|
|
1854
|
-
continue;
|
|
1855
|
-
}
|
|
1856
|
-
const key = getKeyForTween(tw);
|
|
1857
|
-
if (!key) continue;
|
|
1858
|
-
switch (tw.tweenType) {
|
|
1859
|
-
case "rect": {
|
|
1860
|
-
const g = lerpGeom(tw.from, tw.to, easedUpdate);
|
|
1861
|
-
snap.set(key, { type: "rect", ...g });
|
|
1862
|
-
break;
|
|
1863
|
-
}
|
|
1864
|
-
case "point": {
|
|
1865
|
-
const cx = tw.fromCx + (tw.toCx - tw.fromCx) * easedUpdate;
|
|
1866
|
-
const cy = tw.fromCy + (tw.toCy - tw.fromCy) * easedUpdate;
|
|
1867
|
-
const entry = { type: "point", cx, cy };
|
|
1868
|
-
if (tw.fromR !== void 0 && tw.toR !== void 0) {
|
|
1869
|
-
entry.r = tw.fromR + (tw.toR - tw.fromR) * easedUpdate;
|
|
1870
|
-
}
|
|
1871
|
-
snap.set(key, entry);
|
|
1872
|
-
break;
|
|
1873
|
-
}
|
|
1874
|
-
case "rule":
|
|
1875
|
-
case "tick": {
|
|
1876
|
-
snap.set(key, {
|
|
1877
|
-
type: tw.tweenType,
|
|
1878
|
-
x1: tw.fromX1 + (tw.toX1 - tw.fromX1) * easedUpdate,
|
|
1879
|
-
y1: tw.fromY1 + (tw.toY1 - tw.fromY1) * easedUpdate,
|
|
1880
|
-
x2: tw.fromX2 + (tw.toX2 - tw.fromX2) * easedUpdate,
|
|
1881
|
-
y2: tw.fromY2 + (tw.toY2 - tw.fromY2) * easedUpdate
|
|
1882
|
-
});
|
|
1883
|
-
break;
|
|
1884
|
-
}
|
|
1885
|
-
case "textMark": {
|
|
1886
|
-
snap.set(key, {
|
|
1887
|
-
type: "textMark",
|
|
1888
|
-
x: tw.fromX + (tw.toX - tw.fromX) * easedUpdate,
|
|
1889
|
-
y: tw.fromY + (tw.toY - tw.fromY) * easedUpdate
|
|
1890
|
-
});
|
|
1891
|
-
break;
|
|
1892
|
-
}
|
|
1893
|
-
case "line": {
|
|
1894
|
-
const pts = interpolatePoints(tw.fromPts, tw.toPts, easedUpdate);
|
|
1895
|
-
const d = buildLinePath(pts, tw.interpolate);
|
|
1896
|
-
snap.set(key, { type: "line", d });
|
|
1897
|
-
break;
|
|
1898
|
-
}
|
|
1899
|
-
case "area": {
|
|
1900
|
-
const top = interpolatePoints(tw.fromTop, tw.toTop, easedUpdate);
|
|
1901
|
-
const bottom = interpolatePoints(tw.fromBottom, tw.toBottom, easedUpdate);
|
|
1902
|
-
const d = buildAreaPath(top, bottom, tw.interpolate);
|
|
1903
|
-
let topD;
|
|
1904
|
-
if (tw.hasStroke) {
|
|
1905
|
-
topD = buildLinePath(top, tw.interpolate);
|
|
1906
|
-
}
|
|
1907
|
-
snap.set(key, { type: "area", d, topD });
|
|
1908
|
-
break;
|
|
1909
|
-
}
|
|
1910
|
-
}
|
|
2019
|
+
while (ni < nextKeys.length) {
|
|
2020
|
+
if (!added.has(nextKeys[ni])) {
|
|
2021
|
+
result.push(nextKeys[ni]);
|
|
2022
|
+
added.add(nextKeys[ni]);
|
|
1911
2023
|
}
|
|
1912
|
-
|
|
1913
|
-
}
|
|
1914
|
-
if (!manual) {
|
|
1915
|
-
rafId = requestAnimationFrame(tick);
|
|
2024
|
+
ni++;
|
|
1916
2025
|
}
|
|
1917
|
-
return
|
|
1918
|
-
cancel() {
|
|
1919
|
-
if (!running) return;
|
|
1920
|
-
running = false;
|
|
1921
|
-
if (rafId !== null) {
|
|
1922
|
-
cancelAnimationFrame(rafId);
|
|
1923
|
-
rafId = null;
|
|
1924
|
-
}
|
|
1925
|
-
snapToFinal();
|
|
1926
|
-
removeGhosts();
|
|
1927
|
-
settleCanvas();
|
|
1928
|
-
for (let i = 0; i < secondaryEls.length; i++) {
|
|
1929
|
-
secondaryEls[i].style.opacity = secondaryOriginalOpacity[i];
|
|
1930
|
-
}
|
|
1931
|
-
},
|
|
1932
|
-
get running() {
|
|
1933
|
-
return running;
|
|
1934
|
-
},
|
|
1935
|
-
snapshot() {
|
|
1936
|
-
return captureSnapshot();
|
|
1937
|
-
},
|
|
1938
|
-
step(elapsedMs) {
|
|
1939
|
-
lastElapsed = elapsedMs;
|
|
1940
|
-
for (const tw of tweens) {
|
|
1941
|
-
applyTweenState(tw, elapsedMs, update, exit, enterDelay, enterDuration);
|
|
1942
|
-
}
|
|
1943
|
-
applySecondaryOpacity(secondaryEls, elapsedMs, enterDelay, enterDuration);
|
|
1944
|
-
if (elapsedMs >= totalMs) {
|
|
1945
|
-
snapToFinal();
|
|
1946
|
-
removeGhosts();
|
|
1947
|
-
settleCanvas();
|
|
1948
|
-
return false;
|
|
1949
|
-
}
|
|
1950
|
-
canvas?.repaint();
|
|
1951
|
-
return true;
|
|
1952
|
-
},
|
|
1953
|
-
totalMs
|
|
1954
|
-
};
|
|
1955
|
-
}
|
|
1956
|
-
function collectSecondaryElements(svg) {
|
|
1957
|
-
const els = [];
|
|
1958
|
-
const epLabels = svg.querySelector(".oc-endpoint-labels");
|
|
1959
|
-
if (epLabels) els.push(epLabels);
|
|
1960
|
-
const markLabels = svg.querySelector(".oc-mark-labels");
|
|
1961
|
-
if (markLabels) els.push(markLabels);
|
|
1962
|
-
return els;
|
|
2026
|
+
return result;
|
|
1963
2027
|
}
|
|
1964
|
-
function
|
|
1965
|
-
|
|
1966
|
-
let
|
|
1967
|
-
|
|
1968
|
-
|
|
1969
|
-
|
|
1970
|
-
|
|
2028
|
+
function findInsertionPosition(key, merged, mergedIndex, prevByKey, nextByKey, nextPt) {
|
|
2029
|
+
const idx = mergedIndex.get(key) ?? -1;
|
|
2030
|
+
let beforeKey = null;
|
|
2031
|
+
for (let i = idx - 1; i >= 0; i--) {
|
|
2032
|
+
if (prevByKey.has(merged[i]) && nextByKey.has(merged[i])) {
|
|
2033
|
+
beforeKey = merged[i];
|
|
2034
|
+
break;
|
|
2035
|
+
}
|
|
1971
2036
|
}
|
|
1972
|
-
|
|
1973
|
-
for (
|
|
1974
|
-
|
|
2037
|
+
let afterKey = null;
|
|
2038
|
+
for (let i = idx + 1; i < merged.length; i++) {
|
|
2039
|
+
if (prevByKey.has(merged[i]) && nextByKey.has(merged[i])) {
|
|
2040
|
+
afterKey = merged[i];
|
|
2041
|
+
break;
|
|
2042
|
+
}
|
|
1975
2043
|
}
|
|
1976
|
-
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
|
|
1980
|
-
|
|
1981
|
-
|
|
1982
|
-
|
|
1983
|
-
|
|
1984
|
-
}
|
|
1985
|
-
function applyTweenState(tw, elapsed, update, exit, enterDelay, enterDuration) {
|
|
1986
|
-
if (tw.tweenType === "canvasPoints") {
|
|
1987
|
-
applyCanvasPointsState(tw, elapsed, update, exit, enterDelay, enterDuration);
|
|
1988
|
-
return;
|
|
2044
|
+
if (beforeKey && afterKey) {
|
|
2045
|
+
const beforeNext = nextByKey.get(beforeKey);
|
|
2046
|
+
const afterNext = nextByKey.get(afterKey);
|
|
2047
|
+
const beforePrev = prevByKey.get(beforeKey);
|
|
2048
|
+
const afterPrev = prevByKey.get(afterKey);
|
|
2049
|
+
const range = afterNext.x - beforeNext.x;
|
|
2050
|
+
const t = range === 0 ? 0.5 : (nextPt.x - beforeNext.x) / range;
|
|
2051
|
+
return lerpPoint(beforePrev, afterPrev, Math.max(0, Math.min(1, t)));
|
|
1989
2052
|
}
|
|
1990
|
-
if (
|
|
1991
|
-
|
|
1992
|
-
return;
|
|
2053
|
+
if (beforeKey) {
|
|
2054
|
+
return { ...prevByKey.get(beforeKey) };
|
|
1993
2055
|
}
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
|
|
2056
|
+
if (afterKey) {
|
|
2057
|
+
return { ...prevByKey.get(afterKey) };
|
|
2058
|
+
}
|
|
2059
|
+
return nextPt;
|
|
2060
|
+
}
|
|
2061
|
+
function findRemovalPosition(key, merged, mergedIndex, prevByKey, nextByKey, prevPt) {
|
|
2062
|
+
const idx = mergedIndex.get(key) ?? -1;
|
|
2063
|
+
let beforeKey = null;
|
|
2064
|
+
for (let i = idx - 1; i >= 0; i--) {
|
|
2065
|
+
if (prevByKey.has(merged[i]) && nextByKey.has(merged[i])) {
|
|
2066
|
+
beforeKey = merged[i];
|
|
2067
|
+
break;
|
|
2068
|
+
}
|
|
2069
|
+
}
|
|
2070
|
+
let afterKey = null;
|
|
2071
|
+
for (let i = idx + 1; i < merged.length; i++) {
|
|
2072
|
+
if (prevByKey.has(merged[i]) && nextByKey.has(merged[i])) {
|
|
2073
|
+
afterKey = merged[i];
|
|
2074
|
+
break;
|
|
2075
|
+
}
|
|
2076
|
+
}
|
|
2077
|
+
if (beforeKey && afterKey) {
|
|
2078
|
+
const beforePrev = prevByKey.get(beforeKey);
|
|
2079
|
+
const afterPrev = prevByKey.get(afterKey);
|
|
2080
|
+
const beforeNext = nextByKey.get(beforeKey);
|
|
2081
|
+
const afterNext = nextByKey.get(afterKey);
|
|
2082
|
+
const range = afterPrev.x - beforePrev.x;
|
|
2083
|
+
const t = range === 0 ? 0.5 : (prevPt.x - beforePrev.x) / range;
|
|
2084
|
+
return lerpPoint(beforeNext, afterNext, Math.max(0, Math.min(1, t)));
|
|
2085
|
+
}
|
|
2086
|
+
if (beforeKey) {
|
|
2087
|
+
return { ...nextByKey.get(beforeKey) };
|
|
2088
|
+
}
|
|
2089
|
+
if (afterKey) {
|
|
2090
|
+
return { ...nextByKey.get(afterKey) };
|
|
2091
|
+
}
|
|
2092
|
+
return prevPt;
|
|
2093
|
+
}
|
|
2094
|
+
function interpolatePoints(fromPts, toPts, t) {
|
|
2095
|
+
const len = Math.min(fromPts.length, toPts.length);
|
|
2096
|
+
const result = new Array(len);
|
|
2097
|
+
for (let i = 0; i < len; i++) {
|
|
2098
|
+
result[i] = lerpPoint(fromPts[i], toPts[i], t);
|
|
2099
|
+
}
|
|
2100
|
+
return result;
|
|
2101
|
+
}
|
|
2102
|
+
function applyLinePath(el, points, interpolate) {
|
|
2103
|
+
const pathEl = el.querySelector("path");
|
|
2104
|
+
if (!pathEl) return;
|
|
2105
|
+
pathEl.setAttribute("d", buildLinePath(points, interpolate));
|
|
2106
|
+
}
|
|
2107
|
+
function applyAreaPaths(el, topPoints, bottomPoints, interpolate, hasStroke) {
|
|
2108
|
+
const paths = el.querySelectorAll("path");
|
|
2109
|
+
if (paths[0]) {
|
|
2110
|
+
paths[0].setAttribute("d", buildAreaPath(topPoints, bottomPoints, interpolate));
|
|
2111
|
+
}
|
|
2112
|
+
if (hasStroke && paths[1]) {
|
|
2113
|
+
paths[1].setAttribute("d", buildLinePath(topPoints, interpolate));
|
|
2114
|
+
}
|
|
2115
|
+
}
|
|
2116
|
+
function applyFinalLinePath(el, mark) {
|
|
2117
|
+
const pathEl = el.querySelector("path");
|
|
2118
|
+
if (!pathEl || !mark.path) return;
|
|
2119
|
+
pathEl.setAttribute("d", mark.path);
|
|
2120
|
+
}
|
|
2121
|
+
function applyFinalAreaPaths(el, mark) {
|
|
2122
|
+
const paths = el.querySelectorAll("path");
|
|
2123
|
+
if (paths[0]) {
|
|
2124
|
+
paths[0].setAttribute("d", mark.path);
|
|
2125
|
+
}
|
|
2126
|
+
if (paths[1] && mark.topPath) {
|
|
2127
|
+
paths[1].setAttribute("d", mark.topPath);
|
|
2128
|
+
}
|
|
2129
|
+
}
|
|
2130
|
+
|
|
2131
|
+
// src/transition/apply.ts
|
|
2132
|
+
function getKeyForTween(tw) {
|
|
2133
|
+
if (tw.tweenType === "canvasPoints" || tw.tweenType === "canvasGridlines") return null;
|
|
2134
|
+
if ("ghost" in tw && tw.ghost) return null;
|
|
2135
|
+
return tw.el.getAttribute("data-key");
|
|
2136
|
+
}
|
|
2137
|
+
function resolveLineElement(el) {
|
|
2138
|
+
return el.tagName === "line" ? el : el.querySelector("line") ?? el;
|
|
2139
|
+
}
|
|
2140
|
+
function applyTweenState(tw, elapsed, update, exit, enterDelay, enterDuration) {
|
|
2141
|
+
if (tw.tweenType === "canvasPoints") {
|
|
2142
|
+
applyCanvasPointsState(tw, elapsed, update, exit, enterDelay, enterDuration);
|
|
2143
|
+
return;
|
|
2144
|
+
}
|
|
2145
|
+
if (tw.tweenType === "canvasGridlines") {
|
|
2146
|
+
applyCanvasGridlinesState(tw, elapsed, update, enterDelay, enterDuration);
|
|
2147
|
+
return;
|
|
2148
|
+
}
|
|
2149
|
+
let tLocal;
|
|
2150
|
+
if (tw.kind === "exit") {
|
|
2151
|
+
tLocal = Math.min(elapsed / exit.duration, 1);
|
|
1997
2152
|
} else if (tw.kind === "enter") {
|
|
1998
2153
|
if (elapsed < enterDelay) {
|
|
1999
2154
|
tLocal = 0;
|
|
@@ -2160,12 +2315,41 @@ function snapTweenToFinal(tw) {
|
|
|
2160
2315
|
tw.el.setAttribute("opacity", tw.suppressedOpacity);
|
|
2161
2316
|
}
|
|
2162
2317
|
}
|
|
2318
|
+
|
|
2319
|
+
// src/transition/dom-index.ts
|
|
2320
|
+
function buildMarkDomIndex(marksContainer) {
|
|
2321
|
+
const anyM = /* @__PURE__ */ new Map();
|
|
2322
|
+
const pointM = /* @__PURE__ */ new Map();
|
|
2323
|
+
const ruleM = /* @__PURE__ */ new Map();
|
|
2324
|
+
const tickM = /* @__PURE__ */ new Map();
|
|
2325
|
+
const textM = /* @__PURE__ */ new Map();
|
|
2326
|
+
for (const node of marksContainer.querySelectorAll("[data-key]")) {
|
|
2327
|
+
const el = node;
|
|
2328
|
+
const key = el.getAttribute("data-key");
|
|
2329
|
+
if (!key) continue;
|
|
2330
|
+
if (!anyM.has(key)) anyM.set(key, el);
|
|
2331
|
+
const cl = el.classList;
|
|
2332
|
+
if (el.tagName === "circle" && cl.contains("oc-mark-point")) {
|
|
2333
|
+
if (!pointM.has(key)) pointM.set(key, el);
|
|
2334
|
+
} else if (cl.contains("oc-mark-rule")) {
|
|
2335
|
+
if (!ruleM.has(key)) ruleM.set(key, el);
|
|
2336
|
+
} else if (cl.contains("oc-mark-tick")) {
|
|
2337
|
+
if (!tickM.has(key)) tickM.set(key, el);
|
|
2338
|
+
} else if (cl.contains("oc-mark-text")) {
|
|
2339
|
+
if (!textM.has(key)) textM.set(key, el);
|
|
2340
|
+
}
|
|
2341
|
+
}
|
|
2342
|
+
const g = (m) => (key) => m.get(key) ?? null;
|
|
2343
|
+
return { any: g(anyM), point: g(pointM), rule: g(ruleM), tick: g(tickM), text: g(textM) };
|
|
2344
|
+
}
|
|
2345
|
+
|
|
2346
|
+
// src/transition/svg-tweens.ts
|
|
2163
2347
|
function resolveGhostGradientFill(mark, ghostGradientMap) {
|
|
2164
2348
|
if (!mark.fill || typeof mark.fill === "string" || ghostGradientMap.size === 0) return mark;
|
|
2165
2349
|
const resolved = resolveMarkFill(mark.fill, ghostGradientMap);
|
|
2166
2350
|
return { ...mark, fill: resolved };
|
|
2167
2351
|
}
|
|
2168
|
-
function buildRectTweens(prevLayout, nextLayout, marksContainer, tweens, ghosts, ghostGradientMap, fromSnapshot) {
|
|
2352
|
+
function buildRectTweens(prevLayout, nextLayout, marksContainer, dom, tweens, ghosts, ghostGradientMap, fromSnapshot) {
|
|
2169
2353
|
const prevRects = prevLayout.marks.filter((m) => m.type === "rect");
|
|
2170
2354
|
const nextRects = nextLayout.marks.filter((m) => m.type === "rect");
|
|
2171
2355
|
const prevByKey = /* @__PURE__ */ new Map();
|
|
@@ -2179,7 +2363,7 @@ function buildRectTweens(prevLayout, nextLayout, marksContainer, tweens, ghosts,
|
|
|
2179
2363
|
for (const [key, next] of nextByKey) {
|
|
2180
2364
|
const prev = prevByKey.get(key);
|
|
2181
2365
|
if (!prev) continue;
|
|
2182
|
-
const el =
|
|
2366
|
+
const el = dom.any(key);
|
|
2183
2367
|
if (!el) continue;
|
|
2184
2368
|
let fromGeom = geomFromMark(prev);
|
|
2185
2369
|
const snap = fromSnapshot?.get(key);
|
|
@@ -2197,7 +2381,7 @@ function buildRectTweens(prevLayout, nextLayout, marksContainer, tweens, ghosts,
|
|
|
2197
2381
|
}
|
|
2198
2382
|
for (const [key, next] of nextByKey) {
|
|
2199
2383
|
if (prevByKey.has(key)) continue;
|
|
2200
|
-
const el =
|
|
2384
|
+
const el = dom.any(key);
|
|
2201
2385
|
if (!el) continue;
|
|
2202
2386
|
let fromGeom;
|
|
2203
2387
|
if (next.orient === "horizontal") {
|
|
@@ -2244,7 +2428,7 @@ function buildRectTweens(prevLayout, nextLayout, marksContainer, tweens, ghosts,
|
|
|
2244
2428
|
});
|
|
2245
2429
|
}
|
|
2246
2430
|
}
|
|
2247
|
-
function buildLineTweens(prevLayout, nextLayout, marksContainer, tweens, ghosts, fromSnapshot) {
|
|
2431
|
+
function buildLineTweens(prevLayout, nextLayout, marksContainer, dom, tweens, ghosts, fromSnapshot) {
|
|
2248
2432
|
const prevLines = prevLayout.marks.filter((m) => m.type === "line");
|
|
2249
2433
|
const nextLines = nextLayout.marks.filter((m) => m.type === "line");
|
|
2250
2434
|
const prevByKey = /* @__PURE__ */ new Map();
|
|
@@ -2258,7 +2442,7 @@ function buildLineTweens(prevLayout, nextLayout, marksContainer, tweens, ghosts,
|
|
|
2258
2442
|
for (const [key, next] of nextByKey) {
|
|
2259
2443
|
const prev = prevByKey.get(key);
|
|
2260
2444
|
if (!prev) continue;
|
|
2261
|
-
const el =
|
|
2445
|
+
const el = dom.any(key);
|
|
2262
2446
|
if (!el) continue;
|
|
2263
2447
|
const snap = fromSnapshot?.get(key);
|
|
2264
2448
|
if (snap && snap.type === "line") {
|
|
@@ -2349,7 +2533,7 @@ function buildLineTweens(prevLayout, nextLayout, marksContainer, tweens, ghosts,
|
|
|
2349
2533
|
}
|
|
2350
2534
|
for (const [key, next] of nextByKey) {
|
|
2351
2535
|
if (prevByKey.has(key)) continue;
|
|
2352
|
-
const el =
|
|
2536
|
+
const el = dom.any(key);
|
|
2353
2537
|
if (!el) continue;
|
|
2354
2538
|
tweens.push({
|
|
2355
2539
|
tweenType: "line",
|
|
@@ -2387,7 +2571,7 @@ function buildLineTweens(prevLayout, nextLayout, marksContainer, tweens, ghosts,
|
|
|
2387
2571
|
});
|
|
2388
2572
|
}
|
|
2389
2573
|
}
|
|
2390
|
-
function buildAreaTweens(prevLayout, nextLayout, marksContainer, tweens, ghosts, ghostGradientMap, fromSnapshot) {
|
|
2574
|
+
function buildAreaTweens(prevLayout, nextLayout, marksContainer, dom, tweens, ghosts, ghostGradientMap, fromSnapshot) {
|
|
2391
2575
|
const prevAreas = prevLayout.marks.filter((m) => m.type === "area");
|
|
2392
2576
|
const nextAreas = nextLayout.marks.filter((m) => m.type === "area");
|
|
2393
2577
|
const prevByKey = /* @__PURE__ */ new Map();
|
|
@@ -2401,7 +2585,7 @@ function buildAreaTweens(prevLayout, nextLayout, marksContainer, tweens, ghosts,
|
|
|
2401
2585
|
for (const [key, next] of nextByKey) {
|
|
2402
2586
|
const prev = prevByKey.get(key);
|
|
2403
2587
|
if (!prev) continue;
|
|
2404
|
-
const el =
|
|
2588
|
+
const el = dom.any(key);
|
|
2405
2589
|
if (!el) continue;
|
|
2406
2590
|
const snap = fromSnapshot?.get(key);
|
|
2407
2591
|
if (snap && snap.type === "area") {
|
|
@@ -2523,7 +2707,7 @@ function buildAreaTweens(prevLayout, nextLayout, marksContainer, tweens, ghosts,
|
|
|
2523
2707
|
}
|
|
2524
2708
|
for (const [key, next] of nextByKey) {
|
|
2525
2709
|
if (prevByKey.has(key)) continue;
|
|
2526
|
-
const el =
|
|
2710
|
+
const el = dom.any(key);
|
|
2527
2711
|
if (!el) continue;
|
|
2528
2712
|
tweens.push({
|
|
2529
2713
|
tweenType: "area",
|
|
@@ -2570,7 +2754,7 @@ function buildAreaTweens(prevLayout, nextLayout, marksContainer, tweens, ghosts,
|
|
|
2570
2754
|
});
|
|
2571
2755
|
}
|
|
2572
2756
|
}
|
|
2573
|
-
function buildPointTweens(prevLayout, nextLayout, marksContainer, tweens, ghosts, ghostGradientMap, fromSnapshot) {
|
|
2757
|
+
function buildPointTweens(prevLayout, nextLayout, marksContainer, dom, tweens, ghosts, ghostGradientMap, fromSnapshot) {
|
|
2574
2758
|
const prevPoints = prevLayout.marks.filter((m) => m.type === "point");
|
|
2575
2759
|
const nextPoints = nextLayout.marks.filter((m) => m.type === "point");
|
|
2576
2760
|
const prevByKey = /* @__PURE__ */ new Map();
|
|
@@ -2584,9 +2768,7 @@ function buildPointTweens(prevLayout, nextLayout, marksContainer, tweens, ghosts
|
|
|
2584
2768
|
for (const [key, next] of nextByKey) {
|
|
2585
2769
|
const prev = prevByKey.get(key);
|
|
2586
2770
|
if (!prev) continue;
|
|
2587
|
-
const el =
|
|
2588
|
-
`circle.oc-mark-point[data-key="${key}"]`
|
|
2589
|
-
);
|
|
2771
|
+
const el = dom.point(key);
|
|
2590
2772
|
if (!el) continue;
|
|
2591
2773
|
const renderedOpacity = el.getAttribute("opacity");
|
|
2592
2774
|
const isSuppressed = renderedOpacity === "0";
|
|
@@ -2617,9 +2799,7 @@ function buildPointTweens(prevLayout, nextLayout, marksContainer, tweens, ghosts
|
|
|
2617
2799
|
}
|
|
2618
2800
|
for (const [key, next] of nextByKey) {
|
|
2619
2801
|
if (prevByKey.has(key)) continue;
|
|
2620
|
-
const el =
|
|
2621
|
-
`circle.oc-mark-point[data-key="${key}"]`
|
|
2622
|
-
);
|
|
2802
|
+
const el = dom.point(key);
|
|
2623
2803
|
if (!el) continue;
|
|
2624
2804
|
const renderedOpacity = el.getAttribute("opacity");
|
|
2625
2805
|
const targetOpacity = renderedOpacity != null ? Number(renderedOpacity) : 1;
|
|
@@ -2661,310 +2841,96 @@ function buildPointTweens(prevLayout, nextLayout, marksContainer, tweens, ghosts
|
|
|
2661
2841
|
});
|
|
2662
2842
|
}
|
|
2663
2843
|
}
|
|
2664
|
-
function
|
|
2665
|
-
const
|
|
2666
|
-
const
|
|
2844
|
+
function buildRuleTweens(prevLayout, nextLayout, marksContainer, dom, tweens, ghosts, fromSnapshot) {
|
|
2845
|
+
const prevRules = prevLayout.marks.filter((m) => m.type === "rule");
|
|
2846
|
+
const nextRules = nextLayout.marks.filter((m) => m.type === "rule");
|
|
2667
2847
|
const prevByKey = /* @__PURE__ */ new Map();
|
|
2668
|
-
for (const m of
|
|
2848
|
+
for (const m of prevRules) {
|
|
2669
2849
|
if (m.key) prevByKey.set(m.key, m);
|
|
2670
2850
|
}
|
|
2671
|
-
const
|
|
2672
|
-
const
|
|
2673
|
-
|
|
2674
|
-
for (let i = 0; i < soa.n; i++) {
|
|
2675
|
-
const key = soa.keys[i];
|
|
2676
|
-
if (key !== void 0 && prevByKey.has(key)) survivors.push(i);
|
|
2677
|
-
else enters.push(i);
|
|
2678
|
-
}
|
|
2679
|
-
const exits = [];
|
|
2680
|
-
const nextKeys = /* @__PURE__ */ new Set();
|
|
2681
|
-
for (const m of nextPoints) {
|
|
2682
|
-
if (m.key) nextKeys.add(m.key);
|
|
2683
|
-
}
|
|
2684
|
-
for (const [key, prev] of prevByKey) {
|
|
2685
|
-
if (!nextKeys.has(key)) exits.push(prev);
|
|
2851
|
+
const nextByKey = /* @__PURE__ */ new Map();
|
|
2852
|
+
for (const m of nextRules) {
|
|
2853
|
+
if (m.key) nextByKey.set(m.key, m);
|
|
2686
2854
|
}
|
|
2687
|
-
const
|
|
2688
|
-
const soaIndex = new Uint32Array(sn);
|
|
2689
|
-
const fromCx = new Float32Array(sn);
|
|
2690
|
-
const fromCy = new Float32Array(sn);
|
|
2691
|
-
const fromR = new Float32Array(sn);
|
|
2692
|
-
const toCx = new Float32Array(sn);
|
|
2693
|
-
const toCy = new Float32Array(sn);
|
|
2694
|
-
const toR = new Float32Array(sn);
|
|
2695
|
-
const soaKeys = new Array(sn);
|
|
2696
|
-
for (let s = 0; s < sn; s++) {
|
|
2697
|
-
const i = survivors[s];
|
|
2698
|
-
const key = soa.keys[i];
|
|
2855
|
+
for (const [key, next] of nextByKey) {
|
|
2699
2856
|
const prev = prevByKey.get(key);
|
|
2700
|
-
|
|
2701
|
-
|
|
2702
|
-
|
|
2857
|
+
if (!prev) continue;
|
|
2858
|
+
const el = dom.rule(key);
|
|
2859
|
+
if (!el) continue;
|
|
2860
|
+
let fromX1 = prev.x1;
|
|
2861
|
+
let fromY1 = prev.y1;
|
|
2862
|
+
let fromX2 = prev.x2;
|
|
2863
|
+
let fromY2 = prev.y2;
|
|
2703
2864
|
const snap = fromSnapshot?.get(key);
|
|
2704
|
-
if (snap && snap.type === "
|
|
2705
|
-
|
|
2706
|
-
|
|
2707
|
-
|
|
2865
|
+
if (snap && snap.type === "rule") {
|
|
2866
|
+
fromX1 = snap.x1;
|
|
2867
|
+
fromY1 = snap.y1;
|
|
2868
|
+
fromX2 = snap.x2;
|
|
2869
|
+
fromY2 = snap.y2;
|
|
2708
2870
|
}
|
|
2709
|
-
|
|
2710
|
-
|
|
2711
|
-
|
|
2712
|
-
|
|
2713
|
-
|
|
2714
|
-
|
|
2715
|
-
|
|
2716
|
-
|
|
2871
|
+
tweens.push({
|
|
2872
|
+
tweenType: "rule",
|
|
2873
|
+
kind: "update",
|
|
2874
|
+
el,
|
|
2875
|
+
fromX1,
|
|
2876
|
+
fromY1,
|
|
2877
|
+
fromX2,
|
|
2878
|
+
fromY2,
|
|
2879
|
+
toX1: next.x1,
|
|
2880
|
+
toY1: next.y1,
|
|
2881
|
+
toX2: next.x2,
|
|
2882
|
+
toY2: next.y2
|
|
2883
|
+
});
|
|
2717
2884
|
}
|
|
2718
|
-
const
|
|
2719
|
-
|
|
2720
|
-
const
|
|
2721
|
-
|
|
2722
|
-
|
|
2885
|
+
for (const [key, next] of nextByKey) {
|
|
2886
|
+
if (prevByKey.has(key)) continue;
|
|
2887
|
+
const el = dom.rule(key);
|
|
2888
|
+
if (!el) continue;
|
|
2889
|
+
tweens.push({
|
|
2890
|
+
tweenType: "rule",
|
|
2891
|
+
kind: "enter",
|
|
2892
|
+
el,
|
|
2893
|
+
fromX1: next.x1,
|
|
2894
|
+
fromY1: next.y1,
|
|
2895
|
+
fromX2: next.x2,
|
|
2896
|
+
fromY2: next.y2,
|
|
2897
|
+
toX1: next.x1,
|
|
2898
|
+
toY1: next.y1,
|
|
2899
|
+
toX2: next.x2,
|
|
2900
|
+
toY2: next.y2,
|
|
2901
|
+
fromOpacity: 0,
|
|
2902
|
+
toOpacity: 1
|
|
2903
|
+
});
|
|
2723
2904
|
}
|
|
2724
|
-
const
|
|
2725
|
-
|
|
2726
|
-
|
|
2727
|
-
|
|
2728
|
-
|
|
2729
|
-
|
|
2730
|
-
|
|
2731
|
-
|
|
2732
|
-
|
|
2733
|
-
|
|
2905
|
+
for (const [key, prev] of prevByKey) {
|
|
2906
|
+
if (nextByKey.has(key)) continue;
|
|
2907
|
+
const ghost = renderSingleMark(prev, 0);
|
|
2908
|
+
if (!ghost) continue;
|
|
2909
|
+
ghost.classList.add("oc-ghost");
|
|
2910
|
+
ghost.setAttribute("aria-hidden", "true");
|
|
2911
|
+
ghost.setAttribute("pointer-events", "none");
|
|
2912
|
+
ghost.removeAttribute("data-key");
|
|
2913
|
+
marksContainer.appendChild(ghost);
|
|
2914
|
+
ghosts.push(ghost);
|
|
2915
|
+
tweens.push({
|
|
2916
|
+
tweenType: "rule",
|
|
2917
|
+
kind: "exit",
|
|
2918
|
+
el: ghost,
|
|
2919
|
+
fromX1: prev.x1,
|
|
2920
|
+
fromY1: prev.y1,
|
|
2921
|
+
fromX2: prev.x2,
|
|
2922
|
+
fromY2: prev.y2,
|
|
2923
|
+
toX1: prev.x1,
|
|
2924
|
+
toY1: prev.y1,
|
|
2925
|
+
toX2: prev.x2,
|
|
2926
|
+
toY2: prev.y2,
|
|
2927
|
+
ghost,
|
|
2928
|
+
fromOpacity: 1,
|
|
2929
|
+
toOpacity: 0
|
|
2930
|
+
});
|
|
2734
2931
|
}
|
|
2735
|
-
tweens.push({
|
|
2736
|
-
tweenType: "canvasPoints",
|
|
2737
|
-
kind: "update",
|
|
2738
|
-
layer,
|
|
2739
|
-
soaIndex,
|
|
2740
|
-
fromCx,
|
|
2741
|
-
fromCy,
|
|
2742
|
-
fromR,
|
|
2743
|
-
toCx,
|
|
2744
|
-
toCy,
|
|
2745
|
-
toR,
|
|
2746
|
-
soaKeys,
|
|
2747
|
-
enterSoaIndex,
|
|
2748
|
-
exitCx,
|
|
2749
|
-
exitCy,
|
|
2750
|
-
exitR,
|
|
2751
|
-
exitFill
|
|
2752
|
-
});
|
|
2753
2932
|
}
|
|
2754
|
-
function
|
|
2755
|
-
const soa = tw.layer.state.marks;
|
|
2756
|
-
const easedUpdate = cubicOut(Math.min(elapsed / update.duration, 1));
|
|
2757
|
-
for (let s = 0; s < tw.soaIndex.length; s++) {
|
|
2758
|
-
const i = tw.soaIndex[s];
|
|
2759
|
-
soa.x[i] = tw.fromCx[s] + (tw.toCx[s] - tw.fromCx[s]) * easedUpdate;
|
|
2760
|
-
soa.y[i] = tw.fromCy[s] + (tw.toCy[s] - tw.fromCy[s]) * easedUpdate;
|
|
2761
|
-
soa.r[i] = tw.fromR[s] + (tw.toR[s] - tw.fromR[s]) * easedUpdate;
|
|
2762
|
-
}
|
|
2763
|
-
const alpha = tw.layer.state.enterAlpha;
|
|
2764
|
-
if (alpha && tw.enterSoaIndex.length > 0) {
|
|
2765
|
-
const tEnter = elapsed < enterDelay ? 0 : Math.min((elapsed - enterDelay) / enterDuration, 1);
|
|
2766
|
-
const easedEnter = cubicOut(tEnter);
|
|
2767
|
-
for (let e = 0; e < tw.enterSoaIndex.length; e++) {
|
|
2768
|
-
alpha[tw.enterSoaIndex[e]] = easedEnter;
|
|
2769
|
-
}
|
|
2770
|
-
}
|
|
2771
|
-
if (tw.exitCx.length > 0) {
|
|
2772
|
-
const easedExit = cubicOut(Math.min(elapsed / exit.duration, 1));
|
|
2773
|
-
tw.layer.state.exiting = {
|
|
2774
|
-
x: tw.exitCx,
|
|
2775
|
-
y: tw.exitCy,
|
|
2776
|
-
r: tw.exitR,
|
|
2777
|
-
fill: tw.exitFill,
|
|
2778
|
-
alpha: 1 - easedExit
|
|
2779
|
-
};
|
|
2780
|
-
}
|
|
2781
|
-
}
|
|
2782
|
-
function canvasGridlineAxes(layout) {
|
|
2783
|
-
return [
|
|
2784
|
-
{ axis: layout.axes.y, orient: "y" },
|
|
2785
|
-
{ axis: layout.axes.y2, orient: "y" },
|
|
2786
|
-
{ axis: layout.axes.x, orient: "x" }
|
|
2787
|
-
];
|
|
2788
|
-
}
|
|
2789
|
-
function axisEmitsGridlines(axis, orient) {
|
|
2790
|
-
if (!axis) return false;
|
|
2791
|
-
return !(orient === "y" && axis.orient === "right");
|
|
2792
|
-
}
|
|
2793
|
-
function buildCanvasGridlinesTween(prevLayout, nextLayout, layer, tweens) {
|
|
2794
|
-
const live = layer.state.gridlines;
|
|
2795
|
-
const index = [];
|
|
2796
|
-
const fromPos = [];
|
|
2797
|
-
const toPos = [];
|
|
2798
|
-
const fromAlpha = [];
|
|
2799
|
-
const toAlpha = [];
|
|
2800
|
-
const prevAxes = canvasGridlineAxes(prevLayout);
|
|
2801
|
-
const nextAxes = canvasGridlineAxes(nextLayout);
|
|
2802
|
-
let cursor = 0;
|
|
2803
|
-
for (let a = 0; a < nextAxes.length; a++) {
|
|
2804
|
-
const nextAxis = nextAxes[a].axis;
|
|
2805
|
-
const orient = nextAxes[a].orient;
|
|
2806
|
-
if (!axisEmitsGridlines(nextAxis, orient)) continue;
|
|
2807
|
-
const prevAxis = prevAxes[a].axis;
|
|
2808
|
-
const deltas = axisEmitsGridlines(prevAxis, orient) ? computeGridlineDeltas(prevAxis, nextAxis) : null;
|
|
2809
|
-
const valueAtPosition = /* @__PURE__ */ new Map();
|
|
2810
|
-
for (const tick of nextAxis.ticks) {
|
|
2811
|
-
valueAtPosition.set(tick.position, serializeKeyValue(tick.value));
|
|
2812
|
-
}
|
|
2813
|
-
for (const gridline of nextAxis.gridlines) {
|
|
2814
|
-
const slot = cursor++;
|
|
2815
|
-
if (slot >= live.length) break;
|
|
2816
|
-
const key = valueAtPosition.get(gridline.position);
|
|
2817
|
-
const prevPos = key !== void 0 ? deltas?.prevGridByValue.get(key) : void 0;
|
|
2818
|
-
index.push(slot);
|
|
2819
|
-
toPos.push(gridline.position);
|
|
2820
|
-
toAlpha.push(live[slot].alpha);
|
|
2821
|
-
if (prevPos !== void 0) {
|
|
2822
|
-
fromPos.push(prevPos);
|
|
2823
|
-
fromAlpha.push(live[slot].alpha);
|
|
2824
|
-
} else {
|
|
2825
|
-
fromPos.push(gridline.position);
|
|
2826
|
-
fromAlpha.push(0);
|
|
2827
|
-
}
|
|
2828
|
-
}
|
|
2829
|
-
}
|
|
2830
|
-
if (index.length === 0) return;
|
|
2831
|
-
tweens.push({
|
|
2832
|
-
tweenType: "canvasGridlines",
|
|
2833
|
-
kind: "update",
|
|
2834
|
-
layer,
|
|
2835
|
-
index: Uint32Array.from(index),
|
|
2836
|
-
fromPos: Float32Array.from(fromPos),
|
|
2837
|
-
toPos: Float32Array.from(toPos),
|
|
2838
|
-
fromAlpha: Float32Array.from(fromAlpha),
|
|
2839
|
-
toAlpha: Float32Array.from(toAlpha)
|
|
2840
|
-
});
|
|
2841
|
-
}
|
|
2842
|
-
function applyCanvasGridlinesState(tw, elapsed, update, enterDelay, enterDuration) {
|
|
2843
|
-
const live = tw.layer.state.gridlines;
|
|
2844
|
-
const easedUpdate = cubicOut(Math.min(elapsed / update.duration, 1));
|
|
2845
|
-
const tEnter = elapsed < enterDelay ? 0 : Math.min((elapsed - enterDelay) / enterDuration, 1);
|
|
2846
|
-
const easedEnter = cubicOut(tEnter);
|
|
2847
|
-
for (let i = 0; i < tw.index.length; i++) {
|
|
2848
|
-
const g = live[tw.index[i]];
|
|
2849
|
-
g.position = tw.fromPos[i] + (tw.toPos[i] - tw.fromPos[i]) * easedUpdate;
|
|
2850
|
-
const from = tw.fromAlpha[i];
|
|
2851
|
-
const to = tw.toAlpha[i];
|
|
2852
|
-
g.alpha = from === to ? to : from + (to - from) * easedEnter;
|
|
2853
|
-
}
|
|
2854
|
-
}
|
|
2855
|
-
function snapCanvasGridlinesToFinal(tw) {
|
|
2856
|
-
const live = tw.layer.state.gridlines;
|
|
2857
|
-
for (let i = 0; i < tw.index.length; i++) {
|
|
2858
|
-
const g = live[tw.index[i]];
|
|
2859
|
-
g.position = tw.toPos[i];
|
|
2860
|
-
g.alpha = tw.toAlpha[i];
|
|
2861
|
-
}
|
|
2862
|
-
}
|
|
2863
|
-
function snapCanvasPointsToFinal(tw) {
|
|
2864
|
-
const soa = tw.layer.state.marks;
|
|
2865
|
-
for (let s = 0; s < tw.soaIndex.length; s++) {
|
|
2866
|
-
const i = tw.soaIndex[s];
|
|
2867
|
-
soa.x[i] = tw.toCx[s];
|
|
2868
|
-
soa.y[i] = tw.toCy[s];
|
|
2869
|
-
soa.r[i] = tw.toR[s];
|
|
2870
|
-
}
|
|
2871
|
-
tw.layer.state.exiting = null;
|
|
2872
|
-
tw.layer.state.enterAlpha = null;
|
|
2873
|
-
}
|
|
2874
|
-
function buildRuleTweens(prevLayout, nextLayout, marksContainer, tweens, ghosts, fromSnapshot) {
|
|
2875
|
-
const prevRules = prevLayout.marks.filter((m) => m.type === "rule");
|
|
2876
|
-
const nextRules = nextLayout.marks.filter((m) => m.type === "rule");
|
|
2877
|
-
const prevByKey = /* @__PURE__ */ new Map();
|
|
2878
|
-
for (const m of prevRules) {
|
|
2879
|
-
if (m.key) prevByKey.set(m.key, m);
|
|
2880
|
-
}
|
|
2881
|
-
const nextByKey = /* @__PURE__ */ new Map();
|
|
2882
|
-
for (const m of nextRules) {
|
|
2883
|
-
if (m.key) nextByKey.set(m.key, m);
|
|
2884
|
-
}
|
|
2885
|
-
for (const [key, next] of nextByKey) {
|
|
2886
|
-
const prev = prevByKey.get(key);
|
|
2887
|
-
if (!prev) continue;
|
|
2888
|
-
const el = marksContainer.querySelector(
|
|
2889
|
-
`.oc-mark-rule[data-key="${key}"]`
|
|
2890
|
-
);
|
|
2891
|
-
if (!el) continue;
|
|
2892
|
-
let fromX1 = prev.x1;
|
|
2893
|
-
let fromY1 = prev.y1;
|
|
2894
|
-
let fromX2 = prev.x2;
|
|
2895
|
-
let fromY2 = prev.y2;
|
|
2896
|
-
const snap = fromSnapshot?.get(key);
|
|
2897
|
-
if (snap && snap.type === "rule") {
|
|
2898
|
-
fromX1 = snap.x1;
|
|
2899
|
-
fromY1 = snap.y1;
|
|
2900
|
-
fromX2 = snap.x2;
|
|
2901
|
-
fromY2 = snap.y2;
|
|
2902
|
-
}
|
|
2903
|
-
tweens.push({
|
|
2904
|
-
tweenType: "rule",
|
|
2905
|
-
kind: "update",
|
|
2906
|
-
el,
|
|
2907
|
-
fromX1,
|
|
2908
|
-
fromY1,
|
|
2909
|
-
fromX2,
|
|
2910
|
-
fromY2,
|
|
2911
|
-
toX1: next.x1,
|
|
2912
|
-
toY1: next.y1,
|
|
2913
|
-
toX2: next.x2,
|
|
2914
|
-
toY2: next.y2
|
|
2915
|
-
});
|
|
2916
|
-
}
|
|
2917
|
-
for (const [key, next] of nextByKey) {
|
|
2918
|
-
if (prevByKey.has(key)) continue;
|
|
2919
|
-
const el = marksContainer.querySelector(
|
|
2920
|
-
`.oc-mark-rule[data-key="${key}"]`
|
|
2921
|
-
);
|
|
2922
|
-
if (!el) continue;
|
|
2923
|
-
tweens.push({
|
|
2924
|
-
tweenType: "rule",
|
|
2925
|
-
kind: "enter",
|
|
2926
|
-
el,
|
|
2927
|
-
fromX1: next.x1,
|
|
2928
|
-
fromY1: next.y1,
|
|
2929
|
-
fromX2: next.x2,
|
|
2930
|
-
fromY2: next.y2,
|
|
2931
|
-
toX1: next.x1,
|
|
2932
|
-
toY1: next.y1,
|
|
2933
|
-
toX2: next.x2,
|
|
2934
|
-
toY2: next.y2,
|
|
2935
|
-
fromOpacity: 0,
|
|
2936
|
-
toOpacity: 1
|
|
2937
|
-
});
|
|
2938
|
-
}
|
|
2939
|
-
for (const [key, prev] of prevByKey) {
|
|
2940
|
-
if (nextByKey.has(key)) continue;
|
|
2941
|
-
const ghost = renderSingleMark(prev, 0);
|
|
2942
|
-
if (!ghost) continue;
|
|
2943
|
-
ghost.classList.add("oc-ghost");
|
|
2944
|
-
ghost.setAttribute("aria-hidden", "true");
|
|
2945
|
-
ghost.setAttribute("pointer-events", "none");
|
|
2946
|
-
ghost.removeAttribute("data-key");
|
|
2947
|
-
marksContainer.appendChild(ghost);
|
|
2948
|
-
ghosts.push(ghost);
|
|
2949
|
-
tweens.push({
|
|
2950
|
-
tweenType: "rule",
|
|
2951
|
-
kind: "exit",
|
|
2952
|
-
el: ghost,
|
|
2953
|
-
fromX1: prev.x1,
|
|
2954
|
-
fromY1: prev.y1,
|
|
2955
|
-
fromX2: prev.x2,
|
|
2956
|
-
fromY2: prev.y2,
|
|
2957
|
-
toX1: prev.x1,
|
|
2958
|
-
toY1: prev.y1,
|
|
2959
|
-
toX2: prev.x2,
|
|
2960
|
-
toY2: prev.y2,
|
|
2961
|
-
ghost,
|
|
2962
|
-
fromOpacity: 1,
|
|
2963
|
-
toOpacity: 0
|
|
2964
|
-
});
|
|
2965
|
-
}
|
|
2966
|
-
}
|
|
2967
|
-
function buildTickTweens(prevLayout, nextLayout, marksContainer, tweens, ghosts, fromSnapshot) {
|
|
2933
|
+
function buildTickTweens(prevLayout, nextLayout, marksContainer, dom, tweens, ghosts, fromSnapshot) {
|
|
2968
2934
|
const prevTicks = prevLayout.marks.filter((m) => m.type === "tick");
|
|
2969
2935
|
const nextTicks = nextLayout.marks.filter((m) => m.type === "tick");
|
|
2970
2936
|
const prevByKey = /* @__PURE__ */ new Map();
|
|
@@ -2985,9 +2951,7 @@ function buildTickTweens(prevLayout, nextLayout, marksContainer, tweens, ghosts,
|
|
|
2985
2951
|
for (const [key, next] of nextByKey) {
|
|
2986
2952
|
const prev = prevByKey.get(key);
|
|
2987
2953
|
if (!prev) continue;
|
|
2988
|
-
const el =
|
|
2989
|
-
`.oc-mark-tick[data-key="${key}"]`
|
|
2990
|
-
);
|
|
2954
|
+
const el = dom.tick(key);
|
|
2991
2955
|
if (!el) continue;
|
|
2992
2956
|
let pEnd = tickEndpoints(prev);
|
|
2993
2957
|
const nEnd = tickEndpoints(next);
|
|
@@ -3011,9 +2975,7 @@ function buildTickTweens(prevLayout, nextLayout, marksContainer, tweens, ghosts,
|
|
|
3011
2975
|
}
|
|
3012
2976
|
for (const [key, next] of nextByKey) {
|
|
3013
2977
|
if (prevByKey.has(key)) continue;
|
|
3014
|
-
const el =
|
|
3015
|
-
`.oc-mark-tick[data-key="${key}"]`
|
|
3016
|
-
);
|
|
2978
|
+
const el = dom.tick(key);
|
|
3017
2979
|
if (!el) continue;
|
|
3018
2980
|
const nEnd = tickEndpoints(next);
|
|
3019
2981
|
tweens.push({
|
|
@@ -3061,7 +3023,7 @@ function buildTickTweens(prevLayout, nextLayout, marksContainer, tweens, ghosts,
|
|
|
3061
3023
|
});
|
|
3062
3024
|
}
|
|
3063
3025
|
}
|
|
3064
|
-
function buildTextMarkTweens(prevLayout, nextLayout, marksContainer, tweens, ghosts, fromSnapshot) {
|
|
3026
|
+
function buildTextMarkTweens(prevLayout, nextLayout, marksContainer, dom, tweens, ghosts, fromSnapshot) {
|
|
3065
3027
|
const prevTexts = prevLayout.marks.filter((m) => m.type === "textMark");
|
|
3066
3028
|
const nextTexts = nextLayout.marks.filter((m) => m.type === "textMark");
|
|
3067
3029
|
const prevByKey = /* @__PURE__ */ new Map();
|
|
@@ -3075,9 +3037,7 @@ function buildTextMarkTweens(prevLayout, nextLayout, marksContainer, tweens, gho
|
|
|
3075
3037
|
for (const [key, next] of nextByKey) {
|
|
3076
3038
|
const prev = prevByKey.get(key);
|
|
3077
3039
|
if (!prev) continue;
|
|
3078
|
-
const el =
|
|
3079
|
-
`.oc-mark-text[data-key="${key}"]`
|
|
3080
|
-
);
|
|
3040
|
+
const el = dom.text(key);
|
|
3081
3041
|
if (!el) continue;
|
|
3082
3042
|
let fromX = prev.x;
|
|
3083
3043
|
let fromY = prev.y;
|
|
@@ -3098,9 +3058,7 @@ function buildTextMarkTweens(prevLayout, nextLayout, marksContainer, tweens, gho
|
|
|
3098
3058
|
}
|
|
3099
3059
|
for (const [key, next] of nextByKey) {
|
|
3100
3060
|
if (prevByKey.has(key)) continue;
|
|
3101
|
-
const el =
|
|
3102
|
-
`.oc-mark-text[data-key="${key}"]`
|
|
3103
|
-
);
|
|
3061
|
+
const el = dom.text(key);
|
|
3104
3062
|
if (!el) continue;
|
|
3105
3063
|
tweens.push({
|
|
3106
3064
|
tweenType: "textMark",
|
|
@@ -3138,243 +3096,322 @@ function buildTextMarkTweens(prevLayout, nextLayout, marksContainer, tweens, gho
|
|
|
3138
3096
|
});
|
|
3139
3097
|
}
|
|
3140
3098
|
}
|
|
3141
|
-
|
|
3142
|
-
|
|
3143
|
-
|
|
3144
|
-
|
|
3145
|
-
|
|
3146
|
-
}
|
|
3147
|
-
|
|
3148
|
-
|
|
3149
|
-
|
|
3150
|
-
|
|
3151
|
-
|
|
3152
|
-
|
|
3153
|
-
|
|
3154
|
-
|
|
3155
|
-
|
|
3099
|
+
|
|
3100
|
+
// src/transition/driver.ts
|
|
3101
|
+
function runTransition(args) {
|
|
3102
|
+
const { svg, prevLayout, nextLayout, animation, onComplete, fromSnapshot, manual, canvas } = args;
|
|
3103
|
+
const update = animation.update;
|
|
3104
|
+
const exit = animation.exit ?? { ...EXIT_DEFAULTS };
|
|
3105
|
+
const totalMs = Math.max(update.duration, exit.duration);
|
|
3106
|
+
const enterDelay = 0.4 * update.duration;
|
|
3107
|
+
const enterDuration = update.duration - enterDelay;
|
|
3108
|
+
const marksContainer = svg.querySelector(".oc-marks");
|
|
3109
|
+
if (!marksContainer) {
|
|
3110
|
+
onComplete();
|
|
3111
|
+
return {
|
|
3112
|
+
cancel() {
|
|
3113
|
+
},
|
|
3114
|
+
get running() {
|
|
3115
|
+
return false;
|
|
3116
|
+
},
|
|
3117
|
+
snapshot() {
|
|
3118
|
+
return /* @__PURE__ */ new Map();
|
|
3119
|
+
},
|
|
3120
|
+
step() {
|
|
3121
|
+
return false;
|
|
3122
|
+
},
|
|
3123
|
+
totalMs: 0
|
|
3124
|
+
};
|
|
3156
3125
|
}
|
|
3157
|
-
|
|
3158
|
-
|
|
3159
|
-
|
|
3160
|
-
|
|
3161
|
-
|
|
3162
|
-
|
|
3163
|
-
|
|
3164
|
-
|
|
3165
|
-
|
|
3166
|
-
|
|
3167
|
-
|
|
3168
|
-
|
|
3169
|
-
|
|
3170
|
-
|
|
3171
|
-
|
|
3172
|
-
attr,
|
|
3173
|
-
from,
|
|
3174
|
-
to
|
|
3175
|
-
});
|
|
3126
|
+
const dom = buildMarkDomIndex(marksContainer);
|
|
3127
|
+
const tweens = [];
|
|
3128
|
+
const ghosts = [];
|
|
3129
|
+
const defs = svg.querySelector("defs");
|
|
3130
|
+
let ghostGradientMap = /* @__PURE__ */ new Map();
|
|
3131
|
+
if (defs) {
|
|
3132
|
+
const nextKeySet = new Set(nextLayout.marks.filter((m) => m.key).map((m) => m.key));
|
|
3133
|
+
const exitingMarks = prevLayout.marks.filter(
|
|
3134
|
+
(m) => m.key && !nextKeySet.has(m.key) && "fill" in m
|
|
3135
|
+
);
|
|
3136
|
+
const gradientMarks = exitingMarks.filter(
|
|
3137
|
+
(m) => "fill" in m && isGradientDef(m.fill)
|
|
3138
|
+
);
|
|
3139
|
+
if (gradientMarks.length > 0) {
|
|
3140
|
+
ghostGradientMap = buildGradientDefs(gradientMarks, defs);
|
|
3176
3141
|
}
|
|
3177
3142
|
}
|
|
3178
|
-
|
|
3179
|
-
|
|
3180
|
-
const
|
|
3181
|
-
const
|
|
3182
|
-
|
|
3183
|
-
const
|
|
3184
|
-
|
|
3185
|
-
|
|
3186
|
-
|
|
3187
|
-
|
|
3188
|
-
|
|
3189
|
-
|
|
3190
|
-
|
|
3191
|
-
|
|
3192
|
-
|
|
3193
|
-
|
|
3194
|
-
|
|
3195
|
-
|
|
3196
|
-
el,
|
|
3197
|
-
fromDx: 0,
|
|
3198
|
-
fromDy: 0,
|
|
3199
|
-
fromOpacity: 0,
|
|
3200
|
-
toOpacity: 1
|
|
3201
|
-
});
|
|
3202
|
-
continue;
|
|
3203
|
-
}
|
|
3204
|
-
const dx = (before.label?.x ?? 0) - (next[i].label?.x ?? 0);
|
|
3205
|
-
const dy = (before.label?.y ?? 0) - (next[i].label?.y ?? 0);
|
|
3206
|
-
if (dx === 0 && dy === 0) continue;
|
|
3207
|
-
tweens.push({
|
|
3208
|
-
tweenType: "annotation",
|
|
3209
|
-
kind: "update",
|
|
3210
|
-
el,
|
|
3211
|
-
fromDx: dx,
|
|
3212
|
-
fromDy: dy
|
|
3213
|
-
});
|
|
3143
|
+
const hasRects = prevLayout.marks.some((m) => m.type === "rect") || nextLayout.marks.some((m) => m.type === "rect");
|
|
3144
|
+
const hasLines = prevLayout.marks.some((m) => m.type === "line") || nextLayout.marks.some((m) => m.type === "line");
|
|
3145
|
+
const hasAreas = prevLayout.marks.some((m) => m.type === "area") || nextLayout.marks.some((m) => m.type === "area");
|
|
3146
|
+
const hasPoints = prevLayout.marks.some((m) => m.type === "point") || nextLayout.marks.some((m) => m.type === "point");
|
|
3147
|
+
const hasRules = prevLayout.marks.some((m) => m.type === "rule") || nextLayout.marks.some((m) => m.type === "rule");
|
|
3148
|
+
const hasTicks = prevLayout.marks.some((m) => m.type === "tick") || nextLayout.marks.some((m) => m.type === "tick");
|
|
3149
|
+
const hasTextMarks = prevLayout.marks.some((m) => m.type === "textMark") || nextLayout.marks.some((m) => m.type === "textMark");
|
|
3150
|
+
if (hasRects) {
|
|
3151
|
+
buildRectTweens(
|
|
3152
|
+
prevLayout,
|
|
3153
|
+
nextLayout,
|
|
3154
|
+
marksContainer,
|
|
3155
|
+
dom,
|
|
3156
|
+
tweens,
|
|
3157
|
+
ghosts,
|
|
3158
|
+
ghostGradientMap,
|
|
3159
|
+
fromSnapshot
|
|
3160
|
+
);
|
|
3214
3161
|
}
|
|
3215
|
-
|
|
3216
|
-
|
|
3217
|
-
buildSingleAxisTweens(svg, prevLayout.axes.x, nextLayout.axes.x, "x", nextLayout, tweens, ghosts);
|
|
3218
|
-
buildSingleAxisTweens(svg, prevLayout.axes.y, nextLayout.axes.y, "y", nextLayout, tweens, ghosts);
|
|
3219
|
-
}
|
|
3220
|
-
function computeGridlineDeltas(prevAxis, nextAxis) {
|
|
3221
|
-
const byValue = (axis) => {
|
|
3222
|
-
const map = /* @__PURE__ */ new Map();
|
|
3223
|
-
for (const tick of axis.ticks) {
|
|
3224
|
-
const matching = axis.gridlines.find((g) => g.position === tick.position);
|
|
3225
|
-
if (matching) map.set(serializeKeyValue(tick.value), matching.position);
|
|
3226
|
-
}
|
|
3227
|
-
return map;
|
|
3228
|
-
};
|
|
3229
|
-
return { prevGridByValue: byValue(prevAxis), nextGridByValue: byValue(nextAxis) };
|
|
3230
|
-
}
|
|
3231
|
-
function buildSingleAxisTweens(svg, prevAxis, nextAxis, orientation, layout, tweens, ghosts) {
|
|
3232
|
-
if (!prevAxis || !nextAxis) return;
|
|
3233
|
-
const axisClass = `oc-axis-${orientation}`;
|
|
3234
|
-
const axisGroup = svg.querySelector(`.${axisClass}`);
|
|
3235
|
-
if (!axisGroup) return;
|
|
3236
|
-
const isRotated = !!(nextAxis.tickAngle && Math.abs(nextAxis.tickAngle) > 10);
|
|
3237
|
-
const prevTickMap = /* @__PURE__ */ new Map();
|
|
3238
|
-
for (const tick of prevAxis.ticks) {
|
|
3239
|
-
prevTickMap.set(serializeKeyValue(tick.value), tick.position);
|
|
3162
|
+
if (hasLines) {
|
|
3163
|
+
buildLineTweens(prevLayout, nextLayout, marksContainer, dom, tweens, ghosts, fromSnapshot);
|
|
3240
3164
|
}
|
|
3241
|
-
|
|
3242
|
-
|
|
3243
|
-
|
|
3165
|
+
if (hasAreas) {
|
|
3166
|
+
buildAreaTweens(
|
|
3167
|
+
prevLayout,
|
|
3168
|
+
nextLayout,
|
|
3169
|
+
marksContainer,
|
|
3170
|
+
dom,
|
|
3171
|
+
tweens,
|
|
3172
|
+
ghosts,
|
|
3173
|
+
ghostGradientMap,
|
|
3174
|
+
fromSnapshot
|
|
3175
|
+
);
|
|
3244
3176
|
}
|
|
3245
|
-
|
|
3246
|
-
|
|
3247
|
-
|
|
3248
|
-
|
|
3249
|
-
|
|
3250
|
-
|
|
3251
|
-
|
|
3252
|
-
|
|
3253
|
-
|
|
3254
|
-
|
|
3255
|
-
|
|
3256
|
-
|
|
3257
|
-
|
|
3258
|
-
|
|
3259
|
-
posAttr,
|
|
3260
|
-
fromPos: prevPos,
|
|
3261
|
-
toPos: nextPos,
|
|
3262
|
-
crossfade: isRotated
|
|
3263
|
-
});
|
|
3264
|
-
} else if (prevPos === void 0 && nextPos !== void 0) {
|
|
3265
|
-
matchedNextKeys.add(key);
|
|
3266
|
-
tweens.push({
|
|
3267
|
-
tweenType: "axisTick",
|
|
3268
|
-
kind: "enter",
|
|
3269
|
-
el: labelEl,
|
|
3270
|
-
posAttr,
|
|
3271
|
-
fromPos: nextPos,
|
|
3272
|
-
toPos: nextPos,
|
|
3273
|
-
crossfade: false,
|
|
3274
|
-
fromOpacity: 0,
|
|
3275
|
-
toOpacity: 1
|
|
3276
|
-
});
|
|
3177
|
+
if (hasPoints) {
|
|
3178
|
+
if (canvas) {
|
|
3179
|
+
buildCanvasPointsTween(prevLayout, nextLayout, canvas, tweens, fromSnapshot);
|
|
3180
|
+
} else {
|
|
3181
|
+
buildPointTweens(
|
|
3182
|
+
prevLayout,
|
|
3183
|
+
nextLayout,
|
|
3184
|
+
marksContainer,
|
|
3185
|
+
dom,
|
|
3186
|
+
tweens,
|
|
3187
|
+
ghosts,
|
|
3188
|
+
ghostGradientMap,
|
|
3189
|
+
fromSnapshot
|
|
3190
|
+
);
|
|
3277
3191
|
}
|
|
3278
3192
|
}
|
|
3279
|
-
|
|
3280
|
-
|
|
3281
|
-
|
|
3282
|
-
|
|
3283
|
-
|
|
3284
|
-
|
|
3285
|
-
|
|
3286
|
-
|
|
3287
|
-
|
|
3288
|
-
|
|
3289
|
-
|
|
3290
|
-
|
|
3291
|
-
|
|
3292
|
-
|
|
3293
|
-
|
|
3294
|
-
|
|
3193
|
+
if (hasRules) {
|
|
3194
|
+
buildRuleTweens(prevLayout, nextLayout, marksContainer, dom, tweens, ghosts, fromSnapshot);
|
|
3195
|
+
}
|
|
3196
|
+
if (hasTicks) {
|
|
3197
|
+
buildTickTweens(prevLayout, nextLayout, marksContainer, dom, tweens, ghosts, fromSnapshot);
|
|
3198
|
+
}
|
|
3199
|
+
if (hasTextMarks) {
|
|
3200
|
+
buildTextMarkTweens(prevLayout, nextLayout, marksContainer, dom, tweens, ghosts, fromSnapshot);
|
|
3201
|
+
}
|
|
3202
|
+
buildAxisTweens(svg, prevLayout, nextLayout, tweens, ghosts);
|
|
3203
|
+
if (canvas) {
|
|
3204
|
+
buildCanvasGridlinesTween(prevLayout, nextLayout, canvas, tweens);
|
|
3205
|
+
}
|
|
3206
|
+
buildColorTweens(prevLayout, nextLayout, dom, tweens);
|
|
3207
|
+
buildAnnotationTweens(svg, prevLayout, nextLayout, tweens);
|
|
3208
|
+
const secondaryEls = collectSecondaryElements(svg);
|
|
3209
|
+
const secondaryOriginalOpacity = secondaryEls.map((el) => el.style.opacity ?? "");
|
|
3210
|
+
for (const tw of tweens) {
|
|
3211
|
+
applyTweenState(tw, 0, update, exit, enterDelay, enterDuration);
|
|
3212
|
+
}
|
|
3213
|
+
canvas?.repaint();
|
|
3214
|
+
canvas?.setInteractionSuspended(true);
|
|
3215
|
+
for (const el of secondaryEls) {
|
|
3216
|
+
el.style.opacity = "0";
|
|
3217
|
+
}
|
|
3218
|
+
let rafId = null;
|
|
3219
|
+
let running = true;
|
|
3220
|
+
let startTime = null;
|
|
3221
|
+
let lastElapsed = 0;
|
|
3222
|
+
const nextLineMarks = nextLayout.marks.filter((m) => m.type === "line");
|
|
3223
|
+
const nextAreaMarks = nextLayout.marks.filter((m) => m.type === "area");
|
|
3224
|
+
function tick(now) {
|
|
3225
|
+
if (!running) return;
|
|
3226
|
+
if (startTime === null) startTime = now;
|
|
3227
|
+
const elapsed = now - startTime;
|
|
3228
|
+
lastElapsed = elapsed;
|
|
3229
|
+
const tGlobal = Math.min(elapsed / totalMs, 1);
|
|
3230
|
+
for (const tw of tweens) {
|
|
3231
|
+
applyTweenState(tw, elapsed, update, exit, enterDelay, enterDuration);
|
|
3232
|
+
}
|
|
3233
|
+
applySecondaryOpacity(secondaryEls, elapsed, enterDelay, enterDuration);
|
|
3234
|
+
canvas?.repaint();
|
|
3235
|
+
if (tGlobal >= 1) {
|
|
3236
|
+
finish();
|
|
3295
3237
|
} else {
|
|
3296
|
-
|
|
3297
|
-
|
|
3298
|
-
|
|
3299
|
-
|
|
3300
|
-
|
|
3238
|
+
rafId = requestAnimationFrame(tick);
|
|
3239
|
+
}
|
|
3240
|
+
}
|
|
3241
|
+
function settleCanvas() {
|
|
3242
|
+
if (!canvas) return;
|
|
3243
|
+
canvas.repaint();
|
|
3244
|
+
canvas.rebuildIndex();
|
|
3245
|
+
canvas.setInteractionSuspended(false);
|
|
3246
|
+
}
|
|
3247
|
+
function finish() {
|
|
3248
|
+
if (!running) return;
|
|
3249
|
+
running = false;
|
|
3250
|
+
rafId = null;
|
|
3251
|
+
snapToFinal();
|
|
3252
|
+
removeGhosts();
|
|
3253
|
+
settleCanvas();
|
|
3254
|
+
for (let i = 0; i < secondaryEls.length; i++) {
|
|
3255
|
+
secondaryEls[i].style.opacity = secondaryOriginalOpacity[i];
|
|
3256
|
+
}
|
|
3257
|
+
onComplete();
|
|
3258
|
+
}
|
|
3259
|
+
function snapToFinal() {
|
|
3260
|
+
for (const tw of tweens) {
|
|
3261
|
+
snapTweenToFinal(tw);
|
|
3262
|
+
}
|
|
3263
|
+
for (const mark of nextLineMarks) {
|
|
3264
|
+
if (!mark.key) continue;
|
|
3265
|
+
const el = dom.any(mark.key);
|
|
3266
|
+
if (el) applyFinalLinePath(el, mark);
|
|
3267
|
+
}
|
|
3268
|
+
for (const mark of nextAreaMarks) {
|
|
3269
|
+
if (!mark.key) continue;
|
|
3270
|
+
const el = dom.any(mark.key);
|
|
3271
|
+
if (el) applyFinalAreaPaths(el, mark);
|
|
3301
3272
|
}
|
|
3302
|
-
axisGroup.appendChild(ghost);
|
|
3303
|
-
ghosts.push(ghost);
|
|
3304
|
-
tweens.push({
|
|
3305
|
-
tweenType: "axisTick",
|
|
3306
|
-
kind: "exit",
|
|
3307
|
-
el: ghost,
|
|
3308
|
-
posAttr,
|
|
3309
|
-
fromPos: prevPos,
|
|
3310
|
-
toPos: prevPos,
|
|
3311
|
-
crossfade: false,
|
|
3312
|
-
ghost,
|
|
3313
|
-
fromOpacity: 1,
|
|
3314
|
-
toOpacity: 0
|
|
3315
|
-
});
|
|
3316
3273
|
}
|
|
3317
|
-
|
|
3318
|
-
|
|
3319
|
-
|
|
3320
|
-
const key = glEl.getAttribute("data-tick-key");
|
|
3321
|
-
if (!key) continue;
|
|
3322
|
-
const nextPos = nextGridByValue.get(key);
|
|
3323
|
-
const prevPos = prevGridByValue.get(key);
|
|
3324
|
-
if (prevPos !== void 0 && nextPos !== void 0) {
|
|
3325
|
-
tweens.push({
|
|
3326
|
-
tweenType: "gridline",
|
|
3327
|
-
kind: "update",
|
|
3328
|
-
el: glEl,
|
|
3329
|
-
orientation,
|
|
3330
|
-
fromPos: prevPos,
|
|
3331
|
-
toPos: nextPos
|
|
3332
|
-
});
|
|
3333
|
-
} else if (prevPos === void 0 && nextPos !== void 0) {
|
|
3334
|
-
tweens.push({
|
|
3335
|
-
tweenType: "gridline",
|
|
3336
|
-
kind: "enter",
|
|
3337
|
-
el: glEl,
|
|
3338
|
-
orientation,
|
|
3339
|
-
fromPos: nextPos,
|
|
3340
|
-
toPos: nextPos,
|
|
3341
|
-
fromOpacity: 0,
|
|
3342
|
-
toOpacity: 1
|
|
3343
|
-
});
|
|
3274
|
+
function removeGhosts() {
|
|
3275
|
+
for (const ghost of ghosts) {
|
|
3276
|
+
ghost.parentNode?.removeChild(ghost);
|
|
3344
3277
|
}
|
|
3345
3278
|
}
|
|
3346
|
-
|
|
3347
|
-
|
|
3348
|
-
const
|
|
3349
|
-
|
|
3350
|
-
|
|
3351
|
-
|
|
3352
|
-
|
|
3353
|
-
|
|
3354
|
-
|
|
3355
|
-
|
|
3356
|
-
|
|
3357
|
-
|
|
3358
|
-
|
|
3359
|
-
|
|
3360
|
-
|
|
3361
|
-
|
|
3362
|
-
|
|
3363
|
-
|
|
3279
|
+
function captureSnapshot() {
|
|
3280
|
+
const snap = /* @__PURE__ */ new Map();
|
|
3281
|
+
const tUpdate = Math.min(lastElapsed / update.duration, 1);
|
|
3282
|
+
const easedUpdate = cubicOut(tUpdate);
|
|
3283
|
+
for (const tw of tweens) {
|
|
3284
|
+
if (tw.kind !== "update") continue;
|
|
3285
|
+
if (tw.tweenType === "canvasPoints") {
|
|
3286
|
+
for (let s = 0; s < tw.soaIndex.length; s++) {
|
|
3287
|
+
snap.set(tw.soaKeys[s], {
|
|
3288
|
+
type: "point",
|
|
3289
|
+
cx: tw.fromCx[s] + (tw.toCx[s] - tw.fromCx[s]) * easedUpdate,
|
|
3290
|
+
cy: tw.fromCy[s] + (tw.toCy[s] - tw.fromCy[s]) * easedUpdate,
|
|
3291
|
+
r: tw.fromR[s] + (tw.toR[s] - tw.fromR[s]) * easedUpdate
|
|
3292
|
+
});
|
|
3293
|
+
}
|
|
3294
|
+
continue;
|
|
3295
|
+
}
|
|
3296
|
+
const key = getKeyForTween(tw);
|
|
3297
|
+
if (!key) continue;
|
|
3298
|
+
switch (tw.tweenType) {
|
|
3299
|
+
case "rect": {
|
|
3300
|
+
const g = lerpGeom(tw.from, tw.to, easedUpdate);
|
|
3301
|
+
snap.set(key, { type: "rect", ...g });
|
|
3302
|
+
break;
|
|
3303
|
+
}
|
|
3304
|
+
case "point": {
|
|
3305
|
+
const cx = tw.fromCx + (tw.toCx - tw.fromCx) * easedUpdate;
|
|
3306
|
+
const cy = tw.fromCy + (tw.toCy - tw.fromCy) * easedUpdate;
|
|
3307
|
+
const entry = { type: "point", cx, cy };
|
|
3308
|
+
if (tw.fromR !== void 0 && tw.toR !== void 0) {
|
|
3309
|
+
entry.r = tw.fromR + (tw.toR - tw.fromR) * easedUpdate;
|
|
3310
|
+
}
|
|
3311
|
+
snap.set(key, entry);
|
|
3312
|
+
break;
|
|
3313
|
+
}
|
|
3314
|
+
case "rule":
|
|
3315
|
+
case "tick": {
|
|
3316
|
+
snap.set(key, {
|
|
3317
|
+
type: tw.tweenType,
|
|
3318
|
+
x1: tw.fromX1 + (tw.toX1 - tw.fromX1) * easedUpdate,
|
|
3319
|
+
y1: tw.fromY1 + (tw.toY1 - tw.fromY1) * easedUpdate,
|
|
3320
|
+
x2: tw.fromX2 + (tw.toX2 - tw.fromX2) * easedUpdate,
|
|
3321
|
+
y2: tw.fromY2 + (tw.toY2 - tw.fromY2) * easedUpdate
|
|
3322
|
+
});
|
|
3323
|
+
break;
|
|
3324
|
+
}
|
|
3325
|
+
case "textMark": {
|
|
3326
|
+
snap.set(key, {
|
|
3327
|
+
type: "textMark",
|
|
3328
|
+
x: tw.fromX + (tw.toX - tw.fromX) * easedUpdate,
|
|
3329
|
+
y: tw.fromY + (tw.toY - tw.fromY) * easedUpdate
|
|
3330
|
+
});
|
|
3331
|
+
break;
|
|
3332
|
+
}
|
|
3333
|
+
case "line": {
|
|
3334
|
+
const pts = interpolatePoints(tw.fromPts, tw.toPts, easedUpdate);
|
|
3335
|
+
const d = buildLinePath2(pts, tw.interpolate);
|
|
3336
|
+
snap.set(key, { type: "line", d });
|
|
3337
|
+
break;
|
|
3338
|
+
}
|
|
3339
|
+
case "area": {
|
|
3340
|
+
const top = interpolatePoints(tw.fromTop, tw.toTop, easedUpdate);
|
|
3341
|
+
const bottom = interpolatePoints(tw.fromBottom, tw.toBottom, easedUpdate);
|
|
3342
|
+
const d = buildAreaPath2(top, bottom, tw.interpolate);
|
|
3343
|
+
let topD;
|
|
3344
|
+
if (tw.hasStroke) {
|
|
3345
|
+
topD = buildLinePath2(top, tw.interpolate);
|
|
3346
|
+
}
|
|
3347
|
+
snap.set(key, { type: "area", d, topD });
|
|
3348
|
+
break;
|
|
3349
|
+
}
|
|
3350
|
+
}
|
|
3364
3351
|
}
|
|
3365
|
-
|
|
3366
|
-
|
|
3367
|
-
|
|
3368
|
-
|
|
3369
|
-
|
|
3370
|
-
|
|
3371
|
-
|
|
3372
|
-
|
|
3373
|
-
|
|
3374
|
-
|
|
3375
|
-
|
|
3376
|
-
|
|
3377
|
-
|
|
3352
|
+
return snap;
|
|
3353
|
+
}
|
|
3354
|
+
if (!manual) {
|
|
3355
|
+
rafId = requestAnimationFrame(tick);
|
|
3356
|
+
}
|
|
3357
|
+
return {
|
|
3358
|
+
cancel() {
|
|
3359
|
+
if (!running) return;
|
|
3360
|
+
running = false;
|
|
3361
|
+
if (rafId !== null) {
|
|
3362
|
+
cancelAnimationFrame(rafId);
|
|
3363
|
+
rafId = null;
|
|
3364
|
+
}
|
|
3365
|
+
snapToFinal();
|
|
3366
|
+
removeGhosts();
|
|
3367
|
+
settleCanvas();
|
|
3368
|
+
for (let i = 0; i < secondaryEls.length; i++) {
|
|
3369
|
+
secondaryEls[i].style.opacity = secondaryOriginalOpacity[i];
|
|
3370
|
+
}
|
|
3371
|
+
},
|
|
3372
|
+
get running() {
|
|
3373
|
+
return running;
|
|
3374
|
+
},
|
|
3375
|
+
snapshot() {
|
|
3376
|
+
return captureSnapshot();
|
|
3377
|
+
},
|
|
3378
|
+
step(elapsedMs) {
|
|
3379
|
+
lastElapsed = elapsedMs;
|
|
3380
|
+
for (const tw of tweens) {
|
|
3381
|
+
applyTweenState(tw, elapsedMs, update, exit, enterDelay, enterDuration);
|
|
3382
|
+
}
|
|
3383
|
+
applySecondaryOpacity(secondaryEls, elapsedMs, enterDelay, enterDuration);
|
|
3384
|
+
if (elapsedMs >= totalMs) {
|
|
3385
|
+
snapToFinal();
|
|
3386
|
+
removeGhosts();
|
|
3387
|
+
settleCanvas();
|
|
3388
|
+
return false;
|
|
3389
|
+
}
|
|
3390
|
+
canvas?.repaint();
|
|
3391
|
+
return true;
|
|
3392
|
+
},
|
|
3393
|
+
totalMs
|
|
3394
|
+
};
|
|
3395
|
+
}
|
|
3396
|
+
function collectSecondaryElements(svg) {
|
|
3397
|
+
const els = [];
|
|
3398
|
+
const epLabels = svg.querySelector(".oc-endpoint-labels");
|
|
3399
|
+
if (epLabels) els.push(epLabels);
|
|
3400
|
+
const markLabels = svg.querySelector(".oc-mark-labels");
|
|
3401
|
+
if (markLabels) els.push(markLabels);
|
|
3402
|
+
return els;
|
|
3403
|
+
}
|
|
3404
|
+
function applySecondaryOpacity(els, elapsed, enterDelay, enterDuration) {
|
|
3405
|
+
if (els.length === 0) return;
|
|
3406
|
+
let t;
|
|
3407
|
+
if (elapsed < enterDelay) {
|
|
3408
|
+
t = 0;
|
|
3409
|
+
} else {
|
|
3410
|
+
t = Math.min((elapsed - enterDelay) / enterDuration, 1);
|
|
3411
|
+
}
|
|
3412
|
+
const opacity = String(cubicOut(t));
|
|
3413
|
+
for (const el of els) {
|
|
3414
|
+
el.style.opacity = opacity;
|
|
3378
3415
|
}
|
|
3379
3416
|
}
|
|
3380
3417
|
|
|
@@ -5162,6 +5199,16 @@ function scheduleFontReload(fontFamily, isAlive, onReady) {
|
|
|
5162
5199
|
return true;
|
|
5163
5200
|
}
|
|
5164
5201
|
|
|
5202
|
+
// src/resolve-dark-mode.ts
|
|
5203
|
+
function resolveDarkMode(mode) {
|
|
5204
|
+
if (mode === "force") return true;
|
|
5205
|
+
if (mode === "off" || mode === void 0) return false;
|
|
5206
|
+
if (typeof window !== "undefined" && window.matchMedia) {
|
|
5207
|
+
return window.matchMedia("(prefers-color-scheme: dark)").matches;
|
|
5208
|
+
}
|
|
5209
|
+
return false;
|
|
5210
|
+
}
|
|
5211
|
+
|
|
5165
5212
|
// src/scatter-canvas/interactions.ts
|
|
5166
5213
|
var HIT_TOLERANCE_MOUSE = 8;
|
|
5167
5214
|
var HIT_TOLERANCE_TOUCH = 24;
|
|
@@ -5694,15 +5741,8 @@ var SpatialIndex = class {
|
|
|
5694
5741
|
};
|
|
5695
5742
|
|
|
5696
5743
|
// src/motion/tween.ts
|
|
5697
|
-
function cubicOut2(t) {
|
|
5698
|
-
const f = 1 - t;
|
|
5699
|
-
return 1 - f * f * f;
|
|
5700
|
-
}
|
|
5701
|
-
function cubicInOut(t) {
|
|
5702
|
-
return t < 0.5 ? 4 * t * t * t : 1 - (-2 * t + 2) ** 3 / 2;
|
|
5703
|
-
}
|
|
5704
5744
|
function resolveEase(ease) {
|
|
5705
|
-
return ease === "snappy" ?
|
|
5745
|
+
return ease === "snappy" ? cubicOut : cubicInOut;
|
|
5706
5746
|
}
|
|
5707
5747
|
function prefersReducedMotion() {
|
|
5708
5748
|
if (typeof window === "undefined" || typeof window.matchMedia !== "function") return false;
|
|
@@ -6218,14 +6258,6 @@ function stampThemeProperties(el, theme) {
|
|
|
6218
6258
|
|
|
6219
6259
|
// src/mount.ts
|
|
6220
6260
|
var FALLBACK_HEIGHT = 400;
|
|
6221
|
-
function resolveDarkMode(mode) {
|
|
6222
|
-
if (mode === "force") return true;
|
|
6223
|
-
if (mode === "off" || mode === void 0) return false;
|
|
6224
|
-
if (typeof window !== "undefined" && window.matchMedia) {
|
|
6225
|
-
return window.matchMedia("(prefers-color-scheme: dark)").matches;
|
|
6226
|
-
}
|
|
6227
|
-
return false;
|
|
6228
|
-
}
|
|
6229
6261
|
var EDITABLE_HOVER_CSS = `
|
|
6230
6262
|
.oc-editable-hover {
|
|
6231
6263
|
outline: 1.5px solid ${cssTokenDefault2("--oc-editable-hover", "light")};
|
|
@@ -6316,6 +6348,7 @@ function createChart(container, spec, options) {
|
|
|
6316
6348
|
height,
|
|
6317
6349
|
theme: options?.theme,
|
|
6318
6350
|
darkMode,
|
|
6351
|
+
renderer: options?.renderer,
|
|
6319
6352
|
watermark: options?.watermark,
|
|
6320
6353
|
measureText
|
|
6321
6354
|
};
|
|
@@ -6753,7 +6786,7 @@ function createChart(container, spec, options) {
|
|
|
6753
6786
|
if (!warnedCanvasEditMode && (options?.editable || hasEditingCallbacks(options) || options?.onAnnotationEdit)) {
|
|
6754
6787
|
warnedCanvasEditMode = true;
|
|
6755
6788
|
console.warn(
|
|
6756
|
-
"openchart: canvas mark mode does not support per-mark edit selection. Annotation, chrome, and legend editing still work.
|
|
6789
|
+
"openchart: canvas mark mode does not support per-mark edit selection. Annotation, chrome, and legend editing still work. Pass renderer: 'svg' to createChart() if you need to select individual points."
|
|
6757
6790
|
);
|
|
6758
6791
|
}
|
|
6759
6792
|
}
|
|
@@ -7210,12 +7243,10 @@ function createChart(container, spec, options) {
|
|
|
7210
7243
|
}
|
|
7211
7244
|
|
|
7212
7245
|
// src/story/tween.ts
|
|
7213
|
-
var clamp01 = (t) => Math.min(1, Math.max(0, t));
|
|
7214
|
-
var lerp = (a, b, t) => a + (b - a) * t;
|
|
7215
7246
|
var easingFns = {
|
|
7216
|
-
linear
|
|
7217
|
-
easeOutCubic:
|
|
7218
|
-
easeInOutCubic:
|
|
7247
|
+
linear,
|
|
7248
|
+
easeOutCubic: cubicOut,
|
|
7249
|
+
easeInOutCubic: cubicInOut,
|
|
7219
7250
|
easeOutQuint: (t) => 1 - (1 - t) ** 5
|
|
7220
7251
|
};
|
|
7221
7252
|
var storyMotion = {
|
|
@@ -7327,7 +7358,7 @@ function scrubCamera(step, stepProgress, fitted, holdUntil, ease) {
|
|
|
7327
7358
|
}
|
|
7328
7359
|
|
|
7329
7360
|
// src/map-mount.ts
|
|
7330
|
-
import {
|
|
7361
|
+
import { compileGeoMap } from "@opendata-ai/openchart-engine";
|
|
7331
7362
|
|
|
7332
7363
|
// src/map-camera.ts
|
|
7333
7364
|
var FOCUS_DIM_OPACITY = 0.25;
|
|
@@ -7800,15 +7831,7 @@ function prefersReducedMotion2() {
|
|
|
7800
7831
|
return false;
|
|
7801
7832
|
}
|
|
7802
7833
|
}
|
|
7803
|
-
function
|
|
7804
|
-
if (mode === "force") return true;
|
|
7805
|
-
if (mode === "off" || mode === void 0) return false;
|
|
7806
|
-
if (typeof window !== "undefined" && window.matchMedia) {
|
|
7807
|
-
return window.matchMedia("(prefers-color-scheme: dark)").matches;
|
|
7808
|
-
}
|
|
7809
|
-
return false;
|
|
7810
|
-
}
|
|
7811
|
-
function createMap(container, spec, options) {
|
|
7834
|
+
function createGeoMap(container, spec, options) {
|
|
7812
7835
|
let currentSpec = spec;
|
|
7813
7836
|
let currentLayout;
|
|
7814
7837
|
let destroyed = false;
|
|
@@ -7845,7 +7868,7 @@ function createMap(container, spec, options) {
|
|
|
7845
7868
|
}
|
|
7846
7869
|
function compile() {
|
|
7847
7870
|
const { width, height } = getContainerDimensions();
|
|
7848
|
-
const darkMode =
|
|
7871
|
+
const darkMode = resolveDarkMode(options?.darkMode);
|
|
7849
7872
|
const compileOpts = {
|
|
7850
7873
|
width,
|
|
7851
7874
|
height,
|
|
@@ -7854,7 +7877,7 @@ function createMap(container, spec, options) {
|
|
|
7854
7877
|
watermark: options?.watermark,
|
|
7855
7878
|
measureText
|
|
7856
7879
|
};
|
|
7857
|
-
return
|
|
7880
|
+
return compileGeoMap(currentSpec, compileOpts);
|
|
7858
7881
|
}
|
|
7859
7882
|
function wireTooltipAndInteraction(svg, layout) {
|
|
7860
7883
|
const cleanups = [];
|
|
@@ -8219,7 +8242,7 @@ function createMap(container, spec, options) {
|
|
|
8219
8242
|
}
|
|
8220
8243
|
container.classList.remove("oc-map-root", "oc-dark");
|
|
8221
8244
|
}
|
|
8222
|
-
if (
|
|
8245
|
+
if (resolveDarkMode(options?.darkMode)) {
|
|
8223
8246
|
container.classList.add("oc-dark");
|
|
8224
8247
|
}
|
|
8225
8248
|
currentLayout = compile();
|
|
@@ -8305,12 +8328,15 @@ export {
|
|
|
8305
8328
|
resolveFontFamily,
|
|
8306
8329
|
scheduleFontReload,
|
|
8307
8330
|
observeResize,
|
|
8331
|
+
resolveDarkMode,
|
|
8308
8332
|
createTooltipManager,
|
|
8309
8333
|
VECTOR_EXPORT_MAX_POINTS,
|
|
8310
8334
|
materializeCanvasModeSVG,
|
|
8311
8335
|
AnimationScheduler,
|
|
8312
8336
|
quadtree,
|
|
8313
8337
|
SpatialIndex,
|
|
8338
|
+
clamp01,
|
|
8339
|
+
lerp,
|
|
8314
8340
|
resolveEase,
|
|
8315
8341
|
prefersReducedMotion,
|
|
8316
8342
|
createTween,
|
|
@@ -8321,8 +8347,6 @@ export {
|
|
|
8321
8347
|
canTransitionSpecShape,
|
|
8322
8348
|
createYouDrawIt,
|
|
8323
8349
|
createChart,
|
|
8324
|
-
clamp01,
|
|
8325
|
-
lerp,
|
|
8326
8350
|
easingFns,
|
|
8327
8351
|
storyMotion,
|
|
8328
8352
|
createTween2,
|
|
@@ -8334,6 +8358,6 @@ export {
|
|
|
8334
8358
|
dampCamera,
|
|
8335
8359
|
camerasClose,
|
|
8336
8360
|
scrubCamera,
|
|
8337
|
-
|
|
8361
|
+
createGeoMap
|
|
8338
8362
|
};
|
|
8339
|
-
//# sourceMappingURL=chunk-
|
|
8363
|
+
//# sourceMappingURL=chunk-ADWV256V.js.map
|