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
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/runtime/chartAnimation.ts"],
|
|
4
|
-
"sourcesContent": ["import type { ChartSpec } from '../spec/types';\nimport type { Size } from '../types';\nimport { drawAxesUnderlay } from '../axes';\nimport { drawAnnotations, drawTrendlines, type CartesianRenderer, type CustomRenderer, type RenderContext } from '../charts';\nimport type { CanvasLayer } from '../render/canvasLayer';\nimport type { Surface } from '../render/surface';\nimport type { ThemeTokens } from '../theme';\nimport { animate, type AnimationHandle, type ResolvedEntrance } from '../animation';\nimport type { CartesianModel } from './cartesian';\nimport { paintBackground } from './runtimeShared';\n\n/**\n * Cartesian entrance. Two modes: a left-to-right `wipe` with a brief fade\n * (line/area/scatter/box), or `grow` where the renderer re-runs each frame with\n * an `entranceProgress` so bars rise out of the value baseline. Gridlines + axis\n * baselines stay fully drawn throughout; the final frame is pixel-identical to a\n * static draw.\n */\nexport function runCartesianEntrance(\n surface: Surface,\n model: CartesianModel,\n renderer: CartesianRenderer,\n tokens: ThemeTokens,\n background: string | undefined,\n anim: ResolvedEntrance,\n onDone: () => void,\n mode: 'wipe' | 'grow' = 'wipe',\n): AnimationHandle {\n const ctx = surface.marks.ctx;\n const { plot } = model;\n const bg = background ?? tokens.color.background;\n const paintFrame = (t: number): void => {\n surface.marks.clear();\n surface.evidence.reset({ width: surface.width, height: surface.height }, model.spec.data?.length ?? 0, bg);\n ctx.save();\n ctx.fillStyle = bg;\n ctx.fillRect(0, 0, surface.width, surface.height);\n ctx.restore();\n drawAxesUnderlay(surface, model);\n if (mode === 'grow') return paintGrowFrame(surface, model, renderer, t);\n if (t <= 0) return;\n ctx.save();\n ctx.globalAlpha = Math.min(1, 0.2 + 0.8 * t);\n ctx.beginPath();\n ctx.rect(plot.x, plot.y, plot.width * t, plot.height + 1);\n ctx.clip();\n renderer(surface, model);\n ctx.restore();\n drawTrendlines(surface, model);\n drawAnnotations(surface, model);\n };\n paintFrame(0);\n return animate({ duration: anim.duration, easing: anim.easing, onUpdate: paintFrame,\n onComplete: () => { paintFrame(1); onDone(); } });\n}\n\nfunction paintGrowFrame(surface: Surface, model: CartesianModel, renderer: CartesianRenderer, t: number): void {\n // Marks grow from the baseline; leave the shared model clean afterwards so\n // interaction/report code always sees the fully-drawn state.\n model.entranceProgress = t;\n renderer(surface, model);\n model.entranceProgress = undefined;\n drawTrendlines(surface, model);\n drawAnnotations(surface, model);\n}\n\n/**\n * Custom-chart entrance that re-renders the visual each frame with an\n * interpolation progress (0..1) mixed into its RenderContext \u2014 the number\n * roll-up (kpi) and arc sweep (pie/gauge). `paint` clears the layers and\n * repaints; the final frame (t=1) is pixel-identical to a static draw.\n *\n * Note we do *not* paint frame 0 synchronously: the caller already rendered the\n * final state, and `animate()` schedules the first frame via rAF (which runs\n * before the browser's first paint, so the roll still starts from ~0 with no\n * flash). This keeps the synchronous DOM \u2014 and thus SSR / no-rAF / test reads \u2014\n * showing the final value rather than 0.\n */\nfunction runCustomProgress(\n anim: ResolvedEntrance,\n onDone: () => void,\n paint: (t: number) => void,\n): AnimationHandle {\n return animate({ duration: anim.duration, easing: anim.easing, onUpdate: paint,\n onComplete: () => { paint(1); onDone(); } });\n}\n\nexport function runCustomRendererProgress(\n surface: Surface,\n renderer: CustomRenderer,\n spec: ChartSpec,\n tokens: ThemeTokens,\n size: Size,\n options: {\n anim: ResolvedEntrance;\n onDone: () => void;\n dataLength: number;\n background?: string;\n context: RenderContext;\n progressKey: 'valueProgress' | 'sweepProgress';\n extraContext?: Partial<RenderContext>;\n },\n): AnimationHandle {\n return runCustomProgress(options.anim, options.onDone, (t) => {\n surface.overlay.replaceChildren();\n surface.marks.clear();\n surface.labels.clear();\n surface.evidence.reset(size, options.dataLength, options.background ?? tokens.color.background);\n paintBackground(surface, tokens, options.background);\n renderer(surface, spec, tokens, size, { ...options.context, ...options.extraContext, [options.progressKey]: t });\n });\n}\n\n/**\n * Custom-chart entrance: a compositor-friendly opacity + slight upward rise of\n * the whole surface. Used for charts whose content is already fully painted\n * (pie/heatmap canvas, kpi/table/matrix DOM), so re-running the renderer per\n * frame isn't needed.\n */\nexport function runFadeEntrance(surface: Surface, anim: ResolvedEntrance, onDone: () => void): AnimationHandle {\n const apply = (t: number): void => {\n surface.root.style.opacity = String(t);\n const dy = (1 - t) * 8;\n surface.root.style.transform = dy > 0.02 ? `translateY(${dy.toFixed(2)}px)` : '';\n };\n apply(0);\n return animate({ duration: anim.duration, easing: anim.easing, onUpdate: apply,\n onComplete: () => { surface.root.style.opacity = ''; surface.root.style.transform = ''; onDone(); } });\n}\n\n/**\n * Copy a canvas layer's current backing store into a detached canvas so it can\n * be composited later (used to cross-fade the previous frame on update()).\n */\nexport function snapshotLayer(layer: CanvasLayer): HTMLCanvasElement {\n const off = document.createElement('canvas');\n off.width = layer.canvas.width;\n off.height = layer.canvas.height;\n if (off.width > 0 && off.height > 0) off.getContext('2d')?.drawImage(layer.canvas, 0, 0);\n return off;\n}\n\n/**\n * Update transition: cross-fade the marks layer from the previous frame to the\n * freshly drawn one. The new frame is already live on the canvas when this runs,\n * so we snapshot it and composite `new` under `old` with `old` fading out. The\n * final frame is pixel-identical to the static (instant) draw.\n */\nexport function runUpdateCrossfade(surface: Surface, before: HTMLCanvasElement, anim: ResolvedEntrance): AnimationHandle {\n const after = snapshotLayer(surface.marks);\n const ctx = surface.marks.ctx;\n const w = surface.marks.width;\n const h = surface.marks.height;\n const paint = (t: number): void => {\n surface.marks.clear();\n ctx.save();\n ctx.globalAlpha = 1;\n ctx.drawImage(after, 0, 0, w, h);\n if (t < 1) {\n ctx.globalAlpha = 1 - t;\n ctx.drawImage(before, 0, 0, w, h);\n }\n ctx.restore();\n };\n paint(0);\n return animate({ duration: anim.duration, easing: anim.easing, onUpdate: paint, onComplete: () => paint(1) });\n}\n"],
|
|
5
|
-
"mappings": "AAEA,SAAS,wBAAwB;
|
|
4
|
+
"sourcesContent": ["import type { ChartSpec, CurveType } from '../spec/types';\nimport type { Size } from '../types';\nimport { drawAxesUnderlay, drawOverlay } from '../axes';\nimport {\n drawAnnotationLabels,\n drawAnnotations,\n drawTrendlineLabels,\n drawTrendlines,\n type CartesianRenderer,\n type CustomRenderer,\n type RenderContext,\n} from '../charts';\nimport { paintGeometry, transientSurface } from '../charts/geometry';\nimport type { CanvasLayer } from '../render/canvasLayer';\nimport { CHROME_IN_FLIGHT, fadeChrome, revealAt, setChromeEntrance, setChromeMorph, type ChromeSnapshot } from '../render/chromeMotion';\nimport { ANNOTATION_LABELS } from '../charts/annotations';\nimport { TREND_LABELS } from '../charts/trendline';\nimport { PathSampler } from '../render/pathSample';\nimport type { Surface } from '../render/surface';\nimport { line } from '../shape';\nimport type { ThemeTokens } from '../theme';\nimport { withAlpha } from '../color';\nimport { animate, linear, type AnimationHandle, type ResolvedEntrance } from '../animation';\nimport { resolveCurve, type CartesianModel } from './cartesian';\nimport type { GeometryMorph } from './morph';\nimport { paintBackground } from './runtimeShared';\n\n/** Label stashes an entrance fades in place (their DOM is drawn once, then faded). */\nconst LATE_LABEL_STASHES = [ANNOTATION_LABELS, TREND_LABELS];\n\n/** Fraction of a staggered entrance spread across marks as a wave. */\nconst ENTRANCE_STAGGER = 0.4;\n/** Staggered entrances run a little longer so each mark keeps a full ease. */\nconst STAGGER_STRETCH = 1.35;\n\n/**\n * Cartesian entrance. Two modes:\n * - `wipe`: a left-to-right reveal. Lines and areas draw on at full strength\n * with a glowing head riding each series' leading edge; other charts (box)\n * reveal with a brief fade.\n * - `grow`: the renderer re-runs each frame with an `entranceProgress`, so bars\n * rise out of the value baseline and scatter points pop in \u2014 staggered as a\n * left-to-right wave, each mark easing on its own schedule.\n * Gridlines + axis baselines stay fully drawn throughout. Reference lines,\n * bands and trendlines draw in once the marks have mostly arrived, and their\n * labels (`lateLabels`) fade in last. The final frame is pixel-identical to a\n * static draw.\n */\nexport function runCartesianEntrance(\n surface: Surface,\n model: CartesianModel,\n renderer: CartesianRenderer,\n tokens: ThemeTokens,\n background: string | undefined,\n anim: ResolvedEntrance,\n onDone: () => void,\n mode: 'wipe' | 'grow' = 'wipe',\n lateLabels: readonly HTMLElement[] = [],\n): AnimationHandle {\n const ctx = surface.marks.ctx;\n const { plot } = model;\n const bg = background ?? tokens.color.background;\n const drawOn = model.spec.type === 'line' || model.spec.type === 'area';\n const staggered = mode === 'grow' && staggerable(model);\n // Chrome timing only moves forward and finishes with the entrance, so an\n // overshooting easing (backOut, elasticOut) can't flicker reference lines or labels.\n let shown = 0;\n const paintFrame = (t: number, done = false): void => {\n shown = done ? 1 : Math.min(CHROME_IN_FLIGHT, Math.max(shown, t));\n setChromeEntrance(surface, done ? null : shown);\n const labelReveal = done ? 1 : revealAt(shown, 0.78, 1);\n for (const el of lateLabels) el.style.opacity = done ? '' : String(labelReveal);\n // The late labels fade in place; an update that interrupts captures them as shown.\n for (const name of LATE_LABEL_STASHES) fadeChrome(surface, name, labelReveal);\n surface.marks.clear();\n surface.evidence.reset({ width: surface.width, height: surface.height }, model.spec.data?.length ?? 0, bg);\n ctx.save();\n ctx.fillStyle = bg;\n ctx.fillRect(0, 0, surface.width, surface.height);\n ctx.restore();\n drawAxesUnderlay(surface, model);\n if (mode === 'grow') return paintGrowFrame(surface, model, renderer, t, staggered ? anim.easing : undefined);\n if (t <= 0) return;\n ctx.save();\n ctx.globalAlpha = drawOn ? 1 : Math.min(1, 0.2 + 0.8 * t);\n ctx.beginPath();\n ctx.rect(plot.x, plot.y, plot.width * t, plot.height + 1);\n ctx.clip();\n renderer(surface, model);\n ctx.restore();\n if (drawOn) paintDrawOnHeads(ctx, model, bg, t);\n drawTrendlines(surface, model);\n drawAnnotations(surface, model);\n };\n paintFrame(0);\n // A staggered grow runs on a linear clock; each mark applies the easing itself.\n return animate({\n duration: staggered ? anim.duration * STAGGER_STRETCH : anim.duration,\n easing: staggered ? linear : anim.easing,\n onUpdate: (t, raw) => paintFrame(t, raw >= 1),\n onComplete: () => { paintFrame(1, true); onDone(); },\n });\n}\n\n/** Staggering needs a few marks to read as a wave (and never applies to sketches). */\nfunction staggerable(model: CartesianModel): boolean {\n if (model.sketch) return false;\n if (model.spec.type === 'scatter') return true;\n return (model.x.categories?.length ?? 0) >= 3;\n}\n\nfunction paintGrowFrame(\n surface: Surface,\n model: CartesianModel,\n renderer: CartesianRenderer,\n t: number,\n staggerEase?: (t: number) => number,\n): void {\n // Marks grow from the baseline; leave the shared model clean afterwards so\n // interaction/report code always sees the fully-drawn state.\n model.entranceProgress = t;\n if (staggerEase) {\n model.entranceStagger = ENTRANCE_STAGGER;\n model.entranceEase = staggerEase;\n }\n try {\n renderer(surface, model);\n } finally {\n model.entranceProgress = undefined;\n model.entranceStagger = undefined;\n model.entranceEase = undefined;\n }\n drawTrendlines(surface, model);\n drawAnnotations(surface, model);\n}\n\n/**\n * Glowing heads that ride each line/area series' leading edge during the\n * draw-on reveal. They sit exactly on the stroke (sampled from the same curve\n * the renderer drew) and fade out before the final frame, which stays the\n * static draw.\n */\nfunction paintDrawOnHeads(ctx: CanvasRenderingContext2D, model: CartesianModel, background: string, t: number): void {\n const geometry = model.geometry;\n if (!geometry || (geometry.kind !== 'line' && geometry.kind !== 'area') || model.sketch) return;\n const fade = t < 0.72 ? 1 : Math.max(0, (1 - t) / 0.28);\n if (!(fade > 0)) return;\n const x = model.plot.x + model.plot.width * t;\n const path = line({ curve: resolveCurve((model.spec as { curve?: CurveType }).curve) });\n const strokeWidth = geometry.metrics.strokeWidth;\n const tracks =\n geometry.kind === 'line'\n ? geometry.series.map((s) => ({ color: s.series.color, alpha: s.alpha, points: s.points }))\n : geometry.bands.map((b) => ({ color: b.series.color, alpha: b.alpha, points: b.points.map((p) => ({ x: p.x, y: p.y1 })) }));\n ctx.save();\n for (const track of tracks) {\n const sampler = new PathSampler();\n path(track.points, sampler);\n const y = sampler.yAt(x);\n if (y === undefined || !Number.isFinite(y)) continue;\n const alpha = fade * track.alpha;\n const glow = strokeWidth * 5;\n const halo = ctx.createRadialGradient(x, y, 0, x, y, glow);\n halo.addColorStop(0, withAlpha(track.color, 0.45 * alpha));\n halo.addColorStop(1, withAlpha(track.color, 0));\n ctx.fillStyle = halo;\n ctx.beginPath();\n ctx.arc(x, y, glow, 0, Math.PI * 2);\n ctx.fill();\n ctx.globalAlpha = alpha;\n ctx.beginPath();\n ctx.arc(x, y, strokeWidth * 1.6, 0, Math.PI * 2);\n ctx.fillStyle = background;\n ctx.fill();\n ctx.beginPath();\n ctx.arc(x, y, strokeWidth * 1.05, 0, Math.PI * 2);\n ctx.fillStyle = track.color;\n ctx.fill();\n ctx.globalAlpha = 1;\n }\n ctx.restore();\n}\n\n/**\n * Custom-chart entrance that re-renders the visual each frame with an\n * interpolation progress (0..1) mixed into its RenderContext \u2014 the number\n * roll-up (kpi) and arc sweep (pie/gauge). `paint` clears the layers and\n * repaints; the final frame (t=1) is pixel-identical to a static draw.\n *\n * Note we do *not* paint frame 0 synchronously: the caller already rendered the\n * final state, and `animate()` schedules the first frame via rAF (which runs\n * before the browser's first paint, so the roll still starts from ~0 with no\n * flash). This keeps the synchronous DOM \u2014 and thus SSR / no-rAF / test reads \u2014\n * showing the final value rather than 0.\n */\nexport function runCustomRendererProgress(\n surface: Surface,\n renderer: CustomRenderer,\n spec: ChartSpec,\n tokens: ThemeTokens,\n size: Size,\n options: {\n anim: ResolvedEntrance;\n onDone: () => void;\n dataLength: number;\n background?: string;\n context: RenderContext;\n progressKey: 'valueProgress' | 'sweepProgress' | 'morphProgress' | 'entranceProgress';\n extraContext?: Partial<RenderContext>;\n /**\n * Paint frames on a transient view so they never reach the evidence ledger\n * (update transitions, whose static final frame was already drawn and reported).\n */\n transient?: boolean;\n /**\n * Paint the t = 0 frame synchronously, replacing the static final frame\n * before the browser can present it (update morphs start from what was on\n * screen, so showing the destination for a frame would flash).\n */\n paintInitial?: boolean;\n /** The chrome on screen when an update morph began, so axes and annotations glide too. */\n chrome?: ChromeSnapshot;\n /** An entrance: reference lines, trendlines and their labels draw in after the marks. */\n entranceChrome?: boolean;\n },\n): AnimationHandle {\n const target = options.transient ? transientSurface(surface) : surface;\n let shown = 0;\n const paint = (t: number, done = false): void => {\n // Chrome stays mid-morph / mid-entrance until the animation completes, even\n // when an overshooting easing passes 1 on the way.\n if (options.chrome) setChromeMorph(target, options.chrome, done ? 1 : Math.min(CHROME_IN_FLIGHT, t));\n if (options.entranceChrome) {\n shown = done ? 1 : Math.min(CHROME_IN_FLIGHT, Math.max(shown, t));\n setChromeEntrance(surface, done ? null : shown);\n }\n surface.overlay.replaceChildren();\n surface.marks.clear();\n target.labels.clear();\n if (!options.transient) surface.evidence.reset(size, options.dataLength, options.background ?? tokens.color.background);\n paintBackground(surface, tokens, options.background);\n renderer(target, spec, tokens, size, { ...options.context, ...options.extraContext, [options.progressKey]: t });\n };\n if (options.paintInitial) paint(0);\n return animate({ duration: options.anim.duration, easing: options.anim.easing, onUpdate: (t, raw) => paint(t, raw >= 1),\n onComplete: () => { paint(1, true); options.onDone(); } });\n}\n\n/**\n * Custom-chart entrance: a compositor-friendly opacity + slight upward rise of\n * the whole surface. Used for charts whose content is already fully painted\n * (pie/heatmap canvas, kpi/table/matrix DOM), so re-running the renderer per\n * frame isn't needed.\n */\nexport function runFadeEntrance(surface: Surface, anim: ResolvedEntrance, onDone: () => void): AnimationHandle {\n const apply = (t: number): void => {\n surface.root.style.opacity = String(t);\n const dy = (1 - t) * 8;\n surface.root.style.transform = dy > 0.02 ? `translateY(${dy.toFixed(2)}px)` : '';\n };\n apply(0);\n return animate({ duration: anim.duration, easing: anim.easing, onUpdate: apply,\n onComplete: () => { surface.root.style.opacity = ''; surface.root.style.transform = ''; onDone(); } });\n}\n\n/**\n * Update morph: repaint the marks layer each frame with geometry interpolated\n * from the outgoing frame to the incoming one. With the outgoing frame's\n * `chrome`, the axes, gridlines, tick labels, annotations and trendlines glide\n * from where they were too (the overlay text is rebuilt each frame); without it\n * they sit at the incoming frame's positions. The incoming frame has already\n * been drawn statically (so reports, SSR and test reads see the final state),\n * and the transient surface keeps tween frames out of the render-evidence\n * ledger. The last frame repaints the incoming frame itself, so it is the\n * static draw.\n */\nexport function runCartesianMorph(\n surface: Surface,\n model: CartesianModel,\n morph: GeometryMorph,\n tokens: ThemeTokens,\n background: string | undefined,\n anim: ResolvedEntrance,\n onFrame: (t: number) => void,\n onDone: () => void,\n chrome?: ChromeSnapshot,\n): AnimationHandle {\n const ctx = surface.marks.ctx;\n const bg = background ?? tokens.color.background;\n const transient = transientSurface(surface);\n const moveChrome = !!chrome && chrome.size > 0;\n const paint = (t: number, done = false): void => {\n onFrame(t);\n // Chrome stays mid-morph until the animation completes, even when an\n // overshooting easing passes 1 on the way; the final paint is the static chrome.\n setChromeMorph(transient, chrome, done ? 1 : Math.min(CHROME_IN_FLIGHT, t));\n surface.marks.clear();\n ctx.save();\n ctx.fillStyle = bg;\n ctx.fillRect(0, 0, surface.width, surface.height);\n ctx.restore();\n drawAxesUnderlay(transient, model);\n paintGeometry(transient, model, morph.at(t));\n drawTrendlines(transient, model);\n drawAnnotations(transient, model);\n if (!moveChrome) return;\n surface.overlay.replaceChildren();\n transient.labels.clear();\n drawOverlay(transient, model);\n drawAnnotationLabels(transient, model);\n drawTrendlineLabels(transient, model);\n };\n paint(0);\n return animate({ duration: anim.duration, easing: anim.easing, onUpdate: (t, raw) => paint(t, raw >= 1),\n onComplete: () => { paint(1, true); onDone(); } });\n}\n\n/**\n * Copy a canvas layer's current backing store into a detached canvas so it can\n * be composited later (used to cross-fade the previous frame on update()).\n */\nexport function snapshotLayer(layer: CanvasLayer): HTMLCanvasElement {\n const off = document.createElement('canvas');\n off.width = layer.canvas.width;\n off.height = layer.canvas.height;\n if (off.width > 0 && off.height > 0) off.getContext('2d')?.drawImage(layer.canvas, 0, 0);\n return off;\n}\n\n/**\n * Update transition: cross-fade the marks layer from the previous frame to the\n * freshly drawn one. The new frame is already live on the canvas when this runs,\n * so we snapshot it and composite `new` under `old` with `old` fading out. The\n * final frame is pixel-identical to the static (instant) draw.\n */\nexport function runUpdateCrossfade(surface: Surface, before: HTMLCanvasElement, anim: ResolvedEntrance): AnimationHandle {\n const after = snapshotLayer(surface.marks);\n const ctx = surface.marks.ctx;\n const w = surface.marks.width;\n const h = surface.marks.height;\n const paint = (t: number): void => {\n surface.marks.clear();\n ctx.save();\n ctx.globalAlpha = 1;\n ctx.drawImage(after, 0, 0, w, h);\n if (t < 1) {\n ctx.globalAlpha = 1 - t;\n ctx.drawImage(before, 0, 0, w, h);\n }\n ctx.restore();\n };\n paint(0);\n return animate({ duration: anim.duration, easing: anim.easing, onUpdate: paint, onComplete: () => paint(1) });\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -14,6 +14,12 @@ export declare class ChartRuntime {
|
|
|
14
14
|
private interaction?;
|
|
15
15
|
private entrance?;
|
|
16
16
|
private updateTransition?;
|
|
17
|
+
private lastModel?;
|
|
18
|
+
private morphState?;
|
|
19
|
+
private pendingMorph?;
|
|
20
|
+
private pendingSliceMorph?;
|
|
21
|
+
private pendingCustomMorph?;
|
|
22
|
+
private pendingChrome?;
|
|
17
23
|
private preview?;
|
|
18
24
|
private destroyed;
|
|
19
25
|
private lastValue;
|
|
@@ -55,7 +61,43 @@ export declare class ChartRuntime {
|
|
|
55
61
|
private dispatchDebug;
|
|
56
62
|
private dispatchFacet;
|
|
57
63
|
private dispatchCartesian;
|
|
64
|
+
/**
|
|
65
|
+
* Start an update morph from `from` (the outgoing frame's geometry) to the
|
|
66
|
+
* frame just drawn statically. A no-op when the pair can't be morphed, which
|
|
67
|
+
* leaves update() free to fall back to its cross-fade.
|
|
68
|
+
*/
|
|
69
|
+
private startMorph;
|
|
70
|
+
/** Update-transition timing for `spec` under the current motion environment. */
|
|
71
|
+
private updateMotion;
|
|
72
|
+
/**
|
|
73
|
+
* The geometry an update from `prev` to `next` should morph from — what is on
|
|
74
|
+
* screen right now, including a partially-played morph — or undefined when the
|
|
75
|
+
* transition shouldn't morph (different or non-cartesian types, sketch/facet/
|
|
76
|
+
* debug compositions, or motion disabled).
|
|
77
|
+
*/
|
|
78
|
+
private morphSource;
|
|
58
79
|
private dispatchCustom;
|
|
80
|
+
/**
|
|
81
|
+
* Custom-chart update morph: the renderer re-runs each frame with the marks
|
|
82
|
+
* that were on screen (`morphFrom`) and a morph progress, so bars, tiles,
|
|
83
|
+
* cells, nodes and links travel to the new data. The static draw above is
|
|
84
|
+
* the final frame; tween frames are transient, so reports stay on it.
|
|
85
|
+
*/
|
|
86
|
+
private startCustomMorph;
|
|
87
|
+
/**
|
|
88
|
+
* The marks a custom chart's update from `prev` to `next` should travel from
|
|
89
|
+
* (including a partially-played morph), or undefined when it can't morph:
|
|
90
|
+
* a type change, pie (which re-balances slices instead), sketch/debug, or
|
|
91
|
+
* motion disabled. Renderers opt in by stashing their marks.
|
|
92
|
+
*/
|
|
93
|
+
private customMorphSource;
|
|
94
|
+
/**
|
|
95
|
+
* Re-balance pie/donut slices from the ones on screen: the renderer re-runs
|
|
96
|
+
* each frame with a morph progress (the static draw above is the final frame).
|
|
97
|
+
*/
|
|
98
|
+
private startSliceMorph;
|
|
99
|
+
/** The pie/donut slices an update from `prev` to `next` should re-balance from. */
|
|
100
|
+
private sliceMorphSource;
|
|
59
101
|
private dispatchPlaceholder;
|
|
60
102
|
private customContext;
|
|
61
103
|
private startCustomEntrance;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chartRuntime.d.ts","sourceRoot":"","sources":["../../src/runtime/chartRuntime.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAqB,MAAM,eAAe,CAAC;AAMlE,OAAO,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAM5C,OAAO,EAAqB,KAAK,YAAY,EAAE,MAAM,UAAU,CAAC;AAiBhE,OAAO,EAAwB,KAAK,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAIjF,OAAO,KAAK,EAAkB,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAExE,OAAO,KAAK,EAAE,aAAa,EAAE,aAAa,EAA2B,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"chartRuntime.d.ts","sourceRoot":"","sources":["../../src/runtime/chartRuntime.ts"],"names":[],"mappings":"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"}
|
|
@@ -48,7 +48,13 @@ import {
|
|
|
48
48
|
specLegendParam,
|
|
49
49
|
SWEEP_TYPES
|
|
50
50
|
} from "./runtimeShared.js";
|
|
51
|
-
import { runCartesianEntrance, runCustomRendererProgress, runFadeEntrance, runUpdateCrossfade, snapshotLayer } from "./chartAnimation.js";
|
|
51
|
+
import { runCartesianEntrance, runCartesianMorph, runCustomRendererProgress, runFadeEntrance, runUpdateCrossfade, snapshotLayer } from "./chartAnimation.js";
|
|
52
|
+
import { planGeometryMorph } from "./morph.js";
|
|
53
|
+
import { pieStateOf } from "../charts/pieState.js";
|
|
54
|
+
import { clearMorphFrame, morphFrameOf } from "../charts/morphFrame.js";
|
|
55
|
+
import { captureChrome, clearChrome, setChromeEntrance } from "../render/chromeMotion.js";
|
|
56
|
+
const MORPH_TYPES = /* @__PURE__ */ new Set(["bar", "line", "area", "scatter", "box"]);
|
|
57
|
+
const CUSTOM_MORPH_ROW_LIMIT = 5e3;
|
|
52
58
|
class ChartRuntime {
|
|
53
59
|
constructor(container, spec, options = {}) {
|
|
54
60
|
__publicField(this, "container", container);
|
|
@@ -60,6 +66,22 @@ class ChartRuntime {
|
|
|
60
66
|
__publicField(this, "interaction");
|
|
61
67
|
__publicField(this, "entrance");
|
|
62
68
|
__publicField(this, "updateTransition");
|
|
69
|
+
// The cartesian model behind the frame on screen; its `geometry` is where an
|
|
70
|
+
// update morph starts from. Cleared whenever a non-cartesian frame is drawn.
|
|
71
|
+
__publicField(this, "lastModel");
|
|
72
|
+
// The in-flight update morph and its latest eased progress, so an update that
|
|
73
|
+
// interrupts it morphs onward from what is actually on screen.
|
|
74
|
+
__publicField(this, "morphState");
|
|
75
|
+
// Outgoing geometry handed from update()/selection redraws to the next draw.
|
|
76
|
+
__publicField(this, "pendingMorph");
|
|
77
|
+
// Outgoing pie/donut slices handed to the next draw so slices re-balance.
|
|
78
|
+
__publicField(this, "pendingSliceMorph");
|
|
79
|
+
// Outgoing keyed marks (see charts/morphFrame) a custom renderer stashed,
|
|
80
|
+
// handed to the next draw so its marks travel instead of cross-fading.
|
|
81
|
+
__publicField(this, "pendingCustomMorph");
|
|
82
|
+
// The axes, annotations and trendlines on screen when an update began, so a
|
|
83
|
+
// morph moves them with the marks (see render/chromeMotion).
|
|
84
|
+
__publicField(this, "pendingChrome");
|
|
63
85
|
// The nested chart instance backing the debug view's live preview (when
|
|
64
86
|
// spec.debug is set). Destroyed and recreated on every draw() so it never
|
|
65
87
|
// leaks observers/rAF when the overlay is cleared.
|
|
@@ -204,6 +226,8 @@ class ChartRuntime {
|
|
|
204
226
|
this.entrance = void 0;
|
|
205
227
|
this.updateTransition?.cancel();
|
|
206
228
|
this.updateTransition = void 0;
|
|
229
|
+
this.morphState = void 0;
|
|
230
|
+
setChromeEntrance(this.surface, null);
|
|
207
231
|
this.preview?.destroy();
|
|
208
232
|
this.preview = void 0;
|
|
209
233
|
}
|
|
@@ -246,6 +270,9 @@ class ChartRuntime {
|
|
|
246
270
|
this.lastSparkline = prepared.type === "kpi" ? kpiSparklineSeries(prepared.effectiveSpec, data) : null;
|
|
247
271
|
}
|
|
248
272
|
dispatch(frame, prepared, valueFrom, compareFrom, sparklineFrom) {
|
|
273
|
+
this.lastModel = void 0;
|
|
274
|
+
clearMorphFrame(this.surface);
|
|
275
|
+
clearChrome(this.surface);
|
|
249
276
|
const facet = !this.currentSpec.debug && isFaceted(prepared.effectiveSpec) ? buildFacetModels(prepared.effectiveSpec, frame.tokens, frame.size, prepared.colorDomain) : null;
|
|
250
277
|
if (this.currentSpec.debug) return this.dispatchDebug(frame, prepared);
|
|
251
278
|
if (facet) return this.dispatchFacet(frame, prepared, facet);
|
|
@@ -285,8 +312,7 @@ class ChartRuntime {
|
|
|
285
312
|
drawAnnotations(this.surface, model);
|
|
286
313
|
}
|
|
287
314
|
drawOverlay(this.surface, model);
|
|
288
|
-
drawAnnotationLabels(this.surface, model);
|
|
289
|
-
drawTrendlineLabels(this.surface, model);
|
|
315
|
+
const lateLabels = [...drawAnnotationLabels(this.surface, model), ...drawTrendlineLabels(this.surface, model)];
|
|
290
316
|
const override = cartesianInteractionBuilders[prepared.type];
|
|
291
317
|
const interactionModel = override ? override(model) ?? null : buildCartesianInteraction(model);
|
|
292
318
|
if (frame.anim.enabled && renderer) this.entrance = runCartesianEntrance(
|
|
@@ -297,19 +323,143 @@ class ChartRuntime {
|
|
|
297
323
|
this.currentSpec.background,
|
|
298
324
|
frame.anim,
|
|
299
325
|
() => this.finishEntrance(),
|
|
300
|
-
chartDefinition(prepared.type).entrance === "grow" ? "grow" : "wipe"
|
|
326
|
+
chartDefinition(prepared.type).entrance === "grow" ? "grow" : "wipe",
|
|
327
|
+
lateLabels
|
|
301
328
|
);
|
|
329
|
+
this.lastModel = model;
|
|
330
|
+
const morphFrom = this.pendingMorph;
|
|
331
|
+
this.pendingMorph = void 0;
|
|
332
|
+
if (morphFrom && !frame.anim.enabled) this.startMorph(frame, model, morphFrom);
|
|
302
333
|
return { interactionModel, reportModel: model, legendSelect };
|
|
303
334
|
}
|
|
335
|
+
/**
|
|
336
|
+
* Start an update morph from `from` (the outgoing frame's geometry) to the
|
|
337
|
+
* frame just drawn statically. A no-op when the pair can't be morphed, which
|
|
338
|
+
* leaves update() free to fall back to its cross-fade.
|
|
339
|
+
*/
|
|
340
|
+
startMorph(frame, model, from) {
|
|
341
|
+
const to = model.geometry;
|
|
342
|
+
const anim = this.updateMotion(this.currentSpec);
|
|
343
|
+
if (!to || !anim.enabled) return;
|
|
344
|
+
const morph = planGeometryMorph(from, to);
|
|
345
|
+
if (!morph) return;
|
|
346
|
+
const timing = morph.durationScale ? { ...anim, duration: anim.duration * morph.durationScale } : anim;
|
|
347
|
+
this.updateTransition = runCartesianMorph(
|
|
348
|
+
this.surface,
|
|
349
|
+
model,
|
|
350
|
+
morph,
|
|
351
|
+
frame.tokens,
|
|
352
|
+
this.currentSpec.background,
|
|
353
|
+
timing,
|
|
354
|
+
(t) => {
|
|
355
|
+
this.morphState = { morph, t };
|
|
356
|
+
},
|
|
357
|
+
() => {
|
|
358
|
+
this.morphState = void 0;
|
|
359
|
+
this.updateTransition = void 0;
|
|
360
|
+
this.interaction?.refresh();
|
|
361
|
+
},
|
|
362
|
+
this.pendingChrome
|
|
363
|
+
);
|
|
364
|
+
}
|
|
365
|
+
/** Update-transition timing for `spec` under the current motion environment. */
|
|
366
|
+
updateMotion(spec) {
|
|
367
|
+
return resolveUpdate(spec.animation, {
|
|
368
|
+
reducedMotion: prefersReducedMotion(),
|
|
369
|
+
disabled: this.options.synchronous === true || globalThis.__GRAPHEIN_DISABLE_ANIM === true
|
|
370
|
+
});
|
|
371
|
+
}
|
|
372
|
+
/**
|
|
373
|
+
* The geometry an update from `prev` to `next` should morph from — what is on
|
|
374
|
+
* screen right now, including a partially-played morph — or undefined when the
|
|
375
|
+
* transition shouldn't morph (different or non-cartesian types, sketch/facet/
|
|
376
|
+
* debug compositions, or motion disabled).
|
|
377
|
+
*/
|
|
378
|
+
morphSource(prev, next) {
|
|
379
|
+
if (prev.type !== next.type || !MORPH_TYPES.has(next.type)) return void 0;
|
|
380
|
+
if (prev.debug || next.debug || isFaceted(prev) || isFaceted(next)) return void 0;
|
|
381
|
+
if (resolveSketch(prev) || resolveSketch(next)) return void 0;
|
|
382
|
+
if (!this.updateMotion(next).enabled) return void 0;
|
|
383
|
+
if (this.morphState) return this.morphState.morph.at(this.morphState.t);
|
|
384
|
+
return this.lastModel?.geometry;
|
|
385
|
+
}
|
|
304
386
|
dispatchCustom(frame, prepared, valueFrom, compareFrom, sparklineFrom) {
|
|
305
387
|
const renderer = customRenderers[prepared.type];
|
|
306
388
|
if (!renderer) return this.dispatchPlaceholder(frame, prepared.type);
|
|
307
389
|
const ctx = this.customContext(frame, prepared);
|
|
308
390
|
const interactionModel = renderer(this.surface, prepared.effectiveSpec, frame.tokens, frame.size, ctx) ?? null;
|
|
391
|
+
const sliceFrom = this.pendingSliceMorph;
|
|
392
|
+
this.pendingSliceMorph = void 0;
|
|
393
|
+
const morphFrom = this.pendingCustomMorph;
|
|
394
|
+
this.pendingCustomMorph = void 0;
|
|
309
395
|
if (frame.anim.enabled) this.startCustomEntrance(frame, prepared, renderer, ctx);
|
|
310
|
-
else this.
|
|
396
|
+
else if (sliceFrom && prepared.type === "pie") this.startSliceMorph(frame, prepared, renderer, ctx, sliceFrom);
|
|
397
|
+
else if (morphFrom !== void 0 && morphFrameOf(this.surface, prepared.type) !== void 0) {
|
|
398
|
+
this.startCustomMorph(frame, prepared, renderer, ctx, morphFrom);
|
|
399
|
+
} else this.startValueTween(frame, prepared, renderer, ctx, valueFrom, compareFrom, sparklineFrom);
|
|
311
400
|
return { interactionModel };
|
|
312
401
|
}
|
|
402
|
+
/**
|
|
403
|
+
* Custom-chart update morph: the renderer re-runs each frame with the marks
|
|
404
|
+
* that were on screen (`morphFrom`) and a morph progress, so bars, tiles,
|
|
405
|
+
* cells, nodes and links travel to the new data. The static draw above is
|
|
406
|
+
* the final frame; tween frames are transient, so reports stay on it.
|
|
407
|
+
*/
|
|
408
|
+
startCustomMorph(frame, prepared, renderer, ctx, morphFrom) {
|
|
409
|
+
const tween = this.updateMotion(this.currentSpec);
|
|
410
|
+
if (!tween.enabled) return;
|
|
411
|
+
this.entrance = runCustomRendererProgress(this.surface, renderer, prepared.effectiveSpec, frame.tokens, frame.size, {
|
|
412
|
+
anim: tween,
|
|
413
|
+
onDone: () => this.finishEntrance(),
|
|
414
|
+
dataLength: prepared.filtered.length,
|
|
415
|
+
background: this.currentSpec.background,
|
|
416
|
+
context: ctx,
|
|
417
|
+
progressKey: "morphProgress",
|
|
418
|
+
extraContext: { morphFrom },
|
|
419
|
+
transient: true,
|
|
420
|
+
paintInitial: true,
|
|
421
|
+
chrome: this.pendingChrome
|
|
422
|
+
});
|
|
423
|
+
}
|
|
424
|
+
/**
|
|
425
|
+
* The marks a custom chart's update from `prev` to `next` should travel from
|
|
426
|
+
* (including a partially-played morph), or undefined when it can't morph:
|
|
427
|
+
* a type change, pie (which re-balances slices instead), sketch/debug, or
|
|
428
|
+
* motion disabled. Renderers opt in by stashing their marks.
|
|
429
|
+
*/
|
|
430
|
+
customMorphSource(prev, next) {
|
|
431
|
+
if (prev.type !== next.type || next.type === "pie" || CARTESIAN_TYPES.has(next.type)) return void 0;
|
|
432
|
+
if (prev.debug || next.debug || resolveSketch(prev) || resolveSketch(next)) return void 0;
|
|
433
|
+
if ((prev.data?.length ?? 0) > CUSTOM_MORPH_ROW_LIMIT || (next.data?.length ?? 0) > CUSTOM_MORPH_ROW_LIMIT) return void 0;
|
|
434
|
+
if (!this.updateMotion(next).enabled) return void 0;
|
|
435
|
+
return morphFrameOf(this.surface, next.type);
|
|
436
|
+
}
|
|
437
|
+
/**
|
|
438
|
+
* Re-balance pie/donut slices from the ones on screen: the renderer re-runs
|
|
439
|
+
* each frame with a morph progress (the static draw above is the final frame).
|
|
440
|
+
*/
|
|
441
|
+
startSliceMorph(frame, prepared, renderer, ctx, sliceFrom) {
|
|
442
|
+
const tween = this.updateMotion(this.currentSpec);
|
|
443
|
+
if (!tween.enabled) return;
|
|
444
|
+
this.entrance = runCustomRendererProgress(this.surface, renderer, prepared.effectiveSpec, frame.tokens, frame.size, {
|
|
445
|
+
anim: tween,
|
|
446
|
+
onDone: () => this.finishEntrance(),
|
|
447
|
+
dataLength: prepared.filtered.length,
|
|
448
|
+
background: this.currentSpec.background,
|
|
449
|
+
context: ctx,
|
|
450
|
+
progressKey: "morphProgress",
|
|
451
|
+
extraContext: { sliceFrom },
|
|
452
|
+
transient: true,
|
|
453
|
+
paintInitial: true
|
|
454
|
+
});
|
|
455
|
+
}
|
|
456
|
+
/** The pie/donut slices an update from `prev` to `next` should re-balance from. */
|
|
457
|
+
sliceMorphSource(prev, next) {
|
|
458
|
+
if (prev.type !== "pie" || next.type !== "pie" || prev.debug || next.debug) return void 0;
|
|
459
|
+
if (resolveSketch(prev) || resolveSketch(next) || !this.updateMotion(next).enabled) return void 0;
|
|
460
|
+
const slices = pieStateOf(this.surface);
|
|
461
|
+
return slices?.length ? slices : void 0;
|
|
462
|
+
}
|
|
313
463
|
dispatchPlaceholder(frame, type) {
|
|
314
464
|
drawPlaceholder(this.surface, frame.tokens, `\u201C${type}\u201D renderer not yet registered`);
|
|
315
465
|
if (frame.anim.enabled) this.entrance = runFadeEntrance(this.surface, frame.anim, () => this.finishEntrance());
|
|
@@ -330,26 +480,24 @@ class ChartRuntime {
|
|
|
330
480
|
};
|
|
331
481
|
}
|
|
332
482
|
startCustomEntrance(frame, prepared, renderer, ctx) {
|
|
333
|
-
|
|
483
|
+
const key = COUNT_UP_TYPES.has(prepared.type) ? "valueProgress" : SWEEP_TYPES.has(prepared.type) ? "sweepProgress" : chartDefinition(prepared.type).entrance === "grow" ? "entranceProgress" : null;
|
|
484
|
+
if (!key) {
|
|
334
485
|
this.entrance = runFadeEntrance(this.surface, frame.anim, () => this.finishEntrance());
|
|
335
486
|
return;
|
|
336
487
|
}
|
|
337
|
-
const key = COUNT_UP_TYPES.has(prepared.type) ? "valueProgress" : "sweepProgress";
|
|
338
488
|
this.entrance = runCustomRendererProgress(this.surface, renderer, prepared.effectiveSpec, frame.tokens, frame.size, {
|
|
339
489
|
anim: frame.anim,
|
|
340
490
|
onDone: () => this.finishEntrance(),
|
|
341
491
|
dataLength: prepared.filtered.length,
|
|
342
492
|
background: this.currentSpec.background,
|
|
343
493
|
context: ctx,
|
|
344
|
-
progressKey: key
|
|
494
|
+
progressKey: key,
|
|
495
|
+
entranceChrome: true
|
|
345
496
|
});
|
|
346
497
|
}
|
|
347
498
|
startValueTween(frame, prepared, renderer, ctx, valueFrom, compareFrom, sparklineFrom) {
|
|
348
499
|
if (valueFrom === void 0 && sparklineFrom === void 0 || !COUNT_UP_TYPES.has(prepared.type) && !SWEEP_TYPES.has(prepared.type)) return;
|
|
349
|
-
const tween =
|
|
350
|
-
reducedMotion: prefersReducedMotion(),
|
|
351
|
-
disabled: this.options.synchronous === true || globalThis.__GRAPHEIN_DISABLE_ANIM === true
|
|
352
|
-
});
|
|
500
|
+
const tween = this.updateMotion(this.currentSpec);
|
|
353
501
|
if (!tween.enabled) return;
|
|
354
502
|
const key = COUNT_UP_TYPES.has(prepared.type) ? "valueProgress" : "sweepProgress";
|
|
355
503
|
this.entrance = runCustomRendererProgress(this.surface, renderer, prepared.effectiveSpec, frame.tokens, frame.size, {
|
|
@@ -403,6 +551,7 @@ class ChartRuntime {
|
|
|
403
551
|
finishEntrance() {
|
|
404
552
|
if (this.refreshReport) this.lastReport = this.refreshReport();
|
|
405
553
|
signalReady(this.surface);
|
|
554
|
+
this.interaction?.refresh();
|
|
406
555
|
if (this.pendingFontRefresh && !this.destroyed) {
|
|
407
556
|
this.pendingFontRefresh = false;
|
|
408
557
|
this.draw(false);
|
|
@@ -467,6 +616,9 @@ class ChartRuntime {
|
|
|
467
616
|
this.invalidateTransforms();
|
|
468
617
|
this.seedParams(next);
|
|
469
618
|
const prevType = this.currentSpec.type;
|
|
619
|
+
const morphFrom = this.morphSource(this.currentSpec, next);
|
|
620
|
+
const sliceFrom = this.sliceMorphSource(this.currentSpec, next);
|
|
621
|
+
const customFrom = this.customMorphSource(this.currentSpec, next);
|
|
470
622
|
const before = this.updateSnapshot(prevType, next);
|
|
471
623
|
const prevW = this.surface.width;
|
|
472
624
|
const prevH = this.surface.height;
|
|
@@ -474,29 +626,32 @@ class ChartRuntime {
|
|
|
474
626
|
this.currentSpec = next;
|
|
475
627
|
const wantValue = prevType === next.type && (COUNT_UP_TYPES.has(next.type) || SWEEP_TYPES.has(next.type)) && prev.value != null;
|
|
476
628
|
const wantSparkline = prevType === next.type && next.type === "kpi" && !!prev.sparkline?.length;
|
|
477
|
-
this.
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
629
|
+
this.pendingMorph = morphFrom;
|
|
630
|
+
this.pendingSliceMorph = sliceFrom;
|
|
631
|
+
this.pendingCustomMorph = customFrom;
|
|
632
|
+
this.pendingChrome = captureChrome(this.surface);
|
|
633
|
+
try {
|
|
634
|
+
this.draw(
|
|
635
|
+
false,
|
|
636
|
+
wantValue ? prev.value ?? void 0 : void 0,
|
|
637
|
+
wantValue ? prev.compare ?? void 0 : void 0,
|
|
638
|
+
wantValue || wantSparkline ? prev.sparkline ?? void 0 : void 0
|
|
639
|
+
);
|
|
640
|
+
} finally {
|
|
641
|
+
this.pendingMorph = void 0;
|
|
642
|
+
this.pendingSliceMorph = void 0;
|
|
643
|
+
this.pendingCustomMorph = void 0;
|
|
644
|
+
this.pendingChrome = void 0;
|
|
645
|
+
}
|
|
646
|
+
if (!this.morphState && !this.entrance) this.startUpdateCrossfade(before, prevW, prevH, next);
|
|
484
647
|
}
|
|
485
648
|
updateSnapshot(prevType, next) {
|
|
486
|
-
const
|
|
487
|
-
reducedMotion: prefersReducedMotion(),
|
|
488
|
-
disabled: this.options.synchronous === true || globalThis.__GRAPHEIN_DISABLE_ANIM === true
|
|
489
|
-
});
|
|
490
|
-
const wantFade = anim.enabled && CANVAS_MARK_TYPES.has(prevType) && CANVAS_MARK_TYPES.has(next.type);
|
|
649
|
+
const wantFade = this.updateMotion(next).enabled && CANVAS_MARK_TYPES.has(prevType) && CANVAS_MARK_TYPES.has(next.type);
|
|
491
650
|
return wantFade ? snapshotLayer(this.surface.marks) : void 0;
|
|
492
651
|
}
|
|
493
652
|
startUpdateCrossfade(before, prevW, prevH, next) {
|
|
494
653
|
if (!before || this.surface.width !== prevW || this.surface.height !== prevH || this.surface.marks.canvas.width !== before.width || this.surface.marks.canvas.height !== before.height) return;
|
|
495
|
-
|
|
496
|
-
reducedMotion: prefersReducedMotion(),
|
|
497
|
-
disabled: this.options.synchronous === true || globalThis.__GRAPHEIN_DISABLE_ANIM === true
|
|
498
|
-
});
|
|
499
|
-
this.updateTransition = runUpdateCrossfade(this.surface, before, anim);
|
|
654
|
+
this.updateTransition = runUpdateCrossfade(this.surface, before, this.updateMotion(next));
|
|
500
655
|
}
|
|
501
656
|
resize() {
|
|
502
657
|
if (!this.destroyed) this.draw(false);
|
|
@@ -556,7 +711,18 @@ class ChartRuntime {
|
|
|
556
711
|
if (!this.pendingSelectionRedraw || this.destroyed) return;
|
|
557
712
|
this.pendingSelectionRedraw = false;
|
|
558
713
|
this.selectionRedrawQueued = false;
|
|
559
|
-
this.
|
|
714
|
+
this.pendingMorph = this.morphSource(this.currentSpec, this.currentSpec);
|
|
715
|
+
this.pendingSliceMorph = this.sliceMorphSource(this.currentSpec, this.currentSpec);
|
|
716
|
+
this.pendingCustomMorph = this.customMorphSource(this.currentSpec, this.currentSpec);
|
|
717
|
+
this.pendingChrome = captureChrome(this.surface);
|
|
718
|
+
try {
|
|
719
|
+
this.draw(false);
|
|
720
|
+
} finally {
|
|
721
|
+
this.pendingMorph = void 0;
|
|
722
|
+
this.pendingSliceMorph = void 0;
|
|
723
|
+
this.pendingCustomMorph = void 0;
|
|
724
|
+
this.pendingChrome = void 0;
|
|
725
|
+
}
|
|
560
726
|
}
|
|
561
727
|
applyExternalEdit(config) {
|
|
562
728
|
if (this.destroyed) return;
|