@motionscript/charts 0.0.0-stage → 0.1.0-alpha.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/CHANGELOG.md +5 -0
- package/LICENSE +201 -0
- package/dist/bar-chart/bar-chart.d.ts +286 -0
- package/dist/bar-chart/bar-chart.d.ts.map +1 -0
- package/dist/bar-chart/bar-chart.js +610 -0
- package/dist/bar-chart/bar-chart.js.map +1 -0
- package/dist/bar-chart/category-axis.d.ts +77 -0
- package/dist/bar-chart/category-axis.d.ts.map +1 -0
- package/dist/bar-chart/category-axis.js +141 -0
- package/dist/bar-chart/category-axis.js.map +1 -0
- package/dist/bar-chart/chart-bars.d.ts +149 -0
- package/dist/bar-chart/chart-bars.d.ts.map +1 -0
- package/dist/bar-chart/chart-bars.js +236 -0
- package/dist/bar-chart/chart-bars.js.map +1 -0
- package/dist/bar-chart/index.d.ts +16 -0
- package/dist/bar-chart/index.d.ts.map +1 -0
- package/dist/bar-chart/index.js +12 -0
- package/dist/bar-chart/index.js.map +1 -0
- package/dist/bar-chart/shared.d.ts +146 -0
- package/dist/bar-chart/shared.d.ts.map +1 -0
- package/dist/bar-chart/shared.js +182 -0
- package/dist/bar-chart/shared.js.map +1 -0
- package/dist/browser/chunks/chunk-ZMBOBHYL.js +2 -0
- package/dist/browser/chunks/chunk-ZMBOBHYL.js.map +7 -0
- package/dist/browser/index.js +2 -0
- package/dist/browser/index.js.map +7 -0
- package/dist/browser/kit.js +2 -0
- package/dist/browser/kit.js.map +7 -0
- package/dist/browser/manifest.json +12 -0
- package/dist/engine.d.ts +27 -0
- package/dist/engine.d.ts.map +1 -0
- package/dist/engine.js +27 -0
- package/dist/engine.js.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -0
- package/dist/kit/chart-border.d.ts +28 -0
- package/dist/kit/chart-border.d.ts.map +1 -0
- package/dist/kit/chart-border.js +45 -0
- package/dist/kit/chart-border.js.map +1 -0
- package/dist/kit/chart-canvas.d.ts +56 -0
- package/dist/kit/chart-canvas.d.ts.map +1 -0
- package/dist/kit/chart-canvas.js +125 -0
- package/dist/kit/chart-canvas.js.map +1 -0
- package/dist/kit/chart-legend.d.ts +126 -0
- package/dist/kit/chart-legend.d.ts.map +1 -0
- package/dist/kit/chart-legend.js +212 -0
- package/dist/kit/chart-legend.js.map +1 -0
- package/dist/kit/shared.d.ts +251 -0
- package/dist/kit/shared.d.ts.map +1 -0
- package/dist/kit/shared.js +401 -0
- package/dist/kit/shared.js.map +1 -0
- package/dist/kit/vertical-axis.d.ts +99 -0
- package/dist/kit/vertical-axis.d.ts.map +1 -0
- package/dist/kit/vertical-axis.js +176 -0
- package/dist/kit/vertical-axis.js.map +1 -0
- package/dist/line-chart/chart-line.d.ts +91 -0
- package/dist/line-chart/chart-line.d.ts.map +1 -0
- package/dist/line-chart/chart-line.js +156 -0
- package/dist/line-chart/chart-line.js.map +1 -0
- package/dist/line-chart/chart-region.d.ts +47 -0
- package/dist/line-chart/chart-region.d.ts.map +1 -0
- package/dist/line-chart/chart-region.js +101 -0
- package/dist/line-chart/chart-region.js.map +1 -0
- package/dist/line-chart/horizontal-axis.d.ts +85 -0
- package/dist/line-chart/horizontal-axis.d.ts.map +1 -0
- package/dist/line-chart/horizontal-axis.js +158 -0
- package/dist/line-chart/horizontal-axis.js.map +1 -0
- package/dist/line-chart/index.d.ts +22 -0
- package/dist/line-chart/index.d.ts.map +1 -0
- package/dist/line-chart/index.js +19 -0
- package/dist/line-chart/index.js.map +1 -0
- package/dist/line-chart/line-chart.d.ts +347 -0
- package/dist/line-chart/line-chart.d.ts.map +1 -0
- package/dist/line-chart/line-chart.js +701 -0
- package/dist/line-chart/line-chart.js.map +1 -0
- package/dist/line-chart/shared.d.ts +171 -0
- package/dist/line-chart/shared.d.ts.map +1 -0
- package/dist/line-chart/shared.js +270 -0
- package/dist/line-chart/shared.js.map +1 -0
- package/dist/line-chart/x-scale.d.ts +84 -0
- package/dist/line-chart/x-scale.d.ts.map +1 -0
- package/dist/line-chart/x-scale.js +302 -0
- package/dist/line-chart/x-scale.js.map +1 -0
- package/dist/nodes.d.ts +20 -0
- package/dist/nodes.d.ts.map +1 -0
- package/dist/nodes.js +20 -0
- package/dist/nodes.js.map +1 -0
- package/dist/pie-chart/index.d.ts +18 -0
- package/dist/pie-chart/index.d.ts.map +1 -0
- package/dist/pie-chart/index.js +14 -0
- package/dist/pie-chart/index.js.map +1 -0
- package/dist/pie-chart/pie-chart.d.ts +170 -0
- package/dist/pie-chart/pie-chart.d.ts.map +1 -0
- package/dist/pie-chart/pie-chart.js +291 -0
- package/dist/pie-chart/pie-chart.js.map +1 -0
- package/dist/pie-chart/pie-legend.d.ts +60 -0
- package/dist/pie-chart/pie-legend.d.ts.map +1 -0
- package/dist/pie-chart/pie-legend.js +131 -0
- package/dist/pie-chart/pie-legend.js.map +1 -0
- package/dist/pie-chart/pie-ring.d.ts +266 -0
- package/dist/pie-chart/pie-ring.d.ts.map +1 -0
- package/dist/pie-chart/pie-ring.js +708 -0
- package/dist/pie-chart/pie-ring.js.map +1 -0
- package/dist/pie-chart/shared.d.ts +210 -0
- package/dist/pie-chart/shared.d.ts.map +1 -0
- package/dist/pie-chart/shared.js +240 -0
- package/dist/pie-chart/shared.js.map +1 -0
- package/package.json +69 -3
- package/registry.json +23 -0
- package/src/bar-chart/bar-chart.ts +804 -0
- package/src/bar-chart/category-axis.ts +177 -0
- package/src/bar-chart/chart-bars.ts +310 -0
- package/src/bar-chart/index.ts +31 -0
- package/src/bar-chart/shared.ts +354 -0
- package/src/engine.ts +26 -0
- package/src/index.ts +5 -0
- package/src/kit/chart-border.ts +61 -0
- package/src/kit/chart-canvas.ts +157 -0
- package/src/kit/chart-legend.ts +250 -0
- package/src/kit/shared.ts +675 -0
- package/src/kit/vertical-axis.ts +224 -0
- package/src/line-chart/chart-line.ts +208 -0
- package/src/line-chart/chart-region.ts +135 -0
- package/src/line-chart/horizontal-axis.ts +202 -0
- package/src/line-chart/index.ts +39 -0
- package/src/line-chart/line-chart.ts +894 -0
- package/src/line-chart/shared.ts +459 -0
- package/src/line-chart/x-scale.ts +367 -0
- package/src/nodes.ts +20 -0
- package/src/pie-chart/index.ts +37 -0
- package/src/pie-chart/pie-chart.ts +374 -0
- package/src/pie-chart/pie-legend.ts +159 -0
- package/src/pie-chart/pie-ring.ts +903 -0
- package/src/pie-chart/shared.ts +490 -0
- package/README.md +0 -4
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"line-chart.js","sourceRoot":"","sources":["../../src/line-chart/line-chart.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n command,\n node,\n Node2D,\n Rect,\n easeOut,\n property,\n type Command,\n type CommandArgs,\n type DataRecord,\n type NodeConfig,\n type Node2DProps,\n type Vector2,\n} from \"@motionscript/core\"\n\nimport { ChartBorder } from \"../kit/chart-border\"\nimport { ChartCanvas } from \"../kit/chart-canvas\"\nimport { ChartLegend } from \"../kit/chart-legend\"\nimport { VerticalAxis } from \"../kit/vertical-axis\"\nimport {\n SPOTLIGHT_DIM,\n formatMarker,\n lerpAxisDomain,\n markerValues,\n resolveAxisDomain,\n resolveSeriesFill,\n resolveSeriesStroke,\n type AxisDomainConfig,\n type Range,\n} from \"../kit/shared\"\nimport { formatNumber } from \"@motionscript/core/component\"\nimport { ChartLine } from \"./chart-line\"\nimport { ChartRegion } from \"./chart-region\"\nimport { HorizontalAxis } from \"./horizontal-axis\"\nimport {\n DEFAULT_CHART_THEME,\n lerpChartTheme,\n resolveChartTheme,\n resolveRegionBox,\n resolveYScale,\n seriesPoints,\n type ChartConfig,\n type ChartTheme,\n type LineSeries,\n type PlotRegion,\n type RegionBox,\n} from \"./shared\"\nimport { resolveXScale, type XScale } from \"./x-scale\"\nimport { hold, sequence as sequenceOf, together, type Seekable } from \"@motionscript/core/component\"\n\nexport interface LineChartProps extends Node2DProps {\n /** One row per sample — a plain record of field name to value. */\n data: DataRecord[]\n /**\n * Key into each row for its x value, shared by every series. Named `xField`\n * rather than `x` because every node already has an `x` — its position.\n */\n xField: string\n /** One polyline per entry: which field it plots, its legend `label`, its `fill`. */\n series: LineSeries[]\n /** X-axis data domain: caption, scale range, and tick placement. */\n xAxis?: AxisDomainConfig\n /** Y-axis data domain: caption, scale range, and tick placement. */\n yAxis?: AxisDomainConfig\n /**\n * A slice of the plot to spotlight, in **data units**. Dashed rules mark the\n * bounded edges and every series fades outside the box — see\n * {@link LineChart.spotlightRegion}, which animates the same thing. `null`\n * (the default) is no region.\n */\n region?: PlotRegion | null\n /**\n * The chart's visual theme — series palette, axis text/grid/gutters, plot\n * panel paint, and legend styling. Every branch is optional and deep-merged\n * onto {@link DEFAULT_CHART_THEME}, so pass only what you want to override.\n */\n theme?: ChartTheme\n /** Whether the legend row below the plot is drawn at all. */\n showLegend?: boolean\n}\n\n/**\n * Headroom above the plot, in px.\n *\n * Two jobs, and the second is why it is real padding on the composition rather\n * than a number the point-mapping math imagines: a series peaking at `yMax`\n * isn't flush to the top edge, **and** the top y-marker — which is centred on\n * that top grid line — has somewhere to be. Without it the marker's upper half\n * is drawn above the chart's own box, outside the rectangle the editor draws\n * around the node.\n */\nconst TOP_HEADROOM = 24\n\n/**\n * The argument every per-series command takes: an index into `series`. Its own\n * kind rather than `number` so a host can offer the series by name.\n */\nconst SERIES_ARG = { key: \"seriesIndex\", kind: \"series\", default: 0, min: 0, step: 1 }\n\n/** How far the legend starts below its slot when it enters, in px. */\nconst LEGEND_SLIDE = 20\n\n/**\n * The two signals the region call-out is made of, as a props type for the\n * commands that move them.\n *\n * Written out rather than reusing `LineChartProps` because the pair is what\n * those commands actually touch, and because `regionReveal` is a signal of the\n * chart's own rather than part of its authored props.\n */\ntype RegionState = { region: PlotRegion | null; regionReveal: number }\n\n/**\n * How {@link LineChart.enter} divides its duration between its three beats: the\n * axes arriving, the lines tracing, and the legend coming up. Shares of the\n * whole, so they must sum to 1 — the entrance takes exactly the time it was\n * given (see the note on `enter`).\n */\nconst AXES_SHARE = 0.35\nconst LINES_SHARE = 0.5\nconst LEGEND_SHARE = 0.15\n\n/**\n * A multi-series line chart, composed from five independent parts rather than\n * one monolithic draw:\n *\n * - {@link ChartCanvas} — the plot panel with a two-way grid, under everything.\n * - {@link VerticalAxis} / {@link HorizontalAxis} — columns/rows of real text\n * markers that stagger in, each carrying its own axis caption.\n * - {@link ChartRegion} — the optional call-out marking a spotlit slice of the\n * plot: dashed rules on its bounded edges, and every series faded outside it.\n * - {@link ChartLine} (one per series) — the traced polylines over the canvas.\n * - {@link ChartLegend} — a row of entries below the chart, one per series.\n *\n * The parts are laid out from this node's `layoutBounds`: a left gutter for the\n * vertical axis, a bottom gutter for the horizontal axis, the plot filling\n * what's left, and the legend row beneath the whole chart. Every child's\n * position/size is bound reactively, so the chart re-flows if its box changes,\n * and the series lines read the same resolved scales as the axes, so points land\n * exactly on their markers.\n *\n * **Resting state is the finished chart.** Unlike the standalone component this\n * was ported from, nothing is built hidden: the studio paints a node's Initial\n * state on a paused canvas, and a chart that only appeared once a command had\n * run would be edited blind. {@link enter} arms every part back to its\n * pre-entrance state before animating, so the entrance itself is unchanged.\n *\n * Past the entrance, three things move the chart around:\n * {@link showSeries}/{@link hideSeries}/{@link spotlightSeries} pick out a\n * *series*, {@link spotlightRegion} marks a *slice of the plot* without changing\n * the scale, and {@link zoomTo} rescales the axes so a slice fills the plot. The\n * last two take the same {@link PlotRegion} and compose — a spotlit region\n * resolves against the live scales, so it travels with a zoom.\n */\n@node({\n key: \"lineChart\",\n parentKey: \"node\",\n forkable: true,\n layout: {\n children: \"freeform\",\n defaultWidthMode: \"fixed\",\n defaultHeightMode: \"fixed\",\n acceptsChildren: true,\n },\n seed: {\n width: 760,\n height: 460,\n },\n})\nexport class LineChart extends Node2D<LineChartProps> {\n @property({ default: () => [] as DataRecord[], kind: \"dataset\" }) declare data: DataRecord[]\n @property({ default: \"\" }) declare xField: string\n @property({ default: () => [] as LineSeries[], kind: \"series\" }) declare series: LineSeries[]\n /**\n * X/Y-axis data domain (label/range/ticks), tweenable and mappable like\n * `theme`: the mapper merges a partial input onto the previous resolved\n * domain (leaving `range`/`ticks` `undefined` — the auto-derive signal — on\n * first resolution), and the tween interpolates them numerically, so\n * `chart.to({ yAxis: { range: [0, 10] } }, 1)` smoothly rescales the plotted\n * lines. Like `theme`, the axis *label* text is captured once at construction.\n */\n @property({\n default: {},\n mapper: resolveAxisDomain,\n tween: lerpAxisDomain,\n })\n declare xAxis: AxisDomainConfig\n @property({\n default: {},\n mapper: resolveAxisDomain,\n tween: lerpAxisDomain,\n })\n declare yAxis: AxisDomainConfig\n /**\n * The chart's visual theme, tweenable and mappable like a `stroke`/`fill`\n * prop: the mapper merges the author's partial input onto the previous\n * resolved theme (or {@link DEFAULT_CHART_THEME} the first time) and resolves\n * every leaf; the tween interpolates two resolved themes leaf-by-leaf, so\n * `chart.to({ theme: next }, 1)` animates smoothly.\n */\n @property({\n default: DEFAULT_CHART_THEME,\n mapper: resolveChartTheme,\n tween: lerpChartTheme,\n })\n declare theme: ChartTheme\n /**\n * The spotlit slice of the plot in data units, or `null` for none. Held as a\n * plain reactive value rather than a tweened one: the box itself snaps, and\n * the *animation* is {@link regionReveal} drawing the rules on and the lines\n * dimming outside it.\n */\n @property({ default: null }) declare region: PlotRegion | null\n /**\n * How far the {@link region} call-out is drawn in, `[0, 1]` — the single\n * signal behind both halves of the effect: the rules grow out and the wash\n * fades up as it climbs, while every line's out-of-region stretch fades from\n * full down to the theme's `region.dimOpacity`. At 0 a chart with a `region`\n * set looks exactly like one without.\n */\n @property({ default: 0 }) declare regionReveal: number\n /**\n * Read once, in the constructor, like `series`: the legend is a part the\n * chart builds or doesn't, so a change reaches it by rebuilding the node.\n */\n @property({ default: true, animatable: false }) declare showLegend: boolean\n\n // ---- Part handles (built in the constructor) --------------------------\n private vAxis: VerticalAxis\n private hAxis: HorizontalAxis\n /** The plot panel — the box the grid, the lines and the region all share. */\n private plotRect: Rect\n private legend: ChartLegend | null = null\n private lines: ChartLine[] = []\n\n /**\n * `this.theme` read back through its *resolved* shape: the property's declared\n * type is the loose author-facing {@link ChartTheme} (so a partial theme is\n * accepted), but the mapper always stores the fully-resolved\n * {@link ChartConfig} at runtime — the same loose-declared/resolved-stored\n * idiom as a shape's `fill`/`stroke`.\n */\n private get resolvedTheme(): ChartConfig {\n return this.theme as unknown as ChartConfig\n }\n\n // ---- Derived scales ---------------------------------------------------\n\n /** Fallback marker count when neither axis's ticks are given. */\n private static readonly DEFAULT_MARKERS = 5\n\n /**\n * What the x column *is* — a number, an instant, or a place in the file — and\n * with it how each row is positioned, ticked and captioned. See `x-scale.ts`.\n */\n private get xColumn(): XScale {\n return resolveXScale(this.data, this.xField, this.xAxis.format)\n }\n\n private get xScale(): Range {\n return this.xAxis.range ?? this.xColumn.extent\n }\n\n private get yScale(): Range {\n // Auto-ranging steps into one fewer segment than the intended marker count\n // — the explicit ticks' count when given, else the default — so the tidy\n // bounds still frame the ticks the axis draws.\n const divisions =\n (this.yAxis.ticks?.length ?? LineChart.DEFAULT_MARKERS) - 1\n return resolveYScale(this.data, this.series, this.yAxis.range, divisions)\n }\n\n /** The vertical axis ticks: the explicit ones, else five across the scale. */\n private get resolvedYMarkers(): number[] {\n return (\n this.yAxis.ticks ??\n markerValues(this.yScale, LineChart.DEFAULT_MARKERS - 1)\n )\n }\n\n /**\n * The horizontal axis ticks: the explicit ones, else five across the scale.\n *\n * Asked of the column rather than spaced evenly, because only a numeric column\n * has round numbers between its samples. On a month column, five evenly spaced\n * values land two-thirds of the way through four different months; the ticks\n * a reader wants are Jan/Apr/Jul/Oct/Dec, which are rows.\n */\n private get resolvedXMarkers(): number[] {\n return (\n this.xAxis.ticks ??\n this.xColumn.ticks(this.xScale, LineChart.DEFAULT_MARKERS - 1)\n )\n }\n\n // ---- Plot geometry ------------------------------------------------------\n\n /**\n * The plot panel's size, **as laid out**.\n *\n * This used to be computed: six constants estimating what the axis gutters and\n * the legend row would take, subtracted from the node's box. The estimate was\n * never the layout — the vertical axis is `width: \"hug\"`, so its real width is\n * whatever its widest marker needs — and everything downstream inherited the\n * gap. The grid is drawn by {@link ChartCanvas} across its *own* allocation,\n * while the lines were mapped across the estimate, so a series sat a few\n * percent off the grid line it was supposed to touch, silently and by an\n * amount that changed with the theme.\n *\n * Asking the panel is exact by construction and cannot drift: the lines, the\n * region rules and the grid all resolve against one box, and it is the box\n * they are drawn in. Zero until the first layout pass, like any other\n * `layoutBounds` read — the bindings that call this re-run on the next frame.\n */\n private plotSize(): { width: number; height: number } {\n const { width, height } = this.plotRect.layoutBounds\n return { width, height }\n }\n\n /**\n * Map one series' data points into the plot's **centred** pixel space (origin\n * at the plot centre, y-up) — the local frame of the clip/line box that fills\n * the plot. x runs `[-w/2, +w/2]`, y runs `[-h/2, +h/2]`.\n */\n private seriesPixels(index: number): Vector2[] {\n const s = this.series[index]\n if (!s) return []\n const points = seriesPoints(this.data, this.xColumn, s)\n if (points.length === 0) return []\n const { width: w, height: h } = this.plotSize()\n const [xMin, xMax] = this.xScale\n const [yMin, yMax] = this.yScale\n // Plot centre is the origin; map the data fraction to [-half, +half].\n const xToPx = (x: number) =>\n xMax <= xMin ? 0 : ((x - xMin) / (xMax - xMin) - 0.5) * w\n const yToPx = (y: number) =>\n yMax <= yMin ? 0 : ((y - yMin) / (yMax - yMin) - 0.5) * h\n // `seriesPoints` already sorted them along x.\n return points.map(([x, y]) => ({ x: xToPx(x), y: yToPx(y) }))\n }\n\n /**\n * {@link region} mapped into the plot's **centred** pixel space — the same\n * frame {@link seriesPixels} returns, so the region's rules and each line's\n * clip resolve against one box from one place. Reads the live scales, so it\n * re-maps when `xAxis`/`yAxis` tween.\n */\n /**\n * Whether a call-out is authored at all — the question {@link enter} and\n * {@link spotlightRegion} branch on.\n *\n * Deliberately **not** `hasRegion(this.regionBox())`, which they used to ask.\n * That resolves the region into pixels, so it answers \"and has the chart been\n * laid out yet\" as well, and comes back false for a perfectly real region on a\n * chart that has not been measured. A generator never noticed, because it only\n * ever ran mid-playback; a command is *built* before the first layout pass, and\n * would have quietly dropped the region beat every time.\n *\n * What is left once the pixels are taken out is the same test\n * {@link resolveRegionBox} applies before it maps anything: a region bounding\n * *neither* axis is not a call-out, so `{}` counts as none exactly as `null`\n * does.\n */\n private hasCallout(): boolean {\n const region = this.region\n return region != null && (region.x !== undefined || region.y !== undefined)\n }\n\n private regionBox(): RegionBox {\n const { width: w, height: h } = this.plotSize()\n // The region lives in the plot's own centred frame, the same one\n // seriesPixels maps its points into.\n return resolveRegionBox(\n this.region,\n { left: -w / 2, right: w / 2, bottom: -h / 2, top: h / 2 },\n this.xScale,\n this.yScale\n )\n }\n\n // ---- Build ------------------------------------------------------------\n\n constructor(props?: NodeConfig<LineChart, LineChartProps>) {\n super(props)\n\n // The whole chart is composed from plain props/`data` — no context needed,\n // so the parts are built here (super() applied the props above).\n //\n // Every theme/axis-derived prop below that a *leaf* drawing part reads live\n // in `renderSelf` every frame — the canvas's fill/grid/extent, the border's\n // stroke, each line's stroke/points — is passed as a closure, not a one-time\n // snapshot, so `chart.to({ theme })` and `chart.to({ yAxis: { range } })`\n // genuinely animate the panel, grid, border, and plotted lines. The two axes\n // compose their child text nodes *once* (the marker count is fixed at\n // construction) but bind each marker's caption and position to the live\n // range/ticks, so a rescale re-labels and re-places the row as it tweens.\n const enabled = this.series.map((s) => s.enabled ?? true)\n const showLegend = this.showLegend !== false\n\n this.vAxis = new VerticalAxis({\n // Bound, not snapshotted — this is the half of a rescale the axis owns.\n // The marker *count* is still read once (it fixes how many text nodes get\n // built), which is why `zoomTo` keeps the count constant.\n range: () => this.yScale,\n markers: () => this.resolvedYMarkers,\n axis: () => this.resolvedTheme.yAxis,\n label: this.yAxis.label ?? \"\",\n width: \"hug\",\n height: \"fill\",\n })\n // The y axis is always numbers, so its format is simply the pattern.\n this.vAxis.labelFor = (value) =>\n this.yAxis.format === undefined\n ? formatMarker(value)\n : formatNumber(value, this.yAxis.format)\n\n this.hAxis = new HorizontalAxis({\n range: () => this.xScale,\n markers: () => this.resolvedXMarkers,\n axis: () => this.resolvedTheme.xAxis,\n label: this.xAxis.label ?? \"\",\n width: \"fill\",\n height: \"hug\",\n })\n // A tick on a month or category column is captioned with the cell it came\n // out of — `Jan`, not the instant it parsed to. Assigned rather than passed:\n // see the note on the field.\n this.hAxis.labelFor = (value) => this.xColumn.label(value)\n\n this.lines = this.series.map(\n (s, i) =>\n new ChartLine({\n points: () => this.seriesPixels(i),\n stroke: () => resolveSeriesStroke(this.resolvedTheme.seriesStyles, s, i),\n enabled: enabled[i],\n // Each line clips itself against the same box the rules are drawn\n // from, so the dim/bright boundary can't drift from the dashes.\n spotlight: () => this.regionBox(),\n // Ramped by the same reveal that draws the rules, so at reveal 0 the\n // line is uniform and the region invisible — one signal, both halves.\n dimOpacity: () =>\n 1 - (1 - this.resolvedTheme.region.dimOpacity) * this.regionReveal,\n })\n )\n\n if (showLegend) {\n this.legend = new ChartLegend({\n series: this.series,\n // The kit's legend paints a swatch, not a line, so the chart hands it\n // the *colour* each stroke resolves to rather than the stroke itself —\n // which is also what lets a bar chart's fill palette drive the same row.\n swatches: () =>\n this.series.map((s, i) =>\n resolveSeriesFill(this.resolvedTheme.seriesStyles, s, i)\n ),\n legend: () => this.resolvedTheme.legend,\n })\n }\n\n this.plotRect = new Rect({\n clip: true,\n children: [\n new ChartCanvas({\n fill: () => this.resolvedTheme.plotArea.fill,\n shadow: () => this.resolvedTheme.plotArea.shadow,\n xGridStroke: () => this.resolvedTheme.xAxis.lineStyle,\n yGridStroke: () => this.resolvedTheme.yAxis.lineStyle,\n // A grid line under every axis marker; the canvas maps the marker\n // values through the extents and skips the edges.\n xMarkers: () => this.resolvedXMarkers,\n yMarkers: () => this.resolvedYMarkers,\n xExtent: () => this.xScale,\n yExtent: () => this.yScale,\n }),\n // Region wash + dashed rules: over the grid, under the lines, so a\n // spotlit stretch of a series isn't tinted by the highlight meant to\n // pick it out.\n new ChartRegion({\n box: () => this.regionBox(),\n stroke: () => this.resolvedTheme.region.stroke,\n fill: () => this.resolvedTheme.region.fill,\n reveal: () => this.regionReveal,\n }),\n ...this.lines,\n new ChartBorder({\n stroke: () => this.resolvedTheme.plotArea.stroke,\n }),\n ],\n })\n\n // Invisible twin of the vertical axis, reserving the same left gutter under\n // the plot so the horizontal axis starts at the plot's left edge rather than\n // the chart's.\n const gutterSpacer = new VerticalAxis({\n opacity: 0,\n range: () => this.yScale,\n markers: () => this.resolvedYMarkers,\n axis: () => this.resolvedTheme.yAxis,\n label: this.yAxis.label ?? \"\",\n width: \"hug\",\n height: 0,\n })\n\n const below: Node2D[] = [this.hAxis]\n if (this.legend) below.push(this.legend)\n\n this.add(\n new Rect({ flow: \"vertical\",\n width: \"fill\",\n height: \"fill\",\n // See {@link TOP_HEADROOM}: the plot's top grid line is the one place a\n // marker would otherwise be drawn outside the chart's own box.\n padding: { top: TOP_HEADROOM },\n children: [\n new Rect({ flow: \"horizontal\",\n height: \"fill\",\n width: \"fill\",\n children: [this.vAxis, this.plotRect],\n }),\n new Rect({ flow: \"horizontal\",\n width: \"fill\",\n children: [\n gutterSpacer,\n new Rect({ flow: \"vertical\", width: \"fill\", gap: 20, children: below }),\n ],\n }),\n ],\n })\n )\n }\n\n // ---- Orchestrated entrance --------------------------------------------\n\n /**\n * Prime every part at its pre-entrance state — axis markers shifted and\n * transparent, lines untraced, legend dropped and transparent.\n *\n * Called by {@link enter} before its first frame so nothing flashes ahead of\n * its beat. Idempotent, and public so a scene can hide a chart ahead of time\n * without starting the entrance.\n */\n arm(): void {\n this.vAxis.arm()\n this.hAxis.arm()\n for (const line of this.lines) line.set({ progress: 0 })\n this.legend?.set({ opacity: 0, y: -LEGEND_SLIDE })\n }\n\n /**\n * Animate the whole chart in: the two axes stagger their markers in (vertical\n * bottom-to-top, horizontal left-to-right), the series lines trace\n * left-to-right, and the legend fades up last.\n *\n * `duration` is the **whole** entrance. The phases below are shares of it, not\n * multiples — a command that declares 1.4 seconds has to take 1.4 seconds,\n * because that is the slot the timeline lays out for it, the length its\n * parallel siblings are timed against, and its contribution to the scene's own\n * duration. (The component this was ported from scaled every phase *off* the\n * line trace and let the total fall where it may, which came out around 3×.)\n *\n * A chart authored with a `region` lands its call-out last, over lines that\n * have already traced — the same order a scene would get by calling\n * {@link spotlightRegion} right after this — and that beat comes out of the\n * same budget.\n */\n @command()\n enter(\n args: CommandArgs<Record<string, never>> & { duration: number }\n ): Seekable {\n const duration = args.duration\n const easing = args.easing ?? easeOut()\n this.arm()\n\n const revealing = this.hasCallout() && this.regionReveal === 0\n // The region call-out, when there is one, takes the last quarter.\n const body = revealing ? duration * 0.75 : duration\n\n // The same three phases, in the same order and with the same shares — placed\n // at their offsets rather than sequenced by a generator, so the whole\n // entrance can be asked what it looks like at a time. Each part writes to its\n // own node (the axes, the lines, the legend), which is why these compose as\n // steppers rather than as merged props.\n const axes = together(\n this.vAxis.enter({ data: { slide: 24 }, duration: body * AXES_SHARE, easing }),\n this.hAxis.enter({ data: { slide: 24 }, duration: body * AXES_SHARE, easing })\n )\n const lines = together(\n ...this.lines.map((line) => line.enter({ duration: body * LINES_SHARE, easing }))\n )\n const legend = this.legend\n ? [this.legend.to({ data: { opacity: 1, y: 0 }, duration: body * LEGEND_SHARE, easing })]\n : []\n\n const phases = sequenceOf(axes, lines, ...legend)\n\n return revealing\n ? sequenceOf(\n phases,\n // Typed to what it writes rather than to `LineChartProps`: `regionReveal`\n // is a signal of the chart's own, not part of its authored props.\n this.command<{ regionReveal: number }>(\n (t) => ({ regionReveal: t }),\n duration * 0.25,\n easing\n )\n )\n : phases\n }\n\n // ---- Region spotlight --------------------------------------------------\n\n /**\n * Spotlight a rectangular slice of the plot given in **data units**: dashed\n * rules draw themselves onto each bounded edge while every series fades\n * outside the box and stays full inside it.\n *\n * Either axis alone is a band — `{ x: [80, 100] }` picks out the last fifth\n * across all series, `{ y: [8, 10] }` a value band across the whole width —\n * and both together a box. The unbounded axis spans the plot and draws no\n * rule, since there's no data bound there to mark.\n *\n * Calling it while another region is already up cross-fades: the old call-out\n * retracts, then the new one draws in, each over half `duration`.\n *\n * Both the call-out's shape and its draw-on are plain signals — `region` and\n * {@link regionReveal} — so the whole thing is a function of `t`, including\n * the swap: which region is up is a step at the halfway point rather than an\n * effect that has to have happened.\n */\n @command({\n args: [\n // One argument, two controls: the method takes a `PlotRegion`, so the x\n // and y spans a host draws are declared inside it.\n {\n key: \"region\", kind: \"region\", properties: {\n x: { kind: \"range\", default: true, defaultMin: 0, defaultMax: 100 },\n y: { kind: \"range\", default: false, defaultMin: 0, defaultMax: 100 },\n },\n },\n ],\n })\n spotlightRegion(\n args: CommandArgs<{ region: PlotRegion }> & { duration?: number }\n ): Command<RegionState> {\n const region = LineChart.regionArg(args.data)\n const duration = args.duration ?? 0.5\n const easing = args.easing ?? easeOut()\n const from = this.regionReveal\n const previous = this.region\n\n // A region bounding neither axis is no call-out: spotlighting it is a clear.\n if (region.x === undefined && region.y === undefined) {\n return this.clearRegion({ duration, easing })\n }\n\n // Nothing up yet: the region is set from the first frame and just draws on.\n if (from <= 0 || !this.hasCallout()) {\n return this.command<RegionState>(\n (t) => ({ region, regionReveal: from + (1 - from) * t }),\n duration,\n easing\n )\n }\n\n // Something already up: retract it first so the rules don't jump across the\n // plot mid-draw. Each half eases on its own — which is why the easing is\n // applied here rather than handed to `animate`, whose easing would shape the\n // pair as one curve and leave both halves crawling past the seam.\n return this.command<RegionState>(\n (t) =>\n t < 0.5\n ? { region: previous, regionReveal: from * (1 - easing(t * 2)) }\n : { region, regionReveal: easing(t * 2 - 1) },\n duration\n )\n }\n\n /**\n * Drop the region call-out — the rules retract, the wash fades, and every\n * series comes back to full across its whole length. A no-op when nothing is\n * spotlit.\n */\n @command()\n clearRegion(\n args: CommandArgs<Record<string, never>> & { duration?: number } = {}\n ): Command<RegionState> {\n const duration = args.duration ?? 0.5\n const easing = args.easing ?? easeOut()\n const from = this.regionReveal\n\n if (from === 0) {\n // Nothing to retract, but the call still takes its slot: in the studio a\n // command's duration is what the timeline lays out and what parallel\n // siblings are timed against, so a no-op that took no frames would pull\n // everything after it forward. Same reason for `zoomTo`/`resetZoom` below.\n return this.command<RegionState>(\n () => ({ region: null, regionReveal: 0 }),\n duration\n )\n }\n\n // `region` is left alone until the retraction lands — cleared at `t === 1`\n // rather than up front, or there would be nothing left to retract.\n return this.command<RegionState>(\n (t) => (t >= 1 ? { region: null, regionReveal: 0 } : { regionReveal: from * (1 - t) }),\n duration,\n easing\n )\n }\n\n // ---- Zoom --------------------------------------------------------------\n\n /**\n * The domain to come back to, captured the first time {@link zoomTo} runs so a\n * later {@link resetZoom} restores the chart as authored — including ticks\n * that were auto-derived rather than given, which the props alone don't\n * record. Cleared by {@link resetZoom}, so a second zoom captures wherever the\n * chart genuinely rests then.\n */\n private home: { x: AxisDomainConfig; y: AxisDomainConfig } | null = null\n\n /**\n * The `region` a document handed a command, or `{}`. A command is added\n * before its arguments are filled in, so an unstated region is ordinary input\n * rather than a malformed one.\n */\n private static regionArg(data: { region?: PlotRegion | null } | undefined): PlotRegion {\n const region = data?.region\n return region != null && typeof region === \"object\" ? region : {}\n }\n\n /** A range read as a span, whichever way round the author wrote it. */\n private static span([a, b]: Range): Range {\n return a <= b ? [a, b] : [b, a]\n }\n\n /**\n * Rescale an axis to `range`, keeping the tick *count* it already has — the\n * axis tween interpolates ticks pairwise by index, so a constant count lets\n * each marker slide from its old value to its new one instead of the row\n * popping.\n */\n private static rescale(range: Range, ticks: number[]): AxisDomainConfig {\n const span = LineChart.span(range)\n const count = Math.max(2, ticks.length)\n return { range: span, ticks: markerValues(span, count - 1) }\n }\n\n /**\n * Zoom the plot to a slice of itself, given in **data units**: the named axes\n * rescale so that slice fills the plot, the grid and both marker rows\n * following the new scale, and every series re-tracing itself into the new\n * frame. All of it tweens, so the move reads as a camera push rather than a\n * cut.\n *\n * An **omitted axis is left as it is** rather than being fitted to what's\n * visible — so a zoom is exactly what was asked for, and two calls compose\n * predictably. A spotlit region, if one is up, follows the zoom: it resolves\n * against the same live scales, so its rules stay on their data bounds.\n */\n @command({\n args: [\n // One argument, two controls: the method takes a `PlotRegion`, so the x\n // and y spans a host draws are declared inside it.\n {\n key: \"region\", kind: \"region\", properties: {\n x: { kind: \"range\", default: true, defaultMin: 0, defaultMax: 100 },\n y: { kind: \"range\", default: false, defaultMin: 0, defaultMax: 100 },\n },\n },\n ],\n })\n zoomTo(\n args: CommandArgs<{ region: PlotRegion }> & { duration?: number }\n ): Seekable {\n const region = LineChart.regionArg(args.data)\n const duration = args.duration ?? 0.8\n const easing = args.easing ?? easeOut()\n if (!region.x && !region.y) return hold(duration)\n\n // Capture the resting domain *before* the first zoom moves it. Ticks are\n // read through the resolved getters rather than off `xAxis`/`yAxis`, so an\n // auto-derived tick row comes back as itself.\n this.home ??= {\n x: {\n label: this.xAxis.label,\n range: this.xScale,\n ticks: this.resolvedXMarkers,\n },\n y: {\n label: this.yAxis.label,\n range: this.yScale,\n ticks: this.resolvedYMarkers,\n },\n }\n\n const next: { xAxis?: AxisDomainConfig; yAxis?: AxisDomainConfig } = {}\n if (region.x) next.xAxis = LineChart.rescale(region.x, this.resolvedXMarkers)\n if (region.y) next.yAxis = LineChart.rescale(region.y, this.resolvedYMarkers)\n\n return this.to({ data: next, duration, easing })\n }\n\n /**\n * Pull back out to the domain the chart was authored with — the mirror of\n * {@link zoomTo}, and a no-op if it was never zoomed.\n */\n @command()\n resetZoom(\n args: CommandArgs<Record<string, never>> & { duration?: number } = {}\n ): Seekable {\n const duration = args.duration ?? 0.8\n const easing = args.easing ?? easeOut()\n const home = this.home\n if (!home) return hold(duration)\n\n // Cleared here rather than once the move lands. Nothing reads `home` while\n // it runs, and a value has no \"after\" to clear it in — what matters is that\n // the *next* `zoomTo` captures wherever the chart genuinely rests by then,\n // and both this and its capture happen as the command list is walked.\n this.home = null\n return this.to({ data: { xAxis: home.x, yAxis: home.y }, duration, easing })\n }\n\n // ---- Per-series -------------------------------------------------------\n\n /**\n * Show series `index`: **trace** its line in left-to-right — the same draw as\n * {@link enter}, not an opacity fade — in lockstep with its legend entry\n * growing in.\n *\n * `enabled` is set as part of the command's own value rather than before it,\n * so the line is drawable for every `t` the trace covers and undrawn outside\n * it — which is what makes arriving here backwards show the same thing as\n * arriving forwards.\n */\n @command({ args: [SERIES_ARG] })\n showSeries(\n args: CommandArgs<{ seriesIndex: number }> & { duration?: number }\n ): Seekable {\n const index = args.data?.seriesIndex ?? 0\n const duration = args.duration ?? 0.35\n const easing = args.easing ?? easeOut()\n const line = this.lines[index]\n if (!line) return hold(duration)\n\n return together(\n line.enterFrom(0, duration, easing),\n ...(this.legend ? [this.legend.showSeries({ data: { index }, duration, easing })] : [])\n )\n }\n\n /**\n * Hide series `index`: **retrace** its line back out (`progress` 1 → 0) as its\n * legend entry shrinks away — the mirror of {@link showSeries}.\n */\n @command({ args: [SERIES_ARG] })\n hideSeries(\n args: CommandArgs<{ seriesIndex: number }> & { duration?: number }\n ): Seekable {\n const index = args.data?.seriesIndex ?? 0\n const duration = args.duration ?? 0.35\n const easing = args.easing ?? easeOut()\n const line = this.lines[index]\n if (!line) return hold(duration)\n\n return together(\n line.enterFrom(1, duration, easing, 0),\n ...(this.legend ? [this.legend.hideSeries({ data: { index }, duration, easing })] : [])\n )\n }\n\n /**\n * Fade out all other series — each line **and its legend entry** — to focus\n * attention on `index`, which comes back to full. The legend dims in place\n * (opacity only), so no entry moves and the row doesn't reflow.\n */\n @command({ args: [SERIES_ARG] })\n spotlightSeries(\n args: CommandArgs<{ seriesIndex: number }> & { duration?: number }\n ): Seekable {\n const index = args.data?.seriesIndex ?? 0\n const duration = args.duration ?? 0.35\n const easing = args.easing ?? easeOut()\n return together(\n ...this.lines.map((line, i) =>\n line.to({ data: { opacity: i === index ? 1 : SPOTLIGHT_DIM }, duration, easing })\n ),\n ...(this.legend\n ? [this.legend.spotlightSeries({ data: { index }, duration, easing })]\n : [])\n )\n }\n}\n"]}
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Types and pure helpers specific to the {@link LineChart} family: the traced
|
|
3
|
+
* polylines, the spotlit region they dim outside of, and the theme those two
|
|
4
|
+
* add to the shared chart vocabulary.
|
|
5
|
+
*
|
|
6
|
+
* Everything a bar or a pie chart would want too — what a series is, how an axis
|
|
7
|
+
* is scaled and formatted, the theme leaf resolvers, the legend and plot-panel
|
|
8
|
+
* branches — lives in `nodes/chart-kit/shared.ts` and is imported here. What's
|
|
9
|
+
* left below is what only a line chart has: points sorted along an x column,
|
|
10
|
+
* a region clipped out of a polyline, and the `region` branch of the theme.
|
|
11
|
+
*
|
|
12
|
+
* Kept renderer-agnostic (no `Node` imports) so every part shares one
|
|
13
|
+
* scale/format/palette/theme vocabulary, and so the studio's own inspector
|
|
14
|
+
* mapping (`line-chart-props.ts`) can build a partial {@link ChartTheme} without
|
|
15
|
+
* pulling the node classes in.
|
|
16
|
+
*/
|
|
17
|
+
import { type DataRecord, type Fill, type Stroke } from "@motionscript/core";
|
|
18
|
+
import { type AxisConfig, type ChartSeries, type LegendConfig, type LegendTheme, type PlotAreaConfig, type Range } from "../kit/shared.js";
|
|
19
|
+
import type { XScale } from "./x-scale.js";
|
|
20
|
+
/**
|
|
21
|
+
* One series in a {@link LineChart}: a polyline traced through the values in one
|
|
22
|
+
* column of the chart's `data`, drawn in `fill` (or the theme's `seriesStyles`
|
|
23
|
+
* palette when omitted) and captioned by `label` in the legend.
|
|
24
|
+
*
|
|
25
|
+
* The family-wide {@link ChartSeries} under a name that says what it draws here;
|
|
26
|
+
* the chart's own `xField` prop names the column carrying the shared x values,
|
|
27
|
+
* so every series is read off the same rows — one row per sample, one column per
|
|
28
|
+
* series.
|
|
29
|
+
*/
|
|
30
|
+
export type LineSeries = ChartSeries;
|
|
31
|
+
/**
|
|
32
|
+
* A rectangular slice of the plot, in **data units** — the author-facing input
|
|
33
|
+
* to {@link LineChart.spotlightRegion} / {@link LineChart.zoomTo}.
|
|
34
|
+
*
|
|
35
|
+
* Either axis may be omitted, and that's the point: `{ x: [60, 100] }` is a
|
|
36
|
+
* vertical band spanning the full height, `{ y: [8, 10] }` a horizontal band
|
|
37
|
+
* spanning the full width, and both together a box. A reversed range is read
|
|
38
|
+
* the same as the forward one — a region is a span, not a direction.
|
|
39
|
+
*/
|
|
40
|
+
export interface PlotRegion {
|
|
41
|
+
/** Horizontal span in x-axis data units. Omit to span the full plot width. */
|
|
42
|
+
x?: Range;
|
|
43
|
+
/** Vertical span in y-axis data units. Omit to span the full plot height. */
|
|
44
|
+
y?: Range;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* A {@link PlotRegion} resolved into the plot's **centred pixel space** (origin
|
|
48
|
+
* at the plot centre, y-up) — the same local frame the series points live in,
|
|
49
|
+
* so a line can be clipped against it directly.
|
|
50
|
+
*
|
|
51
|
+
* `xBounded`/`yBounded` carry which axes the author actually constrained: an
|
|
52
|
+
* unbounded axis has its edges pinned to the plot's own and draws no rule.
|
|
53
|
+
*/
|
|
54
|
+
export interface RegionBox {
|
|
55
|
+
left: number;
|
|
56
|
+
right: number;
|
|
57
|
+
bottom: number;
|
|
58
|
+
top: number;
|
|
59
|
+
/** The author gave an x range — the left/right edges are real data bounds. */
|
|
60
|
+
xBounded: boolean;
|
|
61
|
+
/** The author gave a y range — the bottom/top edges are real data bounds. */
|
|
62
|
+
yBounded: boolean;
|
|
63
|
+
}
|
|
64
|
+
/** The empty box, used as the "no region" resting value. */
|
|
65
|
+
export declare const EMPTY_REGION_BOX: RegionBox;
|
|
66
|
+
/** Is `box` a real, non-degenerate region — i.e. is there anything to spotlight? */
|
|
67
|
+
export declare function hasRegion(box: RegionBox): boolean;
|
|
68
|
+
/**
|
|
69
|
+
* Resolve a {@link PlotRegion} against the plot's pixel box and the chart's
|
|
70
|
+
* scales. `plot` is the plot rectangle in centred pixel space, and
|
|
71
|
+
* `xScale`/`yScale` the data ranges those edges span.
|
|
72
|
+
*
|
|
73
|
+
* An omitted axis takes the plot's own edges, so the region spans it. A given
|
|
74
|
+
* axis is clamped to the plot, so a range running off the scale still produces
|
|
75
|
+
* a box inside the panel.
|
|
76
|
+
*/
|
|
77
|
+
export declare function resolveRegionBox(region: PlotRegion | null | undefined, plot: {
|
|
78
|
+
left: number;
|
|
79
|
+
right: number;
|
|
80
|
+
bottom: number;
|
|
81
|
+
top: number;
|
|
82
|
+
}, xScale: Range, yScale: Range): RegionBox;
|
|
83
|
+
/** A bare `{x, y}` — declared locally so this module stays free of node imports. */
|
|
84
|
+
interface Vector2Like {
|
|
85
|
+
x: number;
|
|
86
|
+
y: number;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* The parts of `points` that fall **inside** `box`, as a list of contiguous
|
|
90
|
+
* sub-polylines — the geometry behind the region spotlight: a series is drawn
|
|
91
|
+
* dimmed in full, then these runs are re-drawn over it at full strength.
|
|
92
|
+
*
|
|
93
|
+
* Segments are clipped against the box rather than filtered by endpoint, so a
|
|
94
|
+
* line entering the region mid-segment is cut exactly on the boundary.
|
|
95
|
+
*/
|
|
96
|
+
export declare function clipPolylineToBox(points: Vector2Like[], box: RegionBox): Vector2Like[][];
|
|
97
|
+
/**
|
|
98
|
+
* How a spotlit {@link PlotRegion} is drawn — the dashed rules on its bounded
|
|
99
|
+
* edges, the wash filling it, and how far the series fade outside it.
|
|
100
|
+
*/
|
|
101
|
+
export interface RegionConfig {
|
|
102
|
+
/** The dashed rule marking each bounded edge. */
|
|
103
|
+
stroke: Stroke;
|
|
104
|
+
/** Wash filling the region, drawn under the series lines. */
|
|
105
|
+
fill: Fill;
|
|
106
|
+
/** Opacity the stretch of every series *outside* the region fades to. */
|
|
107
|
+
dimOpacity: number;
|
|
108
|
+
}
|
|
109
|
+
/** A {@link LineChart}'s full, resolved visual theme. */
|
|
110
|
+
export interface ChartConfig {
|
|
111
|
+
/**
|
|
112
|
+
* Default per-series line stroke, cycled by series index (`i % length`). A
|
|
113
|
+
* series' own `fill`, when set, overrides just the colour.
|
|
114
|
+
*/
|
|
115
|
+
seriesStyles: Stroke[];
|
|
116
|
+
xAxis: AxisConfig;
|
|
117
|
+
yAxis: AxisConfig;
|
|
118
|
+
/** The plot panel: border, fill, and drop shadow. */
|
|
119
|
+
plotArea: PlotAreaConfig;
|
|
120
|
+
legend: LegendConfig;
|
|
121
|
+
/** The spotlit-region annotation — see {@link RegionConfig}. */
|
|
122
|
+
region: RegionConfig;
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Author-facing partial theme, passed as {@link LineChart}'s `theme` prop —
|
|
126
|
+
* every branch optional and deep-merged onto {@link DEFAULT_CHART_THEME}.
|
|
127
|
+
*/
|
|
128
|
+
export type ChartTheme = {
|
|
129
|
+
seriesStyles?: Stroke[];
|
|
130
|
+
xAxis?: Partial<AxisConfig>;
|
|
131
|
+
yAxis?: Partial<AxisConfig>;
|
|
132
|
+
plotArea?: Partial<PlotAreaConfig>;
|
|
133
|
+
legend?: LegendTheme;
|
|
134
|
+
region?: Partial<RegionConfig>;
|
|
135
|
+
};
|
|
136
|
+
/** The chart's out-of-the-box look. */
|
|
137
|
+
export declare const DEFAULT_CHART_THEME: ChartConfig;
|
|
138
|
+
/**
|
|
139
|
+
* {@link LineChart}'s `theme` @property mapper: merges the author's partial
|
|
140
|
+
* {@link ChartTheme} onto `previous` (falling back to
|
|
141
|
+
* {@link DEFAULT_CHART_THEME} on first resolution), fully resolving every leaf.
|
|
142
|
+
*/
|
|
143
|
+
export declare function resolveChartTheme(theme: ChartTheme | undefined, previous?: ChartConfig): ChartConfig;
|
|
144
|
+
/** {@link LineChart}'s `theme` @property tween — leaf by leaf. */
|
|
145
|
+
export declare function lerpChartTheme(from: ChartConfig, to: ChartConfig, t: number): ChartConfig;
|
|
146
|
+
/**
|
|
147
|
+
* Resolve one series' `[x, y]` points out of the chart's rows: each row's
|
|
148
|
+
* position on the {@link XScale} paired with its own `field` column, sorted
|
|
149
|
+
* along x so the polyline traces left-to-right whatever order the rows arrived
|
|
150
|
+
* in.
|
|
151
|
+
*
|
|
152
|
+
* A row missing its y column contributes a 0 rather than a gap — these charts
|
|
153
|
+
* draw continuous lines, so dropping the point would silently bridge the hole.
|
|
154
|
+
*
|
|
155
|
+
* Takes the resolved scale rather than the column *name*, because what a row's x
|
|
156
|
+
* is depends on what kind of column it came out of: a number, an instant, or a
|
|
157
|
+
* place in the file. See `x-scale.ts`.
|
|
158
|
+
*/
|
|
159
|
+
export declare function seriesPoints(data: DataRecord[], x: XScale, series: LineSeries): [x: number, y: number][];
|
|
160
|
+
/** Min/max across every series' column, the fallback when unset. */
|
|
161
|
+
export declare function yExtent(data: DataRecord[], series: LineSeries[]): Range;
|
|
162
|
+
/**
|
|
163
|
+
* Effective vertical scale: the explicit `range`, else the data's y extent
|
|
164
|
+
* nudged out to tidy step bounds so markers read as round numbers.
|
|
165
|
+
*
|
|
166
|
+
* `divisions` is how many segments the auto-range is stepped into (one fewer
|
|
167
|
+
* than a marker count) — it only shapes the tidy step when `range` is omitted.
|
|
168
|
+
*/
|
|
169
|
+
export declare function resolveYScale(data: DataRecord[], series: LineSeries[], range: Range | undefined, divisions: number): Range;
|
|
170
|
+
export {};
|
|
171
|
+
//# sourceMappingURL=shared.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shared.d.ts","sourceRoot":"","sources":["../../src/line-chart/shared.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Types and pure helpers specific to the {@link LineChart} family: the traced
|
|
3
|
+
* polylines, the spotlit region they dim outside of, and the theme those two
|
|
4
|
+
* add to the shared chart vocabulary.
|
|
5
|
+
*
|
|
6
|
+
* Everything a bar or a pie chart would want too — what a series is, how an axis
|
|
7
|
+
* is scaled and formatted, the theme leaf resolvers, the legend and plot-panel
|
|
8
|
+
* branches — lives in `nodes/chart-kit/shared.ts` and is imported here. What's
|
|
9
|
+
* left below is what only a line chart has: points sorted along an x column,
|
|
10
|
+
* a region clipped out of a polyline, and the `region` branch of the theme.
|
|
11
|
+
*
|
|
12
|
+
* Kept renderer-agnostic (no `Node` imports) so every part shares one
|
|
13
|
+
* scale/format/palette/theme vocabulary, and so the studio's own inspector
|
|
14
|
+
* mapping (`line-chart-props.ts`) can build a partial {@link ChartTheme} without
|
|
15
|
+
* pulling the node classes in.
|
|
16
|
+
*/
|
|
17
|
+
import { Fills, fillOps, lerpNumber, strokeOps, } from "@motionscript/core";
|
|
18
|
+
import { CHART_PALETTE, DEFAULT_LEGEND, DEFAULT_PLOT_AREA, DEFAULT_SERIES_STROKES, DEFAULT_X_AXIS, DEFAULT_Y_AXIS, SPOTLIGHT_DIM, lerpAxisConfig, lerpLegendConfig, lerpPlotArea, lerpSeriesStrokes, niceStep, num, resolveAxisConfig, resolveLegendConfig, resolvePlotArea, resolveSeriesStrokes, } from "../kit/shared.js";
|
|
19
|
+
/** The empty box, used as the "no region" resting value. */
|
|
20
|
+
export const EMPTY_REGION_BOX = {
|
|
21
|
+
left: 0,
|
|
22
|
+
right: 0,
|
|
23
|
+
bottom: 0,
|
|
24
|
+
top: 0,
|
|
25
|
+
xBounded: false,
|
|
26
|
+
yBounded: false,
|
|
27
|
+
};
|
|
28
|
+
/** Is `box` a real, non-degenerate region — i.e. is there anything to spotlight? */
|
|
29
|
+
export function hasRegion(box) {
|
|
30
|
+
return box.right > box.left && box.top > box.bottom;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Resolve a {@link PlotRegion} against the plot's pixel box and the chart's
|
|
34
|
+
* scales. `plot` is the plot rectangle in centred pixel space, and
|
|
35
|
+
* `xScale`/`yScale` the data ranges those edges span.
|
|
36
|
+
*
|
|
37
|
+
* An omitted axis takes the plot's own edges, so the region spans it. A given
|
|
38
|
+
* axis is clamped to the plot, so a range running off the scale still produces
|
|
39
|
+
* a box inside the panel.
|
|
40
|
+
*/
|
|
41
|
+
export function resolveRegionBox(region, plot, xScale, yScale) {
|
|
42
|
+
if (!region || (region.x === undefined && region.y === undefined)) {
|
|
43
|
+
return EMPTY_REGION_BOX;
|
|
44
|
+
}
|
|
45
|
+
const span = (range, [min, max], lo, hi) => {
|
|
46
|
+
if (range === undefined || max <= min)
|
|
47
|
+
return [lo, hi, false];
|
|
48
|
+
const a = Math.min(range[0], range[1]);
|
|
49
|
+
const b = Math.max(range[0], range[1]);
|
|
50
|
+
const toPx = (v) => lo + ((v - min) / (max - min)) * (hi - lo);
|
|
51
|
+
return [
|
|
52
|
+
Math.max(lo, Math.min(hi, toPx(a))),
|
|
53
|
+
Math.max(lo, Math.min(hi, toPx(b))),
|
|
54
|
+
true,
|
|
55
|
+
];
|
|
56
|
+
};
|
|
57
|
+
const [left, right, xBounded] = span(region.x, xScale, plot.left, plot.right);
|
|
58
|
+
const [bottom, top, yBounded] = span(region.y, yScale, plot.bottom, plot.top);
|
|
59
|
+
return { left, right, bottom, top, xBounded, yBounded };
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* The parts of `points` that fall **inside** `box`, as a list of contiguous
|
|
63
|
+
* sub-polylines — the geometry behind the region spotlight: a series is drawn
|
|
64
|
+
* dimmed in full, then these runs are re-drawn over it at full strength.
|
|
65
|
+
*
|
|
66
|
+
* Segments are clipped against the box rather than filtered by endpoint, so a
|
|
67
|
+
* line entering the region mid-segment is cut exactly on the boundary.
|
|
68
|
+
*/
|
|
69
|
+
export function clipPolylineToBox(points, box) {
|
|
70
|
+
if (points.length < 2 || !hasRegion(box))
|
|
71
|
+
return [];
|
|
72
|
+
const runs = [];
|
|
73
|
+
let run = [];
|
|
74
|
+
for (let i = 1; i < points.length; i++) {
|
|
75
|
+
const seg = clipSegment(points[i - 1], points[i], box);
|
|
76
|
+
if (!seg) {
|
|
77
|
+
// Segment misses the box entirely — close whatever run was open.
|
|
78
|
+
if (run.length >= 2)
|
|
79
|
+
runs.push(run);
|
|
80
|
+
run = [];
|
|
81
|
+
continue;
|
|
82
|
+
}
|
|
83
|
+
const [a, b] = seg;
|
|
84
|
+
// Continue the open run when this clipped segment starts where the last one
|
|
85
|
+
// ended; otherwise the line left the box and came back, which is a new run.
|
|
86
|
+
if (run.length > 0 && samePoint(run[run.length - 1], a))
|
|
87
|
+
run.push(b);
|
|
88
|
+
else {
|
|
89
|
+
if (run.length >= 2)
|
|
90
|
+
runs.push(run);
|
|
91
|
+
run = [a, b];
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
if (run.length >= 2)
|
|
95
|
+
runs.push(run);
|
|
96
|
+
return runs;
|
|
97
|
+
}
|
|
98
|
+
/** Points within half a pixel are the same point, for run-joining purposes. */
|
|
99
|
+
function samePoint(a, b) {
|
|
100
|
+
return Math.abs(a.x - b.x) < 0.5 && Math.abs(a.y - b.y) < 0.5;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Liang–Barsky clip of one segment against the axis-aligned `box`. Returns the
|
|
104
|
+
* surviving `[start, end]`, or `null` when the segment lies wholly outside.
|
|
105
|
+
*/
|
|
106
|
+
function clipSegment(a, b, box) {
|
|
107
|
+
const dx = b.x - a.x;
|
|
108
|
+
const dy = b.y - a.y;
|
|
109
|
+
let t0 = 0;
|
|
110
|
+
let t1 = 1;
|
|
111
|
+
// Each edge as (p, q): the segment survives where p·t <= q.
|
|
112
|
+
const edges = [
|
|
113
|
+
[-dx, a.x - box.left],
|
|
114
|
+
[dx, box.right - a.x],
|
|
115
|
+
[-dy, a.y - box.bottom],
|
|
116
|
+
[dy, box.top - a.y],
|
|
117
|
+
];
|
|
118
|
+
for (const [p, q] of edges) {
|
|
119
|
+
if (p === 0) {
|
|
120
|
+
// Parallel to this edge: outside it means the whole segment is out.
|
|
121
|
+
if (q < 0)
|
|
122
|
+
return null;
|
|
123
|
+
continue;
|
|
124
|
+
}
|
|
125
|
+
const r = q / p;
|
|
126
|
+
if (p < 0) {
|
|
127
|
+
if (r > t1)
|
|
128
|
+
return null;
|
|
129
|
+
if (r > t0)
|
|
130
|
+
t0 = r;
|
|
131
|
+
}
|
|
132
|
+
else {
|
|
133
|
+
if (r < t0)
|
|
134
|
+
return null;
|
|
135
|
+
if (r < t1)
|
|
136
|
+
t1 = r;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
return [
|
|
140
|
+
{ x: a.x + t0 * dx, y: a.y + t0 * dy },
|
|
141
|
+
{ x: a.x + t1 * dx, y: a.y + t1 * dy },
|
|
142
|
+
];
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* The legend of a line chart: the shared one, with a small rounded-square
|
|
146
|
+
* swatch in place of the wide chip. A bar's or a wedge's swatch stands in for
|
|
147
|
+
* an area of paint and is drawn like one; a line's stands in for a colour, and
|
|
148
|
+
* a square reads as the sample it is.
|
|
149
|
+
*/
|
|
150
|
+
const LINE_CHART_LEGEND = {
|
|
151
|
+
...DEFAULT_LEGEND,
|
|
152
|
+
markerStyle: {
|
|
153
|
+
...DEFAULT_LEGEND.markerStyle,
|
|
154
|
+
width: 20,
|
|
155
|
+
height: 20,
|
|
156
|
+
borderRadius: 6,
|
|
157
|
+
},
|
|
158
|
+
};
|
|
159
|
+
/** The chart's out-of-the-box look. */
|
|
160
|
+
export const DEFAULT_CHART_THEME = {
|
|
161
|
+
seriesStyles: DEFAULT_SERIES_STROKES,
|
|
162
|
+
xAxis: DEFAULT_X_AXIS,
|
|
163
|
+
yAxis: DEFAULT_Y_AXIS,
|
|
164
|
+
plotArea: DEFAULT_PLOT_AREA,
|
|
165
|
+
legend: LINE_CHART_LEGEND,
|
|
166
|
+
region: {
|
|
167
|
+
// Brighter than the grid and dashed, so the boundary reads as a call-out
|
|
168
|
+
// rather than another axis line; `butt` caps keep the dash lengths exact.
|
|
169
|
+
stroke: {
|
|
170
|
+
weight: 3,
|
|
171
|
+
fill: CHART_PALETTE.regionColor,
|
|
172
|
+
dash: [14, 12],
|
|
173
|
+
cap: "butt",
|
|
174
|
+
},
|
|
175
|
+
// A wash barely above the panel — enough to tint the band, not enough to
|
|
176
|
+
// mute the series drawn over it.
|
|
177
|
+
fill: Fills.color(CHART_PALETTE.regionColor, { opacity: 0.08 }),
|
|
178
|
+
dimOpacity: SPOTLIGHT_DIM,
|
|
179
|
+
},
|
|
180
|
+
};
|
|
181
|
+
function resolveRegionConfig(region, previous) {
|
|
182
|
+
return {
|
|
183
|
+
stroke: strokeOps.resolve(region?.stroke ?? previous.stroke),
|
|
184
|
+
fill: fillOps.resolve(region?.fill ?? previous.fill),
|
|
185
|
+
dimOpacity: region?.dimOpacity ?? previous.dimOpacity,
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
function lerpRegionConfig(from, to, t) {
|
|
189
|
+
return {
|
|
190
|
+
stroke: strokeOps.lerp(from.stroke, to.stroke, t),
|
|
191
|
+
fill: fillOps.lerp(from.fill, to.fill, t),
|
|
192
|
+
dimOpacity: lerpNumber(from.dimOpacity, to.dimOpacity, t),
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* {@link LineChart}'s `theme` @property mapper: merges the author's partial
|
|
197
|
+
* {@link ChartTheme} onto `previous` (falling back to
|
|
198
|
+
* {@link DEFAULT_CHART_THEME} on first resolution), fully resolving every leaf.
|
|
199
|
+
*/
|
|
200
|
+
export function resolveChartTheme(theme, previous) {
|
|
201
|
+
const base = previous ?? DEFAULT_CHART_THEME;
|
|
202
|
+
return {
|
|
203
|
+
seriesStyles: resolveSeriesStrokes(theme?.seriesStyles, base.seriesStyles),
|
|
204
|
+
xAxis: resolveAxisConfig(theme?.xAxis, base.xAxis),
|
|
205
|
+
yAxis: resolveAxisConfig(theme?.yAxis, base.yAxis),
|
|
206
|
+
plotArea: resolvePlotArea(theme?.plotArea, base.plotArea),
|
|
207
|
+
legend: resolveLegendConfig(theme?.legend, base.legend),
|
|
208
|
+
region: resolveRegionConfig(theme?.region, base.region),
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
/** {@link LineChart}'s `theme` @property tween — leaf by leaf. */
|
|
212
|
+
export function lerpChartTheme(from, to, t) {
|
|
213
|
+
return {
|
|
214
|
+
seriesStyles: lerpSeriesStrokes(from.seriesStyles, to.seriesStyles, t),
|
|
215
|
+
xAxis: lerpAxisConfig(from.xAxis, to.xAxis, t),
|
|
216
|
+
yAxis: lerpAxisConfig(from.yAxis, to.yAxis, t),
|
|
217
|
+
plotArea: lerpPlotArea(from.plotArea, to.plotArea, t),
|
|
218
|
+
legend: lerpLegendConfig(from.legend, to.legend, t),
|
|
219
|
+
region: lerpRegionConfig(from.region, to.region, t),
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
// ---- Scales --------------------------------------------------------------
|
|
223
|
+
/**
|
|
224
|
+
* Resolve one series' `[x, y]` points out of the chart's rows: each row's
|
|
225
|
+
* position on the {@link XScale} paired with its own `field` column, sorted
|
|
226
|
+
* along x so the polyline traces left-to-right whatever order the rows arrived
|
|
227
|
+
* in.
|
|
228
|
+
*
|
|
229
|
+
* A row missing its y column contributes a 0 rather than a gap — these charts
|
|
230
|
+
* draw continuous lines, so dropping the point would silently bridge the hole.
|
|
231
|
+
*
|
|
232
|
+
* Takes the resolved scale rather than the column *name*, because what a row's x
|
|
233
|
+
* is depends on what kind of column it came out of: a number, an instant, or a
|
|
234
|
+
* place in the file. See `x-scale.ts`.
|
|
235
|
+
*/
|
|
236
|
+
export function seriesPoints(data, x, series) {
|
|
237
|
+
return data
|
|
238
|
+
.map((row, i) => [x.at(i), num(row, series.field)])
|
|
239
|
+
.sort((a, b) => a[0] - b[0]);
|
|
240
|
+
}
|
|
241
|
+
/** Min/max across every series' column, the fallback when unset. */
|
|
242
|
+
export function yExtent(data, series) {
|
|
243
|
+
let lo = Infinity;
|
|
244
|
+
let hi = -Infinity;
|
|
245
|
+
for (const row of data)
|
|
246
|
+
for (const s of series) {
|
|
247
|
+
const v = num(row, s.field);
|
|
248
|
+
if (v < lo)
|
|
249
|
+
lo = v;
|
|
250
|
+
if (v > hi)
|
|
251
|
+
hi = v;
|
|
252
|
+
}
|
|
253
|
+
return lo <= hi ? [lo, hi] : [0, 1];
|
|
254
|
+
}
|
|
255
|
+
/**
|
|
256
|
+
* Effective vertical scale: the explicit `range`, else the data's y extent
|
|
257
|
+
* nudged out to tidy step bounds so markers read as round numbers.
|
|
258
|
+
*
|
|
259
|
+
* `divisions` is how many segments the auto-range is stepped into (one fewer
|
|
260
|
+
* than a marker count) — it only shapes the tidy step when `range` is omitted.
|
|
261
|
+
*/
|
|
262
|
+
export function resolveYScale(data, series, range, divisions) {
|
|
263
|
+
if (range)
|
|
264
|
+
return range;
|
|
265
|
+
const [lo, hi] = yExtent(data, series);
|
|
266
|
+
const segments = Math.max(1, Math.round(divisions));
|
|
267
|
+
const step = niceStep((hi - lo) / segments || 1);
|
|
268
|
+
return [Math.floor(lo / step) * step, Math.ceil(hi / step) * step];
|
|
269
|
+
}
|
|
270
|
+
//# sourceMappingURL=shared.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shared.js","sourceRoot":"","sources":["../../src/line-chart/shared.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Types and pure helpers specific to the {@link LineChart} family: the traced\n * polylines, the spotlit region they dim outside of, and the theme those two\n * add to the shared chart vocabulary.\n *\n * Everything a bar or a pie chart would want too — what a series is, how an axis\n * is scaled and formatted, the theme leaf resolvers, the legend and plot-panel\n * branches — lives in `nodes/chart-kit/shared.ts` and is imported here. What's\n * left below is what only a line chart has: points sorted along an x column,\n * a region clipped out of a polyline, and the `region` branch of the theme.\n *\n * Kept renderer-agnostic (no `Node` imports) so every part shares one\n * scale/format/palette/theme vocabulary, and so the studio's own inspector\n * mapping (`line-chart-props.ts`) can build a partial {@link ChartTheme} without\n * pulling the node classes in.\n */\n\nimport {\n Fills,\n fillOps,\n lerpNumber,\n strokeOps,\n type DataRecord,\n type Fill,\n type FillResolved,\n type Stroke,\n type StrokeResolved,\n} from \"@motionscript/core\"\n\nimport {\n CHART_PALETTE,\n DEFAULT_LEGEND,\n DEFAULT_PLOT_AREA,\n DEFAULT_SERIES_STROKES,\n DEFAULT_X_AXIS,\n DEFAULT_Y_AXIS,\n SPOTLIGHT_DIM,\n lerpAxisConfig,\n lerpLegendConfig,\n lerpPlotArea,\n lerpSeriesStrokes,\n niceStep,\n num,\n resolveAxisConfig,\n resolveLegendConfig,\n resolvePlotArea,\n resolveSeriesStrokes,\n type AxisConfig,\n type ChartSeries,\n type LegendConfig,\n type LegendTheme,\n type PlotAreaConfig,\n type Range,\n} from \"../kit/shared\"\nimport type { XScale } from \"./x-scale\"\n\n/**\n * One series in a {@link LineChart}: a polyline traced through the values in one\n * column of the chart's `data`, drawn in `fill` (or the theme's `seriesStyles`\n * palette when omitted) and captioned by `label` in the legend.\n *\n * The family-wide {@link ChartSeries} under a name that says what it draws here;\n * the chart's own `xField` prop names the column carrying the shared x values,\n * so every series is read off the same rows — one row per sample, one column per\n * series.\n */\nexport type LineSeries = ChartSeries\n\n// ---- Plot regions -------------------------------------------------------\n\n/**\n * A rectangular slice of the plot, in **data units** — the author-facing input\n * to {@link LineChart.spotlightRegion} / {@link LineChart.zoomTo}.\n *\n * Either axis may be omitted, and that's the point: `{ x: [60, 100] }` is a\n * vertical band spanning the full height, `{ y: [8, 10] }` a horizontal band\n * spanning the full width, and both together a box. A reversed range is read\n * the same as the forward one — a region is a span, not a direction.\n */\nexport interface PlotRegion {\n /** Horizontal span in x-axis data units. Omit to span the full plot width. */\n x?: Range\n /** Vertical span in y-axis data units. Omit to span the full plot height. */\n y?: Range\n}\n\n/**\n * A {@link PlotRegion} resolved into the plot's **centred pixel space** (origin\n * at the plot centre, y-up) — the same local frame the series points live in,\n * so a line can be clipped against it directly.\n *\n * `xBounded`/`yBounded` carry which axes the author actually constrained: an\n * unbounded axis has its edges pinned to the plot's own and draws no rule.\n */\nexport interface RegionBox {\n left: number\n right: number\n bottom: number\n top: number\n /** The author gave an x range — the left/right edges are real data bounds. */\n xBounded: boolean\n /** The author gave a y range — the bottom/top edges are real data bounds. */\n yBounded: boolean\n}\n\n/** The empty box, used as the \"no region\" resting value. */\nexport const EMPTY_REGION_BOX: RegionBox = {\n left: 0,\n right: 0,\n bottom: 0,\n top: 0,\n xBounded: false,\n yBounded: false,\n}\n\n/** Is `box` a real, non-degenerate region — i.e. is there anything to spotlight? */\nexport function hasRegion(box: RegionBox): boolean {\n return box.right > box.left && box.top > box.bottom\n}\n\n/**\n * Resolve a {@link PlotRegion} against the plot's pixel box and the chart's\n * scales. `plot` is the plot rectangle in centred pixel space, and\n * `xScale`/`yScale` the data ranges those edges span.\n *\n * An omitted axis takes the plot's own edges, so the region spans it. A given\n * axis is clamped to the plot, so a range running off the scale still produces\n * a box inside the panel.\n */\nexport function resolveRegionBox(\n region: PlotRegion | null | undefined,\n plot: { left: number; right: number; bottom: number; top: number },\n xScale: Range,\n yScale: Range\n): RegionBox {\n if (!region || (region.x === undefined && region.y === undefined)) {\n return EMPTY_REGION_BOX\n }\n\n const span = (\n range: Range | undefined,\n [min, max]: Range,\n lo: number,\n hi: number\n ): [number, number, boolean] => {\n if (range === undefined || max <= min) return [lo, hi, false]\n const a = Math.min(range[0], range[1])\n const b = Math.max(range[0], range[1])\n const toPx = (v: number) => lo + ((v - min) / (max - min)) * (hi - lo)\n return [\n Math.max(lo, Math.min(hi, toPx(a))),\n Math.max(lo, Math.min(hi, toPx(b))),\n true,\n ]\n }\n\n const [left, right, xBounded] = span(region.x, xScale, plot.left, plot.right)\n const [bottom, top, yBounded] = span(region.y, yScale, plot.bottom, plot.top)\n return { left, right, bottom, top, xBounded, yBounded }\n}\n\n/** A bare `{x, y}` — declared locally so this module stays free of node imports. */\ninterface Vector2Like {\n x: number\n y: number\n}\n\n/**\n * The parts of `points` that fall **inside** `box`, as a list of contiguous\n * sub-polylines — the geometry behind the region spotlight: a series is drawn\n * dimmed in full, then these runs are re-drawn over it at full strength.\n *\n * Segments are clipped against the box rather than filtered by endpoint, so a\n * line entering the region mid-segment is cut exactly on the boundary.\n */\nexport function clipPolylineToBox(\n points: Vector2Like[],\n box: RegionBox\n): Vector2Like[][] {\n if (points.length < 2 || !hasRegion(box)) return []\n\n const runs: Vector2Like[][] = []\n let run: Vector2Like[] = []\n\n for (let i = 1; i < points.length; i++) {\n const seg = clipSegment(points[i - 1], points[i], box)\n if (!seg) {\n // Segment misses the box entirely — close whatever run was open.\n if (run.length >= 2) runs.push(run)\n run = []\n continue\n }\n const [a, b] = seg\n // Continue the open run when this clipped segment starts where the last one\n // ended; otherwise the line left the box and came back, which is a new run.\n if (run.length > 0 && samePoint(run[run.length - 1], a)) run.push(b)\n else {\n if (run.length >= 2) runs.push(run)\n run = [a, b]\n }\n }\n if (run.length >= 2) runs.push(run)\n return runs\n}\n\n/** Points within half a pixel are the same point, for run-joining purposes. */\nfunction samePoint(a: Vector2Like, b: Vector2Like): boolean {\n return Math.abs(a.x - b.x) < 0.5 && Math.abs(a.y - b.y) < 0.5\n}\n\n/**\n * Liang–Barsky clip of one segment against the axis-aligned `box`. Returns the\n * surviving `[start, end]`, or `null` when the segment lies wholly outside.\n */\nfunction clipSegment(\n a: Vector2Like,\n b: Vector2Like,\n box: RegionBox\n): [Vector2Like, Vector2Like] | null {\n const dx = b.x - a.x\n const dy = b.y - a.y\n let t0 = 0\n let t1 = 1\n\n // Each edge as (p, q): the segment survives where p·t <= q.\n const edges: [number, number][] = [\n [-dx, a.x - box.left],\n [dx, box.right - a.x],\n [-dy, a.y - box.bottom],\n [dy, box.top - a.y],\n ]\n for (const [p, q] of edges) {\n if (p === 0) {\n // Parallel to this edge: outside it means the whole segment is out.\n if (q < 0) return null\n continue\n }\n const r = q / p\n if (p < 0) {\n if (r > t1) return null\n if (r > t0) t0 = r\n } else {\n if (r < t0) return null\n if (r < t1) t1 = r\n }\n }\n return [\n { x: a.x + t0 * dx, y: a.y + t0 * dy },\n { x: a.x + t1 * dx, y: a.y + t1 * dy },\n ]\n}\n\n// ---- Theme ---------------------------------------------------------------\n\n/**\n * How a spotlit {@link PlotRegion} is drawn — the dashed rules on its bounded\n * edges, the wash filling it, and how far the series fade outside it.\n */\nexport interface RegionConfig {\n /** The dashed rule marking each bounded edge. */\n stroke: Stroke\n /** Wash filling the region, drawn under the series lines. */\n fill: Fill\n /** Opacity the stretch of every series *outside* the region fades to. */\n dimOpacity: number\n}\n\n/** A {@link LineChart}'s full, resolved visual theme. */\nexport interface ChartConfig {\n /**\n * Default per-series line stroke, cycled by series index (`i % length`). A\n * series' own `fill`, when set, overrides just the colour.\n */\n seriesStyles: Stroke[]\n xAxis: AxisConfig\n yAxis: AxisConfig\n /** The plot panel: border, fill, and drop shadow. */\n plotArea: PlotAreaConfig\n legend: LegendConfig\n /** The spotlit-region annotation — see {@link RegionConfig}. */\n region: RegionConfig\n}\n\n/**\n * Author-facing partial theme, passed as {@link LineChart}'s `theme` prop —\n * every branch optional and deep-merged onto {@link DEFAULT_CHART_THEME}.\n */\nexport type ChartTheme = {\n seriesStyles?: Stroke[]\n xAxis?: Partial<AxisConfig>\n yAxis?: Partial<AxisConfig>\n plotArea?: Partial<PlotAreaConfig>\n legend?: LegendTheme\n region?: Partial<RegionConfig>\n}\n\n/**\n * The legend of a line chart: the shared one, with a small rounded-square\n * swatch in place of the wide chip. A bar's or a wedge's swatch stands in for\n * an area of paint and is drawn like one; a line's stands in for a colour, and\n * a square reads as the sample it is.\n */\nconst LINE_CHART_LEGEND: LegendConfig = {\n ...DEFAULT_LEGEND,\n markerStyle: {\n ...DEFAULT_LEGEND.markerStyle,\n width: 20,\n height: 20,\n borderRadius: 6,\n },\n}\n\n/** The chart's out-of-the-box look. */\nexport const DEFAULT_CHART_THEME: ChartConfig = {\n seriesStyles: DEFAULT_SERIES_STROKES,\n xAxis: DEFAULT_X_AXIS,\n yAxis: DEFAULT_Y_AXIS,\n plotArea: DEFAULT_PLOT_AREA,\n legend: LINE_CHART_LEGEND,\n region: {\n // Brighter than the grid and dashed, so the boundary reads as a call-out\n // rather than another axis line; `butt` caps keep the dash lengths exact.\n stroke: {\n weight: 3,\n fill: CHART_PALETTE.regionColor,\n dash: [14, 12],\n cap: \"butt\",\n },\n // A wash barely above the panel — enough to tint the band, not enough to\n // mute the series drawn over it.\n fill: Fills.color(CHART_PALETTE.regionColor, { opacity: 0.08 }),\n dimOpacity: SPOTLIGHT_DIM,\n },\n}\n\nfunction resolveRegionConfig(\n region: Partial<RegionConfig> | undefined,\n previous: RegionConfig\n): RegionConfig {\n return {\n stroke: strokeOps.resolve(region?.stroke ?? previous.stroke),\n fill: fillOps.resolve(region?.fill ?? previous.fill),\n dimOpacity: region?.dimOpacity ?? previous.dimOpacity,\n }\n}\n\nfunction lerpRegionConfig(\n from: RegionConfig,\n to: RegionConfig,\n t: number\n): RegionConfig {\n return {\n stroke: strokeOps.lerp(\n from.stroke as StrokeResolved[],\n to.stroke as StrokeResolved[],\n t\n ),\n fill: fillOps.lerp(\n from.fill as FillResolved[],\n to.fill as FillResolved[],\n t\n ),\n dimOpacity: lerpNumber(from.dimOpacity, to.dimOpacity, t),\n }\n}\n\n/**\n * {@link LineChart}'s `theme` @property mapper: merges the author's partial\n * {@link ChartTheme} onto `previous` (falling back to\n * {@link DEFAULT_CHART_THEME} on first resolution), fully resolving every leaf.\n */\nexport function resolveChartTheme(\n theme: ChartTheme | undefined,\n previous?: ChartConfig\n): ChartConfig {\n const base = previous ?? DEFAULT_CHART_THEME\n return {\n seriesStyles: resolveSeriesStrokes(theme?.seriesStyles, base.seriesStyles),\n xAxis: resolveAxisConfig(theme?.xAxis, base.xAxis),\n yAxis: resolveAxisConfig(theme?.yAxis, base.yAxis),\n plotArea: resolvePlotArea(theme?.plotArea, base.plotArea),\n legend: resolveLegendConfig(theme?.legend, base.legend),\n region: resolveRegionConfig(theme?.region, base.region),\n }\n}\n\n/** {@link LineChart}'s `theme` @property tween — leaf by leaf. */\nexport function lerpChartTheme(\n from: ChartConfig,\n to: ChartConfig,\n t: number\n): ChartConfig {\n return {\n seriesStyles: lerpSeriesStrokes(from.seriesStyles, to.seriesStyles, t),\n xAxis: lerpAxisConfig(from.xAxis, to.xAxis, t),\n yAxis: lerpAxisConfig(from.yAxis, to.yAxis, t),\n plotArea: lerpPlotArea(from.plotArea, to.plotArea, t),\n legend: lerpLegendConfig(from.legend, to.legend, t),\n region: lerpRegionConfig(from.region, to.region, t),\n }\n}\n\n// ---- Scales --------------------------------------------------------------\n\n/**\n * Resolve one series' `[x, y]` points out of the chart's rows: each row's\n * position on the {@link XScale} paired with its own `field` column, sorted\n * along x so the polyline traces left-to-right whatever order the rows arrived\n * in.\n *\n * A row missing its y column contributes a 0 rather than a gap — these charts\n * draw continuous lines, so dropping the point would silently bridge the hole.\n *\n * Takes the resolved scale rather than the column *name*, because what a row's x\n * is depends on what kind of column it came out of: a number, an instant, or a\n * place in the file. See `x-scale.ts`.\n */\nexport function seriesPoints(\n data: DataRecord[],\n x: XScale,\n series: LineSeries\n): [x: number, y: number][] {\n return data\n .map((row, i): [number, number] => [x.at(i), num(row, series.field)])\n .sort((a, b) => a[0] - b[0])\n}\n\n/** Min/max across every series' column, the fallback when unset. */\nexport function yExtent(data: DataRecord[], series: LineSeries[]): Range {\n let lo = Infinity\n let hi = -Infinity\n for (const row of data)\n for (const s of series) {\n const v = num(row, s.field)\n if (v < lo) lo = v\n if (v > hi) hi = v\n }\n return lo <= hi ? [lo, hi] : [0, 1]\n}\n\n/**\n * Effective vertical scale: the explicit `range`, else the data's y extent\n * nudged out to tidy step bounds so markers read as round numbers.\n *\n * `divisions` is how many segments the auto-range is stepped into (one fewer\n * than a marker count) — it only shapes the tidy step when `range` is omitted.\n */\nexport function resolveYScale(\n data: DataRecord[],\n series: LineSeries[],\n range: Range | undefined,\n divisions: number\n): Range {\n if (range) return range\n const [lo, hi] = yExtent(data, series)\n const segments = Math.max(1, Math.round(divisions))\n const step = niceStep((hi - lo) / segments || 1)\n return [Math.floor(lo / step) * step, Math.ceil(hi / step) * step]\n}\n"]}
|