@primeui/chart-core 0.0.1-alpha.1
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/LICENSE +23 -0
- package/README.md +1 -0
- package/dist/animations/index.d.mts +136 -0
- package/dist/animations/index.mjs +18 -0
- package/dist/annotation.utils-Bm0lOO1o.d.mts +290 -0
- package/dist/borderRadius.utils-Cz73LLR_.d.mts +54 -0
- package/dist/canvas-D4vigq47.d.mts +34 -0
- package/dist/canvas.utils-D2WHi2gL.d.mts +167 -0
- package/dist/cartesian/index.d.mts +94 -0
- package/dist/cartesian/index.mjs +93 -0
- package/dist/chunk-22ST6YPP.mjs +304 -0
- package/dist/chunk-2QK2KOBN.mjs +10 -0
- package/dist/chunk-2QRS4YQ5.mjs +18 -0
- package/dist/chunk-3FFJEX4A.mjs +261 -0
- package/dist/chunk-3IYSJ2U7.mjs +567 -0
- package/dist/chunk-3OZLP4I4.mjs +190 -0
- package/dist/chunk-3WEMHXZI.mjs +198 -0
- package/dist/chunk-3Z62EUJN.mjs +138 -0
- package/dist/chunk-4C6EVJ54.mjs +362 -0
- package/dist/chunk-53HW45JB.mjs +102 -0
- package/dist/chunk-55Y3WI6S.mjs +186 -0
- package/dist/chunk-5JCI2DEB.mjs +97 -0
- package/dist/chunk-66T4MRC5.mjs +113 -0
- package/dist/chunk-6HSEJLSR.mjs +376 -0
- package/dist/chunk-6STOLMCA.mjs +187 -0
- package/dist/chunk-7CMVDIOU.mjs +54 -0
- package/dist/chunk-7QQ6ETB4.mjs +228 -0
- package/dist/chunk-A6ZQZFL2.mjs +272 -0
- package/dist/chunk-ADKLH73T.mjs +1 -0
- package/dist/chunk-AGU3NG6D.mjs +22 -0
- package/dist/chunk-AHYIS6EB.mjs +230 -0
- package/dist/chunk-AP3UYWYT.mjs +4 -0
- package/dist/chunk-ARB5T6MP.mjs +326 -0
- package/dist/chunk-ARRGOEFX.mjs +585 -0
- package/dist/chunk-AUF4CHDP.mjs +422 -0
- package/dist/chunk-B4FTADAZ.mjs +561 -0
- package/dist/chunk-BABQKA6K.mjs +339 -0
- package/dist/chunk-BETFQBM2.mjs +197 -0
- package/dist/chunk-BKP26M4K.mjs +413 -0
- package/dist/chunk-BZN2QHGP.mjs +200 -0
- package/dist/chunk-C36VWQ7A.mjs +86 -0
- package/dist/chunk-CHW4RKY3.mjs +16 -0
- package/dist/chunk-CINXJIRR.mjs +120 -0
- package/dist/chunk-DN6AXQYZ.mjs +667 -0
- package/dist/chunk-DP2IZNN3.mjs +92 -0
- package/dist/chunk-DTWTCFRG.mjs +119 -0
- package/dist/chunk-EAMUNLRU.mjs +172 -0
- package/dist/chunk-EDAKJLNA.mjs +17 -0
- package/dist/chunk-ERVQB2VZ.mjs +59 -0
- package/dist/chunk-FFMT6OCO.mjs +92 -0
- package/dist/chunk-FHTC2YDB.mjs +102 -0
- package/dist/chunk-FRST55HY.mjs +16 -0
- package/dist/chunk-HDFGCN2F.mjs +132 -0
- package/dist/chunk-IEGLX7VL.mjs +42 -0
- package/dist/chunk-ILUWFYGY.mjs +220 -0
- package/dist/chunk-IXOWSEHO.mjs +114 -0
- package/dist/chunk-J4RI2C2G.mjs +172 -0
- package/dist/chunk-J65DBT4R.mjs +13 -0
- package/dist/chunk-JGOVWSKH.mjs +179 -0
- package/dist/chunk-JO7VACY2.mjs +25 -0
- package/dist/chunk-JWFBOPM6.mjs +122 -0
- package/dist/chunk-KNDZP446.mjs +895 -0
- package/dist/chunk-KP2TWD4Z.mjs +90 -0
- package/dist/chunk-KQIFO5I3.mjs +225 -0
- package/dist/chunk-KVDEROP6.mjs +59 -0
- package/dist/chunk-LKC7MZKK.mjs +87 -0
- package/dist/chunk-LVMDQ4OJ.mjs +305 -0
- package/dist/chunk-M7B3JF43.mjs +90 -0
- package/dist/chunk-MTGMXRNF.mjs +136 -0
- package/dist/chunk-N3TIT3OH.mjs +1040 -0
- package/dist/chunk-NHRK5KU2.mjs +890 -0
- package/dist/chunk-NKUYIWAP.mjs +243 -0
- package/dist/chunk-NPDZLYIF.mjs +238 -0
- package/dist/chunk-O2X6FF45.mjs +499 -0
- package/dist/chunk-OGJ6IIBW.mjs +176 -0
- package/dist/chunk-OHGCZZPZ.mjs +403 -0
- package/dist/chunk-OWW3K55O.mjs +351 -0
- package/dist/chunk-OXTFAWSK.mjs +60 -0
- package/dist/chunk-PLSDU3C2.mjs +890 -0
- package/dist/chunk-PRDVPOZX.mjs +223 -0
- package/dist/chunk-Q6PPVIHU.mjs +21 -0
- package/dist/chunk-QQBXUDM4.mjs +885 -0
- package/dist/chunk-QS76E3TD.mjs +111 -0
- package/dist/chunk-QWQ6HY4I.mjs +209 -0
- package/dist/chunk-R6Y3R7EW.mjs +135 -0
- package/dist/chunk-RBLZRT5K.mjs +190 -0
- package/dist/chunk-RO4N6YFS.mjs +167 -0
- package/dist/chunk-RQ3CKQOX.mjs +984 -0
- package/dist/chunk-SALTGZFR.mjs +208 -0
- package/dist/chunk-SANZPAJ4.mjs +14 -0
- package/dist/chunk-SDBPQ5CF.mjs +624 -0
- package/dist/chunk-SSLTFJ3U.mjs +364 -0
- package/dist/chunk-SXHVDJGF.mjs +77 -0
- package/dist/chunk-TA4MVAEX.mjs +243 -0
- package/dist/chunk-TAHCOZHF.mjs +1772 -0
- package/dist/chunk-TQ6S34QZ.mjs +152 -0
- package/dist/chunk-UPRXABX5.mjs +90 -0
- package/dist/chunk-VGLSBZDN.mjs +71 -0
- package/dist/chunk-VN7CKCSE.mjs +364 -0
- package/dist/chunk-VVI3OBPJ.mjs +524 -0
- package/dist/chunk-VWF57TS3.mjs +62 -0
- package/dist/chunk-WA3OVISZ.mjs +179 -0
- package/dist/chunk-WCG35U6M.mjs +964 -0
- package/dist/chunk-WFTX4AQJ.mjs +194 -0
- package/dist/chunk-WFVOQ2QZ.mjs +18 -0
- package/dist/chunk-WH3C3Y7P.mjs +149 -0
- package/dist/chunk-WPFUV7K3.mjs +488 -0
- package/dist/chunk-WRULPWHD.mjs +492 -0
- package/dist/chunk-WS64BZXT.mjs +1 -0
- package/dist/chunk-WY4AURRE.mjs +2419 -0
- package/dist/chunk-WYLILAOO.mjs +167 -0
- package/dist/chunk-X4D7FKUS.mjs +62 -0
- package/dist/chunk-X7T34OLW.mjs +139 -0
- package/dist/chunk-XIHBK5D3.mjs +68 -0
- package/dist/chunk-XQQCGFYB.mjs +50 -0
- package/dist/chunk-XTVE4P3L.mjs +214 -0
- package/dist/chunk-XUAASRXW.mjs +579 -0
- package/dist/chunk-Y3L3D4GQ.mjs +685 -0
- package/dist/chunk-YBJ56XJS.mjs +132 -0
- package/dist/chunk-ZQFK6CAE.mjs +1 -0
- package/dist/chunk-ZT2Z7ERM.mjs +874 -0
- package/dist/chunk-ZTL2FQEW.mjs +714 -0
- package/dist/circular/arc/index.d.mts +8 -0
- package/dist/circular/arc/index.mjs +3 -0
- package/dist/circular/index.d.mts +44 -0
- package/dist/circular/index.mjs +13 -0
- package/dist/collect.utils-DiKB4ciO.d.mts +12 -0
- package/dist/computeChartState-BTVIqwyO.d.mts +304 -0
- package/dist/controller-BJE1AZ3q.d.mts +82 -0
- package/dist/controller-BoNigQJr.d.mts +63 -0
- package/dist/controllers/index.d.mts +16 -0
- package/dist/controllers/index.mjs +110 -0
- package/dist/datalabel.utils-CkjGeB8S.d.mts +122 -0
- package/dist/decimation.utils-CcvJVhI4.d.mts +244 -0
- package/dist/geometry-DUUQJXVM.d.mts +60 -0
- package/dist/index-DseIZa1j.d.mts +167 -0
- package/dist/index.d.mts +88 -0
- package/dist/index.mjs +110 -0
- package/dist/orchestrator/index.d.mts +264 -0
- package/dist/orchestrator/index.mjs +33 -0
- package/dist/plugins/index.d.mts +18 -0
- package/dist/plugins/index.mjs +1 -0
- package/dist/property-animations-D433wXzz.d.mts +580 -0
- package/dist/property-store-NORUWFND.d.mts +17 -0
- package/dist/radial/index.d.mts +14 -0
- package/dist/radial/index.mjs +37 -0
- package/dist/renderers/axis/index.d.mts +39 -0
- package/dist/renderers/axis/index.mjs +8 -0
- package/dist/renderers/circular/index.d.mts +13 -0
- package/dist/renderers/circular/index.mjs +13 -0
- package/dist/renderers/index.d.mts +83 -0
- package/dist/renderers/index.mjs +75 -0
- package/dist/renderers/navigator/index.d.mts +103 -0
- package/dist/renderers/navigator/index.mjs +8 -0
- package/dist/resize.utils-D_2qm6rv.d.mts +142 -0
- package/dist/ring.utils-DXvrxMkU.d.mts +138 -0
- package/dist/scale-KFv30jqZ.d.mts +307 -0
- package/dist/scales-Drf8AIhL.d.mts +75 -0
- package/dist/series/bar/canvas/index.d.mts +8 -0
- package/dist/series/bar/canvas/index.mjs +10 -0
- package/dist/series/bar/controller/index.d.mts +105 -0
- package/dist/series/bar/controller/index.mjs +44 -0
- package/dist/series/bar/controller-canvas/index.d.mts +7 -0
- package/dist/series/bar/controller-canvas/index.mjs +49 -0
- package/dist/series/bar/controller-svg/index.d.mts +7 -0
- package/dist/series/bar/controller-svg/index.mjs +49 -0
- package/dist/series/bar/index.d.mts +60 -0
- package/dist/series/bar/index.mjs +13 -0
- package/dist/series/bar/svg/index.d.mts +8 -0
- package/dist/series/bar/svg/index.mjs +11 -0
- package/dist/series/candlestick/canvas/index.d.mts +8 -0
- package/dist/series/candlestick/canvas/index.mjs +8 -0
- package/dist/series/candlestick/controller/index.d.mts +123 -0
- package/dist/series/candlestick/controller/index.mjs +40 -0
- package/dist/series/candlestick/controller-canvas/index.d.mts +7 -0
- package/dist/series/candlestick/controller-canvas/index.mjs +45 -0
- package/dist/series/candlestick/controller-svg/index.d.mts +7 -0
- package/dist/series/candlestick/controller-svg/index.mjs +45 -0
- package/dist/series/candlestick/index.d.mts +11 -0
- package/dist/series/candlestick/index.mjs +10 -0
- package/dist/series/candlestick/svg/index.d.mts +8 -0
- package/dist/series/candlestick/svg/index.mjs +8 -0
- package/dist/series/heatmap/canvas/index.d.mts +16 -0
- package/dist/series/heatmap/canvas/index.mjs +9 -0
- package/dist/series/heatmap/controller/index.d.mts +110 -0
- package/dist/series/heatmap/controller/index.mjs +23 -0
- package/dist/series/heatmap/controller-canvas/index.d.mts +7 -0
- package/dist/series/heatmap/controller-canvas/index.mjs +28 -0
- package/dist/series/heatmap/controller-svg/index.d.mts +7 -0
- package/dist/series/heatmap/controller-svg/index.mjs +28 -0
- package/dist/series/heatmap/index.d.mts +34 -0
- package/dist/series/heatmap/index.mjs +13 -0
- package/dist/series/heatmap/svg/index.d.mts +15 -0
- package/dist/series/heatmap/svg/index.mjs +10 -0
- package/dist/series/line/canvas/index.d.mts +6 -0
- package/dist/series/line/canvas/index.mjs +9 -0
- package/dist/series/line/controller/index.d.mts +111 -0
- package/dist/series/line/controller/index.mjs +47 -0
- package/dist/series/line/controller-canvas/index.d.mts +7 -0
- package/dist/series/line/controller-canvas/index.mjs +54 -0
- package/dist/series/line/controller-svg/index.d.mts +7 -0
- package/dist/series/line/controller-svg/index.mjs +54 -0
- package/dist/series/line/index.d.mts +49 -0
- package/dist/series/line/index.mjs +13 -0
- package/dist/series/line/svg/index.d.mts +6 -0
- package/dist/series/line/svg/index.mjs +9 -0
- package/dist/series/pie/canvas/index.d.mts +8 -0
- package/dist/series/pie/canvas/index.mjs +10 -0
- package/dist/series/pie/controller/index.d.mts +174 -0
- package/dist/series/pie/controller/index.mjs +110 -0
- package/dist/series/pie/controller-canvas/index.d.mts +8 -0
- package/dist/series/pie/controller-canvas/index.mjs +119 -0
- package/dist/series/pie/controller-svg/index.d.mts +8 -0
- package/dist/series/pie/controller-svg/index.mjs +118 -0
- package/dist/series/pie/index.d.mts +59 -0
- package/dist/series/pie/index.mjs +15 -0
- package/dist/series/pie/svg/index.d.mts +6 -0
- package/dist/series/pie/svg/index.mjs +11 -0
- package/dist/series/polar/canvas/index.d.mts +6 -0
- package/dist/series/polar/canvas/index.mjs +7 -0
- package/dist/series/polar/controller/index.d.mts +102 -0
- package/dist/series/polar/controller/index.mjs +46 -0
- package/dist/series/polar/controller-canvas/index.d.mts +8 -0
- package/dist/series/polar/controller-canvas/index.mjs +52 -0
- package/dist/series/polar/controller-svg/index.d.mts +8 -0
- package/dist/series/polar/controller-svg/index.mjs +52 -0
- package/dist/series/polar/index.d.mts +25 -0
- package/dist/series/polar/index.mjs +16 -0
- package/dist/series/polar/svg/index.d.mts +10 -0
- package/dist/series/polar/svg/index.mjs +8 -0
- package/dist/series/radar/canvas/index.d.mts +6 -0
- package/dist/series/radar/canvas/index.mjs +8 -0
- package/dist/series/radar/controller/index.d.mts +121 -0
- package/dist/series/radar/controller/index.mjs +43 -0
- package/dist/series/radar/controller-canvas/index.d.mts +8 -0
- package/dist/series/radar/controller-canvas/index.mjs +51 -0
- package/dist/series/radar/controller-svg/index.d.mts +8 -0
- package/dist/series/radar/controller-svg/index.mjs +51 -0
- package/dist/series/radar/index.d.mts +40 -0
- package/dist/series/radar/index.mjs +13 -0
- package/dist/series/radar/svg/index.d.mts +12 -0
- package/dist/series/radar/svg/index.mjs +9 -0
- package/dist/series/scatter/canvas/index.d.mts +8 -0
- package/dist/series/scatter/canvas/index.mjs +11 -0
- package/dist/series/scatter/controller/index.d.mts +124 -0
- package/dist/series/scatter/controller/index.mjs +44 -0
- package/dist/series/scatter/controller-canvas/index.d.mts +7 -0
- package/dist/series/scatter/controller-canvas/index.mjs +51 -0
- package/dist/series/scatter/controller-svg/index.d.mts +7 -0
- package/dist/series/scatter/controller-svg/index.mjs +51 -0
- package/dist/series/scatter/index.d.mts +25 -0
- package/dist/series/scatter/index.mjs +14 -0
- package/dist/series/scatter/svg/index.d.mts +8 -0
- package/dist/series/scatter/svg/index.mjs +12 -0
- package/dist/series/treemap/canvas/index.d.mts +50 -0
- package/dist/series/treemap/canvas/index.mjs +10 -0
- package/dist/series/treemap/controller/index.d.mts +130 -0
- package/dist/series/treemap/controller/index.mjs +20 -0
- package/dist/series/treemap/controller-canvas/index.d.mts +7 -0
- package/dist/series/treemap/controller-canvas/index.mjs +25 -0
- package/dist/series/treemap/controller-svg/index.d.mts +7 -0
- package/dist/series/treemap/controller-svg/index.mjs +25 -0
- package/dist/series/treemap/index.d.mts +15 -0
- package/dist/series/treemap/index.mjs +12 -0
- package/dist/series/treemap/svg/index.d.mts +15 -0
- package/dist/series/treemap/svg/index.mjs +9 -0
- package/dist/slices-DtewiwJx.d.mts +72 -0
- package/dist/spatialIndex.utils-B_GJkotZ.d.mts +5 -0
- package/dist/squarify.utils-B9CQBpa1.d.mts +50 -0
- package/dist/stacking-CChuAcLN.d.mts +319 -0
- package/dist/streaming.utils-DH-g1gNP.d.mts +49 -0
- package/dist/sync/index.d.mts +130 -0
- package/dist/sync/index.mjs +5 -0
- package/dist/tooltip.renderer-D5wpSlBa.d.mts +210 -0
- package/dist/utils/color/index.d.mts +58 -0
- package/dist/utils/color/index.mjs +4 -0
- package/dist/utils/data/index.d.mts +180 -0
- package/dist/utils/data/index.mjs +7 -0
- package/dist/utils/export/index.d.mts +14 -0
- package/dist/utils/export/index.mjs +6 -0
- package/dist/utils/index.d.mts +49 -0
- package/dist/utils/index.mjs +29 -0
- package/dist/utils/interaction/index.d.mts +255 -0
- package/dist/utils/interaction/index.mjs +9 -0
- package/dist/utils/layout/index.d.mts +3 -0
- package/dist/utils/layout/index.mjs +10 -0
- package/dist/utils/math/index.d.mts +162 -0
- package/dist/utils/math/index.mjs +1 -0
- package/dist/utils/render/index.d.mts +19 -0
- package/dist/utils/render/index.mjs +3 -0
- package/dist/utils/specialized/index.d.mts +37 -0
- package/dist/utils/specialized/index.mjs +66 -0
- package/dist/utils/text/index.d.mts +39 -0
- package/dist/utils/text/index.mjs +8 -0
- package/dist/utils/theme/index.d.mts +295 -0
- package/dist/utils/theme/index.mjs +5 -0
- package/dist/utils/zoom/index.d.mts +90 -0
- package/dist/utils/zoom/index.mjs +3 -0
- package/package.json +56 -0
|
@@ -0,0 +1,579 @@
|
|
|
1
|
+
import { scatterHitTest } from './chunk-LKC7MZKK.mjs';
|
|
2
|
+
import { collectScatterMarkerOverlays } from './chunk-X4D7FKUS.mjs';
|
|
3
|
+
import { registerDatasetLayers, triggerCompositorRepaint } from './chunk-Q6PPVIHU.mjs';
|
|
4
|
+
import { resolveScatterLabels } from './chunk-66T4MRC5.mjs';
|
|
5
|
+
import { renderResolvedLabels } from './chunk-QQBXUDM4.mjs';
|
|
6
|
+
import { AnimatedScene, resolveAnimatedProps, SCATTER_ANIMATABLE_PROPS } from './chunk-VN7CKCSE.mjs';
|
|
7
|
+
import { calculateScatterLayout } from './chunk-DTWTCFRG.mjs';
|
|
8
|
+
import { reconcileSvgChildren } from './chunk-KP2TWD4Z.mjs';
|
|
9
|
+
import { parseAnimationConfig } from './chunk-3WEMHXZI.mjs';
|
|
10
|
+
import { raf, cancelRaf } from './chunk-EDAKJLNA.mjs';
|
|
11
|
+
import { buildAccessibilityRenderContext, generateSeriesDescription } from './chunk-OGJ6IIBW.mjs';
|
|
12
|
+
import { collectItems } from './chunk-FFMT6OCO.mjs';
|
|
13
|
+
import { SCATTER_BOOST_AUTO_THRESHOLD, DEFAULT_HOVER_DIM_OPACITY, DEFAULT_HOVER_BRIGHTNESS, SCATTER_SPATIAL_INDEX_THRESHOLD, DEFAULT_FALLBACK_COLOR } from './chunk-NKUYIWAP.mjs';
|
|
14
|
+
import { ScatterDecimator } from './chunk-OWW3K55O.mjs';
|
|
15
|
+
import { buildQuadtree } from './chunk-C36VWQ7A.mjs';
|
|
16
|
+
import { defaultLightTheme } from './chunk-O2X6FF45.mjs';
|
|
17
|
+
import { materializeSvgNode, setAttr, createSvgGroup } from './chunk-SSLTFJ3U.mjs';
|
|
18
|
+
|
|
19
|
+
// src/series/scatter/controller/index.ts
|
|
20
|
+
function scatterHoverInteraction(base, dsId, hover) {
|
|
21
|
+
const anyHovered = hover.datasetId !== null;
|
|
22
|
+
const isThisSeries = hover.datasetId === dsId;
|
|
23
|
+
return {
|
|
24
|
+
...base.interaction ?? {},
|
|
25
|
+
hoveredIndex: isThisSeries ? hover.index : null,
|
|
26
|
+
isSeriesDimmed: anyHovered && !isThisSeries
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
function buildScatterSvgChildren(params) {
|
|
30
|
+
const { paint, renderLayouts, activeRenderProps, visibleLayouts, visibleRenderProps, context, hover, labelConfig, datasetVisibility } = params;
|
|
31
|
+
const children = [];
|
|
32
|
+
for (const [dsId, scatterLayout] of renderLayouts) {
|
|
33
|
+
const props = activeRenderProps.get(dsId);
|
|
34
|
+
if (!props || props.renderMarker) continue;
|
|
35
|
+
const propsWithHover = {
|
|
36
|
+
...props,
|
|
37
|
+
interaction: scatterHoverInteraction(props, dsId, hover)
|
|
38
|
+
};
|
|
39
|
+
const node = paint.renderSvg(propsWithHover, scatterLayout, context);
|
|
40
|
+
setAttr(node, "data-dataset", dsId);
|
|
41
|
+
if (context.accessibility?.enabled && context.accessibility.landmarkVerbosity === "all") {
|
|
42
|
+
setAttr(node, "role", "region");
|
|
43
|
+
setAttr(node, "aria-label", generateSeriesDescription(props.name ?? dsId, "scatter", scatterLayout.visiblePoints.length));
|
|
44
|
+
}
|
|
45
|
+
children.push(node);
|
|
46
|
+
}
|
|
47
|
+
if (labelConfig && !labelConfig.render) {
|
|
48
|
+
const labelGroup = createSvgGroup();
|
|
49
|
+
setAttr(labelGroup, "data-layer", "labels");
|
|
50
|
+
for (const [dsId, scatterLayout] of visibleLayouts) {
|
|
51
|
+
if (datasetVisibility?.get(dsId) === false) continue;
|
|
52
|
+
const props = visibleRenderProps.get(dsId);
|
|
53
|
+
const seriesColor = typeof props?.color === "string" ? props.color : DEFAULT_FALLBACK_COLOR;
|
|
54
|
+
renderResolvedLabels(resolveScatterLabels(scatterLayout.visiblePoints, seriesColor, labelConfig, props?.name, props?.data), labelConfig, {
|
|
55
|
+
renderer: "svg",
|
|
56
|
+
svgGroup: labelGroup,
|
|
57
|
+
theme: context.theme
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
children.push(labelGroup);
|
|
61
|
+
}
|
|
62
|
+
return children;
|
|
63
|
+
}
|
|
64
|
+
var SCATTER_DATASET_REGISTRY = {
|
|
65
|
+
number: ["opacity"],
|
|
66
|
+
color: []
|
|
67
|
+
};
|
|
68
|
+
var ScatterRendererController = class {
|
|
69
|
+
constructor(paint) {
|
|
70
|
+
// Animation lifecycle — local raf clock + fingerprint for phase detection.
|
|
71
|
+
this._animRafId = null;
|
|
72
|
+
this._lastFingerprint = "";
|
|
73
|
+
// Canonical layout caches — VISIBLE entries only (exiting excluded).
|
|
74
|
+
// Used for hit-test, legend, and marker overlays. Per-design: users can't
|
|
75
|
+
// hover points that are fading out.
|
|
76
|
+
this.layoutCache = /* @__PURE__ */ new Map();
|
|
77
|
+
this.renderPropsCache = /* @__PURE__ */ new Map();
|
|
78
|
+
// Render-time caches — include visible + exiting entries. Canvas paint
|
|
79
|
+
// callbacks and SVG render read these so fading points stay on screen.
|
|
80
|
+
this.renderLayouts = /* @__PURE__ */ new Map();
|
|
81
|
+
this.activeRenderPropsCache = /* @__PURE__ */ new Map();
|
|
82
|
+
// Per-dataset property-animation overrides resolved from AnimatedPropertyStore.
|
|
83
|
+
// Set by `applyPropertyAnimations()` each property-animation tick and merged
|
|
84
|
+
// into the active render props at read time. Cleared by `destroy()`.
|
|
85
|
+
this._propertyOverrides = /* @__PURE__ */ new Map();
|
|
86
|
+
this.scatterDatasets = [];
|
|
87
|
+
this.decimator = new ScatterDecimator();
|
|
88
|
+
this._markerOverlays = [];
|
|
89
|
+
this.lastInput = null;
|
|
90
|
+
// Single source of truth for the current hover. Written ONLY by applyHover (never
|
|
91
|
+
// re-seeded from input.hover), read by renderFrame and the compositor paint callback.
|
|
92
|
+
// Hover is event-driven and always arrives via applyHover, so re-seeding from the
|
|
93
|
+
// swappable input would let a stale input.hover clobber the live hover. Mirrors
|
|
94
|
+
// candlestick/heatmap/radar/polar.
|
|
95
|
+
this.hover = { datasetId: null, index: null };
|
|
96
|
+
// DOM targets
|
|
97
|
+
this.svgGroup = null;
|
|
98
|
+
this.canvasEl = null;
|
|
99
|
+
this.onFrame = null;
|
|
100
|
+
this._paint = paint;
|
|
101
|
+
this._scene = new AnimatedScene({
|
|
102
|
+
// ENTER: series fades in from transparent.
|
|
103
|
+
emptyState: (target) => ({ ...target, opacity: 0 }),
|
|
104
|
+
// EXIT: series fades out to transparent.
|
|
105
|
+
exitEmptyState: (target) => ({ ...target, opacity: 0 }),
|
|
106
|
+
registry: SCATTER_DATASET_REGISTRY
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
// ================================================================
|
|
110
|
+
// PUBLIC API
|
|
111
|
+
// ================================================================
|
|
112
|
+
update(input) {
|
|
113
|
+
this.lastInput = input;
|
|
114
|
+
this.svgGroup = input.svgGroup ?? null;
|
|
115
|
+
this.canvasEl = input.canvasEl ?? null;
|
|
116
|
+
const { datasets, datasetVisibility, decimationConfig, zoomState, orientation = "vertical", compositor, features } = input;
|
|
117
|
+
const sortedDatasets = Array.from(datasets.entries()).sort(([, a], [, b]) => a.order - b.order);
|
|
118
|
+
const rawDatasets = collectItems(sortedDatasets, datasetVisibility).scatter;
|
|
119
|
+
if (decimationConfig && rawDatasets.length > 0) {
|
|
120
|
+
const zoomX = orientation === "vertical" ? zoomState?.x : zoomState?.y;
|
|
121
|
+
const zoomY = orientation === "vertical" ? zoomState?.y : zoomState?.x;
|
|
122
|
+
this.scatterDatasets = this.decimator.apply(rawDatasets, decimationConfig, zoomX, zoomY);
|
|
123
|
+
} else {
|
|
124
|
+
this.scatterDatasets = rawDatasets;
|
|
125
|
+
}
|
|
126
|
+
const hasScales = !!input.scatterXScales && !!input.valueScales && input.valueScales.size > 0;
|
|
127
|
+
if ((this.scatterDatasets.length === 0 || !hasScales) && this._scene.getElements().length === 0) {
|
|
128
|
+
this.layoutCache.clear();
|
|
129
|
+
this.renderPropsCache.clear();
|
|
130
|
+
this.renderLayouts.clear();
|
|
131
|
+
this.activeRenderPropsCache.clear();
|
|
132
|
+
this._markerOverlays = [];
|
|
133
|
+
this._cancelRaf();
|
|
134
|
+
this._scene.reset();
|
|
135
|
+
this._lastFingerprint = "";
|
|
136
|
+
if (input.renderer === "svg" && this.svgGroup) {
|
|
137
|
+
while (this.svgGroup.firstChild) this.svgGroup.removeChild(this.svgGroup.firstChild);
|
|
138
|
+
}
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
if (input.renderer === "svg" && !this.svgGroup) return;
|
|
142
|
+
const visibleDatasets = this.scatterDatasets.filter((d) => d.visible);
|
|
143
|
+
const fingerprint = visibleDatasets.map((d) => d.id).sort().join("|");
|
|
144
|
+
const phase = this._lastFingerprint === "" ? "entrance" : fingerprint !== this._lastFingerprint ? "update" : "static";
|
|
145
|
+
const animConfig = features.get("animation")?.props;
|
|
146
|
+
const { enabled: animEnabled, duration, easing } = parseAnimationConfig(animConfig);
|
|
147
|
+
const shouldAnimate = animEnabled && duration > 0 && phase !== "static";
|
|
148
|
+
this._updateCachesAndLayout(visibleDatasets, input);
|
|
149
|
+
if (input.renderer === "canvas" && compositor) {
|
|
150
|
+
compositor.removeLayersByPrefix?.("scatter:");
|
|
151
|
+
const liveIds = /* @__PURE__ */ new Set();
|
|
152
|
+
for (const el of this._scene.getElements()) liveIds.add(el.current.datasetId);
|
|
153
|
+
for (const sd of visibleDatasets) liveIds.add(sd.id);
|
|
154
|
+
registerDatasetLayers(
|
|
155
|
+
compositor,
|
|
156
|
+
"scatter",
|
|
157
|
+
liveIds,
|
|
158
|
+
(dsId) => this._scene.getElement(dsId)?.current.stackOrder ?? datasets.get(dsId)?.order ?? 0,
|
|
159
|
+
(dsId) => (ctx) => this.paintCanvasLayer(ctx, dsId)
|
|
160
|
+
);
|
|
161
|
+
}
|
|
162
|
+
const sceneTargets = this._buildSceneTargets(visibleDatasets, input);
|
|
163
|
+
const opts = {
|
|
164
|
+
numbers: { duration: shouldAnimate ? duration : 0, easing },
|
|
165
|
+
colors: { duration: shouldAnimate ? duration : 0, easing }
|
|
166
|
+
};
|
|
167
|
+
if (phase === "static" && this._animRafId !== null) {
|
|
168
|
+
this._commit(fingerprint);
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
this._cancelRaf();
|
|
172
|
+
this._scene.diff(sceneTargets, opts);
|
|
173
|
+
if (shouldAnimate) {
|
|
174
|
+
this._renderSceneFrame();
|
|
175
|
+
const tick = (now) => {
|
|
176
|
+
this._animRafId = null;
|
|
177
|
+
const { allIdle } = this._scene.tick(now);
|
|
178
|
+
this._renderSceneFrame();
|
|
179
|
+
if (allIdle && this.lastInput?.renderer === "canvas" && this.lastInput.compositor) {
|
|
180
|
+
const liveIds = new Set(Array.from(this._scene.getElements()).map((el) => el.current.datasetId));
|
|
181
|
+
this.lastInput.compositor.removeLayersByPrefix?.("scatter:");
|
|
182
|
+
registerDatasetLayers(
|
|
183
|
+
this.lastInput.compositor,
|
|
184
|
+
"scatter",
|
|
185
|
+
liveIds,
|
|
186
|
+
(dsId) => this._scene.getElement(dsId)?.current.stackOrder ?? 0,
|
|
187
|
+
(dsId) => (ctx) => this.paintCanvasLayer(ctx, dsId)
|
|
188
|
+
);
|
|
189
|
+
}
|
|
190
|
+
if (!allIdle) {
|
|
191
|
+
this._animRafId = raf(tick);
|
|
192
|
+
}
|
|
193
|
+
};
|
|
194
|
+
this._animRafId = raf(tick);
|
|
195
|
+
} else {
|
|
196
|
+
this._scene.tick(performance.now());
|
|
197
|
+
this._renderSceneFrame();
|
|
198
|
+
}
|
|
199
|
+
this._commit(fingerprint);
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* Re-project point positions through the chrome-animated scales each frame so the
|
|
203
|
+
* dots track the X/Y axis rescale in lockstep (the value-domain model — points stay
|
|
204
|
+
* glued to their gridlines because both derive from the same interpolating scale).
|
|
205
|
+
*
|
|
206
|
+
* Unlike the line controller, the scatter scene loop animates OPACITY only and reuses
|
|
207
|
+
* cached positions — so the position cache must be refreshed HERE every frame. Mirrors
|
|
208
|
+
* `LineRendererController.syncWithAnimatedScale`. `categoryScale` is unused (scatter X
|
|
209
|
+
* is a numeric value axis, not a band); the animated X scales arrive via `valueXScales`.
|
|
210
|
+
*/
|
|
211
|
+
syncWithAnimatedScale(_categoryScale, valueScales, valueXScales) {
|
|
212
|
+
if (!this.lastInput || this.renderLayouts.size === 0) return;
|
|
213
|
+
if (this.allBoostActive()) return;
|
|
214
|
+
if (valueScales) this.lastInput.valueScales = valueScales;
|
|
215
|
+
if (valueXScales) this.lastInput.scatterXScales = valueXScales;
|
|
216
|
+
const visibleDatasets = this.scatterDatasets.filter((d) => d.visible);
|
|
217
|
+
this._updateCachesAndLayout(visibleDatasets, this.lastInput);
|
|
218
|
+
if (this._animRafId !== null) return;
|
|
219
|
+
if (this.lastInput.renderer === "svg") {
|
|
220
|
+
this._renderSceneFrame();
|
|
221
|
+
} else {
|
|
222
|
+
this._rebuildRenderLayouts();
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
applyHover(hover) {
|
|
226
|
+
this.hover = hover;
|
|
227
|
+
if (this.renderLayouts.size === 0 || !this.lastInput) return;
|
|
228
|
+
if (this.allBoostActive()) {
|
|
229
|
+
return;
|
|
230
|
+
}
|
|
231
|
+
if (this._animRafId !== null) {
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
234
|
+
const input = this.lastInput;
|
|
235
|
+
if (input.renderer === "svg" && this.svgGroup) {
|
|
236
|
+
const context = {
|
|
237
|
+
chartId: input.chartId,
|
|
238
|
+
width: input.width,
|
|
239
|
+
height: input.height,
|
|
240
|
+
renderer: input.renderer,
|
|
241
|
+
chartArea: input.chartArea,
|
|
242
|
+
theme: input.theme,
|
|
243
|
+
accessibility: buildAccessibilityRenderContext(input.features)
|
|
244
|
+
};
|
|
245
|
+
const children = buildScatterSvgChildren({
|
|
246
|
+
paint: this._paint,
|
|
247
|
+
renderLayouts: this.renderLayouts,
|
|
248
|
+
activeRenderProps: this.activeRenderPropsCache,
|
|
249
|
+
visibleLayouts: this.layoutCache,
|
|
250
|
+
visibleRenderProps: this.renderPropsCache,
|
|
251
|
+
context,
|
|
252
|
+
hover,
|
|
253
|
+
labelConfig: input.labelConfig,
|
|
254
|
+
datasetVisibility: input.datasetVisibility
|
|
255
|
+
});
|
|
256
|
+
reconcileSvgChildren(this.svgGroup, children);
|
|
257
|
+
return;
|
|
258
|
+
}
|
|
259
|
+
for (const sd of this.scatterDatasets) {
|
|
260
|
+
const baseProps = this.renderPropsCache.get(sd.id);
|
|
261
|
+
if (!baseProps) continue;
|
|
262
|
+
const updated = this.buildRenderProps(sd, input);
|
|
263
|
+
this.renderPropsCache.set(sd.id, updated);
|
|
264
|
+
const liveOpacity = this._scene.getElement(sd.id)?.current.opacity ?? this.activeRenderPropsCache.get(sd.id)?.animationOpacity ?? 1;
|
|
265
|
+
const overrides = this._propertyOverrides.get(sd.id);
|
|
266
|
+
const merged = overrides ? { ...updated, ...overrides, animationOpacity: liveOpacity } : { ...updated, animationOpacity: liveOpacity };
|
|
267
|
+
this.activeRenderPropsCache.set(sd.id, merged);
|
|
268
|
+
}
|
|
269
|
+
triggerCompositorRepaint(input.renderer, this.canvasEl, input.compositor);
|
|
270
|
+
}
|
|
271
|
+
/** True when every visible scatter series is in boost mode (explicit or auto above 50k). */
|
|
272
|
+
get boostActive() {
|
|
273
|
+
return this.allBoostActive();
|
|
274
|
+
}
|
|
275
|
+
allBoostActive() {
|
|
276
|
+
if (this.renderLayouts.size === 0) return false;
|
|
277
|
+
for (const [datasetId, layout] of this.renderLayouts) {
|
|
278
|
+
const props = this.renderPropsCache.get(datasetId) ?? this.activeRenderPropsCache.get(datasetId);
|
|
279
|
+
const boost = props?.boost;
|
|
280
|
+
if (boost === true) continue;
|
|
281
|
+
if (boost === false) return false;
|
|
282
|
+
if (layout.visiblePoints.length < SCATTER_BOOST_AUTO_THRESHOLD) return false;
|
|
283
|
+
}
|
|
284
|
+
return true;
|
|
285
|
+
}
|
|
286
|
+
hitTest(x, y) {
|
|
287
|
+
return scatterHitTest(x, y, { layouts: this.layoutCache, renderPropsCache: this.renderPropsCache, theme: this.lastInput?.theme ?? defaultLightTheme });
|
|
288
|
+
}
|
|
289
|
+
getSvgOutput() {
|
|
290
|
+
return null;
|
|
291
|
+
}
|
|
292
|
+
get hasData() {
|
|
293
|
+
return this.scatterDatasets.length > 0;
|
|
294
|
+
}
|
|
295
|
+
get layouts() {
|
|
296
|
+
return this.layoutCache;
|
|
297
|
+
}
|
|
298
|
+
get markerOverlays() {
|
|
299
|
+
return this._markerOverlays;
|
|
300
|
+
}
|
|
301
|
+
destroy() {
|
|
302
|
+
this._cancelRaf();
|
|
303
|
+
this._scene.reset();
|
|
304
|
+
this._lastFingerprint = "";
|
|
305
|
+
this._propertyOverrides.clear();
|
|
306
|
+
this.lastInput?.compositor?.removeLayersByPrefix("scatter:");
|
|
307
|
+
}
|
|
308
|
+
/**
|
|
309
|
+
* Apply animated property values without triggering a full layout cycle.
|
|
310
|
+
* Called from the property-animation framework wrapper each animation tick.
|
|
311
|
+
*
|
|
312
|
+
* Per-dataset: writes overrides into `_propertyOverrides` (or deletes the
|
|
313
|
+
* entry when the store has no live values for it), then patches downstream
|
|
314
|
+
* caches and triggers a repaint.
|
|
315
|
+
*
|
|
316
|
+
* SVG: scatter renders points imperatively each frame from
|
|
317
|
+
* `activeRenderPropsCache`, so a `renderFrameCycle()` call replays the merged
|
|
318
|
+
* props onto the DOM. Canvas: refreshes the cache then triggers compositor
|
|
319
|
+
* repaint so the layer paint callback reads the merged props.
|
|
320
|
+
*/
|
|
321
|
+
applyPropertyAnimations(store) {
|
|
322
|
+
const input = this.lastInput;
|
|
323
|
+
if (!input) return;
|
|
324
|
+
let appliedAny = false;
|
|
325
|
+
for (const [dsId, baseProps] of this.activeRenderPropsCache) {
|
|
326
|
+
const overrides = resolveAnimatedProps(store, "scatter", dsId, SCATTER_ANIMATABLE_PROPS);
|
|
327
|
+
if (Object.keys(overrides).length === 0) {
|
|
328
|
+
if (this._propertyOverrides.delete(dsId)) appliedAny = true;
|
|
329
|
+
continue;
|
|
330
|
+
}
|
|
331
|
+
appliedAny = true;
|
|
332
|
+
this._propertyOverrides.set(dsId, overrides);
|
|
333
|
+
this.activeRenderPropsCache.set(dsId, { ...baseProps, ...overrides });
|
|
334
|
+
}
|
|
335
|
+
if (!appliedAny) return;
|
|
336
|
+
if (triggerCompositorRepaint(input.renderer, this.canvasEl, input.compositor)) return;
|
|
337
|
+
if (input.renderer === "svg") {
|
|
338
|
+
this.renderFrame();
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
/**
|
|
342
|
+
* Full re-render of the current scene state.
|
|
343
|
+
*
|
|
344
|
+
* Used by the property-animation framework wrapper: when a property
|
|
345
|
+
* animation completes and its override is released from the store,
|
|
346
|
+
* `_renderSceneFrame()` rebuilds `activeRenderPropsCache` from the now-empty
|
|
347
|
+
* overrides map, then `renderFrame()` projects the cleaned props to DOM /
|
|
348
|
+
* canvas so SVG attributes snap back to base values.
|
|
349
|
+
*/
|
|
350
|
+
renderFrameCycle() {
|
|
351
|
+
this._renderSceneFrame();
|
|
352
|
+
}
|
|
353
|
+
// ================================================================
|
|
354
|
+
// PRIVATE HELPERS
|
|
355
|
+
// ================================================================
|
|
356
|
+
/**
|
|
357
|
+
* Build per-dataset scene targets from visible scatter datasets.
|
|
358
|
+
* Element id format: datasetId. One element per series (opacity-only v1).
|
|
359
|
+
*/
|
|
360
|
+
_buildSceneTargets(visibleDatasets, input) {
|
|
361
|
+
const targets = /* @__PURE__ */ new Map();
|
|
362
|
+
for (const sd of visibleDatasets) {
|
|
363
|
+
const stackOrder = input.datasets.get(sd.id)?.order ?? 0;
|
|
364
|
+
const axisId = sd.props.yAxisId ?? input.firstValueAxisId;
|
|
365
|
+
targets.set(sd.id, {
|
|
366
|
+
opacity: 1,
|
|
367
|
+
stackOrder,
|
|
368
|
+
axisId: axisId ?? "",
|
|
369
|
+
datasetId: sd.id
|
|
370
|
+
});
|
|
371
|
+
}
|
|
372
|
+
return targets;
|
|
373
|
+
}
|
|
374
|
+
/**
|
|
375
|
+
* Walk the scene and rebuild per-dataset render state (renderLayouts +
|
|
376
|
+
* activeRenderPropsCache) from element opacities — WITHOUT painting. Split out so
|
|
377
|
+
* `syncWithAnimatedScale` can refresh the layouts during an in-flight compositor
|
|
378
|
+
* repaint (canvas) without triggering a nested repaint (which would recurse).
|
|
379
|
+
*
|
|
380
|
+
* Mirrors Heatmap's scene-derived render path but at dataset granularity.
|
|
381
|
+
*/
|
|
382
|
+
_rebuildRenderLayouts() {
|
|
383
|
+
const elements = Array.from(this._scene.getElements()).sort((a, b) => (a.current.stackOrder ?? 0) - (b.current.stackOrder ?? 0));
|
|
384
|
+
const newRenderLayouts = /* @__PURE__ */ new Map();
|
|
385
|
+
const newActiveProps = /* @__PURE__ */ new Map();
|
|
386
|
+
for (const el of elements) {
|
|
387
|
+
const dsId = el.current.datasetId;
|
|
388
|
+
const layout = this.layoutCache.get(dsId) ?? this.renderLayouts.get(dsId);
|
|
389
|
+
if (!layout) continue;
|
|
390
|
+
const baseProps = this.renderPropsCache.get(dsId) ?? this.activeRenderPropsCache.get(dsId);
|
|
391
|
+
if (!baseProps) continue;
|
|
392
|
+
const overrides = this._propertyOverrides.get(dsId);
|
|
393
|
+
const renderProps = overrides ? { ...baseProps, ...overrides, animationOpacity: el.current.opacity } : {
|
|
394
|
+
...baseProps,
|
|
395
|
+
animationOpacity: el.current.opacity
|
|
396
|
+
};
|
|
397
|
+
newRenderLayouts.set(dsId, layout);
|
|
398
|
+
newActiveProps.set(dsId, renderProps);
|
|
399
|
+
}
|
|
400
|
+
this.renderLayouts = newRenderLayouts;
|
|
401
|
+
this.activeRenderPropsCache = newActiveProps;
|
|
402
|
+
}
|
|
403
|
+
/** Rebuild render state, then paint (canvas: triggers a compositor repaint). */
|
|
404
|
+
_renderSceneFrame() {
|
|
405
|
+
this._rebuildRenderLayouts();
|
|
406
|
+
this.renderFrame();
|
|
407
|
+
}
|
|
408
|
+
/**
|
|
409
|
+
* Update visible-only caches (layoutCache, renderPropsCache) and marker
|
|
410
|
+
* overlays from the current set of visible scatter datasets.
|
|
411
|
+
*/
|
|
412
|
+
_updateCachesAndLayout(visibleDatasets, input) {
|
|
413
|
+
const newLayoutCache = /* @__PURE__ */ new Map();
|
|
414
|
+
const newRenderPropsCache = /* @__PURE__ */ new Map();
|
|
415
|
+
const sortedVisible = [...visibleDatasets].sort((a, b) => (input.datasets.get(a.id)?.order ?? 0) - (input.datasets.get(b.id)?.order ?? 0));
|
|
416
|
+
let dsIdx = 0;
|
|
417
|
+
for (const sd of sortedVisible) {
|
|
418
|
+
const props = sd.props;
|
|
419
|
+
const targetXAxisId = props.xAxisId ?? input.firstCategoryAxisId;
|
|
420
|
+
const targetYAxisId = props.yAxisId ?? input.firstValueAxisId;
|
|
421
|
+
const xScale = input.scatterXScales?.get(targetXAxisId);
|
|
422
|
+
const sharedValueScale = input.valueScales?.values().next().value;
|
|
423
|
+
const yScale = input.valueScales?.get(targetYAxisId) ?? sharedValueScale;
|
|
424
|
+
if (!xScale || !yScale) continue;
|
|
425
|
+
const baseLayout = calculateScatterLayout(props, input.chartArea, {
|
|
426
|
+
xScale,
|
|
427
|
+
yScale,
|
|
428
|
+
stackBases: input.scatterStackBasesMap?.get(sd.id)
|
|
429
|
+
});
|
|
430
|
+
const layout = { ...baseLayout, datasetIndex: dsIdx++ };
|
|
431
|
+
newLayoutCache.set(sd.id, layout);
|
|
432
|
+
newRenderPropsCache.set(sd.id, this.buildRenderProps(sd, input));
|
|
433
|
+
}
|
|
434
|
+
this.layoutCache = newLayoutCache;
|
|
435
|
+
this.renderPropsCache = newRenderPropsCache;
|
|
436
|
+
this._markerOverlays = collectScatterMarkerOverlays(newLayoutCache, newRenderPropsCache);
|
|
437
|
+
}
|
|
438
|
+
/** Cancel any in-flight raf. */
|
|
439
|
+
_cancelRaf() {
|
|
440
|
+
if (this._animRafId !== null) {
|
|
441
|
+
cancelRaf(this._animRafId);
|
|
442
|
+
this._animRafId = null;
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
_commit(fingerprint) {
|
|
446
|
+
this._lastFingerprint = fingerprint;
|
|
447
|
+
}
|
|
448
|
+
buildRenderProps(sd, input) {
|
|
449
|
+
const anyHovered = this.hover.datasetId !== null;
|
|
450
|
+
const isThisSeries = this.hover.datasetId === sd.id;
|
|
451
|
+
const hoverConfig = input.hoverConfig;
|
|
452
|
+
return {
|
|
453
|
+
...sd.props,
|
|
454
|
+
interaction: {
|
|
455
|
+
hoveredIndex: isThisSeries ? this.hover.index : null,
|
|
456
|
+
isSeriesDimmed: anyHovered && !isThisSeries
|
|
457
|
+
},
|
|
458
|
+
effects: {
|
|
459
|
+
hoverBrightness: hoverConfig?.brightness ?? DEFAULT_HOVER_BRIGHTNESS,
|
|
460
|
+
dimOpacity: hoverConfig?.dimOpacity ?? DEFAULT_HOVER_DIM_OPACITY,
|
|
461
|
+
hoverRadiusMultiplier: hoverConfig?.radiusMultiplier,
|
|
462
|
+
// Per-point hover accessors stay on props.pointHoverBackgroundColor / pointHoverBorderColor;
|
|
463
|
+
// the renderer resolves them per-point and falls back to effects.* (global <Chart.Hover>).
|
|
464
|
+
hoverBackgroundColor: sd.props.hoverColor ?? hoverConfig?.backgroundColor,
|
|
465
|
+
hoverBorderColor: sd.props.hoverBorderColor ?? hoverConfig?.borderColor,
|
|
466
|
+
hoverBorderStrokeWidth: hoverConfig?.borderStrokeWidth,
|
|
467
|
+
hoverPointRadius: sd.props.hoverPointRadius
|
|
468
|
+
}
|
|
469
|
+
};
|
|
470
|
+
}
|
|
471
|
+
/**
|
|
472
|
+
* Paint a frame using already-populated render-time caches.
|
|
473
|
+
* Cache population is the responsibility of `_updateCachesAndLayout`
|
|
474
|
+
* (visible-only caches) and `_renderSceneFrame` (animation-time render caches).
|
|
475
|
+
*/
|
|
476
|
+
renderFrame() {
|
|
477
|
+
if (!this.lastInput) return;
|
|
478
|
+
const input = this.lastInput;
|
|
479
|
+
const renderLayouts = this.renderLayouts;
|
|
480
|
+
const activeRenderProps = this.activeRenderPropsCache;
|
|
481
|
+
const visibleLayouts = this.layoutCache;
|
|
482
|
+
const visibleRenderProps = this.renderPropsCache;
|
|
483
|
+
for (const [, layout] of visibleLayouts) {
|
|
484
|
+
if (layout.visiblePoints.length > SCATTER_SPATIAL_INDEX_THRESHOLD && !layout.spatialIndex) {
|
|
485
|
+
const area = layout.chartArea;
|
|
486
|
+
const pts = layout.visiblePoints;
|
|
487
|
+
const quadPoints = new Array(pts.length);
|
|
488
|
+
const map = /* @__PURE__ */ new Map();
|
|
489
|
+
for (let i = 0; i < pts.length; i++) {
|
|
490
|
+
const pt = pts[i];
|
|
491
|
+
quadPoints[i] = { x: pt.px, y: pt.py, idx: pt.dataIndex, r: pt.radius };
|
|
492
|
+
map.set(pt.dataIndex, pt);
|
|
493
|
+
}
|
|
494
|
+
layout.spatialIndex = buildQuadtree(quadPoints, { x0: area.x, y0: area.y, x1: area.x + area.width, y1: area.y + area.height });
|
|
495
|
+
layout.pointByDataIndex = map;
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
const context = {
|
|
499
|
+
chartId: input.chartId,
|
|
500
|
+
width: input.width,
|
|
501
|
+
height: input.height,
|
|
502
|
+
renderer: input.renderer,
|
|
503
|
+
chartArea: input.chartArea,
|
|
504
|
+
theme: input.theme,
|
|
505
|
+
accessibility: buildAccessibilityRenderContext(input.features)
|
|
506
|
+
};
|
|
507
|
+
if (triggerCompositorRepaint(input.renderer, this.canvasEl, input.compositor)) {
|
|
508
|
+
this.onFrame?.();
|
|
509
|
+
return;
|
|
510
|
+
}
|
|
511
|
+
if (input.renderer === "svg" && this.svgGroup) {
|
|
512
|
+
const group = this.svgGroup;
|
|
513
|
+
const children = buildScatterSvgChildren({
|
|
514
|
+
paint: this._paint,
|
|
515
|
+
renderLayouts,
|
|
516
|
+
activeRenderProps,
|
|
517
|
+
visibleLayouts,
|
|
518
|
+
visibleRenderProps,
|
|
519
|
+
context,
|
|
520
|
+
hover: this.hover,
|
|
521
|
+
labelConfig: input.labelConfig,
|
|
522
|
+
datasetVisibility: input.datasetVisibility
|
|
523
|
+
});
|
|
524
|
+
group.replaceChildren(...children.map(materializeSvgNode));
|
|
525
|
+
} else if (input.renderer === "canvas") {
|
|
526
|
+
const ctx = this.canvasEl?.getContext("2d");
|
|
527
|
+
if (ctx) {
|
|
528
|
+
for (const [, scatterLayout] of renderLayouts) {
|
|
529
|
+
const props = activeRenderProps.get(scatterLayout.datasetId);
|
|
530
|
+
if (!props) continue;
|
|
531
|
+
this._paint.renderCanvas(props, scatterLayout, ctx, context);
|
|
532
|
+
}
|
|
533
|
+
if (input.labelConfig && !input.labelConfig.render) {
|
|
534
|
+
for (const [dsId, scatterLayout] of visibleLayouts) {
|
|
535
|
+
if (input.datasetVisibility?.get(dsId) === false) continue;
|
|
536
|
+
const props = visibleRenderProps.get(dsId);
|
|
537
|
+
const seriesColor = typeof props?.color === "string" ? props.color : DEFAULT_FALLBACK_COLOR;
|
|
538
|
+
renderResolvedLabels(resolveScatterLabels(scatterLayout.visiblePoints, seriesColor, input.labelConfig, props?.name, props?.data), input.labelConfig, {
|
|
539
|
+
renderer: "canvas",
|
|
540
|
+
ctx,
|
|
541
|
+
theme: input.theme
|
|
542
|
+
});
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
this.onFrame?.();
|
|
548
|
+
}
|
|
549
|
+
/**
|
|
550
|
+
* Canvas compositor layer paint callback. Reads the current `renderLayouts`
|
|
551
|
+
* + `activeRenderPropsCache` so every repaint (line-triggered, chrome-triggered,
|
|
552
|
+
* or scatter-triggered) draws the current animated opacity without needing
|
|
553
|
+
* pre-mutated state.
|
|
554
|
+
*/
|
|
555
|
+
paintCanvasLayer(ctx, dsId) {
|
|
556
|
+
const layout = this.renderLayouts.get(dsId);
|
|
557
|
+
const props = this.activeRenderPropsCache.get(dsId);
|
|
558
|
+
if (!layout || !props || props.renderMarker || !this.lastInput) return;
|
|
559
|
+
const context = {
|
|
560
|
+
chartId: this.lastInput.chartId,
|
|
561
|
+
width: this.lastInput.width,
|
|
562
|
+
height: this.lastInput.height,
|
|
563
|
+
renderer: "canvas",
|
|
564
|
+
chartArea: this.lastInput.chartArea,
|
|
565
|
+
theme: this.lastInput.theme
|
|
566
|
+
};
|
|
567
|
+
this._paint.renderCanvas(props, layout, ctx, context);
|
|
568
|
+
if (this.lastInput?.labelConfig && !this.lastInput.labelConfig.render && this.lastInput.datasetVisibility?.get(dsId) !== false) {
|
|
569
|
+
const seriesColor = typeof props.color === "string" ? props.color : DEFAULT_FALLBACK_COLOR;
|
|
570
|
+
renderResolvedLabels(resolveScatterLabels(layout.visiblePoints, seriesColor, this.lastInput.labelConfig, props.name, props.data), this.lastInput.labelConfig, {
|
|
571
|
+
renderer: "canvas",
|
|
572
|
+
ctx,
|
|
573
|
+
theme: this.lastInput.theme
|
|
574
|
+
});
|
|
575
|
+
}
|
|
576
|
+
}
|
|
577
|
+
};
|
|
578
|
+
|
|
579
|
+
export { ScatterRendererController };
|