graphein 0.20.0 → 0.22.0
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/animation/animate.d.ts +6 -1
- package/dist/animation/animate.d.ts.map +1 -1
- package/dist/animation/animate.js +2 -2
- package/dist/animation/animate.js.map +2 -2
- package/dist/animation/env.d.ts +5 -0
- package/dist/animation/env.d.ts.map +1 -1
- package/dist/animation/env.js +4 -0
- package/dist/animation/env.js.map +2 -2
- package/dist/animation/index.d.ts +1 -0
- package/dist/animation/index.d.ts.map +1 -1
- package/dist/animation/index.js +1 -0
- package/dist/animation/index.js.map +2 -2
- package/dist/animation/stagger.d.ts +13 -0
- package/dist/animation/stagger.d.ts.map +1 -0
- package/dist/animation/stagger.js +13 -0
- package/dist/animation/stagger.js.map +7 -0
- package/dist/axes/draw.d.ts +5 -1
- package/dist/axes/draw.d.ts.map +1 -1
- package/dist/axes/draw.js +13 -1
- package/dist/axes/draw.js.map +2 -2
- package/dist/axes/morph.d.ts +111 -0
- package/dist/axes/morph.d.ts.map +1 -0
- package/dist/axes/morph.js +207 -0
- package/dist/axes/morph.js.map +7 -0
- package/dist/axes/overlay.d.ts.map +1 -1
- package/dist/axes/overlay.js +88 -25
- package/dist/axes/overlay.js.map +2 -2
- package/dist/axes/text.d.ts +2 -0
- package/dist/axes/text.d.ts.map +1 -1
- package/dist/axes/text.js +1 -0
- package/dist/axes/text.js.map +2 -2
- package/dist/axes/tickLabels.d.ts +2 -0
- package/dist/axes/tickLabels.d.ts.map +1 -1
- package/dist/axes/tickLabels.js +2 -2
- package/dist/axes/tickLabels.js.map +2 -2
- package/dist/charts/annotations.d.ts +9 -3
- package/dist/charts/annotations.d.ts.map +1 -1
- package/dist/charts/annotations.js +82 -27
- package/dist/charts/annotations.js.map +2 -2
- package/dist/charts/area.d.ts +37 -1
- package/dist/charts/area.d.ts.map +1 -1
- package/dist/charts/area.js +35 -17
- package/dist/charts/area.js.map +2 -2
- package/dist/charts/bar.d.ts +53 -0
- package/dist/charts/bar.d.ts.map +1 -1
- package/dist/charts/bar.js +117 -83
- package/dist/charts/bar.js.map +2 -2
- package/dist/charts/box.d.ts +31 -0
- package/dist/charts/box.d.ts.map +1 -1
- package/dist/charts/box.js +93 -70
- package/dist/charts/box.js.map +2 -2
- package/dist/charts/bubbleMap.d.ts +20 -0
- package/dist/charts/bubbleMap.d.ts.map +1 -0
- package/dist/charts/bubbleMap.js +951 -0
- package/dist/charts/bubbleMap.js.map +7 -0
- package/dist/charts/bullet.d.ts.map +1 -1
- package/dist/charts/bullet.js +69 -51
- package/dist/charts/bullet.js.map +2 -2
- package/dist/charts/calendarHeatmap.d.ts.map +1 -1
- package/dist/charts/calendarHeatmap.js +56 -19
- package/dist/charts/calendarHeatmap.js.map +2 -2
- package/dist/charts/candlestick.d.ts +40 -0
- package/dist/charts/candlestick.d.ts.map +1 -0
- package/dist/charts/candlestick.js +325 -0
- package/dist/charts/candlestick.js.map +7 -0
- package/dist/charts/choropleth.d.ts.map +1 -1
- package/dist/charts/choropleth.js +46 -67
- package/dist/charts/choropleth.js.map +2 -2
- package/dist/charts/combo.d.ts.map +1 -1
- package/dist/charts/combo.js +127 -27
- package/dist/charts/combo.js.map +3 -3
- package/dist/charts/dumbbell.d.ts.map +1 -1
- package/dist/charts/dumbbell.js +100 -31
- package/dist/charts/dumbbell.js.map +2 -2
- package/dist/charts/funnel.d.ts.map +1 -1
- package/dist/charts/funnel.js +93 -28
- package/dist/charts/funnel.js.map +3 -3
- package/dist/charts/gantt.d.ts +22 -0
- package/dist/charts/gantt.d.ts.map +1 -0
- package/dist/charts/gantt.js +564 -0
- package/dist/charts/gantt.js.map +7 -0
- package/dist/charts/gauge.d.ts.map +1 -1
- package/dist/charts/gauge.js +30 -4
- package/dist/charts/gauge.js.map +2 -2
- package/dist/charts/geo.d.ts +87 -0
- package/dist/charts/geo.d.ts.map +1 -0
- package/dist/charts/geo.js +140 -0
- package/dist/charts/geo.js.map +7 -0
- package/dist/charts/geometry.d.ts +20 -0
- package/dist/charts/geometry.d.ts.map +1 -0
- package/dist/charts/geometry.js +25 -0
- package/dist/charts/geometry.js.map +7 -0
- package/dist/charts/heatmap.d.ts.map +1 -1
- package/dist/charts/heatmap.js +58 -49
- package/dist/charts/heatmap.js.map +2 -2
- package/dist/charts/histogram.d.ts +1 -1
- package/dist/charts/histogram.d.ts.map +1 -1
- package/dist/charts/histogram.js +49 -31
- package/dist/charts/histogram.js.map +2 -2
- package/dist/charts/index.d.ts +35 -1
- package/dist/charts/index.d.ts.map +1 -1
- package/dist/charts/index.js +12 -0
- package/dist/charts/index.js.map +2 -2
- package/dist/charts/legibility.d.ts +38 -0
- package/dist/charts/legibility.d.ts.map +1 -0
- package/dist/charts/legibility.js +72 -0
- package/dist/charts/legibility.js.map +7 -0
- package/dist/charts/line.d.ts +39 -1
- package/dist/charts/line.d.ts.map +1 -1
- package/dist/charts/line.js +48 -16
- package/dist/charts/line.js.map +2 -2
- package/dist/charts/matrix.d.ts +2 -1
- package/dist/charts/matrix.d.ts.map +1 -1
- package/dist/charts/matrix.js +481 -319
- package/dist/charts/matrix.js.map +3 -3
- package/dist/charts/morphFrame.d.ts +83 -0
- package/dist/charts/morphFrame.d.ts.map +1 -0
- package/dist/charts/morphFrame.js +128 -0
- package/dist/charts/morphFrame.js.map +7 -0
- package/dist/charts/pie.d.ts.map +1 -1
- package/dist/charts/pie.js +89 -26
- package/dist/charts/pie.js.map +2 -2
- package/dist/charts/pieState.d.ts +27 -0
- package/dist/charts/pieState.d.ts.map +1 -0
- package/dist/charts/pieState.js +55 -0
- package/dist/charts/pieState.js.map +7 -0
- package/dist/charts/radar.d.ts +62 -0
- package/dist/charts/radar.d.ts.map +1 -0
- package/dist/charts/radar.js +912 -0
- package/dist/charts/radar.js.map +7 -0
- package/dist/charts/radialBar.d.ts +60 -0
- package/dist/charts/radialBar.d.ts.map +1 -0
- package/dist/charts/radialBar.js +708 -0
- package/dist/charts/radialBar.js.map +7 -0
- package/dist/charts/sankey.d.ts.map +1 -1
- package/dist/charts/sankey.js +223 -57
- package/dist/charts/sankey.js.map +3 -3
- package/dist/charts/scatter.d.ts +31 -0
- package/dist/charts/scatter.d.ts.map +1 -1
- package/dist/charts/scatter.js +48 -12
- package/dist/charts/scatter.js.map +2 -2
- package/dist/charts/slope.d.ts.map +1 -1
- package/dist/charts/slope.js +55 -3
- package/dist/charts/slope.js.map +2 -2
- package/dist/charts/sunburst.d.ts +14 -0
- package/dist/charts/sunburst.d.ts.map +1 -0
- package/dist/charts/sunburst.js +885 -0
- package/dist/charts/sunburst.js.map +7 -0
- package/dist/charts/table.d.ts +2 -1
- package/dist/charts/table.d.ts.map +1 -1
- package/dist/charts/table.js +214 -224
- package/dist/charts/table.js.map +3 -3
- package/dist/charts/tableView/canvas.d.ts +16 -1
- package/dist/charts/tableView/canvas.d.ts.map +1 -1
- package/dist/charts/tableView/canvas.js +361 -252
- package/dist/charts/tableView/canvas.js.map +3 -3
- package/dist/charts/tableView/conditional.d.ts +66 -40
- package/dist/charts/tableView/conditional.d.ts.map +1 -1
- package/dist/charts/tableView/conditional.js +163 -256
- package/dist/charts/tableView/conditional.js.map +3 -3
- package/dist/charts/tableView/dom.d.ts +26 -2
- package/dist/charts/tableView/dom.d.ts.map +1 -1
- package/dist/charts/tableView/dom.js +609 -269
- package/dist/charts/tableView/dom.js.map +3 -3
- package/dist/charts/tableView/layout.d.ts +22 -0
- package/dist/charts/tableView/layout.d.ts.map +1 -0
- package/dist/charts/tableView/layout.js +246 -0
- package/dist/charts/tableView/layout.js.map +7 -0
- package/dist/charts/tableView/sketch.d.ts +3 -2
- package/dist/charts/tableView/sketch.d.ts.map +1 -1
- package/dist/charts/tableView/sketch.js +2 -2
- package/dist/charts/tableView/sketch.js.map +2 -2
- package/dist/charts/tableView/sketchBar.d.ts +7 -0
- package/dist/charts/tableView/sketchBar.d.ts.map +1 -0
- package/dist/charts/tableView/sketchBar.js +32 -0
- package/dist/charts/tableView/sketchBar.js.map +7 -0
- package/dist/charts/tableView/sort.d.ts +9 -0
- package/dist/charts/tableView/sort.d.ts.map +1 -0
- package/dist/charts/tableView/sort.js +70 -0
- package/dist/charts/tableView/sort.js.map +7 -0
- package/dist/charts/tableView/sparkline.d.ts +30 -0
- package/dist/charts/tableView/sparkline.d.ts.map +1 -0
- package/dist/charts/tableView/sparkline.js +63 -0
- package/dist/charts/tableView/sparkline.js.map +7 -0
- package/dist/charts/tableView/style.d.ts +67 -0
- package/dist/charts/tableView/style.d.ts.map +1 -0
- package/dist/charts/tableView/style.js +131 -0
- package/dist/charts/tableView/style.js.map +7 -0
- package/dist/charts/tableView/types.d.ts +69 -46
- package/dist/charts/tableView/types.d.ts.map +1 -1
- package/dist/charts/tableView/types.js +22 -87
- package/dist/charts/tableView/types.js.map +2 -2
- package/dist/charts/tableView.d.ts +10 -5
- package/dist/charts/tableView.d.ts.map +1 -1
- package/dist/charts/tableView.js +12 -8
- package/dist/charts/tableView.js.map +2 -2
- package/dist/charts/treemap.d.ts.map +1 -1
- package/dist/charts/treemap.js +177 -68
- package/dist/charts/treemap.js.map +3 -3
- package/dist/charts/trendline.d.ts +13 -5
- package/dist/charts/trendline.d.ts.map +1 -1
- package/dist/charts/trendline.js +205 -56
- package/dist/charts/trendline.js.map +2 -2
- package/dist/charts/waterfall.d.ts.map +1 -1
- package/dist/charts/waterfall.js +76 -5
- package/dist/charts/waterfall.js.map +2 -2
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/interaction/cartesian.d.ts +4 -1
- package/dist/interaction/cartesian.d.ts.map +1 -1
- package/dist/interaction/cartesian.js +104 -34
- package/dist/interaction/cartesian.js.map +2 -2
- package/dist/interaction/controller.d.ts +29 -1
- package/dist/interaction/controller.d.ts.map +1 -1
- package/dist/interaction/controller.js +131 -8
- package/dist/interaction/controller.js.map +2 -2
- package/dist/interaction/focus.d.ts +23 -0
- package/dist/interaction/focus.d.ts.map +1 -0
- package/dist/interaction/focus.js +65 -0
- package/dist/interaction/focus.js.map +7 -0
- package/dist/interaction/tooltip.d.ts +6 -0
- package/dist/interaction/tooltip.d.ts.map +1 -1
- package/dist/interaction/tooltip.js +41 -16
- package/dist/interaction/tooltip.js.map +2 -2
- package/dist/interaction/types.d.ts +19 -0
- package/dist/interaction/types.d.ts.map +1 -1
- package/dist/interaction/veil.d.ts +25 -0
- package/dist/interaction/veil.d.ts.map +1 -0
- package/dist/interaction/veil.js +35 -0
- package/dist/interaction/veil.js.map +7 -0
- package/dist/pivot/pivot.d.ts +18 -0
- package/dist/pivot/pivot.d.ts.map +1 -1
- package/dist/pivot/pivot.js +46 -34
- package/dist/pivot/pivot.js.map +2 -2
- package/dist/render/chromeMotion.d.ts +65 -0
- package/dist/render/chromeMotion.d.ts.map +1 -0
- package/dist/render/chromeMotion.js +79 -0
- package/dist/render/chromeMotion.js.map +7 -0
- package/dist/render/pathSample.d.ts +24 -0
- package/dist/render/pathSample.d.ts.map +1 -0
- package/dist/render/pathSample.js +76 -0
- package/dist/render/pathSample.js.map +7 -0
- package/dist/render/transient.d.ts +18 -0
- package/dist/render/transient.d.ts.map +1 -0
- package/dist/render/transient.js +19 -0
- package/dist/render/transient.js.map +7 -0
- package/dist/runtime/candlestick.d.ts +112 -0
- package/dist/runtime/candlestick.d.ts.map +1 -0
- package/dist/runtime/candlestick.js +531 -0
- package/dist/runtime/candlestick.js.map +7 -0
- package/dist/runtime/cartesian.d.ts +14 -3
- package/dist/runtime/cartesian.d.ts.map +1 -1
- package/dist/runtime/cartesian.js.map +2 -2
- package/dist/runtime/chartAnimation.d.ts +54 -7
- package/dist/runtime/chartAnimation.d.ts.map +1 -1
- package/dist/runtime/chartAnimation.js +146 -28
- package/dist/runtime/chartAnimation.js.map +2 -2
- package/dist/runtime/chartRuntime.d.ts +42 -0
- package/dist/runtime/chartRuntime.d.ts.map +1 -1
- package/dist/runtime/chartRuntime.js +196 -30
- package/dist/runtime/chartRuntime.js.map +2 -2
- package/dist/runtime/dashboardDom.d.ts.map +1 -1
- package/dist/runtime/dashboardDom.js +45 -0
- package/dist/runtime/dashboardDom.js.map +2 -2
- package/dist/runtime/facet.d.ts +1 -1
- package/dist/runtime/facet.d.ts.map +1 -1
- package/dist/runtime/gantt.d.ts +137 -0
- package/dist/runtime/gantt.d.ts.map +1 -0
- package/dist/runtime/gantt.js +647 -0
- package/dist/runtime/gantt.js.map +7 -0
- package/dist/runtime/morph.d.ts +33 -0
- package/dist/runtime/morph.d.ts.map +1 -0
- package/dist/runtime/morph.js +332 -0
- package/dist/runtime/morph.js.map +7 -0
- package/dist/runtime/radar.d.ts +75 -0
- package/dist/runtime/radar.d.ts.map +1 -0
- package/dist/runtime/radar.js +201 -0
- package/dist/runtime/radar.js.map +7 -0
- package/dist/runtime/radialBar.d.ts +81 -0
- package/dist/runtime/radialBar.d.ts.map +1 -0
- package/dist/runtime/radialBar.js +125 -0
- package/dist/runtime/radialBar.js.map +7 -0
- package/dist/runtime/report/constants.d.ts +2 -2
- package/dist/runtime/report/constants.d.ts.map +1 -1
- package/dist/runtime/runtimeShared.d.ts +3 -3
- package/dist/runtime/runtimeShared.d.ts.map +1 -1
- package/dist/runtime/sunburst.d.ts +74 -0
- package/dist/runtime/sunburst.d.ts.map +1 -0
- package/dist/runtime/sunburst.js +150 -0
- package/dist/runtime/sunburst.js.map +7 -0
- package/dist/runtime/wire.d.ts.map +1 -1
- package/dist/runtime/wire.js +3 -1
- package/dist/runtime/wire.js.map +2 -2
- package/dist/shape/arc.d.ts +15 -2
- package/dist/shape/arc.d.ts.map +1 -1
- package/dist/shape/arc.js +204 -32
- package/dist/shape/arc.js.map +2 -2
- package/dist/spec/chartDefinitions.d.ts +6 -0
- package/dist/spec/chartDefinitions.d.ts.map +1 -1
- package/dist/spec/chartDefinitions.js +7 -1
- package/dist/spec/chartDefinitions.js.map +2 -2
- package/dist/spec/templates.d.ts.map +1 -1
- package/dist/spec/templates.js +177 -2
- package/dist/spec/templates.js.map +2 -2
- package/dist/spec/types.d.ts +258 -6
- package/dist/spec/types.d.ts.map +1 -1
- package/dist/spec/types.js +6 -0
- package/dist/spec/types.js.map +2 -2
- package/dist/spec/validate/charts.js +147 -15
- package/dist/spec/validate/charts.js.map +2 -2
- package/dist/spec/validate/common.d.ts +6 -0
- package/dist/spec/validate/common.d.ts.map +1 -1
- package/dist/spec/validate/overlays.js +2 -2
- package/dist/spec/validate/overlays.js.map +2 -2
- package/dist/spec/validate.data.d.ts.map +1 -1
- package/dist/spec/validate.data.js +8 -3
- package/dist/spec/validate.data.js.map +2 -2
- package/package.json +1 -1
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Focus veils — the dependency-free half of hover focus. A veil is a
|
|
3
|
+
* translucent wash of the chart background painted on the interaction layer
|
|
4
|
+
* over a plot area, receding every mark beneath it; a cutout veil leaves the
|
|
5
|
+
* hovered mark's own shape unveiled so it stays at full strength.
|
|
6
|
+
*/
|
|
7
|
+
import type { Rect } from '../types.js';
|
|
8
|
+
/** Veil opacity at full focus: unfocused marks keep roughly 40% of their ink. */
|
|
9
|
+
export declare const FOCUS_VEIL = 0.6;
|
|
10
|
+
/** Whether hover focus is on for a spec. `tooltip: { focus: false }` opts out, and
|
|
11
|
+
* hand-drawn (sketch) charts keep their classic highlight because rough marks
|
|
12
|
+
* can't be repainted stroke-for-stroke. */
|
|
13
|
+
export declare function hoverFocusEnabled(spec: {
|
|
14
|
+
tooltip?: unknown;
|
|
15
|
+
sketch?: unknown;
|
|
16
|
+
}): boolean;
|
|
17
|
+
/** Recede `rect` behind a veil of `color` at `strength` (0..1). */
|
|
18
|
+
export declare function paintFocusVeil(ctx: CanvasRenderingContext2D, rect: Rect, color: string, strength: number): void;
|
|
19
|
+
/**
|
|
20
|
+
* Recede `rect` behind a veil everywhere except inside the shape `trace` adds
|
|
21
|
+
* to the current path — the hovered mark stays untouched at full strength, so
|
|
22
|
+
* charts with bespoke mark geometry get focus without repainting anything.
|
|
23
|
+
*/
|
|
24
|
+
export declare function paintCutoutVeil(ctx: CanvasRenderingContext2D, rect: Rect, color: string, strength: number, trace: (ctx: CanvasRenderingContext2D) => void): void;
|
|
25
|
+
//# sourceMappingURL=veil.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"veil.d.ts","sourceRoot":"","sources":["../../src/interaction/veil.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,UAAU,CAAC;AAErC,iFAAiF;AACjF,eAAO,MAAM,UAAU,MAAM,CAAC;AAE9B;;2CAE2C;AAC3C,wBAAgB,iBAAiB,CAAC,IAAI,EAAE;IAAE,OAAO,CAAC,EAAE,OAAO,CAAC;IAAC,MAAM,CAAC,EAAE,OAAO,CAAA;CAAE,GAAG,OAAO,CAIxF;AAED,mEAAmE;AACnE,wBAAgB,cAAc,CAAC,GAAG,EAAE,wBAAwB,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,CAO/G;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAC7B,GAAG,EAAE,wBAAwB,EAC7B,IAAI,EAAE,IAAI,EACV,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,CAAC,GAAG,EAAE,wBAAwB,KAAK,IAAI,GAC7C,IAAI,CAeN"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
const FOCUS_VEIL = 0.6;
|
|
2
|
+
function hoverFocusEnabled(spec) {
|
|
3
|
+
if (spec.sketch) return false;
|
|
4
|
+
const tooltip = spec.tooltip;
|
|
5
|
+
return !(tooltip && typeof tooltip === "object" && tooltip.focus === false);
|
|
6
|
+
}
|
|
7
|
+
function paintFocusVeil(ctx, rect, color, strength) {
|
|
8
|
+
if (!(strength > 0)) return;
|
|
9
|
+
ctx.save();
|
|
10
|
+
ctx.globalAlpha = Math.min(1, strength);
|
|
11
|
+
ctx.fillStyle = color;
|
|
12
|
+
ctx.fillRect(rect.x, rect.y, rect.width, rect.height);
|
|
13
|
+
ctx.restore();
|
|
14
|
+
}
|
|
15
|
+
function paintCutoutVeil(ctx, rect, color, strength, trace) {
|
|
16
|
+
if (!(strength > 0)) return;
|
|
17
|
+
ctx.save();
|
|
18
|
+
ctx.beginPath();
|
|
19
|
+
ctx.rect(rect.x, rect.y, rect.width, rect.height);
|
|
20
|
+
ctx.clip();
|
|
21
|
+
ctx.globalAlpha = Math.min(1, strength);
|
|
22
|
+
ctx.fillStyle = color;
|
|
23
|
+
ctx.beginPath();
|
|
24
|
+
ctx.rect(rect.x, rect.y, rect.width, rect.height);
|
|
25
|
+
trace(ctx);
|
|
26
|
+
ctx.fill("evenodd");
|
|
27
|
+
ctx.restore();
|
|
28
|
+
}
|
|
29
|
+
export {
|
|
30
|
+
FOCUS_VEIL,
|
|
31
|
+
hoverFocusEnabled,
|
|
32
|
+
paintCutoutVeil,
|
|
33
|
+
paintFocusVeil
|
|
34
|
+
};
|
|
35
|
+
//# sourceMappingURL=veil.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/interaction/veil.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * Focus veils \u2014 the dependency-free half of hover focus. A veil is a\n * translucent wash of the chart background painted on the interaction layer\n * over a plot area, receding every mark beneath it; a cutout veil leaves the\n * hovered mark's own shape unveiled so it stays at full strength.\n */\n\nimport type { Rect } from '../types';\n\n/** Veil opacity at full focus: unfocused marks keep roughly 40% of their ink. */\nexport const FOCUS_VEIL = 0.6;\n\n/** Whether hover focus is on for a spec. `tooltip: { focus: false }` opts out, and\n * hand-drawn (sketch) charts keep their classic highlight because rough marks\n * can't be repainted stroke-for-stroke. */\nexport function hoverFocusEnabled(spec: { tooltip?: unknown; sketch?: unknown }): boolean {\n if (spec.sketch) return false;\n const tooltip = spec.tooltip;\n return !(tooltip && typeof tooltip === 'object' && (tooltip as { focus?: unknown }).focus === false);\n}\n\n/** Recede `rect` behind a veil of `color` at `strength` (0..1). */\nexport function paintFocusVeil(ctx: CanvasRenderingContext2D, rect: Rect, color: string, strength: number): void {\n if (!(strength > 0)) return;\n ctx.save();\n ctx.globalAlpha = Math.min(1, strength);\n ctx.fillStyle = color;\n ctx.fillRect(rect.x, rect.y, rect.width, rect.height);\n ctx.restore();\n}\n\n/**\n * Recede `rect` behind a veil everywhere except inside the shape `trace` adds\n * to the current path \u2014 the hovered mark stays untouched at full strength, so\n * charts with bespoke mark geometry get focus without repainting anything.\n */\nexport function paintCutoutVeil(\n ctx: CanvasRenderingContext2D,\n rect: Rect,\n color: string,\n strength: number,\n trace: (ctx: CanvasRenderingContext2D) => void,\n): void {\n if (!(strength > 0)) return;\n ctx.save();\n // Clip to the veil: a cutout reaching past it (say, a bar cut off by a fixed\n // domain) must not flip into painted area under the even-odd rule.\n ctx.beginPath();\n ctx.rect(rect.x, rect.y, rect.width, rect.height);\n ctx.clip();\n ctx.globalAlpha = Math.min(1, strength);\n ctx.fillStyle = color;\n ctx.beginPath();\n ctx.rect(rect.x, rect.y, rect.width, rect.height);\n trace(ctx);\n ctx.fill('evenodd');\n ctx.restore();\n}\n"],
|
|
5
|
+
"mappings": "AAUO,MAAM,aAAa;AAKnB,SAAS,kBAAkB,MAAwD;AACxF,MAAI,KAAK,OAAQ,QAAO;AACxB,QAAM,UAAU,KAAK;AACrB,SAAO,EAAE,WAAW,OAAO,YAAY,YAAa,QAAgC,UAAU;AAChG;AAGO,SAAS,eAAe,KAA+B,MAAY,OAAe,UAAwB;AAC/G,MAAI,EAAE,WAAW,GAAI;AACrB,MAAI,KAAK;AACT,MAAI,cAAc,KAAK,IAAI,GAAG,QAAQ;AACtC,MAAI,YAAY;AAChB,MAAI,SAAS,KAAK,GAAG,KAAK,GAAG,KAAK,OAAO,KAAK,MAAM;AACpD,MAAI,QAAQ;AACd;AAOO,SAAS,gBACd,KACA,MACA,OACA,UACA,OACM;AACN,MAAI,EAAE,WAAW,GAAI;AACrB,MAAI,KAAK;AAGT,MAAI,UAAU;AACd,MAAI,KAAK,KAAK,GAAG,KAAK,GAAG,KAAK,OAAO,KAAK,MAAM;AAChD,MAAI,KAAK;AACT,MAAI,cAAc,KAAK,IAAI,GAAG,QAAQ;AACtC,MAAI,YAAY;AAChB,MAAI,UAAU;AACd,MAAI,KAAK,KAAK,GAAG,KAAK,GAAG,KAAK,OAAO,KAAK,MAAM;AAChD,QAAM,GAAG;AACT,MAAI,KAAK,SAAS;AAClB,MAAI,QAAQ;AACd;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
package/dist/pivot/pivot.d.ts
CHANGED
|
@@ -58,4 +58,22 @@ export declare function resolveValueRef(ref: number | {
|
|
|
58
58
|
} | undefined, data: readonly Datum[]): number | null;
|
|
59
59
|
export declare function groupBy<T extends Record<string, unknown>>(rows: T[], keyFields: string[]): GroupedMap<T>;
|
|
60
60
|
export declare function pivot(data: Datum[], options: PivotOptions): PivotResult;
|
|
61
|
+
/** One distinct prefix path of an axis, in first-seen order (id 0 is the empty path). */
|
|
62
|
+
export interface PivotAxisEntry {
|
|
63
|
+
id: number;
|
|
64
|
+
parent: number;
|
|
65
|
+
depth: number;
|
|
66
|
+
key: string;
|
|
67
|
+
/** The first raw value seen for this key (keeps real types such as dates). */
|
|
68
|
+
value: unknown;
|
|
69
|
+
}
|
|
70
|
+
/** Aggregates for every (row prefix × column prefix) path, built in one pass over the data. */
|
|
71
|
+
export interface PivotCube {
|
|
72
|
+
valueAt(rowPath: string[], colPath: string[], valueIndex: number): number | null;
|
|
73
|
+
/** Same as {@link valueAt} for interned path ids from {@link rowAxis}/{@link columnAxis}. */
|
|
74
|
+
valueAtIds(rowId: number, colId: number, valueIndex: number): number | null;
|
|
75
|
+
readonly rowAxis: readonly PivotAxisEntry[];
|
|
76
|
+
readonly columnAxis: readonly PivotAxisEntry[];
|
|
77
|
+
}
|
|
78
|
+
export declare function buildPivotCube(data: Datum[], rowFields: string[], columnFields: string[], values: PivotValueDef[]): PivotCube;
|
|
61
79
|
//# sourceMappingURL=pivot.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pivot.d.ts","sourceRoot":"","sources":["../../src/pivot/pivot.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,UAAU,CAAC;AAItC,MAAM,MAAM,KAAK,GACb,KAAK,GACL,MAAM,GACN,KAAK,GACL,KAAK,GACL,KAAK,GACL,OAAO,GACP,eAAe,GACf,QAAQ,GACR,OAAO,GACP,MAAM,CAAC;AAEX,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,EAAE,EAAE,KAAK,CAAC;IACV,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,MAAM,EAAE,aAAa,EAAE,CAAC;IACxB,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,sBAAsB,CAAC,EAAE,OAAO,CAAC;IACjC,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,IAAI,CAAC,EAAE,KAAK,GAAG,MAAM,GAAG,MAAM,CAAC;CAChC;AAED,MAAM,WAAW,eAAe;IAC9B,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,eAAe,EAAE,CAAC;IAC5B,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,SAAS;IACxB,MAAM,EAAE,CAAC,MAAM,GAAG,IAAI,CAAC,EAAE,CAAC;CAC3B;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,gBAAgB,EAAE,GAAG,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;CAC1C;AAED,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,eAAe,EAAE,CAAC;IAC3B,UAAU,EAAE,eAAe,EAAE,CAAC;IAC9B,YAAY,EAAE,eAAe,EAAE,CAAC;IAChC,IAAI,EAAE,YAAY,EAAE,CAAC;IACrB,MAAM,EAAE,aAAa,EAAE,CAAC;IACxB,OAAO,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;CAClF;AAED,MAAM,MAAM,UAAU,CAAC,CAAC,IAAI,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;AAM7D,wBAAgB,eAAe,CAAC,MAAM,EAAE,OAAO,EAAE,EAAE,EAAE,EAAE,KAAK,GAAG,MAAM,GAAG,IAAI,CAwD3E;AAED;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAC7B,GAAG,EAAE,MAAM,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,KAAK,CAAA;CAAE,GAAG,SAAS,EAC9D,IAAI,EAAE,SAAS,KAAK,EAAE,GACrB,MAAM,GAAG,IAAI,CAQf;AAED,wBAAgB,OAAO,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACvD,IAAI,EAAE,CAAC,EAAE,EACT,SAAS,EAAE,MAAM,EAAE,GAClB,UAAU,CAAC,CAAC,CAAC,CA6Bf;AAED,wBAAgB,KAAK,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,OAAO,EAAE,YAAY,GAAG,WAAW,CA+BvE"}
|
|
1
|
+
{"version":3,"file":"pivot.d.ts","sourceRoot":"","sources":["../../src/pivot/pivot.ts"],"names":[],"mappings":"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"}
|
package/dist/pivot/pivot.js
CHANGED
|
@@ -260,6 +260,7 @@ class AxisPathInterner {
|
|
|
260
260
|
__publicField(this, "children", /* @__PURE__ */ new Map());
|
|
261
261
|
__publicField(this, "nextKeyId", 1);
|
|
262
262
|
__publicField(this, "nextPathId", 1);
|
|
263
|
+
__publicField(this, "entries", []);
|
|
263
264
|
this.keyIds = fields.map(() => /* @__PURE__ */ new Map());
|
|
264
265
|
}
|
|
265
266
|
keyId(depth, key, create) {
|
|
@@ -271,7 +272,7 @@ class AxisPathInterner {
|
|
|
271
272
|
}
|
|
272
273
|
return id ?? -1;
|
|
273
274
|
}
|
|
274
|
-
child(parentId, keyId, create) {
|
|
275
|
+
child(parentId, keyId, create, depth = 0, key = "", value) {
|
|
275
276
|
let children = this.children.get(parentId);
|
|
276
277
|
if (!children) {
|
|
277
278
|
if (!create) return -1;
|
|
@@ -282,6 +283,7 @@ class AxisPathInterner {
|
|
|
282
283
|
if (id === void 0 && create) {
|
|
283
284
|
id = this.nextPathId++;
|
|
284
285
|
children.set(keyId, id);
|
|
286
|
+
this.entries.push({ id, parent: parentId, depth, key, value });
|
|
285
287
|
}
|
|
286
288
|
return id ?? -1;
|
|
287
289
|
}
|
|
@@ -310,21 +312,28 @@ function buildPivotCube(data, rowFields, columnFields, values) {
|
|
|
310
312
|
const rowPrefixIds = new Array(rowFields.length + 1);
|
|
311
313
|
const columnPrefixIds = new Array(columnFields.length + 1);
|
|
312
314
|
const valueCache = new Array(values.length);
|
|
315
|
+
const numberCache = new Array(values.length);
|
|
313
316
|
const buckets = /* @__PURE__ */ new Map();
|
|
314
317
|
const cache = /* @__PURE__ */ new Map();
|
|
315
318
|
for (const row of data) {
|
|
316
319
|
rowPrefixIds[0] = 0;
|
|
317
320
|
for (let depth = 0; depth < rowReads.length; depth++) {
|
|
318
|
-
const
|
|
319
|
-
|
|
321
|
+
const raw = rowReads[depth](row);
|
|
322
|
+
const key = toKey(raw);
|
|
323
|
+
const keyId = rows.keyId(depth, key, true);
|
|
324
|
+
rowPrefixIds[depth + 1] = rows.child(rowPrefixIds[depth], keyId, true, depth, key, raw);
|
|
320
325
|
}
|
|
321
326
|
columnPrefixIds[0] = 0;
|
|
322
327
|
for (let depth = 0; depth < columnReads.length; depth++) {
|
|
323
|
-
const
|
|
324
|
-
|
|
328
|
+
const raw = columnReads[depth](row);
|
|
329
|
+
const key = toKey(raw);
|
|
330
|
+
const keyId = columns.keyId(depth, key, true);
|
|
331
|
+
columnPrefixIds[depth + 1] = columns.child(columnPrefixIds[depth], keyId, true, depth, key, raw);
|
|
325
332
|
}
|
|
326
333
|
for (let valueIndex = 0; valueIndex < valueReads.length; valueIndex++) {
|
|
327
|
-
|
|
334
|
+
const raw = valueReads[valueIndex](row);
|
|
335
|
+
valueCache[valueIndex] = raw;
|
|
336
|
+
numberCache[valueIndex] = coerceFinite(raw);
|
|
328
337
|
}
|
|
329
338
|
for (let r = 0; r <= rowFields.length; r++) {
|
|
330
339
|
const rowId = rowPrefixIds[r];
|
|
@@ -341,38 +350,40 @@ function buildPivotCube(data, rowFields, columnFields, values) {
|
|
|
341
350
|
rowBuckets.set(colId, bucket);
|
|
342
351
|
}
|
|
343
352
|
for (let valueIndex = 0; valueIndex < values.length; valueIndex++) {
|
|
344
|
-
addToState(bucket[valueIndex], values[valueIndex].op, valueCache[valueIndex]);
|
|
353
|
+
addToState(bucket[valueIndex], values[valueIndex].op, valueCache[valueIndex], numberCache[valueIndex]);
|
|
345
354
|
}
|
|
346
355
|
}
|
|
347
356
|
}
|
|
348
357
|
}
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
if (!rowCache) {
|
|
358
|
-
rowCache = /* @__PURE__ */ new Map();
|
|
359
|
-
cache.set(rowId, rowCache);
|
|
360
|
-
}
|
|
361
|
-
let cached = rowCache.get(colId);
|
|
362
|
-
if (!cached) {
|
|
363
|
-
cached = new Array(values.length);
|
|
364
|
-
rowCache.set(colId, cached);
|
|
365
|
-
} else if (valueIndex in cached) {
|
|
366
|
-
return cached[valueIndex];
|
|
367
|
-
}
|
|
368
|
-
const bucket = buckets.get(rowId)?.get(colId);
|
|
369
|
-
const result = bucket ? stateValue(bucket[valueIndex], valueDef.op) : aggregateValues([], valueDef.op);
|
|
370
|
-
cached[valueIndex] = result;
|
|
371
|
-
return result;
|
|
358
|
+
const valueAtIds = (rowId, colId, valueIndex) => {
|
|
359
|
+
const valueDef = values[valueIndex];
|
|
360
|
+
if (!valueDef) return null;
|
|
361
|
+
if (rowId < 0 || colId < 0) return aggregateValues([], valueDef.op);
|
|
362
|
+
let rowCache = cache.get(rowId);
|
|
363
|
+
if (!rowCache) {
|
|
364
|
+
rowCache = /* @__PURE__ */ new Map();
|
|
365
|
+
cache.set(rowId, rowCache);
|
|
372
366
|
}
|
|
367
|
+
let cached = rowCache.get(colId);
|
|
368
|
+
if (!cached) {
|
|
369
|
+
cached = new Array(values.length);
|
|
370
|
+
rowCache.set(colId, cached);
|
|
371
|
+
} else if (valueIndex in cached) {
|
|
372
|
+
return cached[valueIndex];
|
|
373
|
+
}
|
|
374
|
+
const bucket = buckets.get(rowId)?.get(colId);
|
|
375
|
+
const result = bucket ? stateValue(bucket[valueIndex], valueDef.op) : aggregateValues([], valueDef.op);
|
|
376
|
+
cached[valueIndex] = result;
|
|
377
|
+
return result;
|
|
378
|
+
};
|
|
379
|
+
return {
|
|
380
|
+
valueAt: (rowPath, colPath, valueIndex) => valueAtIds(rows.pathId(rowPath, false), columns.pathId(colPath, false), valueIndex),
|
|
381
|
+
valueAtIds,
|
|
382
|
+
rowAxis: rows.entries,
|
|
383
|
+
columnAxis: columns.entries
|
|
373
384
|
};
|
|
374
385
|
}
|
|
375
|
-
function addToState(state, op, value) {
|
|
386
|
+
function addToState(state, op, value, numeric = coerceFinite(value)) {
|
|
376
387
|
if (op === "count") {
|
|
377
388
|
if (value !== null && value !== void 0) state.count = (state.count ?? 0) + 1;
|
|
378
389
|
return;
|
|
@@ -385,16 +396,16 @@ function addToState(state, op, value) {
|
|
|
385
396
|
}
|
|
386
397
|
if (op === "first") {
|
|
387
398
|
if (!state.hasFirst && value !== null && value !== void 0) {
|
|
388
|
-
state.first =
|
|
399
|
+
state.first = numeric;
|
|
389
400
|
state.hasFirst = true;
|
|
390
401
|
}
|
|
391
402
|
return;
|
|
392
403
|
}
|
|
393
404
|
if (op === "last") {
|
|
394
|
-
if (value !== null && value !== void 0) state.last =
|
|
405
|
+
if (value !== null && value !== void 0) state.last = numeric;
|
|
395
406
|
return;
|
|
396
407
|
}
|
|
397
|
-
const numberValue =
|
|
408
|
+
const numberValue = numeric;
|
|
398
409
|
if (numberValue === null) return;
|
|
399
410
|
if (op === "min") {
|
|
400
411
|
state.min = state.min === void 0 ? numberValue : Math.min(state.min, numberValue);
|
|
@@ -440,6 +451,7 @@ function stateValue(state, op) {
|
|
|
440
451
|
}
|
|
441
452
|
export {
|
|
442
453
|
aggregateValues,
|
|
454
|
+
buildPivotCube,
|
|
443
455
|
groupBy,
|
|
444
456
|
pivot,
|
|
445
457
|
resolveValueRef
|
package/dist/pivot/pivot.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/pivot/pivot.ts"],
|
|
4
|
-
"sourcesContent": ["import type { Datum } from '../types';\nimport { accessor, getField, toKey, toNumber } from '../util/data';\nimport { medianSorted, stableSum } from '../util/math';\n\nexport type AggOp =\n | 'sum'\n | 'mean'\n | 'avg'\n | 'min'\n | 'max'\n | 'count'\n | 'countDistinct'\n | 'median'\n | 'first'\n | 'last';\n\nexport interface PivotValueDef {\n field: string;\n op: AggOp;\n label?: string;\n}\n\nexport interface PivotOptions {\n rows?: string[];\n columns?: string[];\n values: PivotValueDef[];\n includeRowSubtotals?: boolean;\n includeColumnSubtotals?: boolean;\n includeGrandTotals?: boolean;\n sort?: 'asc' | 'desc' | 'none';\n}\n\nexport interface PivotHeaderNode {\n key: string;\n path: string[];\n depth: number;\n children: PivotHeaderNode[];\n isSubtotal?: boolean;\n isGrandTotal?: boolean;\n span: number;\n}\n\nexport interface PivotCell {\n values: (number | null)[];\n}\n\nexport interface PivotFlatRow {\n path: string[];\n depth: number;\n isSubtotal?: boolean;\n isGrandTotal?: boolean;\n label: string;\n cellsByColumnKey: Map<string, PivotCell>;\n}\n\nexport interface PivotResult {\n rowTree: PivotHeaderNode[];\n columnTree: PivotHeaderNode[];\n columnLeaves: PivotHeaderNode[];\n rows: PivotFlatRow[];\n values: PivotValueDef[];\n valueAt(rowPath: string[], colPath: string[], valueIndex: number): number | null;\n}\n\nexport type GroupedMap<T> = Map<string, GroupedMap<T> | T[]>;\n\nconst GRAND_TOTAL_LABEL = 'Grand Total';\nconst SUBTOTAL_LABEL = 'Total';\nconst PATH_SEPARATOR = '\\u0000';\n\nexport function aggregateValues(values: unknown[], op: AggOp): number | null {\n if (op === 'count') {\n return values.filter((value) => value !== null && value !== undefined).length;\n }\n\n if (values.length === 0) {\n return null;\n }\n\n if (op === 'countDistinct') {\n const distinct = new Set(values.filter((value) => !isMissingAggregateValue(value)).map(toKey));\n return distinct.size === 0 ? null : distinct.size;\n }\n\n if (op === 'first') {\n return coerceFinite(values.find((value) => value !== null && value !== undefined));\n }\n\n if (op === 'last') {\n for (let index = values.length - 1; index >= 0; index -= 1) {\n const value = values[index];\n if (value !== null && value !== undefined) {\n return coerceFinite(value);\n }\n }\n return null;\n }\n\n const numbers = values.map(coerceFinite).filter((value): value is number => value !== null);\n if (numbers.length === 0) {\n return null;\n }\n\n switch (op) {\n case 'sum':\n return stableSum(numbers);\n case 'mean':\n case 'avg':\n return stableSum(numbers, numbers.length);\n case 'min': {\n let min = numbers[0];\n for (const value of numbers) min = Math.min(min, value);\n return min;\n }\n case 'max': {\n let max = numbers[0];\n for (const value of numbers) max = Math.max(max, value);\n return max;\n }\n case 'median': {\n const sorted = [...numbers].sort((left, right) => left - right);\n return medianSorted(sorted);\n }\n }\n\n return null;\n}\n\n/**\n * Resolve a value reference \u2014 either a literal number or a field aggregated over\n * `data` \u2014 to a single number (or null). Shared by the single-value visuals\n * (`kpi`, `gauge`) and by the runtime's update value-tween, which needs\n * the previously-displayed value to interpolate from. The parameter is typed\n * structurally (rather than importing `ValueRef`) to avoid a module cycle with\n * `spec/types`, which already imports `AggOp` from here.\n */\nexport function resolveValueRef(\n ref: number | { field: string; aggregate?: AggOp } | undefined,\n data: readonly Datum[],\n): number | null {\n if (ref == null) return null;\n if (typeof ref === 'number') return Number.isFinite(ref) ? ref : null;\n const read = accessor(ref.field);\n return aggregateValues(\n (data ?? []).map((d) => read(d)),\n ref.aggregate ?? 'sum',\n );\n}\n\nexport function groupBy<T extends Record<string, unknown>>(\n rows: T[],\n keyFields: string[],\n): GroupedMap<T> {\n const grouped: GroupedMap<T> = new Map();\n\n for (const row of rows) {\n let current = grouped;\n for (let depth = 0; depth < keyFields.length; depth += 1) {\n const key = toKey(getField(row, keyFields[depth]));\n const isLeaf = depth === keyFields.length - 1;\n const existing = current.get(key);\n\n if (isLeaf) {\n if (Array.isArray(existing)) {\n existing.push(row);\n } else {\n current.set(key, [row]);\n }\n } else {\n if (existing instanceof Map) {\n current = existing;\n } else {\n const next: GroupedMap<T> = new Map();\n current.set(key, next);\n current = next;\n }\n }\n }\n }\n\n return grouped;\n}\n\nexport function pivot(data: Datum[], options: PivotOptions): PivotResult {\n const rowFields = options.rows ?? [];\n const columnFields = options.columns ?? [];\n const sort = options.sort ?? 'asc';\n\n const rowTree = buildHeaderTree(data, rowFields, {\n includeSubtotals: options.includeRowSubtotals === true,\n includeGrandTotal: options.includeGrandTotals === true,\n sort,\n });\n const columnTree = buildHeaderTree(data, columnFields, {\n includeSubtotals: options.includeColumnSubtotals === true,\n includeGrandTotal: columnFields.length === 0 || options.includeGrandTotals === true,\n sort,\n });\n const columnLeaves = flattenColumnLeaves(columnTree);\n const cube = buildPivotCube(data, rowFields, columnFields, options.values);\n const flatRows = buildFlatRows(data, rowFields, columnLeaves, options, sort, cube);\n\n const valueAt = (rowPath: string[], colPath: string[], valueIndex: number): number | null => {\n return cube.valueAt(rowPath, colPath, valueIndex);\n };\n\n return {\n rowTree,\n columnTree,\n columnLeaves,\n rows: flatRows,\n values: options.values,\n valueAt,\n };\n}\n\nfunction buildFlatRows(\n data: Datum[],\n rowFields: string[],\n columnLeaves: PivotHeaderNode[],\n options: PivotOptions,\n sort: 'asc' | 'desc' | 'none',\n cube: PivotCube,\n): PivotFlatRow[] {\n if (rowFields.length === 0) {\n return [makeFlatRow([], 0, true, false, columnLeaves, options, cube)];\n }\n\n const rows: PivotFlatRow[] = [];\n appendFlatRows(rows, data, rowFields, [], 0, columnLeaves, options, sort, cube);\n\n if (options.includeGrandTotals === true) {\n rows.push(makeFlatRow([], 0, true, false, columnLeaves, options, cube));\n }\n\n return rows;\n}\n\nfunction appendFlatRows(\n out: PivotFlatRow[],\n data: Datum[],\n fields: string[],\n path: string[],\n depth: number,\n columnLeaves: PivotHeaderNode[],\n options: PivotOptions,\n sort: 'asc' | 'desc' | 'none',\n cube: PivotCube,\n): void {\n const field = fields[depth];\n const groups = groupRowsAtDepth(data, field, sort);\n\n for (const [key, groupRows] of groups) {\n const nextPath = [...path, key];\n if (depth === fields.length - 1) {\n out.push(makeFlatRow(nextPath, depth, false, false, columnLeaves, options, cube));\n } else {\n appendFlatRows(out, groupRows, fields, nextPath, depth + 1, columnLeaves, options, sort, cube);\n if (options.includeRowSubtotals === true) {\n out.push(makeFlatRow(nextPath, depth, false, true, columnLeaves, options, cube));\n }\n }\n }\n}\n\nfunction makeFlatRow(\n path: string[],\n depth: number,\n isGrandTotal: boolean,\n isSubtotal: boolean,\n columnLeaves: PivotHeaderNode[],\n options: PivotOptions,\n cube: PivotCube,\n): PivotFlatRow {\n const cellsByColumnKey = new Map<string, PivotCell>();\n\n for (const columnLeaf of columnLeaves) {\n const columnKey = makePathKey(columnLeaf.path);\n cellsByColumnKey.set(columnKey, {\n values: options.values.map((_, valueIndex) => cube.valueAt(path, columnLeaf.path, valueIndex)),\n });\n }\n\n return {\n path,\n depth,\n isGrandTotal: isGrandTotal || undefined,\n isSubtotal: isSubtotal || undefined,\n label: isGrandTotal\n ? GRAND_TOTAL_LABEL\n : isSubtotal\n ? SUBTOTAL_LABEL\n : (path[path.length - 1] ?? GRAND_TOTAL_LABEL),\n cellsByColumnKey,\n };\n}\n\nfunction buildHeaderTree(\n data: Datum[],\n fields: string[],\n options: {\n includeSubtotals: boolean;\n includeGrandTotal: boolean;\n sort: 'asc' | 'desc' | 'none';\n },\n): PivotHeaderNode[] {\n const roots = fields.length === 0 ? [] : buildHeaderLevel(data, fields, [], 0, options);\n\n if (fields.length === 0 || options.includeGrandTotal) {\n roots.push({\n key: GRAND_TOTAL_LABEL,\n path: [],\n depth: 0,\n children: [],\n isGrandTotal: true,\n span: 1,\n });\n }\n\n return roots;\n}\n\nfunction buildHeaderLevel(\n data: Datum[],\n fields: string[],\n path: string[],\n depth: number,\n options: {\n includeSubtotals: boolean;\n includeGrandTotal: boolean;\n sort: 'asc' | 'desc' | 'none';\n },\n): PivotHeaderNode[] {\n const field = fields[depth];\n const groups = groupRowsAtDepth(data, field, options.sort);\n const nodes: PivotHeaderNode[] = [];\n\n for (const [key, groupRows] of groups) {\n const nextPath = [...path, key];\n const children =\n depth === fields.length - 1\n ? []\n : buildHeaderLevel(groupRows, fields, nextPath, depth + 1, options);\n\n if (children.length > 0 && options.includeSubtotals) {\n children.push({\n key: SUBTOTAL_LABEL,\n path: nextPath,\n depth: depth + 1,\n children: [],\n isSubtotal: true,\n span: 1,\n });\n }\n\n const span = children.length === 0 ? 1 : children.reduce((sum, child) => sum + child.span, 0);\n nodes.push({\n key,\n path: nextPath,\n depth,\n children,\n span,\n });\n }\n\n return nodes;\n}\n\nfunction flattenColumnLeaves(nodes: PivotHeaderNode[]): PivotHeaderNode[] {\n const leaves: PivotHeaderNode[] = [];\n for (const node of nodes) {\n if (node.children.length === 0) {\n leaves.push(node);\n } else {\n leaves.push(...flattenColumnLeaves(node.children));\n }\n }\n return leaves;\n}\n\nfunction groupRowsAtDepth(\n data: Datum[],\n field: string,\n sort: 'asc' | 'desc' | 'none',\n): Map<string, Datum[]> {\n const grouped = new Map<string, Datum[]>();\n\n for (const row of data) {\n const key = toKey(getField(row, field));\n const rows = grouped.get(key);\n if (rows === undefined) {\n grouped.set(key, [row]);\n } else {\n rows.push(row);\n }\n }\n\n if (sort === 'none') {\n return grouped;\n }\n\n return new Map(\n [...grouped.entries()].sort(([left], [right]) => {\n if (left === right) {\n return 0;\n }\n const direction = sort === 'asc' ? 1 : -1;\n return left < right ? -direction : direction;\n }),\n );\n}\n\nfunction coerceFinite(value: unknown): number | null {\n if (value === null || value === undefined) {\n return null;\n }\n\n const numberValue = toNumber(value);\n return Number.isFinite(numberValue) ? numberValue : null;\n}\n\nfunction makePathKey(path: string[]): string {\n return path.join(PATH_SEPARATOR);\n}\n\nfunction isMissingAggregateValue(value: unknown): boolean {\n return value == null || value === '' || (typeof value === 'number' && Number.isNaN(value));\n}\n\ninterface PivotCube {\n valueAt(rowPath: string[], colPath: string[], valueIndex: number): number | null;\n}\n\ninterface AggregateState {\n count?: number;\n distinct?: Set<string>;\n first?: number | null;\n hasFirst?: boolean;\n last?: number | null;\n sum?: number;\n numericCount?: number;\n min?: number;\n max?: number;\n numbers?: number[];\n}\n\nclass AxisPathInterner {\n private readonly keyIds: Map<string, number>[];\n private readonly children = new Map<number, Map<number, number>>();\n private nextKeyId = 1;\n private nextPathId = 1;\n\n constructor(fields: readonly string[]) {\n this.keyIds = fields.map(() => new Map<string, number>());\n }\n\n keyId(depth: number, key: string, create: boolean): number {\n const ids = this.keyIds[depth];\n let id = ids.get(key);\n if (id === undefined && create) {\n id = this.nextKeyId++;\n ids.set(key, id);\n }\n return id ?? -1;\n }\n\n child(parentId: number, keyId: number, create: boolean): number {\n let children = this.children.get(parentId);\n if (!children) {\n if (!create) return -1;\n children = new Map<number, number>();\n this.children.set(parentId, children);\n }\n let id = children.get(keyId);\n if (id === undefined && create) {\n id = this.nextPathId++;\n children.set(keyId, id);\n }\n return id ?? -1;\n }\n\n pathId(path: readonly string[], create: boolean): number {\n let id = 0;\n for (let depth = 0; depth < path.length; depth++) {\n const keyId = this.keyId(depth, path[depth], create);\n if (keyId < 0) return -1;\n id = this.child(id, keyId, create);\n if (id < 0) return -1;\n }\n return id;\n }\n}\n\nfunction emptyState(values: readonly PivotValueDef[]): AggregateState[] {\n const states: AggregateState[] = [];\n for (let i = 0; i < values.length; i++) states.push({});\n return states;\n}\n\nfunction buildPivotCube(\n data: Datum[],\n rowFields: string[],\n columnFields: string[],\n values: PivotValueDef[],\n): PivotCube {\n const rows = new AxisPathInterner(rowFields);\n const columns = new AxisPathInterner(columnFields);\n const rowReads = rowFields.map((field) => accessor(field));\n const columnReads = columnFields.map((field) => accessor(field));\n const valueReads = values.map((value) => accessor(value.field));\n const rowPrefixIds = new Array<number>(rowFields.length + 1);\n const columnPrefixIds = new Array<number>(columnFields.length + 1);\n const valueCache = new Array<unknown>(values.length);\n const buckets = new Map<number, Map<number, AggregateState[]>>();\n const cache = new Map<number, Map<number, (number | null)[]>>();\n for (const row of data) {\n rowPrefixIds[0] = 0;\n for (let depth = 0; depth < rowReads.length; depth++) {\n const keyId = rows.keyId(depth, toKey(rowReads[depth](row)), true);\n rowPrefixIds[depth + 1] = rows.child(rowPrefixIds[depth], keyId, true);\n }\n columnPrefixIds[0] = 0;\n for (let depth = 0; depth < columnReads.length; depth++) {\n const keyId = columns.keyId(depth, toKey(columnReads[depth](row)), true);\n columnPrefixIds[depth + 1] = columns.child(columnPrefixIds[depth], keyId, true);\n }\n for (let valueIndex = 0; valueIndex < valueReads.length; valueIndex++) {\n valueCache[valueIndex] = valueReads[valueIndex](row);\n }\n for (let r = 0; r <= rowFields.length; r++) {\n const rowId = rowPrefixIds[r];\n let rowBuckets = buckets.get(rowId);\n if (!rowBuckets) {\n rowBuckets = new Map<number, AggregateState[]>();\n buckets.set(rowId, rowBuckets);\n }\n for (let c = 0; c <= columnFields.length; c++) {\n const colId = columnPrefixIds[c];\n let bucket = rowBuckets.get(colId);\n if (!bucket) {\n bucket = emptyState(values);\n rowBuckets.set(colId, bucket);\n }\n for (let valueIndex = 0; valueIndex < values.length; valueIndex++) {\n addToState(bucket[valueIndex], values[valueIndex].op, valueCache[valueIndex]);\n }\n }\n }\n }\n return {\n valueAt(rowPath, colPath, valueIndex) {\n const valueDef = values[valueIndex];\n if (!valueDef) return null;\n const rowId = rows.pathId(rowPath, false);\n const colId = columns.pathId(colPath, false);\n if (rowId < 0 || colId < 0) return aggregateValues([], valueDef.op);\n let rowCache = cache.get(rowId);\n if (!rowCache) {\n rowCache = new Map<number, (number | null)[]>();\n cache.set(rowId, rowCache);\n }\n let cached = rowCache.get(colId);\n if (!cached) {\n cached = new Array<number | null>(values.length);\n rowCache.set(colId, cached);\n } else if (valueIndex in cached) {\n return cached[valueIndex];\n }\n const bucket = buckets.get(rowId)?.get(colId);\n const result = bucket ? stateValue(bucket[valueIndex], valueDef.op) : aggregateValues([], valueDef.op);\n cached[valueIndex] = result;\n return result;\n },\n };\n}\n\nfunction addToState(state: AggregateState, op: AggOp, value: unknown): void {\n if (op === 'count') {\n if (value !== null && value !== undefined) state.count = (state.count ?? 0) + 1;\n return;\n }\n if (op === 'countDistinct') {\n if (!isMissingAggregateValue(value)) {\n (state.distinct ??= new Set()).add(toKey(value));\n }\n return;\n }\n if (op === 'first') {\n if (!state.hasFirst && value !== null && value !== undefined) {\n state.first = coerceFinite(value);\n state.hasFirst = true;\n }\n return;\n }\n if (op === 'last') {\n if (value !== null && value !== undefined) state.last = coerceFinite(value);\n return;\n }\n const numberValue = coerceFinite(value);\n if (numberValue === null) return;\n if (op === 'min') {\n state.min = state.min === undefined ? numberValue : Math.min(state.min, numberValue);\n } else if (op === 'max') {\n state.max = state.max === undefined ? numberValue : Math.max(state.max, numberValue);\n } else if (op === 'median') {\n (state.numbers ??= []).push(numberValue);\n } else {\n const previous = state.sum ?? 0;\n state.sum = previous + numberValue;\n state.numericCount = (state.numericCount ?? 0) + 1;\n if (state.numbers || !Number.isFinite(state.sum) || Math.abs(numberValue) > 1e300) {\n (state.numbers ??= [previous]).push(numberValue);\n }\n }\n}\n\nfunction stateValue(state: AggregateState, op: AggOp): number | null {\n if (op === 'count') return state.count ?? 0;\n if (op === 'countDistinct') return state.distinct?.size ? state.distinct.size : null;\n if (op === 'first') return state.hasFirst ? (state.first ?? null) : null;\n if (op === 'last') return state.last ?? null;\n switch (op) {\n case 'sum':\n if (!state.numericCount) return null;\n return state.numbers ? stableSum(state.numbers) : Number.isFinite(state.sum) ? state.sum! : null;\n case 'mean':\n case 'avg':\n if (!state.numericCount) return null;\n return state.numbers ? stableSum(state.numbers, state.numericCount) : Number.isFinite(state.sum) ? state.sum! / state.numericCount : null;\n case 'min': {\n return state.min ?? null;\n }\n case 'max': {\n return state.max ?? null;\n }\n case 'median': {\n const numbers = state.numbers ?? [];\n if (numbers.length === 0) return null;\n const sorted = [...numbers].sort((left, right) => left - right);\n return medianSorted(sorted);\n }\n }\n}\n"],
|
|
5
|
-
"mappings": ";;;AACA,SAAS,UAAU,UAAU,OAAO,gBAAgB;AACpD,SAAS,cAAc,iBAAiB;AAgExC,MAAM,oBAAoB;AAC1B,MAAM,iBAAiB;AACvB,MAAM,iBAAiB;AAEhB,SAAS,gBAAgB,QAAmB,IAA0B;AAC3E,MAAI,OAAO,SAAS;AAClB,WAAO,OAAO,OAAO,CAAC,UAAU,UAAU,QAAQ,UAAU,MAAS,EAAE;AAAA,EACzE;AAEA,MAAI,OAAO,WAAW,GAAG;AACvB,WAAO;AAAA,EACT;AAEA,MAAI,OAAO,iBAAiB;AAC1B,UAAM,WAAW,IAAI,IAAI,OAAO,OAAO,CAAC,UAAU,CAAC,wBAAwB,KAAK,CAAC,EAAE,IAAI,KAAK,CAAC;AAC7F,WAAO,SAAS,SAAS,IAAI,OAAO,SAAS;AAAA,EAC/C;AAEA,MAAI,OAAO,SAAS;AAClB,WAAO,aAAa,OAAO,KAAK,CAAC,UAAU,UAAU,QAAQ,UAAU,MAAS,CAAC;AAAA,EACnF;AAEA,MAAI,OAAO,QAAQ;AACjB,aAAS,QAAQ,OAAO,SAAS,GAAG,SAAS,GAAG,SAAS,GAAG;AAC1D,YAAM,QAAQ,OAAO,KAAK;AAC1B,UAAI,UAAU,QAAQ,UAAU,QAAW;AACzC,eAAO,aAAa,KAAK;AAAA,MAC3B;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAEA,QAAM,UAAU,OAAO,IAAI,YAAY,EAAE,OAAO,CAAC,UAA2B,UAAU,IAAI;AAC1F,MAAI,QAAQ,WAAW,GAAG;AACxB,WAAO;AAAA,EACT;AAEA,UAAQ,IAAI;AAAA,IACV,KAAK;AACH,aAAO,UAAU,OAAO;AAAA,IAC1B,KAAK;AAAA,IACL,KAAK;AACH,aAAO,UAAU,SAAS,QAAQ,MAAM;AAAA,IAC1C,KAAK,OAAO;AACV,UAAI,MAAM,QAAQ,CAAC;AACnB,iBAAW,SAAS,QAAS,OAAM,KAAK,IAAI,KAAK,KAAK;AACtD,aAAO;AAAA,IACT;AAAA,IACA,KAAK,OAAO;AACV,UAAI,MAAM,QAAQ,CAAC;AACnB,iBAAW,SAAS,QAAS,OAAM,KAAK,IAAI,KAAK,KAAK;AACtD,aAAO;AAAA,IACT;AAAA,IACA,KAAK,UAAU;AACb,YAAM,SAAS,CAAC,GAAG,OAAO,EAAE,KAAK,CAAC,MAAM,UAAU,OAAO,KAAK;AAC9D,aAAO,aAAa,MAAM;AAAA,IAC5B;AAAA,EACF;AAEA,SAAO;AACT;AAUO,SAAS,gBACd,KACA,MACe;AACf,MAAI,OAAO,KAAM,QAAO;AACxB,MAAI,OAAO,QAAQ,SAAU,QAAO,OAAO,SAAS,GAAG,IAAI,MAAM;AACjE,QAAM,OAAO,SAAS,IAAI,KAAK;AAC/B,SAAO;AAAA,KACJ,QAAQ,CAAC,GAAG,IAAI,CAAC,MAAM,KAAK,CAAC,CAAC;AAAA,IAC/B,IAAI,aAAa;AAAA,EACnB;AACF;AAEO,SAAS,QACd,MACA,WACe;AACf,QAAM,UAAyB,oBAAI,IAAI;AAEvC,aAAW,OAAO,MAAM;AACtB,QAAI,UAAU;AACd,aAAS,QAAQ,GAAG,QAAQ,UAAU,QAAQ,SAAS,GAAG;AACxD,YAAM,MAAM,MAAM,SAAS,KAAK,UAAU,KAAK,CAAC,CAAC;AACjD,YAAM,SAAS,UAAU,UAAU,SAAS;AAC5C,YAAM,WAAW,QAAQ,IAAI,GAAG;AAEhC,UAAI,QAAQ;AACV,YAAI,MAAM,QAAQ,QAAQ,GAAG;AAC3B,mBAAS,KAAK,GAAG;AAAA,QACnB,OAAO;AACL,kBAAQ,IAAI,KAAK,CAAC,GAAG,CAAC;AAAA,QACxB;AAAA,MACF,OAAO;AACL,YAAI,oBAAoB,KAAK;AAC3B,oBAAU;AAAA,QACZ,OAAO;AACL,gBAAM,OAAsB,oBAAI,IAAI;AACpC,kBAAQ,IAAI,KAAK,IAAI;AACrB,oBAAU;AAAA,QACZ;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;AAEO,SAAS,MAAM,MAAe,SAAoC;AACvE,QAAM,YAAY,QAAQ,QAAQ,CAAC;AACnC,QAAM,eAAe,QAAQ,WAAW,CAAC;AACzC,QAAM,OAAO,QAAQ,QAAQ;AAE7B,QAAM,UAAU,gBAAgB,MAAM,WAAW;AAAA,IAC/C,kBAAkB,QAAQ,wBAAwB;AAAA,IAClD,mBAAmB,QAAQ,uBAAuB;AAAA,IAClD;AAAA,EACF,CAAC;AACD,QAAM,aAAa,gBAAgB,MAAM,cAAc;AAAA,IACrD,kBAAkB,QAAQ,2BAA2B;AAAA,IACrD,mBAAmB,aAAa,WAAW,KAAK,QAAQ,uBAAuB;AAAA,IAC/E;AAAA,EACF,CAAC;AACD,QAAM,eAAe,oBAAoB,UAAU;AACnD,QAAM,OAAO,eAAe,MAAM,WAAW,cAAc,QAAQ,MAAM;AACzE,QAAM,WAAW,cAAc,MAAM,WAAW,cAAc,SAAS,MAAM,IAAI;AAEjF,QAAM,UAAU,CAAC,SAAmB,SAAmB,eAAsC;AAC3F,WAAO,KAAK,QAAQ,SAAS,SAAS,UAAU;AAAA,EAClD;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA,MAAM;AAAA,IACN,QAAQ,QAAQ;AAAA,IAChB;AAAA,EACF;AACF;AAEA,SAAS,cACP,MACA,WACA,cACA,SACA,MACA,MACgB;AAChB,MAAI,UAAU,WAAW,GAAG;AAC1B,WAAO,CAAC,YAAY,CAAC,GAAG,GAAG,MAAM,OAAO,cAAc,SAAS,IAAI,CAAC;AAAA,EACtE;AAEA,QAAM,OAAuB,CAAC;AAC9B,iBAAe,MAAM,MAAM,WAAW,CAAC,GAAG,GAAG,cAAc,SAAS,MAAM,IAAI;AAE9E,MAAI,QAAQ,uBAAuB,MAAM;AACvC,SAAK,KAAK,YAAY,CAAC,GAAG,GAAG,MAAM,OAAO,cAAc,SAAS,IAAI,CAAC;AAAA,EACxE;AAEA,SAAO;AACT;AAEA,SAAS,eACP,KACA,MACA,QACA,MACA,OACA,cACA,SACA,MACA,MACM;AACN,QAAM,QAAQ,OAAO,KAAK;AAC1B,QAAM,SAAS,iBAAiB,MAAM,OAAO,IAAI;AAEjD,aAAW,CAAC,KAAK,SAAS,KAAK,QAAQ;AACrC,UAAM,WAAW,CAAC,GAAG,MAAM,GAAG;AAC9B,QAAI,UAAU,OAAO,SAAS,GAAG;AAC/B,UAAI,KAAK,YAAY,UAAU,OAAO,OAAO,OAAO,cAAc,SAAS,IAAI,CAAC;AAAA,IAClF,OAAO;AACL,qBAAe,KAAK,WAAW,QAAQ,UAAU,QAAQ,GAAG,cAAc,SAAS,MAAM,IAAI;AAC7F,UAAI,QAAQ,wBAAwB,MAAM;AACxC,YAAI,KAAK,YAAY,UAAU,OAAO,OAAO,MAAM,cAAc,SAAS,IAAI,CAAC;AAAA,MACjF;AAAA,IACF;AAAA,EACF;AACF;AAEA,SAAS,YACP,MACA,OACA,cACA,YACA,cACA,SACA,MACc;AACd,QAAM,mBAAmB,oBAAI,IAAuB;AAEpD,aAAW,cAAc,cAAc;AACrC,UAAM,YAAY,YAAY,WAAW,IAAI;AAC7C,qBAAiB,IAAI,WAAW;AAAA,MAC9B,QAAQ,QAAQ,OAAO,IAAI,CAAC,GAAG,eAAe,KAAK,QAAQ,MAAM,WAAW,MAAM,UAAU,CAAC;AAAA,IAC/F,CAAC;AAAA,EACH;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,cAAc,gBAAgB;AAAA,IAC9B,YAAY,cAAc;AAAA,IAC1B,OAAO,eACH,oBACA,aACE,iBACC,KAAK,KAAK,SAAS,CAAC,KAAK;AAAA,IAChC;AAAA,EACF;AACF;AAEA,SAAS,gBACP,MACA,QACA,SAKmB;AACnB,QAAM,QAAQ,OAAO,WAAW,IAAI,CAAC,IAAI,iBAAiB,MAAM,QAAQ,CAAC,GAAG,GAAG,OAAO;AAEtF,MAAI,OAAO,WAAW,KAAK,QAAQ,mBAAmB;AACpD,UAAM,KAAK;AAAA,MACT,KAAK;AAAA,MACL,MAAM,CAAC;AAAA,MACP,OAAO;AAAA,MACP,UAAU,CAAC;AAAA,MACX,cAAc;AAAA,MACd,MAAM;AAAA,IACR,CAAC;AAAA,EACH;AAEA,SAAO;AACT;AAEA,SAAS,iBACP,MACA,QACA,MACA,OACA,SAKmB;AACnB,QAAM,QAAQ,OAAO,KAAK;AAC1B,QAAM,SAAS,iBAAiB,MAAM,OAAO,QAAQ,IAAI;AACzD,QAAM,QAA2B,CAAC;AAElC,aAAW,CAAC,KAAK,SAAS,KAAK,QAAQ;AACrC,UAAM,WAAW,CAAC,GAAG,MAAM,GAAG;AAC9B,UAAM,WACJ,UAAU,OAAO,SAAS,IACtB,CAAC,IACD,iBAAiB,WAAW,QAAQ,UAAU,QAAQ,GAAG,OAAO;AAEtE,QAAI,SAAS,SAAS,KAAK,QAAQ,kBAAkB;AACnD,eAAS,KAAK;AAAA,QACZ,KAAK;AAAA,QACL,MAAM;AAAA,QACN,OAAO,QAAQ;AAAA,QACf,UAAU,CAAC;AAAA,QACX,YAAY;AAAA,QACZ,MAAM;AAAA,MACR,CAAC;AAAA,IACH;AAEA,UAAM,OAAO,SAAS,WAAW,IAAI,IAAI,SAAS,OAAO,CAAC,KAAK,UAAU,MAAM,MAAM,MAAM,CAAC;AAC5F,UAAM,KAAK;AAAA,MACT;AAAA,MACA,MAAM;AAAA,MACN;AAAA,MACA;AAAA,MACA;AAAA,IACF,CAAC;AAAA,EACH;AAEA,SAAO;AACT;AAEA,SAAS,oBAAoB,OAA6C;AACxE,QAAM,SAA4B,CAAC;AACnC,aAAW,QAAQ,OAAO;AACxB,QAAI,KAAK,SAAS,WAAW,GAAG;AAC9B,aAAO,KAAK,IAAI;AAAA,IAClB,OAAO;AACL,aAAO,KAAK,GAAG,oBAAoB,KAAK,QAAQ,CAAC;AAAA,IACnD;AAAA,EACF;AACA,SAAO;AACT;AAEA,SAAS,iBACP,MACA,OACA,MACsB;AACtB,QAAM,UAAU,oBAAI,IAAqB;AAEzC,aAAW,OAAO,MAAM;AACtB,UAAM,MAAM,MAAM,SAAS,KAAK,KAAK,CAAC;AACtC,UAAM,OAAO,QAAQ,IAAI,GAAG;AAC5B,QAAI,SAAS,QAAW;AACtB,cAAQ,IAAI,KAAK,CAAC,GAAG,CAAC;AAAA,IACxB,OAAO;AACL,WAAK,KAAK,GAAG;AAAA,IACf;AAAA,EACF;AAEA,MAAI,SAAS,QAAQ;AACnB,WAAO;AAAA,EACT;AAEA,SAAO,IAAI;AAAA,IACT,CAAC,GAAG,QAAQ,QAAQ,CAAC,EAAE,KAAK,CAAC,CAAC,IAAI,GAAG,CAAC,KAAK,MAAM;AAC/C,UAAI,SAAS,OAAO;AAClB,eAAO;AAAA,MACT;AACA,YAAM,YAAY,SAAS,QAAQ,IAAI;AACvC,aAAO,OAAO,QAAQ,CAAC,YAAY;AAAA,IACrC,CAAC;AAAA,EACH;AACF;AAEA,SAAS,aAAa,OAA+B;AACnD,MAAI,UAAU,QAAQ,UAAU,QAAW;AACzC,WAAO;AAAA,EACT;AAEA,QAAM,cAAc,SAAS,KAAK;AAClC,SAAO,OAAO,SAAS,WAAW,IAAI,cAAc;AACtD;AAEA,SAAS,YAAY,MAAwB;AAC3C,SAAO,KAAK,KAAK,cAAc;AACjC;AAEA,SAAS,wBAAwB,OAAyB;AACxD,SAAO,SAAS,QAAQ,UAAU,MAAO,OAAO,UAAU,YAAY,OAAO,MAAM,KAAK;AAC1F;AAmBA,MAAM,iBAAiB;AAAA,EAMrB,YAAY,QAA2B;AALvC,wBAAiB;AACjB,wBAAiB,YAAW,oBAAI,IAAiC;AACjE,wBAAQ,aAAY;AACpB,wBAAQ,cAAa;AAGnB,SAAK,SAAS,OAAO,IAAI,MAAM,oBAAI,IAAoB,CAAC;AAAA,EAC1D;AAAA,EAEA,MAAM,OAAe,KAAa,QAAyB;AACzD,UAAM,MAAM,KAAK,OAAO,KAAK;AAC7B,QAAI,KAAK,IAAI,IAAI,GAAG;AACpB,QAAI,OAAO,UAAa,QAAQ;AAC9B,WAAK,KAAK;AACV,UAAI,IAAI,KAAK,EAAE;AAAA,IACjB;AACA,WAAO,MAAM;AAAA,EACf;AAAA,EAEA,MAAM,UAAkB,OAAe,QAAyB;AAC9D,QAAI,WAAW,KAAK,SAAS,IAAI,QAAQ;AACzC,QAAI,CAAC,UAAU;AACb,UAAI,CAAC,OAAQ,QAAO;AACpB,iBAAW,oBAAI,IAAoB;AACnC,WAAK,SAAS,IAAI,UAAU,QAAQ;AAAA,IACtC;AACA,QAAI,KAAK,SAAS,IAAI,KAAK;AAC3B,QAAI,OAAO,UAAa,QAAQ;AAC9B,WAAK,KAAK;AACV,eAAS,IAAI,OAAO,EAAE;AAAA,IACxB;AACA,WAAO,MAAM;AAAA,EACf;AAAA,EAEA,OAAO,MAAyB,QAAyB;AACvD,QAAI,KAAK;AACT,aAAS,QAAQ,GAAG,QAAQ,KAAK,QAAQ,SAAS;AAChD,YAAM,QAAQ,KAAK,MAAM,OAAO,KAAK,KAAK,GAAG,MAAM;AACnD,UAAI,QAAQ,EAAG,QAAO;AACtB,WAAK,KAAK,MAAM,IAAI,OAAO,MAAM;AACjC,UAAI,KAAK,EAAG,QAAO;AAAA,IACrB;AACA,WAAO;AAAA,EACT;AACF;AAEA,SAAS,WAAW,QAAoD;AACtE,QAAM,SAA2B,CAAC;AAClC,WAAS,IAAI,GAAG,IAAI,OAAO,QAAQ,IAAK,QAAO,KAAK,CAAC,CAAC;AACtD,SAAO;AACT;AAEA,SAAS,eACP,MACA,WACA,cACA,QACW;AACX,QAAM,OAAO,IAAI,iBAAiB,SAAS;AAC3C,QAAM,UAAU,IAAI,iBAAiB,YAAY;AACjD,QAAM,WAAW,UAAU,IAAI,CAAC,UAAU,SAAS,KAAK,CAAC;AACzD,QAAM,cAAc,aAAa,IAAI,CAAC,UAAU,SAAS,KAAK,CAAC;AAC/D,QAAM,aAAa,OAAO,IAAI,CAAC,UAAU,SAAS,MAAM,KAAK,CAAC;AAC9D,QAAM,eAAe,IAAI,MAAc,UAAU,SAAS,CAAC;AAC3D,QAAM,kBAAkB,IAAI,MAAc,aAAa,SAAS,CAAC;AACjE,QAAM,aAAa,IAAI,MAAe,OAAO,MAAM;AACnD,QAAM,UAAU,oBAAI,IAA2C;AAC/D,QAAM,QAAQ,oBAAI,IAA4C;AAC9D,aAAW,OAAO,MAAM;AACtB,iBAAa,CAAC,IAAI;AAClB,aAAS,QAAQ,GAAG,QAAQ,SAAS,QAAQ,SAAS;AACpD,YAAM,QAAQ,KAAK,MAAM,OAAO,MAAM,SAAS,KAAK,EAAE,GAAG,CAAC,GAAG,IAAI;AACjE,mBAAa,QAAQ,CAAC,IAAI,KAAK,MAAM,aAAa,KAAK,GAAG,OAAO,IAAI;AAAA,IACvE;AACA,oBAAgB,CAAC,IAAI;AACrB,aAAS,QAAQ,GAAG,QAAQ,YAAY,QAAQ,SAAS;AACvD,YAAM,QAAQ,QAAQ,MAAM,OAAO,MAAM,YAAY,KAAK,EAAE,GAAG,CAAC,GAAG,IAAI;AACvE,sBAAgB,QAAQ,CAAC,IAAI,QAAQ,MAAM,gBAAgB,KAAK,GAAG,OAAO,IAAI;AAAA,IAChF;AACA,aAAS,aAAa,GAAG,aAAa,WAAW,QAAQ,cAAc;AACrE,iBAAW,UAAU,IAAI,WAAW,UAAU,EAAE,GAAG;AAAA,IACrD;AACA,aAAS,IAAI,GAAG,KAAK,UAAU,QAAQ,KAAK;AAC1C,YAAM,QAAQ,aAAa,CAAC;AAC5B,UAAI,aAAa,QAAQ,IAAI,KAAK;AAClC,UAAI,CAAC,YAAY;AACf,qBAAa,oBAAI,IAA8B;AAC/C,gBAAQ,IAAI,OAAO,UAAU;AAAA,MAC/B;AACA,eAAS,IAAI,GAAG,KAAK,aAAa,QAAQ,KAAK;AAC7C,cAAM,QAAQ,gBAAgB,CAAC;AAC/B,YAAI,SAAS,WAAW,IAAI,KAAK;AACjC,YAAI,CAAC,QAAQ;AACX,mBAAS,WAAW,MAAM;AAC1B,qBAAW,IAAI,OAAO,MAAM;AAAA,QAC9B;AACA,iBAAS,aAAa,GAAG,aAAa,OAAO,QAAQ,cAAc;AACjE,qBAAW,OAAO,UAAU,GAAG,OAAO,UAAU,EAAE,IAAI,WAAW,UAAU,CAAC;AAAA,QAC9E;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACA,SAAO;AAAA,IACL,QAAQ,SAAS,SAAS,YAAY;AACpC,YAAM,WAAW,OAAO,UAAU;AAClC,UAAI,CAAC,SAAU,QAAO;AACtB,YAAM,QAAQ,KAAK,OAAO,SAAS,KAAK;AACxC,YAAM,QAAQ,QAAQ,OAAO,SAAS,KAAK;AAC3C,UAAI,QAAQ,KAAK,QAAQ,EAAG,QAAO,gBAAgB,CAAC,GAAG,SAAS,EAAE;AAClE,UAAI,WAAW,MAAM,IAAI,KAAK;AAC9B,UAAI,CAAC,UAAU;AACb,mBAAW,oBAAI,IAA+B;AAC9C,cAAM,IAAI,OAAO,QAAQ;AAAA,MAC3B;AACA,UAAI,SAAS,SAAS,IAAI,KAAK;AAC/B,UAAI,CAAC,QAAQ;AACX,iBAAS,IAAI,MAAqB,OAAO,MAAM;AAC/C,iBAAS,IAAI,OAAO,MAAM;AAAA,MAC5B,WAAW,cAAc,QAAQ;AAC/B,eAAO,OAAO,UAAU;AAAA,MAC1B;AACA,YAAM,SAAS,QAAQ,IAAI,KAAK,GAAG,IAAI,KAAK;AAC5C,YAAM,SAAS,SAAS,WAAW,OAAO,UAAU,GAAG,SAAS,EAAE,IAAI,gBAAgB,CAAC,GAAG,SAAS,EAAE;AACrG,aAAO,UAAU,IAAI;AACrB,aAAO;AAAA,IACT;AAAA,EACF;AACF;AAEA,SAAS,WAAW,OAAuB,IAAW,OAAsB;AAC1E,MAAI,OAAO,SAAS;AAClB,QAAI,UAAU,QAAQ,UAAU,OAAW,OAAM,SAAS,MAAM,SAAS,KAAK;AAC9E;AAAA,EACF;AACA,MAAI,OAAO,iBAAiB;AAC1B,QAAI,CAAC,wBAAwB,KAAK,GAAG;AACnC,OAAC,MAAM,aAAa,oBAAI,IAAI,GAAG,IAAI,MAAM,KAAK,CAAC;AAAA,IACjD;AACA;AAAA,EACF;AACA,MAAI,OAAO,SAAS;AAClB,QAAI,CAAC,MAAM,YAAY,UAAU,QAAQ,UAAU,QAAW;AAC5D,YAAM,QAAQ,aAAa,KAAK;AAChC,YAAM,WAAW;AAAA,IACnB;AACA;AAAA,EACF;AACA,MAAI,OAAO,QAAQ;AACjB,QAAI,UAAU,QAAQ,UAAU,OAAW,OAAM,OAAO,aAAa,KAAK;AAC1E;AAAA,EACF;AACA,QAAM,cAAc,aAAa,KAAK;AACtC,MAAI,gBAAgB,KAAM;AAC1B,MAAI,OAAO,OAAO;AAChB,UAAM,MAAM,MAAM,QAAQ,SAAY,cAAc,KAAK,IAAI,MAAM,KAAK,WAAW;AAAA,EACrF,WAAW,OAAO,OAAO;AACvB,UAAM,MAAM,MAAM,QAAQ,SAAY,cAAc,KAAK,IAAI,MAAM,KAAK,WAAW;AAAA,EACrF,WAAW,OAAO,UAAU;AAC1B,KAAC,MAAM,YAAY,CAAC,GAAG,KAAK,WAAW;AAAA,EACzC,OAAO;AACL,UAAM,WAAW,MAAM,OAAO;AAC9B,UAAM,MAAM,WAAW;AACvB,UAAM,gBAAgB,MAAM,gBAAgB,KAAK;AACjD,QAAI,MAAM,WAAW,CAAC,OAAO,SAAS,MAAM,GAAG,KAAK,KAAK,IAAI,WAAW,IAAI,OAAO;AACjF,OAAC,MAAM,YAAY,CAAC,QAAQ,GAAG,KAAK,WAAW;AAAA,IACjD;AAAA,EACF;AACF;AAEA,SAAS,WAAW,OAAuB,IAA0B;AACnE,MAAI,OAAO,QAAS,QAAO,MAAM,SAAS;AAC1C,MAAI,OAAO,gBAAiB,QAAO,MAAM,UAAU,OAAO,MAAM,SAAS,OAAO;AAChF,MAAI,OAAO,QAAS,QAAO,MAAM,WAAY,MAAM,SAAS,OAAQ;AACpE,MAAI,OAAO,OAAQ,QAAO,MAAM,QAAQ;AACxC,UAAQ,IAAI;AAAA,IACV,KAAK;AACH,UAAI,CAAC,MAAM,aAAc,QAAO;AAChC,aAAO,MAAM,UAAU,UAAU,MAAM,OAAO,IAAI,OAAO,SAAS,MAAM,GAAG,IAAI,MAAM,MAAO;AAAA,IAC9F,KAAK;AAAA,IACL,KAAK;AACH,UAAI,CAAC,MAAM,aAAc,QAAO;AAChC,aAAO,MAAM,UAAU,UAAU,MAAM,SAAS,MAAM,YAAY,IAAI,OAAO,SAAS,MAAM,GAAG,IAAI,MAAM,MAAO,MAAM,eAAe;AAAA,IACvI,KAAK,OAAO;AACV,aAAO,MAAM,OAAO;AAAA,IACtB;AAAA,IACA,KAAK,OAAO;AACV,aAAO,MAAM,OAAO;AAAA,IACtB;AAAA,IACA,KAAK,UAAU;AACb,YAAM,UAAU,MAAM,WAAW,CAAC;AAClC,UAAI,QAAQ,WAAW,EAAG,QAAO;AACjC,YAAM,SAAS,CAAC,GAAG,OAAO,EAAE,KAAK,CAAC,MAAM,UAAU,OAAO,KAAK;AAC9D,aAAO,aAAa,MAAM;AAAA,IAC5B;AAAA,EACF;AACF;",
|
|
4
|
+
"sourcesContent": ["import type { Datum } from '../types';\nimport { accessor, getField, toKey, toNumber } from '../util/data';\nimport { medianSorted, stableSum } from '../util/math';\n\nexport type AggOp =\n | 'sum'\n | 'mean'\n | 'avg'\n | 'min'\n | 'max'\n | 'count'\n | 'countDistinct'\n | 'median'\n | 'first'\n | 'last';\n\nexport interface PivotValueDef {\n field: string;\n op: AggOp;\n label?: string;\n}\n\nexport interface PivotOptions {\n rows?: string[];\n columns?: string[];\n values: PivotValueDef[];\n includeRowSubtotals?: boolean;\n includeColumnSubtotals?: boolean;\n includeGrandTotals?: boolean;\n sort?: 'asc' | 'desc' | 'none';\n}\n\nexport interface PivotHeaderNode {\n key: string;\n path: string[];\n depth: number;\n children: PivotHeaderNode[];\n isSubtotal?: boolean;\n isGrandTotal?: boolean;\n span: number;\n}\n\nexport interface PivotCell {\n values: (number | null)[];\n}\n\nexport interface PivotFlatRow {\n path: string[];\n depth: number;\n isSubtotal?: boolean;\n isGrandTotal?: boolean;\n label: string;\n cellsByColumnKey: Map<string, PivotCell>;\n}\n\nexport interface PivotResult {\n rowTree: PivotHeaderNode[];\n columnTree: PivotHeaderNode[];\n columnLeaves: PivotHeaderNode[];\n rows: PivotFlatRow[];\n values: PivotValueDef[];\n valueAt(rowPath: string[], colPath: string[], valueIndex: number): number | null;\n}\n\nexport type GroupedMap<T> = Map<string, GroupedMap<T> | T[]>;\n\nconst GRAND_TOTAL_LABEL = 'Grand Total';\nconst SUBTOTAL_LABEL = 'Total';\nconst PATH_SEPARATOR = '\\u0000';\n\nexport function aggregateValues(values: unknown[], op: AggOp): number | null {\n if (op === 'count') {\n return values.filter((value) => value !== null && value !== undefined).length;\n }\n\n if (values.length === 0) {\n return null;\n }\n\n if (op === 'countDistinct') {\n const distinct = new Set(values.filter((value) => !isMissingAggregateValue(value)).map(toKey));\n return distinct.size === 0 ? null : distinct.size;\n }\n\n if (op === 'first') {\n return coerceFinite(values.find((value) => value !== null && value !== undefined));\n }\n\n if (op === 'last') {\n for (let index = values.length - 1; index >= 0; index -= 1) {\n const value = values[index];\n if (value !== null && value !== undefined) {\n return coerceFinite(value);\n }\n }\n return null;\n }\n\n const numbers = values.map(coerceFinite).filter((value): value is number => value !== null);\n if (numbers.length === 0) {\n return null;\n }\n\n switch (op) {\n case 'sum':\n return stableSum(numbers);\n case 'mean':\n case 'avg':\n return stableSum(numbers, numbers.length);\n case 'min': {\n let min = numbers[0];\n for (const value of numbers) min = Math.min(min, value);\n return min;\n }\n case 'max': {\n let max = numbers[0];\n for (const value of numbers) max = Math.max(max, value);\n return max;\n }\n case 'median': {\n const sorted = [...numbers].sort((left, right) => left - right);\n return medianSorted(sorted);\n }\n }\n\n return null;\n}\n\n/**\n * Resolve a value reference \u2014 either a literal number or a field aggregated over\n * `data` \u2014 to a single number (or null). Shared by the single-value visuals\n * (`kpi`, `gauge`) and by the runtime's update value-tween, which needs\n * the previously-displayed value to interpolate from. The parameter is typed\n * structurally (rather than importing `ValueRef`) to avoid a module cycle with\n * `spec/types`, which already imports `AggOp` from here.\n */\nexport function resolveValueRef(\n ref: number | { field: string; aggregate?: AggOp } | undefined,\n data: readonly Datum[],\n): number | null {\n if (ref == null) return null;\n if (typeof ref === 'number') return Number.isFinite(ref) ? ref : null;\n const read = accessor(ref.field);\n return aggregateValues(\n (data ?? []).map((d) => read(d)),\n ref.aggregate ?? 'sum',\n );\n}\n\nexport function groupBy<T extends Record<string, unknown>>(\n rows: T[],\n keyFields: string[],\n): GroupedMap<T> {\n const grouped: GroupedMap<T> = new Map();\n\n for (const row of rows) {\n let current = grouped;\n for (let depth = 0; depth < keyFields.length; depth += 1) {\n const key = toKey(getField(row, keyFields[depth]));\n const isLeaf = depth === keyFields.length - 1;\n const existing = current.get(key);\n\n if (isLeaf) {\n if (Array.isArray(existing)) {\n existing.push(row);\n } else {\n current.set(key, [row]);\n }\n } else {\n if (existing instanceof Map) {\n current = existing;\n } else {\n const next: GroupedMap<T> = new Map();\n current.set(key, next);\n current = next;\n }\n }\n }\n }\n\n return grouped;\n}\n\nexport function pivot(data: Datum[], options: PivotOptions): PivotResult {\n const rowFields = options.rows ?? [];\n const columnFields = options.columns ?? [];\n const sort = options.sort ?? 'asc';\n\n const rowTree = buildHeaderTree(data, rowFields, {\n includeSubtotals: options.includeRowSubtotals === true,\n includeGrandTotal: options.includeGrandTotals === true,\n sort,\n });\n const columnTree = buildHeaderTree(data, columnFields, {\n includeSubtotals: options.includeColumnSubtotals === true,\n includeGrandTotal: columnFields.length === 0 || options.includeGrandTotals === true,\n sort,\n });\n const columnLeaves = flattenColumnLeaves(columnTree);\n const cube = buildPivotCube(data, rowFields, columnFields, options.values);\n const flatRows = buildFlatRows(data, rowFields, columnLeaves, options, sort, cube);\n\n const valueAt = (rowPath: string[], colPath: string[], valueIndex: number): number | null => {\n return cube.valueAt(rowPath, colPath, valueIndex);\n };\n\n return {\n rowTree,\n columnTree,\n columnLeaves,\n rows: flatRows,\n values: options.values,\n valueAt,\n };\n}\n\nfunction buildFlatRows(\n data: Datum[],\n rowFields: string[],\n columnLeaves: PivotHeaderNode[],\n options: PivotOptions,\n sort: 'asc' | 'desc' | 'none',\n cube: PivotCube,\n): PivotFlatRow[] {\n if (rowFields.length === 0) {\n return [makeFlatRow([], 0, true, false, columnLeaves, options, cube)];\n }\n\n const rows: PivotFlatRow[] = [];\n appendFlatRows(rows, data, rowFields, [], 0, columnLeaves, options, sort, cube);\n\n if (options.includeGrandTotals === true) {\n rows.push(makeFlatRow([], 0, true, false, columnLeaves, options, cube));\n }\n\n return rows;\n}\n\nfunction appendFlatRows(\n out: PivotFlatRow[],\n data: Datum[],\n fields: string[],\n path: string[],\n depth: number,\n columnLeaves: PivotHeaderNode[],\n options: PivotOptions,\n sort: 'asc' | 'desc' | 'none',\n cube: PivotCube,\n): void {\n const field = fields[depth];\n const groups = groupRowsAtDepth(data, field, sort);\n\n for (const [key, groupRows] of groups) {\n const nextPath = [...path, key];\n if (depth === fields.length - 1) {\n out.push(makeFlatRow(nextPath, depth, false, false, columnLeaves, options, cube));\n } else {\n appendFlatRows(out, groupRows, fields, nextPath, depth + 1, columnLeaves, options, sort, cube);\n if (options.includeRowSubtotals === true) {\n out.push(makeFlatRow(nextPath, depth, false, true, columnLeaves, options, cube));\n }\n }\n }\n}\n\nfunction makeFlatRow(\n path: string[],\n depth: number,\n isGrandTotal: boolean,\n isSubtotal: boolean,\n columnLeaves: PivotHeaderNode[],\n options: PivotOptions,\n cube: PivotCube,\n): PivotFlatRow {\n const cellsByColumnKey = new Map<string, PivotCell>();\n\n for (const columnLeaf of columnLeaves) {\n const columnKey = makePathKey(columnLeaf.path);\n cellsByColumnKey.set(columnKey, {\n values: options.values.map((_, valueIndex) => cube.valueAt(path, columnLeaf.path, valueIndex)),\n });\n }\n\n return {\n path,\n depth,\n isGrandTotal: isGrandTotal || undefined,\n isSubtotal: isSubtotal || undefined,\n label: isGrandTotal\n ? GRAND_TOTAL_LABEL\n : isSubtotal\n ? SUBTOTAL_LABEL\n : (path[path.length - 1] ?? GRAND_TOTAL_LABEL),\n cellsByColumnKey,\n };\n}\n\nfunction buildHeaderTree(\n data: Datum[],\n fields: string[],\n options: {\n includeSubtotals: boolean;\n includeGrandTotal: boolean;\n sort: 'asc' | 'desc' | 'none';\n },\n): PivotHeaderNode[] {\n const roots = fields.length === 0 ? [] : buildHeaderLevel(data, fields, [], 0, options);\n\n if (fields.length === 0 || options.includeGrandTotal) {\n roots.push({\n key: GRAND_TOTAL_LABEL,\n path: [],\n depth: 0,\n children: [],\n isGrandTotal: true,\n span: 1,\n });\n }\n\n return roots;\n}\n\nfunction buildHeaderLevel(\n data: Datum[],\n fields: string[],\n path: string[],\n depth: number,\n options: {\n includeSubtotals: boolean;\n includeGrandTotal: boolean;\n sort: 'asc' | 'desc' | 'none';\n },\n): PivotHeaderNode[] {\n const field = fields[depth];\n const groups = groupRowsAtDepth(data, field, options.sort);\n const nodes: PivotHeaderNode[] = [];\n\n for (const [key, groupRows] of groups) {\n const nextPath = [...path, key];\n const children =\n depth === fields.length - 1\n ? []\n : buildHeaderLevel(groupRows, fields, nextPath, depth + 1, options);\n\n if (children.length > 0 && options.includeSubtotals) {\n children.push({\n key: SUBTOTAL_LABEL,\n path: nextPath,\n depth: depth + 1,\n children: [],\n isSubtotal: true,\n span: 1,\n });\n }\n\n const span = children.length === 0 ? 1 : children.reduce((sum, child) => sum + child.span, 0);\n nodes.push({\n key,\n path: nextPath,\n depth,\n children,\n span,\n });\n }\n\n return nodes;\n}\n\nfunction flattenColumnLeaves(nodes: PivotHeaderNode[]): PivotHeaderNode[] {\n const leaves: PivotHeaderNode[] = [];\n for (const node of nodes) {\n if (node.children.length === 0) {\n leaves.push(node);\n } else {\n leaves.push(...flattenColumnLeaves(node.children));\n }\n }\n return leaves;\n}\n\nfunction groupRowsAtDepth(\n data: Datum[],\n field: string,\n sort: 'asc' | 'desc' | 'none',\n): Map<string, Datum[]> {\n const grouped = new Map<string, Datum[]>();\n\n for (const row of data) {\n const key = toKey(getField(row, field));\n const rows = grouped.get(key);\n if (rows === undefined) {\n grouped.set(key, [row]);\n } else {\n rows.push(row);\n }\n }\n\n if (sort === 'none') {\n return grouped;\n }\n\n return new Map(\n [...grouped.entries()].sort(([left], [right]) => {\n if (left === right) {\n return 0;\n }\n const direction = sort === 'asc' ? 1 : -1;\n return left < right ? -direction : direction;\n }),\n );\n}\n\nfunction coerceFinite(value: unknown): number | null {\n if (value === null || value === undefined) {\n return null;\n }\n\n const numberValue = toNumber(value);\n return Number.isFinite(numberValue) ? numberValue : null;\n}\n\nfunction makePathKey(path: string[]): string {\n return path.join(PATH_SEPARATOR);\n}\n\nfunction isMissingAggregateValue(value: unknown): boolean {\n return value == null || value === '' || (typeof value === 'number' && Number.isNaN(value));\n}\n\n/** One distinct prefix path of an axis, in first-seen order (id 0 is the empty path). */\nexport interface PivotAxisEntry {\n id: number;\n parent: number;\n depth: number;\n key: string;\n /** The first raw value seen for this key (keeps real types such as dates). */\n value: unknown;\n}\n\n/** Aggregates for every (row prefix \u00D7 column prefix) path, built in one pass over the data. */\nexport interface PivotCube {\n valueAt(rowPath: string[], colPath: string[], valueIndex: number): number | null;\n /** Same as {@link valueAt} for interned path ids from {@link rowAxis}/{@link columnAxis}. */\n valueAtIds(rowId: number, colId: number, valueIndex: number): number | null;\n readonly rowAxis: readonly PivotAxisEntry[];\n readonly columnAxis: readonly PivotAxisEntry[];\n}\n\ninterface AggregateState {\n count?: number;\n distinct?: Set<string>;\n first?: number | null;\n hasFirst?: boolean;\n last?: number | null;\n sum?: number;\n numericCount?: number;\n min?: number;\n max?: number;\n numbers?: number[];\n}\n\nclass AxisPathInterner {\n private readonly keyIds: Map<string, number>[];\n private readonly children = new Map<number, Map<number, number>>();\n private nextKeyId = 1;\n private nextPathId = 1;\n readonly entries: PivotAxisEntry[] = [];\n\n constructor(fields: readonly string[]) {\n this.keyIds = fields.map(() => new Map<string, number>());\n }\n\n keyId(depth: number, key: string, create: boolean): number {\n const ids = this.keyIds[depth];\n let id = ids.get(key);\n if (id === undefined && create) {\n id = this.nextKeyId++;\n ids.set(key, id);\n }\n return id ?? -1;\n }\n\n child(parentId: number, keyId: number, create: boolean, depth = 0, key = '', value?: unknown): number {\n let children = this.children.get(parentId);\n if (!children) {\n if (!create) return -1;\n children = new Map<number, number>();\n this.children.set(parentId, children);\n }\n let id = children.get(keyId);\n if (id === undefined && create) {\n id = this.nextPathId++;\n children.set(keyId, id);\n this.entries.push({ id, parent: parentId, depth, key, value });\n }\n return id ?? -1;\n }\n\n pathId(path: readonly string[], create: boolean): number {\n let id = 0;\n for (let depth = 0; depth < path.length; depth++) {\n const keyId = this.keyId(depth, path[depth], create);\n if (keyId < 0) return -1;\n id = this.child(id, keyId, create);\n if (id < 0) return -1;\n }\n return id;\n }\n}\n\nfunction emptyState(values: readonly PivotValueDef[]): AggregateState[] {\n const states: AggregateState[] = [];\n for (let i = 0; i < values.length; i++) states.push({});\n return states;\n}\n\nexport function buildPivotCube(\n data: Datum[],\n rowFields: string[],\n columnFields: string[],\n values: PivotValueDef[],\n): PivotCube {\n const rows = new AxisPathInterner(rowFields);\n const columns = new AxisPathInterner(columnFields);\n const rowReads = rowFields.map((field) => accessor(field));\n const columnReads = columnFields.map((field) => accessor(field));\n const valueReads = values.map((value) => accessor(value.field));\n const rowPrefixIds = new Array<number>(rowFields.length + 1);\n const columnPrefixIds = new Array<number>(columnFields.length + 1);\n const valueCache = new Array<unknown>(values.length);\n const numberCache = new Array<number | null>(values.length);\n const buckets = new Map<number, Map<number, AggregateState[]>>();\n const cache = new Map<number, Map<number, (number | null)[]>>();\n for (const row of data) {\n rowPrefixIds[0] = 0;\n for (let depth = 0; depth < rowReads.length; depth++) {\n const raw = rowReads[depth](row);\n const key = toKey(raw);\n const keyId = rows.keyId(depth, key, true);\n rowPrefixIds[depth + 1] = rows.child(rowPrefixIds[depth], keyId, true, depth, key, raw);\n }\n columnPrefixIds[0] = 0;\n for (let depth = 0; depth < columnReads.length; depth++) {\n const raw = columnReads[depth](row);\n const key = toKey(raw);\n const keyId = columns.keyId(depth, key, true);\n columnPrefixIds[depth + 1] = columns.child(columnPrefixIds[depth], keyId, true, depth, key, raw);\n }\n // Coerce each measure once per row, not once per (row prefix \u00D7 column prefix) bucket.\n for (let valueIndex = 0; valueIndex < valueReads.length; valueIndex++) {\n const raw = valueReads[valueIndex](row);\n valueCache[valueIndex] = raw;\n numberCache[valueIndex] = coerceFinite(raw);\n }\n for (let r = 0; r <= rowFields.length; r++) {\n const rowId = rowPrefixIds[r];\n let rowBuckets = buckets.get(rowId);\n if (!rowBuckets) {\n rowBuckets = new Map<number, AggregateState[]>();\n buckets.set(rowId, rowBuckets);\n }\n for (let c = 0; c <= columnFields.length; c++) {\n const colId = columnPrefixIds[c];\n let bucket = rowBuckets.get(colId);\n if (!bucket) {\n bucket = emptyState(values);\n rowBuckets.set(colId, bucket);\n }\n for (let valueIndex = 0; valueIndex < values.length; valueIndex++) {\n addToState(bucket[valueIndex], values[valueIndex].op, valueCache[valueIndex], numberCache[valueIndex]);\n }\n }\n }\n }\n const valueAtIds = (rowId: number, colId: number, valueIndex: number): number | null => {\n const valueDef = values[valueIndex];\n if (!valueDef) return null;\n if (rowId < 0 || colId < 0) return aggregateValues([], valueDef.op);\n let rowCache = cache.get(rowId);\n if (!rowCache) {\n rowCache = new Map<number, (number | null)[]>();\n cache.set(rowId, rowCache);\n }\n let cached = rowCache.get(colId);\n if (!cached) {\n cached = new Array<number | null>(values.length);\n rowCache.set(colId, cached);\n } else if (valueIndex in cached) {\n return cached[valueIndex];\n }\n const bucket = buckets.get(rowId)?.get(colId);\n const result = bucket ? stateValue(bucket[valueIndex], valueDef.op) : aggregateValues([], valueDef.op);\n cached[valueIndex] = result;\n return result;\n };\n return {\n valueAt: (rowPath, colPath, valueIndex) =>\n valueAtIds(rows.pathId(rowPath, false), columns.pathId(colPath, false), valueIndex),\n valueAtIds,\n rowAxis: rows.entries,\n columnAxis: columns.entries,\n };\n}\n\nfunction addToState(state: AggregateState, op: AggOp, value: unknown, numeric: number | null = coerceFinite(value)): void {\n if (op === 'count') {\n if (value !== null && value !== undefined) state.count = (state.count ?? 0) + 1;\n return;\n }\n if (op === 'countDistinct') {\n if (!isMissingAggregateValue(value)) {\n (state.distinct ??= new Set()).add(toKey(value));\n }\n return;\n }\n if (op === 'first') {\n if (!state.hasFirst && value !== null && value !== undefined) {\n state.first = numeric;\n state.hasFirst = true;\n }\n return;\n }\n if (op === 'last') {\n if (value !== null && value !== undefined) state.last = numeric;\n return;\n }\n const numberValue = numeric;\n if (numberValue === null) return;\n if (op === 'min') {\n state.min = state.min === undefined ? numberValue : Math.min(state.min, numberValue);\n } else if (op === 'max') {\n state.max = state.max === undefined ? numberValue : Math.max(state.max, numberValue);\n } else if (op === 'median') {\n (state.numbers ??= []).push(numberValue);\n } else {\n const previous = state.sum ?? 0;\n state.sum = previous + numberValue;\n state.numericCount = (state.numericCount ?? 0) + 1;\n if (state.numbers || !Number.isFinite(state.sum) || Math.abs(numberValue) > 1e300) {\n (state.numbers ??= [previous]).push(numberValue);\n }\n }\n}\n\nfunction stateValue(state: AggregateState, op: AggOp): number | null {\n if (op === 'count') return state.count ?? 0;\n if (op === 'countDistinct') return state.distinct?.size ? state.distinct.size : null;\n if (op === 'first') return state.hasFirst ? (state.first ?? null) : null;\n if (op === 'last') return state.last ?? null;\n switch (op) {\n case 'sum':\n if (!state.numericCount) return null;\n return state.numbers ? stableSum(state.numbers) : Number.isFinite(state.sum) ? state.sum! : null;\n case 'mean':\n case 'avg':\n if (!state.numericCount) return null;\n return state.numbers ? stableSum(state.numbers, state.numericCount) : Number.isFinite(state.sum) ? state.sum! / state.numericCount : null;\n case 'min': {\n return state.min ?? null;\n }\n case 'max': {\n return state.max ?? null;\n }\n case 'median': {\n const numbers = state.numbers ?? [];\n if (numbers.length === 0) return null;\n const sorted = [...numbers].sort((left, right) => left - right);\n return medianSorted(sorted);\n }\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Chrome motion — lets axes, annotations and trendlines move with the marks.
|
|
3
|
+
*
|
|
4
|
+
* Chart chrome (gridlines, tick labels, reference lines, trendlines) is drawn by
|
|
5
|
+
* shared modules from each frame's model. To animate it, every module stashes
|
|
6
|
+
* what it drew — by name, on the surface the frame belongs to. While a morph
|
|
7
|
+
* runs, the runtime hands the outgoing frame's chrome to the transient view the
|
|
8
|
+
* tween paints on, and each module draws a blend of the outgoing and incoming
|
|
9
|
+
* chrome instead of jumping to the new scale. During an entrance the surface can
|
|
10
|
+
* carry a reveal progress so reference lines and trendlines draw in after the
|
|
11
|
+
* marks. Static draws (no morph, no entrance) are untouched.
|
|
12
|
+
*/
|
|
13
|
+
import type { Surface } from './surface.js';
|
|
14
|
+
/** Everything chrome modules stashed while drawing one frame, keyed by module. */
|
|
15
|
+
export type ChromeSnapshot = ReadonlyMap<string, unknown>;
|
|
16
|
+
/**
|
|
17
|
+
* Below this opacity a chrome element is invisible: it is neither drawn nor
|
|
18
|
+
* carried into the next morph, so back-to-back updates can't pile up faded-out
|
|
19
|
+
* ticks, labels or reference lines.
|
|
20
|
+
*/
|
|
21
|
+
export declare const CHROME_VISIBLE = 0.002;
|
|
22
|
+
/** The items of a blended frame that are still visible (what a morph stashes). */
|
|
23
|
+
export declare function visibleItems<T extends {
|
|
24
|
+
alpha: number;
|
|
25
|
+
}>(items: readonly T[]): T[];
|
|
26
|
+
/**
|
|
27
|
+
* Morph progress a chrome frame may report while the animation is still in
|
|
28
|
+
* flight. Overshooting easings (`backOut`, `elasticOut`) pass 1 mid-flight; chrome
|
|
29
|
+
* stays in its animating state until the animation completes, when it is set to 1.
|
|
30
|
+
*/
|
|
31
|
+
export declare const CHROME_IN_FLIGHT: number;
|
|
32
|
+
/** Remember chrome `name` as drawn on `surface` (static and tween frames alike). */
|
|
33
|
+
export declare function stashChrome(surface: Surface, name: string, frame: unknown): void;
|
|
34
|
+
/** Forget the stashed chrome (the surface is about to draw a new frame). */
|
|
35
|
+
export declare function clearChrome(surface: Surface): void;
|
|
36
|
+
/**
|
|
37
|
+
* Scale stashed chrome `name` (a list of items with `alpha`) by `factor` when it
|
|
38
|
+
* is captured — for labels an entrance fades in place without redrawing, so an
|
|
39
|
+
* update that interrupts it starts from how far they had faded in. Restashing
|
|
40
|
+
* the name, or a factor of 1, clears it.
|
|
41
|
+
*/
|
|
42
|
+
export declare function fadeChrome(surface: Surface, name: string, factor: number): void;
|
|
43
|
+
/** The chrome on screen right now — captured before a redraw replaces it. */
|
|
44
|
+
export declare function captureChrome(surface: Surface): ChromeSnapshot;
|
|
45
|
+
/**
|
|
46
|
+
* Mark a tween view as drawing chrome `t` of the way from `from` to the frame
|
|
47
|
+
* being drawn. At `t >= 1` the view draws plain static chrome again, so the last
|
|
48
|
+
* frame of a morph is exactly the static frame.
|
|
49
|
+
*/
|
|
50
|
+
export declare function setChromeMorph(view: Surface, from: ChromeSnapshot | undefined, t: number): void;
|
|
51
|
+
/** The outgoing chrome frame `name` and the morph progress, or null when not morphing. */
|
|
52
|
+
export declare function chromeMorph<T>(surface: Surface, name: string): {
|
|
53
|
+
from: T;
|
|
54
|
+
t: number;
|
|
55
|
+
} | null;
|
|
56
|
+
/** Set (or clear, with null) the entrance reveal progress chrome reads on `surface`. */
|
|
57
|
+
export declare function setChromeEntrance(surface: Surface, t: number | null): void;
|
|
58
|
+
/** Entrance progress (0..1) while the surface's marks are still entering, else null. */
|
|
59
|
+
export declare function chromeEntrance(surface: Surface): number | null;
|
|
60
|
+
/**
|
|
61
|
+
* The share of an entrance a late element has played: 0 until `start`, rising
|
|
62
|
+
* to 1 by `end` (both fractions of the entrance), eased out.
|
|
63
|
+
*/
|
|
64
|
+
export declare function revealAt(t: number, start: number, end: number): number;
|
|
65
|
+
//# sourceMappingURL=chromeMotion.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chromeMotion.d.ts","sourceRoot":"","sources":["../../src/render/chromeMotion.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAGzC,kFAAkF;AAClF,MAAM,MAAM,cAAc,GAAG,WAAW,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAE1D;;;;GAIG;AACH,eAAO,MAAM,cAAc,QAAQ,CAAC;AAEpC,kFAAkF;AAClF,wBAAgB,YAAY,CAAC,CAAC,SAAS;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,EAAE,KAAK,EAAE,SAAS,CAAC,EAAE,GAAG,CAAC,EAAE,CAElF;AAED;;;;GAIG;AACH,eAAO,MAAM,gBAAgB,QAAW,CAAC;AAOzC,oFAAoF;AACpF,wBAAgB,WAAW,CAAC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,IAAI,CAMhF;AAED,4EAA4E;AAC5E,wBAAgB,WAAW,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAIlD;AAED;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAM/E;AAED,6EAA6E;AAC7E,wBAAgB,aAAa,CAAC,OAAO,EAAE,OAAO,GAAG,cAAc,CAU9D;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,cAAc,GAAG,SAAS,EAAE,CAAC,EAAE,MAAM,GAAG,IAAI,CAG/F;AAED,0FAA0F;AAC1F,wBAAgB,WAAW,CAAC,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,GAAG;IAAE,IAAI,EAAE,CAAC,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAK5F;AAED,wFAAwF;AACxF,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAI1E;AAED,wFAAwF;AACxF,wBAAgB,cAAc,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAE9D;AAED;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAKtE"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { surfaceOwner } from "./transient.js";
|
|
2
|
+
const CHROME_VISIBLE = 2e-3;
|
|
3
|
+
function visibleItems(items) {
|
|
4
|
+
return items.filter((item) => item.alpha > CHROME_VISIBLE);
|
|
5
|
+
}
|
|
6
|
+
const CHROME_IN_FLIGHT = 1 - 1e-6;
|
|
7
|
+
const STASH = /* @__PURE__ */ new WeakMap();
|
|
8
|
+
const MORPHS = /* @__PURE__ */ new WeakMap();
|
|
9
|
+
const ENTRANCES = /* @__PURE__ */ new WeakMap();
|
|
10
|
+
const FADES = /* @__PURE__ */ new WeakMap();
|
|
11
|
+
function stashChrome(surface, name, frame) {
|
|
12
|
+
const owner = surfaceOwner(surface);
|
|
13
|
+
let stash = STASH.get(owner);
|
|
14
|
+
if (!stash) STASH.set(owner, stash = /* @__PURE__ */ new Map());
|
|
15
|
+
stash.set(name, frame);
|
|
16
|
+
FADES.get(owner)?.delete(name);
|
|
17
|
+
}
|
|
18
|
+
function clearChrome(surface) {
|
|
19
|
+
const owner = surfaceOwner(surface);
|
|
20
|
+
STASH.delete(owner);
|
|
21
|
+
FADES.delete(owner);
|
|
22
|
+
}
|
|
23
|
+
function fadeChrome(surface, name, factor) {
|
|
24
|
+
const owner = surfaceOwner(surface);
|
|
25
|
+
let fades = FADES.get(owner);
|
|
26
|
+
if (!fades) FADES.set(owner, fades = /* @__PURE__ */ new Map());
|
|
27
|
+
if (factor >= 1) fades.delete(name);
|
|
28
|
+
else fades.set(name, Math.max(0, factor));
|
|
29
|
+
}
|
|
30
|
+
function captureChrome(surface) {
|
|
31
|
+
const owner = surfaceOwner(surface);
|
|
32
|
+
const snapshot = new Map(STASH.get(owner) ?? []);
|
|
33
|
+
for (const [name, factor] of FADES.get(owner) ?? []) {
|
|
34
|
+
const items = snapshot.get(name);
|
|
35
|
+
if (Array.isArray(items)) {
|
|
36
|
+
snapshot.set(name, visibleItems(items.map((item) => ({ ...item, alpha: (item.alpha ?? 1) * factor }))));
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return snapshot;
|
|
40
|
+
}
|
|
41
|
+
function setChromeMorph(view, from, t) {
|
|
42
|
+
if (from && from.size > 0 && t < 1) MORPHS.set(view, { from, t: Math.max(0, t) });
|
|
43
|
+
else MORPHS.delete(view);
|
|
44
|
+
}
|
|
45
|
+
function chromeMorph(surface, name) {
|
|
46
|
+
const morph = MORPHS.get(surface);
|
|
47
|
+
if (!morph) return null;
|
|
48
|
+
const from = morph.from.get(name);
|
|
49
|
+
return from === void 0 ? null : { from, t: morph.t };
|
|
50
|
+
}
|
|
51
|
+
function setChromeEntrance(surface, t) {
|
|
52
|
+
const owner = surfaceOwner(surface);
|
|
53
|
+
if (t == null || t >= 1) ENTRANCES.delete(owner);
|
|
54
|
+
else ENTRANCES.set(owner, Math.max(0, t));
|
|
55
|
+
}
|
|
56
|
+
function chromeEntrance(surface) {
|
|
57
|
+
return ENTRANCES.get(surfaceOwner(surface)) ?? null;
|
|
58
|
+
}
|
|
59
|
+
function revealAt(t, start, end) {
|
|
60
|
+
if (t <= start) return 0;
|
|
61
|
+
if (t >= end) return 1;
|
|
62
|
+
const k = (t - start) / (end - start);
|
|
63
|
+
return 1 - (1 - k) * (1 - k);
|
|
64
|
+
}
|
|
65
|
+
export {
|
|
66
|
+
CHROME_IN_FLIGHT,
|
|
67
|
+
CHROME_VISIBLE,
|
|
68
|
+
captureChrome,
|
|
69
|
+
chromeEntrance,
|
|
70
|
+
chromeMorph,
|
|
71
|
+
clearChrome,
|
|
72
|
+
fadeChrome,
|
|
73
|
+
revealAt,
|
|
74
|
+
setChromeEntrance,
|
|
75
|
+
setChromeMorph,
|
|
76
|
+
stashChrome,
|
|
77
|
+
visibleItems
|
|
78
|
+
};
|
|
79
|
+
//# sourceMappingURL=chromeMotion.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/render/chromeMotion.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * Chrome motion \u2014 lets axes, annotations and trendlines move with the marks.\n *\n * Chart chrome (gridlines, tick labels, reference lines, trendlines) is drawn by\n * shared modules from each frame's model. To animate it, every module stashes\n * what it drew \u2014 by name, on the surface the frame belongs to. While a morph\n * runs, the runtime hands the outgoing frame's chrome to the transient view the\n * tween paints on, and each module draws a blend of the outgoing and incoming\n * chrome instead of jumping to the new scale. During an entrance the surface can\n * carry a reveal progress so reference lines and trendlines draw in after the\n * marks. Static draws (no morph, no entrance) are untouched.\n */\n\nimport type { Surface } from './surface';\nimport { surfaceOwner } from './transient';\n\n/** Everything chrome modules stashed while drawing one frame, keyed by module. */\nexport type ChromeSnapshot = ReadonlyMap<string, unknown>;\n\n/**\n * Below this opacity a chrome element is invisible: it is neither drawn nor\n * carried into the next morph, so back-to-back updates can't pile up faded-out\n * ticks, labels or reference lines.\n */\nexport const CHROME_VISIBLE = 0.002;\n\n/** The items of a blended frame that are still visible (what a morph stashes). */\nexport function visibleItems<T extends { alpha: number }>(items: readonly T[]): T[] {\n return items.filter((item) => item.alpha > CHROME_VISIBLE);\n}\n\n/**\n * Morph progress a chrome frame may report while the animation is still in\n * flight. Overshooting easings (`backOut`, `elasticOut`) pass 1 mid-flight; chrome\n * stays in its animating state until the animation completes, when it is set to 1.\n */\nexport const CHROME_IN_FLIGHT = 1 - 1e-6;\n\nconst STASH = new WeakMap<Surface, Map<string, unknown>>();\nconst MORPHS = new WeakMap<object, { from: ChromeSnapshot; t: number }>();\nconst ENTRANCES = new WeakMap<Surface, number>();\nconst FADES = new WeakMap<Surface, Map<string, number>>();\n\n/** Remember chrome `name` as drawn on `surface` (static and tween frames alike). */\nexport function stashChrome(surface: Surface, name: string, frame: unknown): void {\n const owner = surfaceOwner(surface);\n let stash = STASH.get(owner);\n if (!stash) STASH.set(owner, (stash = new Map()));\n stash.set(name, frame);\n FADES.get(owner)?.delete(name);\n}\n\n/** Forget the stashed chrome (the surface is about to draw a new frame). */\nexport function clearChrome(surface: Surface): void {\n const owner = surfaceOwner(surface);\n STASH.delete(owner);\n FADES.delete(owner);\n}\n\n/**\n * Scale stashed chrome `name` (a list of items with `alpha`) by `factor` when it\n * is captured \u2014 for labels an entrance fades in place without redrawing, so an\n * update that interrupts it starts from how far they had faded in. Restashing\n * the name, or a factor of 1, clears it.\n */\nexport function fadeChrome(surface: Surface, name: string, factor: number): void {\n const owner = surfaceOwner(surface);\n let fades = FADES.get(owner);\n if (!fades) FADES.set(owner, (fades = new Map()));\n if (factor >= 1) fades.delete(name);\n else fades.set(name, Math.max(0, factor));\n}\n\n/** The chrome on screen right now \u2014 captured before a redraw replaces it. */\nexport function captureChrome(surface: Surface): ChromeSnapshot {\n const owner = surfaceOwner(surface);\n const snapshot = new Map(STASH.get(owner) ?? []);\n for (const [name, factor] of FADES.get(owner) ?? []) {\n const items = snapshot.get(name);\n if (Array.isArray(items)) {\n snapshot.set(name, visibleItems(items.map((item: { alpha?: number }) => ({ ...item, alpha: (item.alpha ?? 1) * factor }))));\n }\n }\n return snapshot;\n}\n\n/**\n * Mark a tween view as drawing chrome `t` of the way from `from` to the frame\n * being drawn. At `t >= 1` the view draws plain static chrome again, so the last\n * frame of a morph is exactly the static frame.\n */\nexport function setChromeMorph(view: Surface, from: ChromeSnapshot | undefined, t: number): void {\n if (from && from.size > 0 && t < 1) MORPHS.set(view, { from, t: Math.max(0, t) });\n else MORPHS.delete(view);\n}\n\n/** The outgoing chrome frame `name` and the morph progress, or null when not morphing. */\nexport function chromeMorph<T>(surface: Surface, name: string): { from: T; t: number } | null {\n const morph = MORPHS.get(surface);\n if (!morph) return null;\n const from = morph.from.get(name);\n return from === undefined ? null : { from: from as T, t: morph.t };\n}\n\n/** Set (or clear, with null) the entrance reveal progress chrome reads on `surface`. */\nexport function setChromeEntrance(surface: Surface, t: number | null): void {\n const owner = surfaceOwner(surface);\n if (t == null || t >= 1) ENTRANCES.delete(owner);\n else ENTRANCES.set(owner, Math.max(0, t));\n}\n\n/** Entrance progress (0..1) while the surface's marks are still entering, else null. */\nexport function chromeEntrance(surface: Surface): number | null {\n return ENTRANCES.get(surfaceOwner(surface)) ?? null;\n}\n\n/**\n * The share of an entrance a late element has played: 0 until `start`, rising\n * to 1 by `end` (both fractions of the entrance), eased out.\n */\nexport function revealAt(t: number, start: number, end: number): number {\n if (t <= start) return 0;\n if (t >= end) return 1;\n const k = (t - start) / (end - start);\n return 1 - (1 - k) * (1 - k);\n}\n"],
|
|
5
|
+
"mappings": "AAcA,SAAS,oBAAoB;AAUtB,MAAM,iBAAiB;AAGvB,SAAS,aAA0C,OAA0B;AAClF,SAAO,MAAM,OAAO,CAAC,SAAS,KAAK,QAAQ,cAAc;AAC3D;AAOO,MAAM,mBAAmB,IAAI;AAEpC,MAAM,QAAQ,oBAAI,QAAuC;AACzD,MAAM,SAAS,oBAAI,QAAqD;AACxE,MAAM,YAAY,oBAAI,QAAyB;AAC/C,MAAM,QAAQ,oBAAI,QAAsC;AAGjD,SAAS,YAAY,SAAkB,MAAc,OAAsB;AAChF,QAAM,QAAQ,aAAa,OAAO;AAClC,MAAI,QAAQ,MAAM,IAAI,KAAK;AAC3B,MAAI,CAAC,MAAO,OAAM,IAAI,OAAQ,QAAQ,oBAAI,IAAI,CAAE;AAChD,QAAM,IAAI,MAAM,KAAK;AACrB,QAAM,IAAI,KAAK,GAAG,OAAO,IAAI;AAC/B;AAGO,SAAS,YAAY,SAAwB;AAClD,QAAM,QAAQ,aAAa,OAAO;AAClC,QAAM,OAAO,KAAK;AAClB,QAAM,OAAO,KAAK;AACpB;AAQO,SAAS,WAAW,SAAkB,MAAc,QAAsB;AAC/E,QAAM,QAAQ,aAAa,OAAO;AAClC,MAAI,QAAQ,MAAM,IAAI,KAAK;AAC3B,MAAI,CAAC,MAAO,OAAM,IAAI,OAAQ,QAAQ,oBAAI,IAAI,CAAE;AAChD,MAAI,UAAU,EAAG,OAAM,OAAO,IAAI;AAAA,MAC7B,OAAM,IAAI,MAAM,KAAK,IAAI,GAAG,MAAM,CAAC;AAC1C;AAGO,SAAS,cAAc,SAAkC;AAC9D,QAAM,QAAQ,aAAa,OAAO;AAClC,QAAM,WAAW,IAAI,IAAI,MAAM,IAAI,KAAK,KAAK,CAAC,CAAC;AAC/C,aAAW,CAAC,MAAM,MAAM,KAAK,MAAM,IAAI,KAAK,KAAK,CAAC,GAAG;AACnD,UAAM,QAAQ,SAAS,IAAI,IAAI;AAC/B,QAAI,MAAM,QAAQ,KAAK,GAAG;AACxB,eAAS,IAAI,MAAM,aAAa,MAAM,IAAI,CAAC,UAA8B,EAAE,GAAG,MAAM,QAAQ,KAAK,SAAS,KAAK,OAAO,EAAE,CAAC,CAAC;AAAA,IAC5H;AAAA,EACF;AACA,SAAO;AACT;AAOO,SAAS,eAAe,MAAe,MAAkC,GAAiB;AAC/F,MAAI,QAAQ,KAAK,OAAO,KAAK,IAAI,EAAG,QAAO,IAAI,MAAM,EAAE,MAAM,GAAG,KAAK,IAAI,GAAG,CAAC,EAAE,CAAC;AAAA,MAC3E,QAAO,OAAO,IAAI;AACzB;AAGO,SAAS,YAAe,SAAkB,MAA6C;AAC5F,QAAM,QAAQ,OAAO,IAAI,OAAO;AAChC,MAAI,CAAC,MAAO,QAAO;AACnB,QAAM,OAAO,MAAM,KAAK,IAAI,IAAI;AAChC,SAAO,SAAS,SAAY,OAAO,EAAE,MAAiB,GAAG,MAAM,EAAE;AACnE;AAGO,SAAS,kBAAkB,SAAkB,GAAwB;AAC1E,QAAM,QAAQ,aAAa,OAAO;AAClC,MAAI,KAAK,QAAQ,KAAK,EAAG,WAAU,OAAO,KAAK;AAAA,MAC1C,WAAU,IAAI,OAAO,KAAK,IAAI,GAAG,CAAC,CAAC;AAC1C;AAGO,SAAS,eAAe,SAAiC;AAC9D,SAAO,UAAU,IAAI,aAAa,OAAO,CAAC,KAAK;AACjD;AAMO,SAAS,SAAS,GAAW,OAAe,KAAqB;AACtE,MAAI,KAAK,MAAO,QAAO;AACvB,MAAI,KAAK,IAAK,QAAO;AACrB,QAAM,KAAK,IAAI,UAAU,MAAM;AAC/B,SAAO,KAAK,IAAI,MAAM,IAAI;AAC5B;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Path sampling — evaluate a drawn path at an x position.
|
|
3
|
+
*
|
|
4
|
+
* Curve generators write into a {@link PathSink}; this sink records the
|
|
5
|
+
* segments instead of drawing them, so animation code can find exactly where an
|
|
6
|
+
* x-monotone path (a line chart's stroke under any curve interpolation) passes
|
|
7
|
+
* a given x — e.g. to ride a marker along the leading edge of a draw-on reveal.
|
|
8
|
+
*/
|
|
9
|
+
import type { PathSink } from '../shape/sink.js';
|
|
10
|
+
export declare class PathSampler implements PathSink {
|
|
11
|
+
private readonly segments;
|
|
12
|
+
private x;
|
|
13
|
+
private y;
|
|
14
|
+
moveTo(x: number, y: number): void;
|
|
15
|
+
lineTo(x: number, y: number): void;
|
|
16
|
+
bezierCurveTo(c1x: number, c1y: number, c2x: number, c2y: number, x: number, y: number): void;
|
|
17
|
+
quadraticCurveTo(cx: number, cy: number, x: number, y: number): void;
|
|
18
|
+
arc(): void;
|
|
19
|
+
arcTo(_x1: number, _y1: number, x: number, y: number): void;
|
|
20
|
+
closePath(): void;
|
|
21
|
+
/** The path's y where it crosses `x`, or undefined when no segment spans it. */
|
|
22
|
+
yAt(x: number): number | undefined;
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=pathSample.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pathSample.d.ts","sourceRoot":"","sources":["../../src/render/pathSample.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AA6B9C,qBAAa,WAAY,YAAW,QAAQ;IAC1C,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAiB;IAC1C,OAAO,CAAC,CAAC,CAAO;IAChB,OAAO,CAAC,CAAC,CAAO;IAEhB,MAAM,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,IAAI;IAKlC,MAAM,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,IAAI;IAMlC,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,IAAI;IAM7F,gBAAgB,CAAC,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,IAAI;IAMpE,GAAG,IAAI,IAAI;IAIX,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,IAAI;IAI3D,SAAS,IAAI,IAAI;IAIjB,gFAAgF;IAChF,GAAG,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;CAiBnC"}
|