@motionscript/charts 0.1.0-alpha.7 → 0.1.0-alpha.8
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 +2 -0
- package/NOTICE +15 -14
- package/dist/bar-chart/bar-chart.d.ts +2 -2
- package/dist/bar-chart/bar-chart.d.ts.map +1 -1
- package/dist/bar-chart/bar-chart.js +13 -5
- package/dist/bar-chart/bar-chart.js.map +1 -1
- package/dist/bar-chart/chart-bars.d.ts.map +1 -1
- package/dist/bar-chart/chart-bars.js +6 -7
- package/dist/bar-chart/chart-bars.js.map +1 -1
- package/dist/browser/index.js +1 -1
- package/dist/browser/index.js.map +3 -3
- package/dist/browser/manifest.json +1 -1
- package/dist/line-chart/line-chart.d.ts +2 -2
- package/dist/line-chart/line-chart.d.ts.map +1 -1
- package/dist/line-chart/line-chart.js +16 -7
- package/dist/line-chart/line-chart.js.map +1 -1
- package/dist/line-chart/x-scale.d.ts +3 -10
- package/dist/line-chart/x-scale.d.ts.map +1 -1
- package/dist/line-chart/x-scale.js +15 -4
- package/dist/line-chart/x-scale.js.map +1 -1
- package/dist/pie-chart/pie-chart.d.ts +2 -2
- package/dist/pie-chart/pie-chart.d.ts.map +1 -1
- package/dist/pie-chart/pie-chart.js +4 -1
- package/dist/pie-chart/pie-chart.js.map +1 -1
- package/dist/pie-chart/shared.d.ts +6 -0
- package/dist/pie-chart/shared.d.ts.map +1 -1
- package/dist/pie-chart/shared.js +8 -2
- package/dist/pie-chart/shared.js.map +1 -1
- package/package.json +5 -4
- package/src/bar-chart/bar-chart.ts +13 -5
- package/src/bar-chart/chart-bars.ts +6 -7
- package/src/line-chart/line-chart.ts +20 -7
- package/src/line-chart/x-scale.ts +18 -3
- package/src/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -0
- package/src/pie-chart/pie-chart.ts +4 -1
- package/src/pie-chart/shared.ts +8 -2
|
@@ -124,7 +124,7 @@ export declare const LineChart: import("@motionscript/sdk").Component<"lineChart
|
|
|
124
124
|
readonly spotlightSeries: {
|
|
125
125
|
readonly seriesIndex: import("@motionscript/sdk").Type<number, number, false>;
|
|
126
126
|
};
|
|
127
|
-
},
|
|
127
|
+
}, readonly [], Node2D<Node2DProps>, import("@motionscript/sdk").CallProps<import("@motionscript/sdk").Merge<import("@motionscript/sdk").Box2DState, {
|
|
128
128
|
readonly data: import("@motionscript/sdk").Type<DataRecord[], DataRecord[], false>;
|
|
129
129
|
readonly xField: "";
|
|
130
130
|
readonly series: import("@motionscript/sdk").Type<import("../index.js").ChartSeries[], import("../index.js").ChartSeries[], false>;
|
|
@@ -150,7 +150,7 @@ export declare const LineChart: import("@motionscript/sdk").Component<"lineChart
|
|
|
150
150
|
* remembers wherever the chart rests then.
|
|
151
151
|
*/
|
|
152
152
|
readonly home: import("@motionscript/sdk").Type<LineChartDomains | null, LineChartDomains | null, false>;
|
|
153
|
-
}>,
|
|
153
|
+
}>, readonly [], import("@motionscript/sdk").BuiltNode<import("@motionscript/sdk").Merge<import("@motionscript/sdk").Box2DState, {
|
|
154
154
|
readonly data: import("@motionscript/sdk").Type<DataRecord[], DataRecord[], false>;
|
|
155
155
|
readonly xField: "";
|
|
156
156
|
readonly series: import("@motionscript/sdk").Type<import("../index.js").ChartSeries[], import("../index.js").ChartSeries[], false>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"line-chart.d.ts","sourceRoot":"","sources":["../../src/line-chart/line-chart.ts"],"names":[],"mappings":"AAAA,OAAO,EAML,KAAK,UAAU,EAEf,KAAK,MAAM,EAEX,KAAK,MAAM,EACX,KAAK,WAAW,EAIjB,MAAM,mBAAmB,CAAA;AAU1B,OAAO,EAWL,KAAK,gBAAgB,EACrB,KAAK,KAAK,EACX,MAAM,eAAe,CAAA;AAItB,OAAO,EAOL,KAAK,WAAW,EAChB,KAAK,UAAU,EACf,KAAK,UAAU,EACf,KAAK,UAAU,EAEhB,MAAM,UAAU,CAAA;AAGjB,MAAM,WAAW,cAAe,SAAQ,WAAW;IACjD,kEAAkE;IAClE,IAAI,EAAE,UAAU,EAAE,CAAA;IAClB;;;OAGG;IACH,MAAM,EAAE,MAAM,CAAA;IACd,oFAAoF;IACpF,MAAM,EAAE,UAAU,EAAE,CAAA;IACpB,oEAAoE;IACpE,KAAK,CAAC,EAAE,gBAAgB,CAAA;IACxB,oEAAoE;IACpE,KAAK,CAAC,EAAE,gBAAgB,CAAA;IACxB;;;;;OAKG;IACH,MAAM,CAAC,EAAE,UAAU,GAAG,IAAI,CAAA;IAC1B;;;;OAIG;IACH,KAAK,CAAC,EAAE,UAAU,CAAA;IAClB,6DAA6D;IAC7D,UAAU,CAAC,EAAE,OAAO,CAAA;CACrB;AAED,+DAA+D;AAC/D,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,CAAC,EAAE,gBAAgB,GAAG;QAAE,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC;QAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,CAAA;KAAE,CAAA;IAClF,QAAQ,CAAC,CAAC,EAAE,gBAAgB,GAAG;QAAE,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC;QAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,CAAA;KAAE,CAAA;CACnF;AAED,uDAAuD;AACvD,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,IAAI,EAAE,UAAU,EAAE,CAAA;IAC3B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,MAAM,EAAE,UAAU,EAAE,CAAA;IAC7B,QAAQ,CAAC,KAAK,EAAE,gBAAgB,CAAA;IAChC,QAAQ,CAAC,KAAK,EAAE,gBAAgB,CAAA;CACjC;
|
|
1
|
+
{"version":3,"file":"line-chart.d.ts","sourceRoot":"","sources":["../../src/line-chart/line-chart.ts"],"names":[],"mappings":"AAAA,OAAO,EAML,KAAK,UAAU,EAEf,KAAK,MAAM,EAEX,KAAK,MAAM,EACX,KAAK,WAAW,EAIjB,MAAM,mBAAmB,CAAA;AAU1B,OAAO,EAWL,KAAK,gBAAgB,EACrB,KAAK,KAAK,EACX,MAAM,eAAe,CAAA;AAItB,OAAO,EAOL,KAAK,WAAW,EAChB,KAAK,UAAU,EACf,KAAK,UAAU,EACf,KAAK,UAAU,EAEhB,MAAM,UAAU,CAAA;AAGjB,MAAM,WAAW,cAAe,SAAQ,WAAW;IACjD,kEAAkE;IAClE,IAAI,EAAE,UAAU,EAAE,CAAA;IAClB;;;OAGG;IACH,MAAM,EAAE,MAAM,CAAA;IACd,oFAAoF;IACpF,MAAM,EAAE,UAAU,EAAE,CAAA;IACpB,oEAAoE;IACpE,KAAK,CAAC,EAAE,gBAAgB,CAAA;IACxB,oEAAoE;IACpE,KAAK,CAAC,EAAE,gBAAgB,CAAA;IACxB;;;;;OAKG;IACH,MAAM,CAAC,EAAE,UAAU,GAAG,IAAI,CAAA;IAC1B;;;;OAIG;IACH,KAAK,CAAC,EAAE,UAAU,CAAA;IAClB,6DAA6D;IAC7D,UAAU,CAAC,EAAE,OAAO,CAAA;CACrB;AAED,+DAA+D;AAC/D,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,CAAC,EAAE,gBAAgB,GAAG;QAAE,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC;QAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,CAAA;KAAE,CAAA;IAClF,QAAQ,CAAC,CAAC,EAAE,gBAAgB,GAAG;QAAE,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC;QAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,CAAA;KAAE,CAAA;CACnF;AAED,uDAAuD;AACvD,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,IAAI,EAAE,UAAU,EAAE,CAAA;IAC3B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,MAAM,EAAE,UAAU,EAAE,CAAA;IAC7B,QAAQ,CAAC,KAAK,EAAE,gBAAgB,CAAA;IAChC,QAAQ,CAAC,KAAK,EAAE,gBAAgB,CAAA;CACjC;AA4ED,+FAA+F;AAC/F,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,eAAe,GAAG,gBAAgB,CAYrE;AAoGD;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,eAAO,MAAM,SAAS;;;;;;;IASlB;;;OAGG;;IAEH;;;;OAIG;;IAEH,oFAAoF;;IAEpF;;;;OAIG;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAjBH;;;OAGG;;IAEH;;;;OAIG;;IAEH,oFAAoF;;IAEpF;;;;OAIG;;;;;;;;;IAjBH;;;OAGG;;IAEH;;;;OAIG;;IAEH,oFAAoF;;IAEpF;;;;OAIG;;;;;;;;;;;;;;;;;;;;;yBA4PL,CAAA;AAEF,MAAM,MAAM,SAAS,GAAG,MAAM,CAAC,OAAO,SAAS,CAAC,CAAA"}
|
|
@@ -65,12 +65,21 @@ function drawnY(s, domain) {
|
|
|
65
65
|
const range = resolveYScale(s.data, s.series, domain.range, divisions);
|
|
66
66
|
return { ...domain, range, ticks: domain.ticks ?? markerValues(range, DEFAULT_MARKERS - 1) };
|
|
67
67
|
}
|
|
68
|
+
/** The last domains worked out from each data array, and what else they were read from. */
|
|
69
|
+
const domainsDrawn = new WeakMap();
|
|
68
70
|
/** Both axes as a line chart draws them now, an auto range or tick row read back as itself. */
|
|
69
71
|
export function lineChartDomains(s) {
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
72
|
+
const { data, xField, xAxis, yAxis, series } = s;
|
|
73
|
+
const kept = domainsDrawn.get(data);
|
|
74
|
+
if (kept && kept.xField === xField && kept.xAxis === xAxis && kept.yAxis === yAxis && kept.series === series) {
|
|
75
|
+
return kept.domains;
|
|
76
|
+
}
|
|
77
|
+
const domains = {
|
|
78
|
+
x: settleAxisDomain(xAxis, (d) => drawnX(s, d)),
|
|
79
|
+
y: settleAxisDomain(yAxis, (d) => drawnY(s, d)),
|
|
73
80
|
};
|
|
81
|
+
domainsDrawn.set(data, { xField, xAxis, yAxis, series, domains });
|
|
82
|
+
return domains;
|
|
74
83
|
}
|
|
75
84
|
/**
|
|
76
85
|
* Map one series' data points into the plot's **centred** pixel space (origin at
|
|
@@ -222,6 +231,7 @@ export const LineChart = component2d({
|
|
|
222
231
|
},
|
|
223
232
|
// Its parts fill it; a node made of them would hug them.
|
|
224
233
|
defaults: { width: "fill", height: "fill" },
|
|
234
|
+
allowedChildren: [],
|
|
225
235
|
children: (state) => {
|
|
226
236
|
const theme = () => state.theme;
|
|
227
237
|
const domains = () => lineChartDomains(state);
|
|
@@ -317,10 +327,7 @@ export const LineChart = component2d({
|
|
|
317
327
|
width: "hug",
|
|
318
328
|
height: 0,
|
|
319
329
|
});
|
|
320
|
-
return asParts([
|
|
321
|
-
...state.children,
|
|
322
|
-
cartesianFrame({ axis: vAxis, plot, gutter, below }),
|
|
323
|
-
]);
|
|
330
|
+
return asParts([cartesianFrame({ axis: vAxis, plot, gutter, below })]);
|
|
324
331
|
},
|
|
325
332
|
commands: {
|
|
326
333
|
/**
|
|
@@ -334,6 +341,8 @@ export const LineChart = component2d({
|
|
|
334
341
|
*/
|
|
335
342
|
enter: {
|
|
336
343
|
args: {},
|
|
344
|
+
// Held from the chart's arrival, so it never shows finished ahead of its draw.
|
|
345
|
+
entrance: true,
|
|
337
346
|
easing: easeOut(),
|
|
338
347
|
run: (timeline, state, children) => {
|
|
339
348
|
const parts = partsOf(children);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"line-chart.js","sourceRoot":"","sources":["../../src/line-chart/line-chart.ts"],"names":[],"mappings":"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","sourcesContent":["import {\r\n Rect,\r\n Types,\r\n component2d,\r\n easeOut,\r\n type ChildView,\r\n type DataRecord,\r\n type EntryOptions,\r\n type NodeOf,\r\n // Named so this component's emitted type reaches `Node2D` through the sdk, not core.\r\n type Node2D,\r\n type Node2DProps,\r\n type Size2D,\r\n type Timeline,\r\n type Vector2,\r\n} from \"@motionscript/sdk\"\r\nimport { formatNumber } from \"@motionscript/sdk/component\"\r\n\r\nimport { cartesianFrame, cartesianViews, laidOutSize } from \"../kit/cartesian\"\r\nimport { ChartBorder } from \"../kit/chart-border\"\r\nimport { ChartCanvas } from \"../kit/chart-canvas\"\r\nimport { ChartLegend } from \"../kit/chart-legend\"\r\nimport { asParts, fresh } from \"../kit/entries\"\r\nimport { beats, type Beat } from \"../kit/motion\"\r\nimport { VerticalAxis } from \"../kit/vertical-axis\"\r\nimport {\r\n SPOTLIGHT_DIM,\r\n formatMarker,\r\n lerpAxisDomain,\r\n lerpAxisEntry,\r\n markerStep,\r\n markerValues,\r\n resolveAxisDomain,\r\n resolveSeriesFill,\r\n resolveSeriesStroke,\r\n settleAxisDomain,\r\n type AxisDomainConfig,\r\n type Range,\r\n} from \"../kit/shared\"\r\nimport { ChartLine } from \"./chart-line\"\r\nimport { ChartRegion } from \"./chart-region\"\r\nimport { HorizontalAxis } from \"./horizontal-axis\"\r\nimport {\r\n DEFAULT_CHART_THEME,\r\n lerpChartTheme,\r\n resolveChartTheme,\r\n resolveRegionBox,\r\n resolveYScale,\r\n seriesPoints,\r\n type ChartConfig,\r\n type ChartTheme,\r\n type LineSeries,\r\n type PlotRegion,\r\n type RegionBox,\r\n} from \"./shared\"\r\nimport { resolveXScale, type XScale } from \"./x-scale\"\r\n\r\nexport interface LineChartProps extends Node2DProps {\r\n /** One row per sample — a plain record of field name to value. */\r\n data: DataRecord[]\r\n /**\r\n * Key into each row for its x value, shared by every series. Named `xField`\r\n * rather than `x` because every node already has an `x` — its position.\r\n */\r\n xField: string\r\n /** One polyline per entry: which field it plots, its legend `label`, its `fill`. */\r\n series: LineSeries[]\r\n /** X-axis data domain: caption, scale range, and tick placement. */\r\n xAxis?: AxisDomainConfig\r\n /** Y-axis data domain: caption, scale range, and tick placement. */\r\n yAxis?: AxisDomainConfig\r\n /**\r\n * A slice of the plot to spotlight, in **data units**. Dashed rules mark the\r\n * bounded edges and every series fades outside the box — see\r\n * `spotlightRegion`, which animates the same thing. `null` (the default) is no\r\n * region.\r\n */\r\n region?: PlotRegion | null\r\n /**\r\n * The chart's visual theme — series palette, axis text/grid/gutters, plot\r\n * panel paint, and legend styling. Every branch is optional and deep-merged\r\n * onto {@link DEFAULT_CHART_THEME}, so pass only what you want to override.\r\n */\r\n theme?: ChartTheme\r\n /** Whether the legend row below the plot is drawn at all. */\r\n showLegend?: boolean\r\n}\r\n\r\n/** Both axes' domains with their ranges and ticks resolved. */\r\nexport interface LineChartDomains {\r\n readonly x: AxisDomainConfig & { readonly range: Range; readonly ticks: number[] }\r\n readonly y: AxisDomainConfig & { readonly range: Range; readonly ticks: number[] }\r\n}\r\n\r\n/** What a line chart plots, as its entries hold it. */\r\nexport interface LineChartValues {\r\n readonly data: DataRecord[]\r\n readonly xField: string\r\n readonly series: LineSeries[]\r\n readonly xAxis: AxisDomainConfig\r\n readonly yAxis: AxisDomainConfig\r\n}\r\n\r\n/**\r\n * The argument every per-series command takes: an index into `series`. Its own\r\n * kind rather than `number` so a host can offer the series by name.\r\n */\r\nconst SERIES_ARG = Types.custom<number, number, EntryOptions & { readonly min: number; readonly step: number }>(0, { kind: \"series\", min: 0, step: 1 })\r\n\r\n/** One argument, two controls: the commands take a `PlotRegion`, so the x and y spans a host draws are declared inside it. */\r\nconst REGION_ARG = Types.custom<PlotRegion | undefined>(undefined, {\r\n kind: \"region\",\r\n properties: {\r\n x: { kind: \"range\", default: true, defaultMin: 0, defaultMax: 100 },\r\n y: { kind: \"range\", default: false, defaultMin: 0, defaultMax: 100 },\r\n },\r\n})\r\n\r\n/** How far the legend starts below its slot when it enters, in px. */\r\nconst LEGEND_SLIDE = 20\r\n\r\n/** Fallback marker count when neither axis's ticks are given. */\r\nconst DEFAULT_MARKERS = 5\r\n\r\n/**\r\n * How `enter` divides its duration between its three beats: the axes arriving,\r\n * the lines tracing, and the legend coming up. Shares of the whole, so they must\r\n * sum to 1 — the entrance takes exactly the time it was given.\r\n */\r\nconst AXES_SHARE = 0.35\r\nconst LINES_SHARE = 0.5\r\nconst LEGEND_SHARE = 0.15\r\n\r\n/** What the chart's own commands read: its entries, and the private `home` a zoom remembers. */\r\ninterface LineState extends LineChartValues {\r\n readonly theme: ChartConfig\r\n readonly region: PlotRegion | null\r\n readonly regionReveal: number\r\n readonly home: LineChartDomains | null\r\n}\r\n\r\n/**\r\n * What the x column *is* — a number, an instant, or a place in the file — and\r\n * with it how each row is positioned, ticked and captioned. See `x-scale.ts`.\r\n */\r\nfunction columnOf(s: LineChartValues, format = s.xAxis.format): XScale {\r\n return resolveXScale(s.data, s.xField, format)\r\n}\r\n\r\n/**\r\n * The horizontal axis with its range and ticks resolved: the explicit ones, else\r\n * the column's extent and five ticks across it, asked of the column because only\r\n * a numeric one has round numbers between its samples.\r\n */\r\nfunction drawnX(s: LineChartValues, domain: AxisDomainConfig): AxisDomainConfig {\r\n const column = columnOf(s, domain.format)\r\n const range = domain.range ?? column.extent\r\n return { ...domain, range, ticks: domain.ticks ?? column.ticks(range, DEFAULT_MARKERS - 1) }\r\n}\r\n\r\n/**\r\n * The vertical axis with its range and ticks resolved. Auto-ranging steps into\r\n * one fewer segment than the intended marker count, so the tidy bounds frame the\r\n * ticks the axis draws.\r\n */\r\nfunction drawnY(s: LineChartValues, domain: AxisDomainConfig): AxisDomainConfig {\r\n const divisions = (domain.ticks?.length ?? DEFAULT_MARKERS) - 1\r\n const range = resolveYScale(s.data, s.series, domain.range, divisions)\r\n return { ...domain, range, ticks: domain.ticks ?? markerValues(range, DEFAULT_MARKERS - 1) }\r\n}\r\n\r\n/** Both axes as a line chart draws them now, an auto range or tick row read back as itself. */\r\nexport function lineChartDomains(s: LineChartValues): LineChartDomains {\r\n return {\r\n x: settleAxisDomain(s.xAxis, (d) => drawnX(s, d)) as LineChartDomains[\"x\"],\r\n y: settleAxisDomain(s.yAxis, (d) => drawnY(s, d)) as LineChartDomains[\"y\"],\r\n }\r\n}\r\n\r\n/**\r\n * Map one series' data points into the plot's **centred** pixel space (origin at\r\n * the plot centre, y-up): x runs `[-w/2, +w/2]`, y runs `[-h/2, +h/2]`.\r\n */\r\nfunction seriesPixels(s: LineChartValues, domains: LineChartDomains, index: number, plot: Size2D): Vector2[] {\r\n const series = s.series[index]\r\n if (!series) return []\r\n const points = seriesPoints(s.data, columnOf(s), series)\r\n if (points.length === 0) return []\r\n const { width: w, height: h } = plot\r\n const [xMin, xMax] = domains.x.range\r\n const [yMin, yMax] = domains.y.range\r\n const xToPx = (x: number) => (xMax <= xMin ? 0 : ((x - xMin) / (xMax - xMin) - 0.5) * w)\r\n const yToPx = (y: number) => (yMax <= yMin ? 0 : ((y - yMin) / (yMax - yMin) - 0.5) * h)\r\n // `seriesPoints` already sorted them along x.\r\n return points.map(([x, y]) => ({ x: xToPx(x), y: yToPx(y) }))\r\n}\r\n\r\n/** `region` mapped into the plot's centred pixel space, against the live scales, so it travels with a zoom. */\r\nfunction regionBox(s: LineChartValues & { readonly region: PlotRegion | null }, domains: LineChartDomains, plot: Size2D): RegionBox {\r\n const { width: w, height: h } = plot\r\n return resolveRegionBox(s.region, { left: -w / 2, right: w / 2, bottom: -h / 2, top: h / 2 }, domains.x.range, domains.y.range)\r\n}\r\n\r\n/**\r\n * Whether a call-out is authored at all. Not whether it resolves to pixels: a\r\n * command is built before the first layout, and a region on a chart not yet\r\n * measured is a real one. A region bounding neither axis is none, as `null` is.\r\n */\r\nfunction hasCallout(s: { readonly region: PlotRegion | null }): boolean {\r\n const region = s.region\r\n return region != null && (region.x !== undefined || region.y !== undefined)\r\n}\r\n\r\n/** The `region` a document handed a command, or `{}`: a command is added before its arguments are filled in. */\r\nfunction regionArg(region: PlotRegion | null | undefined): PlotRegion {\r\n return region != null && typeof region === \"object\" ? region : {}\r\n}\r\n\r\n/** A range read as a span, whichever way round the author wrote it. */\r\nfunction span([a, b]: Range): Range {\r\n return a <= b ? [a, b] : [b, a]\r\n}\r\n\r\n/**\r\n * Rescale an axis to `range`, keeping the tick *count* it already has, so each\r\n * marker slides from its old value to its new one instead of the row popping.\r\n */\r\nfunction rescale(range: Range, ticks: readonly number[]): AxisDomainConfig {\r\n const to = span(range)\r\n return { range: to, ticks: markerValues(to, Math.max(2, ticks.length) - 1) }\r\n}\r\n\r\n/** The axis writes of a move from `from` toward `to` at `t`. */\r\nfunction axesAt(from: LineChartDomains, to: Partial<Record<\"x\" | \"y\", AxisDomainConfig>>, t: number) {\r\n return {\r\n ...(to.x && { xAxis: lerpAxisDomain(from.x, to.x, t) }),\r\n ...(to.y && { yAxis: lerpAxisDomain(from.y, to.y, t) }),\r\n }\r\n}\r\n\r\ntype AnyTimeline = Timeline<any, any>\r\n\r\n/** The parts a line chart's commands drive, found through its children. */\r\nfunction partsOf(children: readonly ChildView[]) {\r\n const frame = cartesianViews(children)\r\n if (!frame) return null\r\n const hAxis = frame.below.find(HorizontalAxis.is)\r\n if (!VerticalAxis.is(frame.axis) || !hAxis) return null\r\n return {\r\n vAxis: frame.axis,\r\n hAxis,\r\n lines: frame.plot.filter(ChartLine.is),\r\n legend: frame.below.find(ChartLegend.is) ?? null,\r\n }\r\n}\r\n\r\n/** Drop the call-out: the rules retract, the wash fades, and every series comes back to full. */\r\nfunction clearing(timeline: AnyTimeline, state: LineState) {\r\n const from = state.regionReveal\r\n const region = state.region\r\n // Nothing to retract, but the call still takes its slot on the timeline.\r\n if (from === 0) return timeline.animate(() => ({ region: null, regionReveal: 0 }), { eased: false })\r\n // `region` is held until the retraction lands, or there would be nothing left to retract.\r\n return timeline.animate((t) => (t >= 1 ? { region: null, regionReveal: 0 } : { region, regionReveal: from * (1 - t) }))\r\n}\r\n\r\n/** Trace series `index`'s line in (`show`) or back out, in lockstep with its legend entry. */\r\nfunction toggling(timeline: AnyTimeline, children: readonly ChildView[], index: number, show: boolean) {\r\n const parts = partsOf(children)\r\n const line = parts?.lines[index]\r\n if (!parts || !line) return timeline.wait(timeline.duration)\r\n return timeline.together([\r\n line.run(\"enter\", show ? { from: 0, to: 1 } : { from: 1, to: 0 }),\r\n ...(parts.legend ? [parts.legend.run(show ? \"showSeries\" : \"hideSeries\", { index })] : []),\r\n ])\r\n}\r\n\r\n/**\r\n * A multi-series line chart, composed from five independent parts rather than\r\n * one monolithic draw:\r\n *\r\n * - {@link ChartCanvas} — the plot panel with a two-way grid, under everything.\r\n * - {@link VerticalAxis} / {@link HorizontalAxis} — columns/rows of real text\r\n * markers that stagger in, each carrying its own axis caption.\r\n * - {@link ChartRegion} — the optional call-out marking a spotlit slice of the\r\n * plot: dashed rules on its bounded edges, and every series faded outside it.\r\n * - {@link ChartLine} (one per series) — the traced polylines over the canvas.\r\n * - {@link ChartLegend} — a row of entries below the chart, one per series.\r\n *\r\n * Every part reads the chart's entries through bindings, and the lines, the\r\n * region and the grid all map against the plot panel's own laid-out box, so\r\n * points land exactly on their markers and the chart re-flows if its box\r\n * changes.\r\n *\r\n * **Resting state is the finished chart**: an editor paints a node's Initial\r\n * state on a paused canvas. `enter` arms every part on its first frame.\r\n *\r\n * Past the entrance, `showSeries`/`hideSeries`/`spotlightSeries` pick out a\r\n * *series*, `spotlightRegion` marks a *slice of the plot* without changing the\r\n * scale, and `zoomTo` rescales the axes so a slice fills the plot. A spotlit\r\n * region resolves against the live scales, so it travels with a zoom. A `to` of\r\n * an axis `range` or `ticks` tweens from the domain as drawn (see\r\n * {@link lerpAxisEntry}), so an auto axis rescales continuously.\r\n */\r\nexport const LineChart = component2d({\r\n key: \"lineChart\",\r\n state: {\r\n data: fresh<DataRecord[]>(() => [], { kind: \"dataset\" }),\r\n xField: \"\",\r\n series: fresh<LineSeries[]>(() => [], { kind: \"series\" }),\r\n xAxis: Types.custom<AxisDomainConfig>({}, { resolve: resolveAxisDomain, lerp: lerpAxisEntry }),\r\n yAxis: Types.custom<AxisDomainConfig>({}, { resolve: resolveAxisDomain, lerp: lerpAxisEntry }),\r\n theme: Types.custom<ChartTheme, ChartConfig>(DEFAULT_CHART_THEME, { resolve: resolveChartTheme, lerp: lerpChartTheme }),\r\n /**\r\n * The spotlit slice of the plot in data units, or `null` for none. The box\r\n * snaps; the animation is {@link regionReveal} drawing the rules on.\r\n */\r\n region: Types.custom<PlotRegion | null>(null),\r\n /**\r\n * How far the `region` call-out is drawn in, `[0, 1]`: the rules grow out and\r\n * the wash fades up as it climbs, while every line's out-of-region stretch\r\n * fades to the theme's `region.dimOpacity`.\r\n */\r\n regionReveal: 0,\r\n /** Read as the chart is built: the legend is a part the chart builds or doesn't. */\r\n showLegend: Types.boolean(true, { animatable: false }),\r\n /**\r\n * The domain `zoomTo` first left, so `resetZoom` restores the chart as it\r\n * stood, auto-derived ticks included. Cleared by `resetZoom`, so the next zoom\r\n * remembers wherever the chart rests then.\r\n */\r\n home: Types.custom<LineChartDomains | null>(null, { private: true }),\r\n },\r\n // Its parts fill it; a node made of them would hug them.\r\n defaults: { width: \"fill\", height: \"fill\" },\r\n children: (state) => {\r\n const theme = () => state.theme\r\n const domains = () => lineChartDomains(state)\r\n let plot: Node2D | undefined\r\n const plotSize = () => laidOutSize(plot)\r\n const enabled = state.series.map((s) => s.enabled ?? true)\r\n\r\n // Bound, not snapshotted, so a rescale re-labels and re-places the row as it\r\n // tweens. The marker *count* is read once, which is why `zoomTo` keeps it.\r\n const vAxis = new VerticalAxis({\r\n range: () => domains().y.range,\r\n markers: () => domains().y.ticks,\r\n // The y axis is always numbers, so its format is simply the pattern.\r\n captions: () => {\r\n const markers = domains().y.ticks\r\n const format = state.yAxis.format\r\n return markers.map((value) => (format === undefined ? formatMarker(value, markerStep(markers)) : formatNumber(value, format)))\r\n },\r\n axis: () => theme().yAxis,\r\n label: state.yAxis.label ?? \"\",\r\n width: \"hug\",\r\n height: \"fill\",\r\n })\r\n\r\n const hAxis = new HorizontalAxis({\r\n range: () => domains().x.range,\r\n markers: () => domains().x.ticks,\r\n // A tick on a month or category column is captioned with the cell it came\r\n // out of — `Jan`, not the instant it parsed to.\r\n captions: () => {\r\n const column = columnOf(state)\r\n return domains().x.ticks.map((value) => column.label(value))\r\n },\r\n axis: () => theme().xAxis,\r\n label: state.xAxis.label ?? \"\",\r\n width: \"fill\",\r\n height: \"hug\",\r\n })\r\n\r\n const lines = state.series.map(\r\n (s, i) =>\r\n new ChartLine({\r\n points: () => seriesPixels(state, domains(), i, plotSize()),\r\n stroke: () => resolveSeriesStroke(theme().seriesStyles, s, i),\r\n enabled: enabled[i],\r\n // Each line clips itself against the box the rules are drawn from, so\r\n // the dim/bright boundary can't drift from the dashes.\r\n spotlight: () => regionBox(state, domains(), plotSize()),\r\n // Ramped by the reveal that draws the rules: one signal, both halves.\r\n dimOpacity: () => 1 - (1 - theme().region.dimOpacity) * state.regionReveal,\r\n }) as unknown as Node2D\r\n )\r\n\r\n const below: Node2D[] = [hAxis as unknown as Node2D]\r\n if (state.showLegend !== false) {\r\n below.push(\r\n new ChartLegend({\r\n series: state.series,\r\n // The legend paints a swatch, not a line, so it is handed the colour each\r\n // stroke resolves to rather than the stroke itself.\r\n swatches: () => state.series.map((s, i) => resolveSeriesFill(theme().seriesStyles, s, i)),\r\n legend: () => theme().legend,\r\n // The row's spacing is the theme's as the chart was built, like the\r\n // entries' type and chips: a theme tween re-paints the swatches only.\r\n gap: state.theme.legend.itemGap,\r\n padding: state.theme.legend.padding,\r\n }) as unknown as Node2D\r\n )\r\n }\r\n\r\n plot = new Rect({\r\n clip: true,\r\n children: [\r\n new ChartCanvas({\r\n fill: () => theme().plotArea.fill,\r\n shadow: () => theme().plotArea.shadow,\r\n xGridStroke: () => theme().xAxis.lineStyle,\r\n yGridStroke: () => theme().yAxis.lineStyle,\r\n // A grid line under every axis marker; the canvas skips the edges.\r\n xMarkers: () => domains().x.ticks,\r\n yMarkers: () => domains().y.ticks,\r\n xExtent: () => domains().x.range,\r\n yExtent: () => domains().y.range,\r\n }),\r\n // Over the grid, under the lines, so a spotlit stretch of a series isn't\r\n // tinted by the highlight meant to pick it out.\r\n new ChartRegion({\r\n box: () => regionBox(state, domains(), plotSize()),\r\n stroke: () => theme().region.stroke,\r\n fill: () => theme().region.fill,\r\n reveal: () => state.regionReveal,\r\n }),\r\n ...lines,\r\n new ChartBorder({ stroke: () => theme().plotArea.stroke }),\r\n ],\r\n }) as unknown as Node2D\r\n\r\n const gutter = new VerticalAxis({\r\n opacity: 0,\r\n range: () => domains().y.range,\r\n markers: () => domains().y.ticks,\r\n axis: () => theme().yAxis,\r\n label: state.yAxis.label ?? \"\",\r\n width: \"hug\",\r\n height: 0,\r\n }) as unknown as Node2D\r\n\r\n return asParts([\r\n ...(state.children as unknown as Node2D[]),\r\n cartesianFrame({ axis: vAxis as unknown as Node2D, plot, gutter, below }),\r\n ])\r\n },\r\n commands: {\r\n /**\r\n * Animate the whole chart in: the two axes stagger their markers in, the\r\n * series lines trace left to right, and the legend fades up last. Its first\r\n * frame arms every part: markers shifted and transparent, lines untraced,\r\n * the legend dropped and transparent.\r\n *\r\n * `duration` is the **whole** entrance; the beats are shares of it. A chart\r\n * authored with a `region` lands its call-out last, in the final quarter.\r\n */\r\n enter: {\r\n args: {},\r\n easing: easeOut(),\r\n run: (timeline, state, children) => {\r\n const parts = partsOf(children)\r\n if (!parts) return timeline.wait(timeline.duration)\r\n const duration = timeline.duration\r\n const revealing = hasCallout(state) && state.regionReveal === 0\r\n const body = revealing ? duration * 0.75 : duration\r\n const axes = body * AXES_SHARE\r\n const traced = body * LINES_SHARE\r\n const { legend } = parts\r\n const at0 = (piece: Beat[\"piece\"]): Beat => ({ at: 0, duration: 0, piece })\r\n // The first frame arms what every later beat moves: a beat ahead of the\r\n // playhead writes nothing. A beat with nothing to do still takes its share.\r\n return beats(timeline, [\r\n ...(revealing ? [at0(timeline.animate(() => ({ regionReveal: 0 })))] : []),\r\n ...parts.lines.map((line) => at0(line.to({ progress: 0 }))),\r\n ...(legend ? [at0(legend.to({ opacity: 0, y: -LEGEND_SLIDE }))] : []),\r\n { at: 0, duration: axes, piece: parts.vAxis.run(\"enter\", { slide: 24 }) },\r\n { at: 0, duration: axes, piece: parts.hAxis.run(\"enter\", { slide: 24 }) },\r\n ...parts.lines.map((line) => ({ at: axes, duration: traced, piece: line.run(\"enter\") })),\r\n ...(legend ? [{ at: axes + traced, duration: body * LEGEND_SHARE, piece: legend.to({ opacity: 1, y: 0 }) }] : []),\r\n ...(revealing ? [{ at: body, duration: duration * 0.25, piece: timeline.animate((t) => ({ regionReveal: t })) }] : []),\r\n ])\r\n },\r\n },\r\n /**\r\n * Spotlight a rectangular slice of the plot given in **data units**: dashed\r\n * rules draw onto each bounded edge while every series fades outside the box.\r\n * Either axis alone is a band; both are a box. Called while another region is\r\n * up, the old call-out retracts over the first half and the new one draws in\r\n * over the second, each half eased on its own.\r\n */\r\n spotlightRegion: {\r\n args: { region: REGION_ARG },\r\n easing: easeOut(),\r\n run: (timeline, state) => {\r\n const region = regionArg(timeline.args.region)\r\n const from = state.regionReveal\r\n const previous = state.region\r\n // A region bounding neither axis is no call-out: spotlighting it is a clear.\r\n if (region.x === undefined && region.y === undefined) return clearing(timeline, state)\r\n // Nothing up yet: the region is set from the first frame and just draws on.\r\n if (from <= 0 || !hasCallout(state)) return timeline.animate((t) => ({ region, regionReveal: from + (1 - from) * t }))\r\n return timeline.animate(\r\n (t) => (t < 0.5\r\n ? { region: previous, regionReveal: from * (1 - timeline.ease(t * 2)) }\r\n : { region, regionReveal: timeline.ease(t * 2 - 1) }),\r\n { eased: false }\r\n )\r\n },\r\n },\r\n /** Drop the region call-out. A no-op when nothing is spotlit, which still takes its slot. */\r\n clearRegion: {\r\n args: {},\r\n easing: easeOut(),\r\n run: (timeline, state) => clearing(timeline, state),\r\n },\r\n /**\r\n * Zoom the plot to a slice of itself, given in **data units**: the named axes\r\n * rescale so that slice fills the plot, the grid, both marker rows and every\r\n * series following. An omitted axis is left as it is. The first zoom\r\n * remembers the domain it left, for `resetZoom`.\r\n */\r\n zoomTo: {\r\n args: { region: REGION_ARG },\r\n easing: easeOut(),\r\n run: (timeline, state) => {\r\n const region = regionArg(timeline.args.region)\r\n if (!region.x && !region.y) return timeline.wait(timeline.duration)\r\n const from = lineChartDomains(state)\r\n const home = state.home ?? from\r\n const to = {\r\n ...(region.x && { x: { ...from.x, ...rescale(region.x, from.x.ticks) } }),\r\n ...(region.y && { y: { ...from.y, ...rescale(region.y, from.y.ticks) } }),\r\n }\r\n return timeline.animate((t) => ({ home, ...axesAt(from, to, t) }))\r\n },\r\n },\r\n /** Pull back out to the domain the first zoom left — the mirror of `zoomTo`, and a hold if it never zoomed. */\r\n resetZoom: {\r\n args: {},\r\n easing: easeOut(),\r\n run: (timeline, state) => {\r\n const home = state.home\r\n if (!home) return timeline.wait(timeline.duration)\r\n const from = lineChartDomains(state)\r\n return timeline.animate((t) => ({ home: null, ...axesAt(from, home, t) }))\r\n },\r\n },\r\n /**\r\n * Show series `index`: **trace** its line in left to right, in lockstep with\r\n * its legend entry growing in.\r\n */\r\n showSeries: {\r\n args: { seriesIndex: SERIES_ARG },\r\n easing: easeOut(),\r\n run: (timeline, _state, children) => toggling(timeline, children, timeline.args.seriesIndex, true),\r\n },\r\n /** Hide series `index`: **retrace** its line back out as its legend entry shrinks away. */\r\n hideSeries: {\r\n args: { seriesIndex: SERIES_ARG },\r\n easing: easeOut(),\r\n run: (timeline, _state, children) => toggling(timeline, children, timeline.args.seriesIndex, false),\r\n },\r\n /**\r\n * Fade every other series — each line **and its legend entry** — to focus on\r\n * `index`, which comes back to full. The legend dims in place, so the row\r\n * doesn't reflow.\r\n */\r\n spotlightSeries: {\r\n args: { seriesIndex: SERIES_ARG },\r\n easing: easeOut(),\r\n run: (timeline, _state, children) => {\r\n const parts = partsOf(children)\r\n if (!parts) return timeline.wait(timeline.duration)\r\n const index = timeline.args.seriesIndex\r\n return timeline.together([\r\n ...parts.lines.map((line, i) => line.to({ opacity: i === index ? 1 : SPOTLIGHT_DIM })),\r\n ...(parts.legend ? [parts.legend.run(\"spotlightSeries\", { index })] : []),\r\n ])\r\n },\r\n },\r\n },\r\n})\r\n\r\nexport type LineChart = NodeOf<typeof LineChart>\r\n"]}
|
|
1
|
+
{"version":3,"file":"line-chart.js","sourceRoot":"","sources":["../../src/line-chart/line-chart.ts"],"names":[],"mappings":"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","sourcesContent":["import {\r\n Rect,\r\n Types,\r\n component2d,\r\n easeOut,\r\n type ChildView,\r\n type DataRecord,\r\n type EntryOptions,\r\n type NodeOf,\r\n // Named so this component's emitted type reaches `Node2D` through the sdk, not core.\r\n type Node2D,\r\n type Node2DProps,\r\n type Size2D,\r\n type Timeline,\r\n type Vector2,\r\n} from \"@motionscript/sdk\"\r\nimport { formatNumber } from \"@motionscript/sdk/component\"\r\n\r\nimport { cartesianFrame, cartesianViews, laidOutSize } from \"../kit/cartesian\"\r\nimport { ChartBorder } from \"../kit/chart-border\"\r\nimport { ChartCanvas } from \"../kit/chart-canvas\"\r\nimport { ChartLegend } from \"../kit/chart-legend\"\r\nimport { asParts, fresh } from \"../kit/entries\"\r\nimport { beats, type Beat } from \"../kit/motion\"\r\nimport { VerticalAxis } from \"../kit/vertical-axis\"\r\nimport {\r\n SPOTLIGHT_DIM,\r\n formatMarker,\r\n lerpAxisDomain,\r\n lerpAxisEntry,\r\n markerStep,\r\n markerValues,\r\n resolveAxisDomain,\r\n resolveSeriesFill,\r\n resolveSeriesStroke,\r\n settleAxisDomain,\r\n type AxisDomainConfig,\r\n type Range,\r\n} from \"../kit/shared\"\r\nimport { ChartLine } from \"./chart-line\"\r\nimport { ChartRegion } from \"./chart-region\"\r\nimport { HorizontalAxis } from \"./horizontal-axis\"\r\nimport {\r\n DEFAULT_CHART_THEME,\r\n lerpChartTheme,\r\n resolveChartTheme,\r\n resolveRegionBox,\r\n resolveYScale,\r\n seriesPoints,\r\n type ChartConfig,\r\n type ChartTheme,\r\n type LineSeries,\r\n type PlotRegion,\r\n type RegionBox,\r\n} from \"./shared\"\r\nimport { resolveXScale, type XScale } from \"./x-scale\"\r\n\r\nexport interface LineChartProps extends Node2DProps {\r\n /** One row per sample — a plain record of field name to value. */\r\n data: DataRecord[]\r\n /**\r\n * Key into each row for its x value, shared by every series. Named `xField`\r\n * rather than `x` because every node already has an `x` — its position.\r\n */\r\n xField: string\r\n /** One polyline per entry: which field it plots, its legend `label`, its `fill`. */\r\n series: LineSeries[]\r\n /** X-axis data domain: caption, scale range, and tick placement. */\r\n xAxis?: AxisDomainConfig\r\n /** Y-axis data domain: caption, scale range, and tick placement. */\r\n yAxis?: AxisDomainConfig\r\n /**\r\n * A slice of the plot to spotlight, in **data units**. Dashed rules mark the\r\n * bounded edges and every series fades outside the box — see\r\n * `spotlightRegion`, which animates the same thing. `null` (the default) is no\r\n * region.\r\n */\r\n region?: PlotRegion | null\r\n /**\r\n * The chart's visual theme — series palette, axis text/grid/gutters, plot\r\n * panel paint, and legend styling. Every branch is optional and deep-merged\r\n * onto {@link DEFAULT_CHART_THEME}, so pass only what you want to override.\r\n */\r\n theme?: ChartTheme\r\n /** Whether the legend row below the plot is drawn at all. */\r\n showLegend?: boolean\r\n}\r\n\r\n/** Both axes' domains with their ranges and ticks resolved. */\r\nexport interface LineChartDomains {\r\n readonly x: AxisDomainConfig & { readonly range: Range; readonly ticks: number[] }\r\n readonly y: AxisDomainConfig & { readonly range: Range; readonly ticks: number[] }\r\n}\r\n\r\n/** What a line chart plots, as its entries hold it. */\r\nexport interface LineChartValues {\r\n readonly data: DataRecord[]\r\n readonly xField: string\r\n readonly series: LineSeries[]\r\n readonly xAxis: AxisDomainConfig\r\n readonly yAxis: AxisDomainConfig\r\n}\r\n\r\n/**\r\n * The argument every per-series command takes: an index into `series`. Its own\r\n * kind rather than `number` so a host can offer the series by name.\r\n */\r\nconst SERIES_ARG = Types.custom<number, number, EntryOptions & { readonly min: number; readonly step: number }>(0, { kind: \"series\", min: 0, step: 1 })\r\n\r\n/** One argument, two controls: the commands take a `PlotRegion`, so the x and y spans a host draws are declared inside it. */\r\nconst REGION_ARG = Types.custom<PlotRegion | undefined>(undefined, {\r\n kind: \"region\",\r\n properties: {\r\n x: { kind: \"range\", default: true, defaultMin: 0, defaultMax: 100 },\r\n y: { kind: \"range\", default: false, defaultMin: 0, defaultMax: 100 },\r\n },\r\n})\r\n\r\n/** How far the legend starts below its slot when it enters, in px. */\r\nconst LEGEND_SLIDE = 20\r\n\r\n/** Fallback marker count when neither axis's ticks are given. */\r\nconst DEFAULT_MARKERS = 5\r\n\r\n/**\r\n * How `enter` divides its duration between its three beats: the axes arriving,\r\n * the lines tracing, and the legend coming up. Shares of the whole, so they must\r\n * sum to 1 — the entrance takes exactly the time it was given.\r\n */\r\nconst AXES_SHARE = 0.35\r\nconst LINES_SHARE = 0.5\r\nconst LEGEND_SHARE = 0.15\r\n\r\n/** What the chart's own commands read: its entries, and the private `home` a zoom remembers. */\r\ninterface LineState extends LineChartValues {\r\n readonly theme: ChartConfig\r\n readonly region: PlotRegion | null\r\n readonly regionReveal: number\r\n readonly home: LineChartDomains | null\r\n}\r\n\r\n/**\r\n * What the x column *is* — a number, an instant, or a place in the file — and\r\n * with it how each row is positioned, ticked and captioned. See `x-scale.ts`.\r\n */\r\nfunction columnOf(s: LineChartValues, format = s.xAxis.format): XScale {\r\n return resolveXScale(s.data, s.xField, format)\r\n}\r\n\r\n/**\r\n * The horizontal axis with its range and ticks resolved: the explicit ones, else\r\n * the column's extent and five ticks across it, asked of the column because only\r\n * a numeric one has round numbers between its samples.\r\n */\r\nfunction drawnX(s: LineChartValues, domain: AxisDomainConfig): AxisDomainConfig {\r\n const column = columnOf(s, domain.format)\r\n const range = domain.range ?? column.extent\r\n return { ...domain, range, ticks: domain.ticks ?? column.ticks(range, DEFAULT_MARKERS - 1) }\r\n}\r\n\r\n/**\r\n * The vertical axis with its range and ticks resolved. Auto-ranging steps into\r\n * one fewer segment than the intended marker count, so the tidy bounds frame the\r\n * ticks the axis draws.\r\n */\r\nfunction drawnY(s: LineChartValues, domain: AxisDomainConfig): AxisDomainConfig {\r\n const divisions = (domain.ticks?.length ?? DEFAULT_MARKERS) - 1\r\n const range = resolveYScale(s.data, s.series, domain.range, divisions)\r\n return { ...domain, range, ticks: domain.ticks ?? markerValues(range, DEFAULT_MARKERS - 1) }\r\n}\r\n\r\n/** The last domains worked out from each data array, and what else they were read from. */\r\nconst domainsDrawn = new WeakMap<\r\n DataRecord[],\r\n Pick<LineChartValues, \"xField\" | \"xAxis\" | \"yAxis\" | \"series\"> & { readonly domains: LineChartDomains }\r\n>()\r\n\r\n/** Both axes as a line chart draws them now, an auto range or tick row read back as itself. */\r\nexport function lineChartDomains(s: LineChartValues): LineChartDomains {\r\n const { data, xField, xAxis, yAxis, series } = s\r\n const kept = domainsDrawn.get(data)\r\n if (kept && kept.xField === xField && kept.xAxis === xAxis && kept.yAxis === yAxis && kept.series === series) {\r\n return kept.domains\r\n }\r\n const domains = {\r\n x: settleAxisDomain(xAxis, (d) => drawnX(s, d)) as LineChartDomains[\"x\"],\r\n y: settleAxisDomain(yAxis, (d) => drawnY(s, d)) as LineChartDomains[\"y\"],\r\n }\r\n domainsDrawn.set(data, { xField, xAxis, yAxis, series, domains })\r\n return domains\r\n}\r\n\r\n/**\r\n * Map one series' data points into the plot's **centred** pixel space (origin at\r\n * the plot centre, y-up): x runs `[-w/2, +w/2]`, y runs `[-h/2, +h/2]`.\r\n */\r\nfunction seriesPixels(s: LineChartValues, domains: LineChartDomains, index: number, plot: Size2D): Vector2[] {\r\n const series = s.series[index]\r\n if (!series) return []\r\n const points = seriesPoints(s.data, columnOf(s), series)\r\n if (points.length === 0) return []\r\n const { width: w, height: h } = plot\r\n const [xMin, xMax] = domains.x.range\r\n const [yMin, yMax] = domains.y.range\r\n const xToPx = (x: number) => (xMax <= xMin ? 0 : ((x - xMin) / (xMax - xMin) - 0.5) * w)\r\n const yToPx = (y: number) => (yMax <= yMin ? 0 : ((y - yMin) / (yMax - yMin) - 0.5) * h)\r\n // `seriesPoints` already sorted them along x.\r\n return points.map(([x, y]) => ({ x: xToPx(x), y: yToPx(y) }))\r\n}\r\n\r\n/** `region` mapped into the plot's centred pixel space, against the live scales, so it travels with a zoom. */\r\nfunction regionBox(s: LineChartValues & { readonly region: PlotRegion | null }, domains: LineChartDomains, plot: Size2D): RegionBox {\r\n const { width: w, height: h } = plot\r\n return resolveRegionBox(s.region, { left: -w / 2, right: w / 2, bottom: -h / 2, top: h / 2 }, domains.x.range, domains.y.range)\r\n}\r\n\r\n/**\r\n * Whether a call-out is authored at all. Not whether it resolves to pixels: a\r\n * command is built before the first layout, and a region on a chart not yet\r\n * measured is a real one. A region bounding neither axis is none, as `null` is.\r\n */\r\nfunction hasCallout(s: { readonly region: PlotRegion | null }): boolean {\r\n const region = s.region\r\n return region != null && (region.x !== undefined || region.y !== undefined)\r\n}\r\n\r\n/** The `region` a document handed a command, or `{}`: a command is added before its arguments are filled in. */\r\nfunction regionArg(region: PlotRegion | null | undefined): PlotRegion {\r\n return region != null && typeof region === \"object\" ? region : {}\r\n}\r\n\r\n/** A range read as a span, whichever way round the author wrote it. */\r\nfunction span([a, b]: Range): Range {\r\n return a <= b ? [a, b] : [b, a]\r\n}\r\n\r\n/**\r\n * Rescale an axis to `range`, keeping the tick *count* it already has, so each\r\n * marker slides from its old value to its new one instead of the row popping.\r\n */\r\nfunction rescale(range: Range, ticks: readonly number[]): AxisDomainConfig {\r\n const to = span(range)\r\n return { range: to, ticks: markerValues(to, Math.max(2, ticks.length) - 1) }\r\n}\r\n\r\n/** The axis writes of a move from `from` toward `to` at `t`. */\r\nfunction axesAt(from: LineChartDomains, to: Partial<Record<\"x\" | \"y\", AxisDomainConfig>>, t: number) {\r\n return {\r\n ...(to.x && { xAxis: lerpAxisDomain(from.x, to.x, t) }),\r\n ...(to.y && { yAxis: lerpAxisDomain(from.y, to.y, t) }),\r\n }\r\n}\r\n\r\ntype AnyTimeline = Timeline<any, any>\r\n\r\n/** The parts a line chart's commands drive, found through its children. */\r\nfunction partsOf(children: readonly ChildView[]) {\r\n const frame = cartesianViews(children)\r\n if (!frame) return null\r\n const hAxis = frame.below.find(HorizontalAxis.is)\r\n if (!VerticalAxis.is(frame.axis) || !hAxis) return null\r\n return {\r\n vAxis: frame.axis,\r\n hAxis,\r\n lines: frame.plot.filter(ChartLine.is),\r\n legend: frame.below.find(ChartLegend.is) ?? null,\r\n }\r\n}\r\n\r\n/** Drop the call-out: the rules retract, the wash fades, and every series comes back to full. */\r\nfunction clearing(timeline: AnyTimeline, state: LineState) {\r\n const from = state.regionReveal\r\n const region = state.region\r\n // Nothing to retract, but the call still takes its slot on the timeline.\r\n if (from === 0) return timeline.animate(() => ({ region: null, regionReveal: 0 }), { eased: false })\r\n // `region` is held until the retraction lands, or there would be nothing left to retract.\r\n return timeline.animate((t) => (t >= 1 ? { region: null, regionReveal: 0 } : { region, regionReveal: from * (1 - t) }))\r\n}\r\n\r\n/** Trace series `index`'s line in (`show`) or back out, in lockstep with its legend entry. */\r\nfunction toggling(timeline: AnyTimeline, children: readonly ChildView[], index: number, show: boolean) {\r\n const parts = partsOf(children)\r\n const line = parts?.lines[index]\r\n if (!parts || !line) return timeline.wait(timeline.duration)\r\n return timeline.together([\r\n line.run(\"enter\", show ? { from: 0, to: 1 } : { from: 1, to: 0 }),\r\n ...(parts.legend ? [parts.legend.run(show ? \"showSeries\" : \"hideSeries\", { index })] : []),\r\n ])\r\n}\r\n\r\n/**\r\n * A multi-series line chart, composed from five independent parts rather than\r\n * one monolithic draw:\r\n *\r\n * - {@link ChartCanvas} — the plot panel with a two-way grid, under everything.\r\n * - {@link VerticalAxis} / {@link HorizontalAxis} — columns/rows of real text\r\n * markers that stagger in, each carrying its own axis caption.\r\n * - {@link ChartRegion} — the optional call-out marking a spotlit slice of the\r\n * plot: dashed rules on its bounded edges, and every series faded outside it.\r\n * - {@link ChartLine} (one per series) — the traced polylines over the canvas.\r\n * - {@link ChartLegend} — a row of entries below the chart, one per series.\r\n *\r\n * Every part reads the chart's entries through bindings, and the lines, the\r\n * region and the grid all map against the plot panel's own laid-out box, so\r\n * points land exactly on their markers and the chart re-flows if its box\r\n * changes.\r\n *\r\n * **Resting state is the finished chart**: an editor paints a node's Initial\r\n * state on a paused canvas. `enter` arms every part on its first frame.\r\n *\r\n * Past the entrance, `showSeries`/`hideSeries`/`spotlightSeries` pick out a\r\n * *series*, `spotlightRegion` marks a *slice of the plot* without changing the\r\n * scale, and `zoomTo` rescales the axes so a slice fills the plot. A spotlit\r\n * region resolves against the live scales, so it travels with a zoom. A `to` of\r\n * an axis `range` or `ticks` tweens from the domain as drawn (see\r\n * {@link lerpAxisEntry}), so an auto axis rescales continuously.\r\n */\r\nexport const LineChart = component2d({\r\n key: \"lineChart\",\r\n state: {\r\n data: fresh<DataRecord[]>(() => [], { kind: \"dataset\" }),\r\n xField: \"\",\r\n series: fresh<LineSeries[]>(() => [], { kind: \"series\" }),\r\n xAxis: Types.custom<AxisDomainConfig>({}, { resolve: resolveAxisDomain, lerp: lerpAxisEntry }),\r\n yAxis: Types.custom<AxisDomainConfig>({}, { resolve: resolveAxisDomain, lerp: lerpAxisEntry }),\r\n theme: Types.custom<ChartTheme, ChartConfig>(DEFAULT_CHART_THEME, { resolve: resolveChartTheme, lerp: lerpChartTheme }),\r\n /**\r\n * The spotlit slice of the plot in data units, or `null` for none. The box\r\n * snaps; the animation is {@link regionReveal} drawing the rules on.\r\n */\r\n region: Types.custom<PlotRegion | null>(null),\r\n /**\r\n * How far the `region` call-out is drawn in, `[0, 1]`: the rules grow out and\r\n * the wash fades up as it climbs, while every line's out-of-region stretch\r\n * fades to the theme's `region.dimOpacity`.\r\n */\r\n regionReveal: 0,\r\n /** Read as the chart is built: the legend is a part the chart builds or doesn't. */\r\n showLegend: Types.boolean(true, { animatable: false }),\r\n /**\r\n * The domain `zoomTo` first left, so `resetZoom` restores the chart as it\r\n * stood, auto-derived ticks included. Cleared by `resetZoom`, so the next zoom\r\n * remembers wherever the chart rests then.\r\n */\r\n home: Types.custom<LineChartDomains | null>(null, { private: true }),\r\n },\r\n // Its parts fill it; a node made of them would hug them.\r\n defaults: { width: \"fill\", height: \"fill\" },\r\n allowedChildren: [],\r\n children: (state) => {\r\n const theme = () => state.theme\r\n const domains = () => lineChartDomains(state)\r\n let plot: Node2D | undefined\r\n const plotSize = () => laidOutSize(plot)\r\n const enabled = state.series.map((s) => s.enabled ?? true)\r\n\r\n // Bound, not snapshotted, so a rescale re-labels and re-places the row as it\r\n // tweens. The marker *count* is read once, which is why `zoomTo` keeps it.\r\n const vAxis = new VerticalAxis({\r\n range: () => domains().y.range,\r\n markers: () => domains().y.ticks,\r\n // The y axis is always numbers, so its format is simply the pattern.\r\n captions: () => {\r\n const markers = domains().y.ticks\r\n const format = state.yAxis.format\r\n return markers.map((value) => (format === undefined ? formatMarker(value, markerStep(markers)) : formatNumber(value, format)))\r\n },\r\n axis: () => theme().yAxis,\r\n label: state.yAxis.label ?? \"\",\r\n width: \"hug\",\r\n height: \"fill\",\r\n })\r\n\r\n const hAxis = new HorizontalAxis({\r\n range: () => domains().x.range,\r\n markers: () => domains().x.ticks,\r\n // A tick on a month or category column is captioned with the cell it came\r\n // out of — `Jan`, not the instant it parsed to.\r\n captions: () => {\r\n const column = columnOf(state)\r\n return domains().x.ticks.map((value) => column.label(value))\r\n },\r\n axis: () => theme().xAxis,\r\n label: state.xAxis.label ?? \"\",\r\n width: \"fill\",\r\n height: \"hug\",\r\n })\r\n\r\n const lines = state.series.map(\r\n (s, i) =>\r\n new ChartLine({\r\n points: () => seriesPixels(state, domains(), i, plotSize()),\r\n stroke: () => resolveSeriesStroke(theme().seriesStyles, s, i),\r\n enabled: enabled[i],\r\n // Each line clips itself against the box the rules are drawn from, so\r\n // the dim/bright boundary can't drift from the dashes.\r\n spotlight: () => regionBox(state, domains(), plotSize()),\r\n // Ramped by the reveal that draws the rules: one signal, both halves.\r\n dimOpacity: () => 1 - (1 - theme().region.dimOpacity) * state.regionReveal,\r\n }) as unknown as Node2D\r\n )\r\n\r\n const below: Node2D[] = [hAxis as unknown as Node2D]\r\n if (state.showLegend !== false) {\r\n below.push(\r\n new ChartLegend({\r\n series: state.series,\r\n // The legend paints a swatch, not a line, so it is handed the colour each\r\n // stroke resolves to rather than the stroke itself.\r\n swatches: () => state.series.map((s, i) => resolveSeriesFill(theme().seriesStyles, s, i)),\r\n legend: () => theme().legend,\r\n // The row's spacing is the theme's as the chart was built, like the\r\n // entries' type and chips: a theme tween re-paints the swatches only.\r\n gap: state.theme.legend.itemGap,\r\n padding: state.theme.legend.padding,\r\n }) as unknown as Node2D\r\n )\r\n }\r\n\r\n plot = new Rect({\r\n clip: true,\r\n children: [\r\n new ChartCanvas({\r\n fill: () => theme().plotArea.fill,\r\n shadow: () => theme().plotArea.shadow,\r\n xGridStroke: () => theme().xAxis.lineStyle,\r\n yGridStroke: () => theme().yAxis.lineStyle,\r\n // A grid line under every axis marker; the canvas skips the edges.\r\n xMarkers: () => domains().x.ticks,\r\n yMarkers: () => domains().y.ticks,\r\n xExtent: () => domains().x.range,\r\n yExtent: () => domains().y.range,\r\n }),\r\n // Over the grid, under the lines, so a spotlit stretch of a series isn't\r\n // tinted by the highlight meant to pick it out.\r\n new ChartRegion({\r\n box: () => regionBox(state, domains(), plotSize()),\r\n stroke: () => theme().region.stroke,\r\n fill: () => theme().region.fill,\r\n reveal: () => state.regionReveal,\r\n }),\r\n ...lines,\r\n new ChartBorder({ stroke: () => theme().plotArea.stroke }),\r\n ],\r\n }) as unknown as Node2D\r\n\r\n const gutter = new VerticalAxis({\r\n opacity: 0,\r\n range: () => domains().y.range,\r\n markers: () => domains().y.ticks,\r\n axis: () => theme().yAxis,\r\n label: state.yAxis.label ?? \"\",\r\n width: \"hug\",\r\n height: 0,\r\n }) as unknown as Node2D\r\n\r\n return asParts([cartesianFrame({ axis: vAxis as unknown as Node2D, plot, gutter, below })])\r\n },\r\n commands: {\r\n /**\r\n * Animate the whole chart in: the two axes stagger their markers in, the\r\n * series lines trace left to right, and the legend fades up last. Its first\r\n * frame arms every part: markers shifted and transparent, lines untraced,\r\n * the legend dropped and transparent.\r\n *\r\n * `duration` is the **whole** entrance; the beats are shares of it. A chart\r\n * authored with a `region` lands its call-out last, in the final quarter.\r\n */\r\n enter: {\r\n args: {},\r\n // Held from the chart's arrival, so it never shows finished ahead of its draw.\r\n entrance: true,\r\n easing: easeOut(),\r\n run: (timeline, state, children) => {\r\n const parts = partsOf(children)\r\n if (!parts) return timeline.wait(timeline.duration)\r\n const duration = timeline.duration\r\n const revealing = hasCallout(state) && state.regionReveal === 0\r\n const body = revealing ? duration * 0.75 : duration\r\n const axes = body * AXES_SHARE\r\n const traced = body * LINES_SHARE\r\n const { legend } = parts\r\n const at0 = (piece: Beat[\"piece\"]): Beat => ({ at: 0, duration: 0, piece })\r\n // The first frame arms what every later beat moves: a beat ahead of the\r\n // playhead writes nothing. A beat with nothing to do still takes its share.\r\n return beats(timeline, [\r\n ...(revealing ? [at0(timeline.animate(() => ({ regionReveal: 0 })))] : []),\r\n ...parts.lines.map((line) => at0(line.to({ progress: 0 }))),\r\n ...(legend ? [at0(legend.to({ opacity: 0, y: -LEGEND_SLIDE }))] : []),\r\n { at: 0, duration: axes, piece: parts.vAxis.run(\"enter\", { slide: 24 }) },\r\n { at: 0, duration: axes, piece: parts.hAxis.run(\"enter\", { slide: 24 }) },\r\n ...parts.lines.map((line) => ({ at: axes, duration: traced, piece: line.run(\"enter\") })),\r\n ...(legend ? [{ at: axes + traced, duration: body * LEGEND_SHARE, piece: legend.to({ opacity: 1, y: 0 }) }] : []),\r\n ...(revealing ? [{ at: body, duration: duration * 0.25, piece: timeline.animate((t) => ({ regionReveal: t })) }] : []),\r\n ])\r\n },\r\n },\r\n /**\r\n * Spotlight a rectangular slice of the plot given in **data units**: dashed\r\n * rules draw onto each bounded edge while every series fades outside the box.\r\n * Either axis alone is a band; both are a box. Called while another region is\r\n * up, the old call-out retracts over the first half and the new one draws in\r\n * over the second, each half eased on its own.\r\n */\r\n spotlightRegion: {\r\n args: { region: REGION_ARG },\r\n easing: easeOut(),\r\n run: (timeline, state) => {\r\n const region = regionArg(timeline.args.region)\r\n const from = state.regionReveal\r\n const previous = state.region\r\n // A region bounding neither axis is no call-out: spotlighting it is a clear.\r\n if (region.x === undefined && region.y === undefined) return clearing(timeline, state)\r\n // Nothing up yet: the region is set from the first frame and just draws on.\r\n if (from <= 0 || !hasCallout(state)) return timeline.animate((t) => ({ region, regionReveal: from + (1 - from) * t }))\r\n return timeline.animate(\r\n (t) => (t < 0.5\r\n ? { region: previous, regionReveal: from * (1 - timeline.ease(t * 2)) }\r\n : { region, regionReveal: timeline.ease(t * 2 - 1) }),\r\n { eased: false }\r\n )\r\n },\r\n },\r\n /** Drop the region call-out. A no-op when nothing is spotlit, which still takes its slot. */\r\n clearRegion: {\r\n args: {},\r\n easing: easeOut(),\r\n run: (timeline, state) => clearing(timeline, state),\r\n },\r\n /**\r\n * Zoom the plot to a slice of itself, given in **data units**: the named axes\r\n * rescale so that slice fills the plot, the grid, both marker rows and every\r\n * series following. An omitted axis is left as it is. The first zoom\r\n * remembers the domain it left, for `resetZoom`.\r\n */\r\n zoomTo: {\r\n args: { region: REGION_ARG },\r\n easing: easeOut(),\r\n run: (timeline, state) => {\r\n const region = regionArg(timeline.args.region)\r\n if (!region.x && !region.y) return timeline.wait(timeline.duration)\r\n const from = lineChartDomains(state)\r\n const home = state.home ?? from\r\n const to = {\r\n ...(region.x && { x: { ...from.x, ...rescale(region.x, from.x.ticks) } }),\r\n ...(region.y && { y: { ...from.y, ...rescale(region.y, from.y.ticks) } }),\r\n }\r\n return timeline.animate((t) => ({ home, ...axesAt(from, to, t) }))\r\n },\r\n },\r\n /** Pull back out to the domain the first zoom left — the mirror of `zoomTo`, and a hold if it never zoomed. */\r\n resetZoom: {\r\n args: {},\r\n easing: easeOut(),\r\n run: (timeline, state) => {\r\n const home = state.home\r\n if (!home) return timeline.wait(timeline.duration)\r\n const from = lineChartDomains(state)\r\n return timeline.animate((t) => ({ home: null, ...axesAt(from, home, t) }))\r\n },\r\n },\r\n /**\r\n * Show series `index`: **trace** its line in left to right, in lockstep with\r\n * its legend entry growing in.\r\n */\r\n showSeries: {\r\n args: { seriesIndex: SERIES_ARG },\r\n easing: easeOut(),\r\n run: (timeline, _state, children) => toggling(timeline, children, timeline.args.seriesIndex, true),\r\n },\r\n /** Hide series `index`: **retrace** its line back out as its legend entry shrinks away. */\r\n hideSeries: {\r\n args: { seriesIndex: SERIES_ARG },\r\n easing: easeOut(),\r\n run: (timeline, _state, children) => toggling(timeline, children, timeline.args.seriesIndex, false),\r\n },\r\n /**\r\n * Fade every other series — each line **and its legend entry** — to focus on\r\n * `index`, which comes back to full. The legend dims in place, so the row\r\n * doesn't reflow.\r\n */\r\n spotlightSeries: {\r\n args: { seriesIndex: SERIES_ARG },\r\n easing: easeOut(),\r\n run: (timeline, _state, children) => {\r\n const parts = partsOf(children)\r\n if (!parts) return timeline.wait(timeline.duration)\r\n const index = timeline.args.seriesIndex\r\n return timeline.together([\r\n ...parts.lines.map((line, i) => line.to({ opacity: i === index ? 1 : SPOTLIGHT_DIM })),\r\n ...(parts.legend ? [parts.legend.run(\"spotlightSeries\", { index })] : []),\r\n ])\r\n },\r\n },\r\n },\r\n})\r\n\r\nexport type LineChart = NodeOf<typeof LineChart>\r\n"]}
|
|
@@ -70,15 +70,8 @@ export declare function formatInstant(value: number, span: number): string;
|
|
|
70
70
|
* How `field` positions the rows: the number it holds, the instant it names, or
|
|
71
71
|
* failing both, the row's own place in the file.
|
|
72
72
|
*
|
|
73
|
-
*
|
|
74
|
-
*
|
|
75
|
-
* array that a rebuild replaces on every edit would miss every time anyway.
|
|
73
|
+
* Kept per `data` array: a chart's bound props ask a dozen times a frame, and
|
|
74
|
+
* parsing every row's instant each time was most of a frame.
|
|
76
75
|
*/
|
|
77
|
-
export declare function resolveXScale(data: DataRecord[], field: string,
|
|
78
|
-
/**
|
|
79
|
-
* The number-format pattern for a *numeric* column. Ignored by the other two
|
|
80
|
-
* kinds, and correctly so: a tick on those is captioned with the cell the
|
|
81
|
-
* author wrote, and `Jan` has no decimal places.
|
|
82
|
-
*/
|
|
83
|
-
pattern?: string): XScale;
|
|
76
|
+
export declare function resolveXScale(data: DataRecord[], field: string, pattern?: string): XScale;
|
|
84
77
|
//# sourceMappingURL=x-scale.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"x-scale.d.ts","sourceRoot":"","sources":["../../src/line-chart/x-scale.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAA;AAEnD,OAAO,EAKL,KAAK,KAAK,EACX,MAAM,eAAe,CAAA;AAGtB,+DAA+D;AAC/D,MAAM,MAAM,UAAU,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAAA;AAEvD;;;;;GAKG;AACH,MAAM,WAAW,MAAM;IACrB,IAAI,EAAE,UAAU,CAAA;IAChB,yEAAyE;IACzE,EAAE,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAAA;IACzB,qEAAqE;IACrE,MAAM,EAAE,KAAK,CAAA;IACb,yCAAyC;IACzC,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAAA;IAC5B,mEAAmE;IACnE,KAAK,CAAC,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,EAAE,CAAA;CACjD;AAmDD;;;;;;;;;GASG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAkDxD;AAED;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAQjE;
|
|
1
|
+
{"version":3,"file":"x-scale.d.ts","sourceRoot":"","sources":["../../src/line-chart/x-scale.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAA;AAEnD,OAAO,EAKL,KAAK,KAAK,EACX,MAAM,eAAe,CAAA;AAGtB,+DAA+D;AAC/D,MAAM,MAAM,UAAU,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAAA;AAEvD;;;;;GAKG;AACH,MAAM,WAAW,MAAM;IACrB,IAAI,EAAE,UAAU,CAAA;IAChB,yEAAyE;IACzE,EAAE,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAAA;IACzB,qEAAqE;IACrE,MAAM,EAAE,KAAK,CAAA;IACb,yCAAyC;IACzC,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAAA;IAC5B,mEAAmE;IACnE,KAAK,CAAC,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,EAAE,CAAA;CACjD;AAmDD;;;;;;;;;GASG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAkDxD;AAED;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAQjE;AA0HD;;;;;;GAMG;AACH,wBAAgB,aAAa,CAC3B,IAAI,EAAE,UAAU,EAAE,EAClB,KAAK,EAAE,MAAM,EACb,OAAO,CAAC,EAAE,MAAM,GACf,MAAM,CAOR"}
|
|
@@ -248,15 +248,26 @@ function labelBySample(positions, captions, value, fallback) {
|
|
|
248
248
|
const i = positions.indexOf(value);
|
|
249
249
|
return i >= 0 ? captions[i] : fallback(value);
|
|
250
250
|
}
|
|
251
|
+
/** Scales already resolved, by data array, then by field and pattern. */
|
|
252
|
+
const scales = new WeakMap();
|
|
251
253
|
/**
|
|
252
254
|
* How `field` positions the rows: the number it holds, the instant it names, or
|
|
253
255
|
* failing both, the row's own place in the file.
|
|
254
256
|
*
|
|
255
|
-
*
|
|
256
|
-
*
|
|
257
|
-
* array that a rebuild replaces on every edit would miss every time anyway.
|
|
257
|
+
* Kept per `data` array: a chart's bound props ask a dozen times a frame, and
|
|
258
|
+
* parsing every row's instant each time was most of a frame.
|
|
258
259
|
*/
|
|
259
|
-
export function resolveXScale(data, field,
|
|
260
|
+
export function resolveXScale(data, field, pattern) {
|
|
261
|
+
let byKey = scales.get(data);
|
|
262
|
+
if (!byKey)
|
|
263
|
+
scales.set(data, (byKey = new Map()));
|
|
264
|
+
const key = JSON.stringify([field, pattern ?? null]);
|
|
265
|
+
let scale = byKey.get(key);
|
|
266
|
+
if (!scale)
|
|
267
|
+
byKey.set(key, (scale = xScaleOf(data, field, pattern)));
|
|
268
|
+
return scale;
|
|
269
|
+
}
|
|
270
|
+
function xScaleOf(data, field,
|
|
260
271
|
/**
|
|
261
272
|
* The number-format pattern for a *numeric* column. Ignored by the other two
|
|
262
273
|
* kinds, and correctly so: a tick on those is captioned with the cell the
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"x-scale.js","sourceRoot":"","sources":["../../src/line-chart/x-scale.ts"],"names":[],"mappings":"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","sourcesContent":["/**\r\n * What a line chart's x column *means* — the one question that has to be\r\n * answered before a row can be given a position along the bottom of the plot.\r\n *\r\n * A y column is always a magnitude. An x column is one of three things, and\r\n * which one is a property of the data rather than something the author states:\r\n *\r\n * - **numeric** — `0, 5, 10` — plot the number.\r\n * - **time** — `Jan`, `2026-03`, `2026-W12`, `2026-03-14` — plot the instant,\r\n * so samples a month apart sit a month apart and a gap in the data reads as a\r\n * gap.\r\n * - **ordinal** — anything else — plot the row's position, evenly spaced.\r\n *\r\n * Before this, every x column went through `num()`, which reads a non-numeric\r\n * cell as `0`. A `Month` column of `Jan…Dec` therefore stacked all twelve\r\n * points on one x and drew a vertical line — no error, no empty chart, just a\r\n * wrong picture. That is the failure this module exists to remove: every column\r\n * now plots as *something*, and the something is the reading a person would\r\n * give it.\r\n *\r\n * The captions come back off the rows rather than out of a formatter. A tick on\r\n * a time or ordinal scale is chosen *from the data* (see {@link XScale.ticks}),\r\n * so the label it wants is the cell the author wrote — `Jan`, not `1970-01-01`,\r\n * and `2026-W12`, not the Monday it resolves to. Only a tick that is not a\r\n * sample — an author-set range, or a `zoomTo` mid-flight — needs formatting,\r\n * and that is the one case {@link formatInstant} covers.\r\n */\r\n\r\nimport type { DataRecord } from \"@motionscript/sdk\"\r\n\r\nimport {\r\n formatMarker,\r\n markerValues,\r\n num,\r\n text,\r\n type Range,\r\n} from \"../kit/shared\"\r\nimport { formatNumber } from \"@motionscript/sdk/component\"\r\n\r\n/** How an x column's cells become positions along the axis. */\r\nexport type XScaleKind = \"numeric\" | \"time\" | \"ordinal\"\r\n\r\n/**\r\n * An x column resolved into positions, captions and ticks.\r\n *\r\n * The three kinds differ in all three answers, so they are three closures built\r\n * once per (data, column) rather than a kind tag every caller switches on.\r\n */\r\nexport interface XScale {\r\n kind: XScaleKind\r\n /** Position of row `index` along the axis, in this scale's own units. */\r\n at(index: number): number\r\n /** `[min, max]` across the rows — the scale when no range is set. */\r\n extent: Range\r\n /** The caption for a tick at `value`. */\r\n label(value: number): string\r\n /** `divisions + 1` tick values spanning `range`, ends included. */\r\n ticks(range: Range, divisions: number): number[]\r\n}\r\n\r\n// ---- Time parsing --------------------------------------------------------\r\n\r\nconst DAY = 86_400_000\r\n\r\nconst MONTHS = [\r\n \"january\",\r\n \"february\",\r\n \"march\",\r\n \"april\",\r\n \"may\",\r\n \"june\",\r\n \"july\",\r\n \"august\",\r\n \"september\",\r\n \"october\",\r\n \"november\",\r\n \"december\",\r\n]\r\n\r\n/**\r\n * The year a cell that names no year is dated into.\r\n *\r\n * Any year would place `Jan…Dec` in the right order at the right spacing; a\r\n * leap year is the one that also spaces February correctly against a column\r\n * that *does* carry years, so the two read alike.\r\n */\r\nconst NOMINAL_YEAR = 2024\r\n\r\n/**\r\n * Month index for any unambiguous abbreviation of a month name — `jan`, `sept`,\r\n * `january` — or -1.\r\n *\r\n * Three letters minimum, and then a prefix match, which is what lets `sept`\r\n * through without letting `janitor` through: a longer word has to still *be*\r\n * the month.\r\n */\r\nfunction monthIndex(word: string): number {\r\n if (word.length < 3) return -1\r\n return MONTHS.findIndex((month) => month.startsWith(word))\r\n}\r\n\r\n/** The Monday of ISO week `week` in `year`, as an epoch timestamp. */\r\nfunction isoWeekStart(year: number, week: number): number {\r\n // ISO week 1 is the week containing 4 January, and weeks start on Monday.\r\n const jan4 = Date.UTC(year, 0, 4)\r\n const weekday = (new Date(jan4).getUTCDay() + 6) % 7 // Monday = 0\r\n return jan4 - weekday * DAY + (week - 1) * 7 * DAY\r\n}\r\n\r\n/**\r\n * One cell read as an instant, or `null` when it isn't one.\r\n *\r\n * Deliberately **not** `Date.parse`. That accepts `\"5\"`, `\"Q3\"` and a good deal\r\n * else besides, differs between engines on anything non-ISO, and reads a bare\r\n * `2026-03-14` as UTC but `2026/03/14` as local — three ways for a column to be\r\n * silently misread as time. Every form below is matched explicitly, and an\r\n * ambiguous all-numeric date (`03/04/2026` — March or April, depending on where\r\n * the author lives) is deliberately not one of them.\r\n */\r\nexport function parseInstant(raw: unknown): number | null {\r\n if (typeof raw !== \"string\") return null\r\n const s = raw.trim().toLowerCase()\r\n if (s === \"\") return null\r\n\r\n // 2026-03-14 · 2026/03/14 · 2026-03 · 2026/03\r\n const ymd = /^(\\d{4})[-/](\\d{1,2})(?:[-/](\\d{1,2}))?$/.exec(s)\r\n if (ymd) {\r\n const month = Number(ymd[2])\r\n const day = ymd[3] === undefined ? 1 : Number(ymd[3])\r\n if (month < 1 || month > 12 || day < 1 || day > 31) return null\r\n return Date.UTC(Number(ymd[1]), month - 1, day)\r\n }\r\n\r\n // 2026-W12 · 2026W12 · w12 · week 12\r\n const week = /^(?:(\\d{4})[-\\s]?)?w(?:ee)?k?[-\\s]?(\\d{1,2})$/.exec(s)\r\n if (week) {\r\n const n = Number(week[2])\r\n if (n < 1 || n > 53) return null\r\n return isoWeekStart(\r\n week[1] === undefined ? NOMINAL_YEAR : Number(week[1]),\r\n n\r\n )\r\n }\r\n\r\n // jan · january · jan 2026 · january-2026 · 2026 jan\r\n const named = /^(?:(\\d{4})[-\\s]+)?([a-z]+)(?:[-\\s]+(\\d{4}))?$/.exec(s)\r\n if (named) {\r\n const month = monthIndex(named[2])\r\n if (month >= 0) {\r\n const year = named[1] ?? named[3]\r\n const y = year === undefined ? NOMINAL_YEAR : Number(year)\r\n return Date.UTC(y, month, 1)\r\n }\r\n }\r\n\r\n // 14 mar 2026 · mar 14 2026 · mar 14, 2026\r\n const dayNamed =\r\n /^(?:(\\d{1,2})[-\\s]+([a-z]+)|([a-z]+)[-\\s]+(\\d{1,2}),?)[-\\s]+(\\d{4})$/.exec(\r\n s\r\n )\r\n if (dayNamed) {\r\n const month = monthIndex(dayNamed[2] ?? dayNamed[3])\r\n const day = Number(dayNamed[1] ?? dayNamed[4])\r\n if (month >= 0 && day >= 1 && day <= 31) {\r\n return Date.UTC(Number(dayNamed[5]), month, day)\r\n }\r\n }\r\n\r\n return null\r\n}\r\n\r\n/**\r\n * An instant captioned at the coarsest granularity the axis's own span can tell\r\n * apart — a decade of samples reads as years, a year of them as months.\r\n *\r\n * Only reached for a tick that is *not* one of the rows (an author-set range, a\r\n * `zoomTo` part-way through). A tick that is a sample is captioned with the\r\n * cell the author wrote; see the note at the top of this file.\r\n */\r\nexport function formatInstant(value: number, span: number): string {\r\n const date = new Date(value)\r\n const year = date.getUTCFullYear()\r\n const month = MONTHS[date.getUTCMonth()].slice(0, 3)\r\n const label = month.charAt(0).toUpperCase() + month.slice(1)\r\n if (span > 4 * 365 * DAY) return String(year)\r\n if (span > 60 * DAY) return `${label} ${year}`\r\n return `${label} ${date.getUTCDate()}`\r\n}\r\n\r\n// ---- Column reading ------------------------------------------------------\r\n\r\n/**\r\n * Whether every non-empty cell of `field` holds a number.\r\n *\r\n * The same rule `numericFields` applies, asked of one column: a single text\r\n * cell in an otherwise numeric column takes the whole column off the numeric\r\n * scale, because plotting that row at 0 is the failure this module is here to\r\n * stop.\r\n */\r\nfunction isNumericColumn(data: DataRecord[], field: string): boolean {\r\n let sawValue = false\r\n for (const row of data) {\r\n const v = row[field]\r\n if (v === undefined || v === null || v === \"\") continue\r\n if (typeof v !== \"number\") return false\r\n sawValue = true\r\n }\r\n return sawValue\r\n}\r\n\r\n/**\r\n * Every non-empty cell of `field` parsed as an instant, or `null` if any one of\r\n * them isn't one — in which case the column isn't a time column at all.\r\n *\r\n * A blank cell keeps its slot, so the returned list stays index-aligned with\r\n * the rows, and takes the nearest known instant: a hole in an x column is a row\r\n * whose date the file didn't say, and stacking it on the epoch would drag the\r\n * whole scale back fifty years to make room for it.\r\n */\r\nfunction instantColumn(data: DataRecord[], field: string): number[] | null {\r\n const parsed: (number | null)[] = []\r\n let sawValue = false\r\n for (const row of data) {\r\n const raw = row[field]\r\n if (raw === undefined || raw === null || raw === \"\") {\r\n parsed.push(null)\r\n continue\r\n }\r\n const t = parseInstant(raw)\r\n if (t === null) return null\r\n parsed.push(t)\r\n sawValue = true\r\n }\r\n if (!sawValue) return null\r\n\r\n const first = parsed.find((t): t is number => t !== null) as number\r\n let last = first\r\n return parsed.map((t) => (t === null ? last : (last = t)))\r\n}\r\n\r\n/** `[min, max]` of `values`, or `[0, 1]` when there is nothing to span. */\r\nfunction extentOf(values: number[]): Range {\r\n let lo = Infinity\r\n let hi = -Infinity\r\n for (const v of values) {\r\n if (v < lo) lo = v\r\n if (v > hi) hi = v\r\n }\r\n return lo <= hi ? [lo, hi] : [0, 1]\r\n}\r\n\r\n/**\r\n * Ticks spanning `range`, each one **a sample** — a row the author can point at\r\n * in their file — placed as near as it can be to where an evenly spaced tick\r\n * would have gone.\r\n *\r\n * Two things have to hold at once, and picking either alone gets it wrong.\r\n * Ticks must be *samples*, because a caption between two of them has nothing to\r\n * say (two-thirds of the way through March is not a month, and on a category\r\n * column it is not anything at all). And they must be *spread*, because the\r\n * labels sit side by side in a row: taking every nth sample instead puts five\r\n * dates in the two weeks a burst of rows happens to cover and prints them on\r\n * top of each other, which is what a column with a gap in it does.\r\n *\r\n * Walking the targets rather than the samples is what satisfies both. A run of\r\n * rows too close together to caption collapses to one tick — consecutive\r\n * targets pick the same sample and the duplicate is dropped — so a chart asked\r\n * for five ticks across a gappy column draws four honest ones instead of five\r\n * overlapping.\r\n */\r\nfunction sampledTicks(\r\n positions: number[],\r\n [min, max]: Range,\r\n divisions: number\r\n): number[] {\r\n const inside = positions.filter((v) => v >= min && v <= max)\r\n const unique = [...new Set(inside)].sort((a, b) => a - b)\r\n if (unique.length === 0) return markerValues([min, max], divisions)\r\n\r\n const nearest = (target: number) =>\r\n unique.reduce((best, v) =>\r\n Math.abs(v - target) < Math.abs(best - target) ? v : best\r\n )\r\n\r\n const out: number[] = []\r\n for (const target of markerValues([min, max], divisions)) {\r\n const tick = nearest(target)\r\n if (out[out.length - 1] !== tick) out.push(tick)\r\n }\r\n return out\r\n}\r\n\r\n/**\r\n * The caption a tick carries on a sample-based scale: the cell of the row it\r\n * came from, or `fallback` when the tick isn't a sample after all.\r\n */\r\nfunction labelBySample(\r\n positions: number[],\r\n captions: string[],\r\n value: number,\r\n fallback: (value: number) => string\r\n): string {\r\n const i = positions.indexOf(value)\r\n return i >= 0 ? captions[i] : fallback(value)\r\n}\r\n\r\n/**\r\n * How `field` positions the rows: the number it holds, the instant it names, or\r\n * failing both, the row's own place in the file.\r\n *\r\n * Resolved from the data on every read rather than cached on the node: it is\r\n * cheap (one pass to classify, one to position), and a cache keyed on a `data`\r\n * array that a rebuild replaces on every edit would miss every time anyway.\r\n */\r\nexport function resolveXScale(\r\n data: DataRecord[],\r\n field: string,\r\n /**\r\n * The number-format pattern for a *numeric* column. Ignored by the other two\r\n * kinds, and correctly so: a tick on those is captioned with the cell the\r\n * author wrote, and `Jan` has no decimal places.\r\n */\r\n pattern?: string\r\n): XScale {\r\n if (field !== \"\" && isNumericColumn(data, field)) {\r\n const positions = data.map((row) => num(row, field))\r\n return {\r\n kind: \"numeric\",\r\n at: (i) => positions[i] ?? 0,\r\n extent: extentOf(positions),\r\n label: (value) =>\r\n pattern === undefined ? formatMarker(value) : formatNumber(value, pattern),\r\n // Round numbers, evenly spaced — a continuous axis is read by its scale\r\n // rather than by which samples happen to be on it.\r\n ticks: markerValues,\r\n }\r\n }\r\n\r\n const captions = data.map((row) => text(row, field))\r\n const instants = field === \"\" ? null : instantColumn(data, field)\r\n\r\n if (instants) {\r\n const extent = extentOf(instants)\r\n const span = extent[1] - extent[0]\r\n return {\r\n kind: \"time\",\r\n at: (i) => instants[i] ?? 0,\r\n extent,\r\n label: (value) =>\r\n labelBySample(instants, captions, value, (v) =>\r\n formatInstant(v, span)\r\n ),\r\n ticks: (range, divisions) => sampledTicks(instants, range, divisions),\r\n }\r\n }\r\n\r\n const positions = data.map((_, i) => i)\r\n return {\r\n kind: \"ordinal\",\r\n at: (i) => i,\r\n // `[0, n-1]` rather than the tidy `[0, n]`: the first and last rows sit on\r\n // the plot's edges, which is where a reader looks for them.\r\n extent: positions.length > 0 ? [0, positions.length - 1] : [0, 1],\r\n label: (value) => captions[Math.round(value)] ?? \"\",\r\n ticks: (range, divisions) => sampledTicks(positions, range, divisions),\r\n }\r\n}\r\n"]}
|
|
1
|
+
{"version":3,"file":"x-scale.js","sourceRoot":"","sources":["../../src/line-chart/x-scale.ts"],"names":[],"mappings":"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","sourcesContent":["/**\r\n * What a line chart's x column *means* — the one question that has to be\r\n * answered before a row can be given a position along the bottom of the plot.\r\n *\r\n * A y column is always a magnitude. An x column is one of three things, and\r\n * which one is a property of the data rather than something the author states:\r\n *\r\n * - **numeric** — `0, 5, 10` — plot the number.\r\n * - **time** — `Jan`, `2026-03`, `2026-W12`, `2026-03-14` — plot the instant,\r\n * so samples a month apart sit a month apart and a gap in the data reads as a\r\n * gap.\r\n * - **ordinal** — anything else — plot the row's position, evenly spaced.\r\n *\r\n * Before this, every x column went through `num()`, which reads a non-numeric\r\n * cell as `0`. A `Month` column of `Jan…Dec` therefore stacked all twelve\r\n * points on one x and drew a vertical line — no error, no empty chart, just a\r\n * wrong picture. That is the failure this module exists to remove: every column\r\n * now plots as *something*, and the something is the reading a person would\r\n * give it.\r\n *\r\n * The captions come back off the rows rather than out of a formatter. A tick on\r\n * a time or ordinal scale is chosen *from the data* (see {@link XScale.ticks}),\r\n * so the label it wants is the cell the author wrote — `Jan`, not `1970-01-01`,\r\n * and `2026-W12`, not the Monday it resolves to. Only a tick that is not a\r\n * sample — an author-set range, or a `zoomTo` mid-flight — needs formatting,\r\n * and that is the one case {@link formatInstant} covers.\r\n */\r\n\r\nimport type { DataRecord } from \"@motionscript/sdk\"\r\n\r\nimport {\r\n formatMarker,\r\n markerValues,\r\n num,\r\n text,\r\n type Range,\r\n} from \"../kit/shared\"\r\nimport { formatNumber } from \"@motionscript/sdk/component\"\r\n\r\n/** How an x column's cells become positions along the axis. */\r\nexport type XScaleKind = \"numeric\" | \"time\" | \"ordinal\"\r\n\r\n/**\r\n * An x column resolved into positions, captions and ticks.\r\n *\r\n * The three kinds differ in all three answers, so they are three closures built\r\n * once per (data, column) rather than a kind tag every caller switches on.\r\n */\r\nexport interface XScale {\r\n kind: XScaleKind\r\n /** Position of row `index` along the axis, in this scale's own units. */\r\n at(index: number): number\r\n /** `[min, max]` across the rows — the scale when no range is set. */\r\n extent: Range\r\n /** The caption for a tick at `value`. */\r\n label(value: number): string\r\n /** `divisions + 1` tick values spanning `range`, ends included. */\r\n ticks(range: Range, divisions: number): number[]\r\n}\r\n\r\n// ---- Time parsing --------------------------------------------------------\r\n\r\nconst DAY = 86_400_000\r\n\r\nconst MONTHS = [\r\n \"january\",\r\n \"february\",\r\n \"march\",\r\n \"april\",\r\n \"may\",\r\n \"june\",\r\n \"july\",\r\n \"august\",\r\n \"september\",\r\n \"october\",\r\n \"november\",\r\n \"december\",\r\n]\r\n\r\n/**\r\n * The year a cell that names no year is dated into.\r\n *\r\n * Any year would place `Jan…Dec` in the right order at the right spacing; a\r\n * leap year is the one that also spaces February correctly against a column\r\n * that *does* carry years, so the two read alike.\r\n */\r\nconst NOMINAL_YEAR = 2024\r\n\r\n/**\r\n * Month index for any unambiguous abbreviation of a month name — `jan`, `sept`,\r\n * `january` — or -1.\r\n *\r\n * Three letters minimum, and then a prefix match, which is what lets `sept`\r\n * through without letting `janitor` through: a longer word has to still *be*\r\n * the month.\r\n */\r\nfunction monthIndex(word: string): number {\r\n if (word.length < 3) return -1\r\n return MONTHS.findIndex((month) => month.startsWith(word))\r\n}\r\n\r\n/** The Monday of ISO week `week` in `year`, as an epoch timestamp. */\r\nfunction isoWeekStart(year: number, week: number): number {\r\n // ISO week 1 is the week containing 4 January, and weeks start on Monday.\r\n const jan4 = Date.UTC(year, 0, 4)\r\n const weekday = (new Date(jan4).getUTCDay() + 6) % 7 // Monday = 0\r\n return jan4 - weekday * DAY + (week - 1) * 7 * DAY\r\n}\r\n\r\n/**\r\n * One cell read as an instant, or `null` when it isn't one.\r\n *\r\n * Deliberately **not** `Date.parse`. That accepts `\"5\"`, `\"Q3\"` and a good deal\r\n * else besides, differs between engines on anything non-ISO, and reads a bare\r\n * `2026-03-14` as UTC but `2026/03/14` as local — three ways for a column to be\r\n * silently misread as time. Every form below is matched explicitly, and an\r\n * ambiguous all-numeric date (`03/04/2026` — March or April, depending on where\r\n * the author lives) is deliberately not one of them.\r\n */\r\nexport function parseInstant(raw: unknown): number | null {\r\n if (typeof raw !== \"string\") return null\r\n const s = raw.trim().toLowerCase()\r\n if (s === \"\") return null\r\n\r\n // 2026-03-14 · 2026/03/14 · 2026-03 · 2026/03\r\n const ymd = /^(\\d{4})[-/](\\d{1,2})(?:[-/](\\d{1,2}))?$/.exec(s)\r\n if (ymd) {\r\n const month = Number(ymd[2])\r\n const day = ymd[3] === undefined ? 1 : Number(ymd[3])\r\n if (month < 1 || month > 12 || day < 1 || day > 31) return null\r\n return Date.UTC(Number(ymd[1]), month - 1, day)\r\n }\r\n\r\n // 2026-W12 · 2026W12 · w12 · week 12\r\n const week = /^(?:(\\d{4})[-\\s]?)?w(?:ee)?k?[-\\s]?(\\d{1,2})$/.exec(s)\r\n if (week) {\r\n const n = Number(week[2])\r\n if (n < 1 || n > 53) return null\r\n return isoWeekStart(\r\n week[1] === undefined ? NOMINAL_YEAR : Number(week[1]),\r\n n\r\n )\r\n }\r\n\r\n // jan · january · jan 2026 · january-2026 · 2026 jan\r\n const named = /^(?:(\\d{4})[-\\s]+)?([a-z]+)(?:[-\\s]+(\\d{4}))?$/.exec(s)\r\n if (named) {\r\n const month = monthIndex(named[2])\r\n if (month >= 0) {\r\n const year = named[1] ?? named[3]\r\n const y = year === undefined ? NOMINAL_YEAR : Number(year)\r\n return Date.UTC(y, month, 1)\r\n }\r\n }\r\n\r\n // 14 mar 2026 · mar 14 2026 · mar 14, 2026\r\n const dayNamed =\r\n /^(?:(\\d{1,2})[-\\s]+([a-z]+)|([a-z]+)[-\\s]+(\\d{1,2}),?)[-\\s]+(\\d{4})$/.exec(\r\n s\r\n )\r\n if (dayNamed) {\r\n const month = monthIndex(dayNamed[2] ?? dayNamed[3])\r\n const day = Number(dayNamed[1] ?? dayNamed[4])\r\n if (month >= 0 && day >= 1 && day <= 31) {\r\n return Date.UTC(Number(dayNamed[5]), month, day)\r\n }\r\n }\r\n\r\n return null\r\n}\r\n\r\n/**\r\n * An instant captioned at the coarsest granularity the axis's own span can tell\r\n * apart — a decade of samples reads as years, a year of them as months.\r\n *\r\n * Only reached for a tick that is *not* one of the rows (an author-set range, a\r\n * `zoomTo` part-way through). A tick that is a sample is captioned with the\r\n * cell the author wrote; see the note at the top of this file.\r\n */\r\nexport function formatInstant(value: number, span: number): string {\r\n const date = new Date(value)\r\n const year = date.getUTCFullYear()\r\n const month = MONTHS[date.getUTCMonth()].slice(0, 3)\r\n const label = month.charAt(0).toUpperCase() + month.slice(1)\r\n if (span > 4 * 365 * DAY) return String(year)\r\n if (span > 60 * DAY) return `${label} ${year}`\r\n return `${label} ${date.getUTCDate()}`\r\n}\r\n\r\n// ---- Column reading ------------------------------------------------------\r\n\r\n/**\r\n * Whether every non-empty cell of `field` holds a number.\r\n *\r\n * The same rule `numericFields` applies, asked of one column: a single text\r\n * cell in an otherwise numeric column takes the whole column off the numeric\r\n * scale, because plotting that row at 0 is the failure this module is here to\r\n * stop.\r\n */\r\nfunction isNumericColumn(data: DataRecord[], field: string): boolean {\r\n let sawValue = false\r\n for (const row of data) {\r\n const v = row[field]\r\n if (v === undefined || v === null || v === \"\") continue\r\n if (typeof v !== \"number\") return false\r\n sawValue = true\r\n }\r\n return sawValue\r\n}\r\n\r\n/**\r\n * Every non-empty cell of `field` parsed as an instant, or `null` if any one of\r\n * them isn't one — in which case the column isn't a time column at all.\r\n *\r\n * A blank cell keeps its slot, so the returned list stays index-aligned with\r\n * the rows, and takes the nearest known instant: a hole in an x column is a row\r\n * whose date the file didn't say, and stacking it on the epoch would drag the\r\n * whole scale back fifty years to make room for it.\r\n */\r\nfunction instantColumn(data: DataRecord[], field: string): number[] | null {\r\n const parsed: (number | null)[] = []\r\n let sawValue = false\r\n for (const row of data) {\r\n const raw = row[field]\r\n if (raw === undefined || raw === null || raw === \"\") {\r\n parsed.push(null)\r\n continue\r\n }\r\n const t = parseInstant(raw)\r\n if (t === null) return null\r\n parsed.push(t)\r\n sawValue = true\r\n }\r\n if (!sawValue) return null\r\n\r\n const first = parsed.find((t): t is number => t !== null) as number\r\n let last = first\r\n return parsed.map((t) => (t === null ? last : (last = t)))\r\n}\r\n\r\n/** `[min, max]` of `values`, or `[0, 1]` when there is nothing to span. */\r\nfunction extentOf(values: number[]): Range {\r\n let lo = Infinity\r\n let hi = -Infinity\r\n for (const v of values) {\r\n if (v < lo) lo = v\r\n if (v > hi) hi = v\r\n }\r\n return lo <= hi ? [lo, hi] : [0, 1]\r\n}\r\n\r\n/**\r\n * Ticks spanning `range`, each one **a sample** — a row the author can point at\r\n * in their file — placed as near as it can be to where an evenly spaced tick\r\n * would have gone.\r\n *\r\n * Two things have to hold at once, and picking either alone gets it wrong.\r\n * Ticks must be *samples*, because a caption between two of them has nothing to\r\n * say (two-thirds of the way through March is not a month, and on a category\r\n * column it is not anything at all). And they must be *spread*, because the\r\n * labels sit side by side in a row: taking every nth sample instead puts five\r\n * dates in the two weeks a burst of rows happens to cover and prints them on\r\n * top of each other, which is what a column with a gap in it does.\r\n *\r\n * Walking the targets rather than the samples is what satisfies both. A run of\r\n * rows too close together to caption collapses to one tick — consecutive\r\n * targets pick the same sample and the duplicate is dropped — so a chart asked\r\n * for five ticks across a gappy column draws four honest ones instead of five\r\n * overlapping.\r\n */\r\nfunction sampledTicks(\r\n positions: number[],\r\n [min, max]: Range,\r\n divisions: number\r\n): number[] {\r\n const inside = positions.filter((v) => v >= min && v <= max)\r\n const unique = [...new Set(inside)].sort((a, b) => a - b)\r\n if (unique.length === 0) return markerValues([min, max], divisions)\r\n\r\n const nearest = (target: number) =>\r\n unique.reduce((best, v) =>\r\n Math.abs(v - target) < Math.abs(best - target) ? v : best\r\n )\r\n\r\n const out: number[] = []\r\n for (const target of markerValues([min, max], divisions)) {\r\n const tick = nearest(target)\r\n if (out[out.length - 1] !== tick) out.push(tick)\r\n }\r\n return out\r\n}\r\n\r\n/**\r\n * The caption a tick carries on a sample-based scale: the cell of the row it\r\n * came from, or `fallback` when the tick isn't a sample after all.\r\n */\r\nfunction labelBySample(\r\n positions: number[],\r\n captions: string[],\r\n value: number,\r\n fallback: (value: number) => string\r\n): string {\r\n const i = positions.indexOf(value)\r\n return i >= 0 ? captions[i] : fallback(value)\r\n}\r\n\r\n/** Scales already resolved, by data array, then by field and pattern. */\r\nconst scales = new WeakMap<DataRecord[], Map<string, XScale>>()\r\n\r\n/**\r\n * How `field` positions the rows: the number it holds, the instant it names, or\r\n * failing both, the row's own place in the file.\r\n *\r\n * Kept per `data` array: a chart's bound props ask a dozen times a frame, and\r\n * parsing every row's instant each time was most of a frame.\r\n */\r\nexport function resolveXScale(\r\n data: DataRecord[],\r\n field: string,\r\n pattern?: string\r\n): XScale {\r\n let byKey = scales.get(data)\r\n if (!byKey) scales.set(data, (byKey = new Map()))\r\n const key = JSON.stringify([field, pattern ?? null])\r\n let scale = byKey.get(key)\r\n if (!scale) byKey.set(key, (scale = xScaleOf(data, field, pattern)))\r\n return scale\r\n}\r\n\r\nfunction xScaleOf(\r\n data: DataRecord[],\r\n field: string,\r\n /**\r\n * The number-format pattern for a *numeric* column. Ignored by the other two\r\n * kinds, and correctly so: a tick on those is captioned with the cell the\r\n * author wrote, and `Jan` has no decimal places.\r\n */\r\n pattern?: string\r\n): XScale {\r\n if (field !== \"\" && isNumericColumn(data, field)) {\r\n const positions = data.map((row) => num(row, field))\r\n return {\r\n kind: \"numeric\",\r\n at: (i) => positions[i] ?? 0,\r\n extent: extentOf(positions),\r\n label: (value) =>\r\n pattern === undefined ? formatMarker(value) : formatNumber(value, pattern),\r\n // Round numbers, evenly spaced — a continuous axis is read by its scale\r\n // rather than by which samples happen to be on it.\r\n ticks: markerValues,\r\n }\r\n }\r\n\r\n const captions = data.map((row) => text(row, field))\r\n const instants = field === \"\" ? null : instantColumn(data, field)\r\n\r\n if (instants) {\r\n const extent = extentOf(instants)\r\n const span = extent[1] - extent[0]\r\n return {\r\n kind: \"time\",\r\n at: (i) => instants[i] ?? 0,\r\n extent,\r\n label: (value) =>\r\n labelBySample(instants, captions, value, (v) =>\r\n formatInstant(v, span)\r\n ),\r\n ticks: (range, divisions) => sampledTicks(instants, range, divisions),\r\n }\r\n }\r\n\r\n const positions = data.map((_, i) => i)\r\n return {\r\n kind: \"ordinal\",\r\n at: (i) => i,\r\n // `[0, n-1]` rather than the tidy `[0, n]`: the first and last rows sit on\r\n // the plot's edges, which is where a reader looks for them.\r\n extent: positions.length > 0 ? [0, positions.length - 1] : [0, 1],\r\n label: (value) => captions[Math.round(value)] ?? \"\",\r\n ticks: (range, divisions) => sampledTicks(positions, range, divisions),\r\n }\r\n}\r\n"]}
|
|
@@ -94,7 +94,7 @@ export declare const PieChart: import("@motionscript/sdk").Component<"pieChart",
|
|
|
94
94
|
readonly sliceIndex: import("@motionscript/sdk").Type<number, number, false>;
|
|
95
95
|
};
|
|
96
96
|
readonly clearSelection: {};
|
|
97
|
-
},
|
|
97
|
+
}, readonly [], Node2D<Node2DProps>, import("@motionscript/sdk").CallProps<import("@motionscript/sdk").Merge<import("@motionscript/sdk").Box2DState, {
|
|
98
98
|
readonly data: import("@motionscript/sdk").Type<DataRecord[], DataRecord[], false>;
|
|
99
99
|
readonly categoryField: "";
|
|
100
100
|
readonly valueField: "";
|
|
@@ -114,7 +114,7 @@ export declare const PieChart: import("@motionscript/sdk").Component<"pieChart",
|
|
|
114
114
|
readonly showLegend: import("@motionscript/sdk").Type<boolean, boolean, false>;
|
|
115
115
|
/** Read as the chart is built: whether the hole's summary is drawn at rest. */
|
|
116
116
|
readonly showCenter: import("@motionscript/sdk").Type<boolean, boolean, false>;
|
|
117
|
-
}>,
|
|
117
|
+
}>, readonly [], import("@motionscript/sdk").BuiltNode<import("@motionscript/sdk").Merge<import("@motionscript/sdk").Box2DState, {
|
|
118
118
|
readonly data: import("@motionscript/sdk").Type<DataRecord[], DataRecord[], false>;
|
|
119
119
|
readonly categoryField: "";
|
|
120
120
|
readonly valueField: "";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pie-chart.d.ts","sourceRoot":"","sources":["../../src/pie-chart/pie-chart.ts"],"names":[],"mappings":"AAAA,OAAO,EAML,KAAK,UAAU,EACf,KAAK,MAAM,EAEX,KAAK,MAAM,EACX,KAAK,WAAW,EAEjB,MAAM,mBAAmB,CAAA;AAO1B,OAAO,EAKL,KAAK,cAAc,EACnB,KAAK,aAAa,EAClB,KAAK,YAAY,EACjB,KAAK,iBAAiB,EAEvB,MAAM,UAAU,CAAA;AAEjB,MAAM,WAAW,aAAc,SAAQ,WAAW;IAChD,iEAAiE;IACjE,IAAI,EAAE,UAAU,EAAE,CAAA;IAClB,kFAAkF;IAClF,aAAa,EAAE,MAAM,CAAA;IACrB,iFAAiF;IACjF,UAAU,EAAE,MAAM,CAAA;IAClB;;;;OAIG;IACH,KAAK,CAAC,EAAE,aAAa,CAAA;IACrB,kCAAkC;IAClC,SAAS,CAAC,EAAE,YAAY,CAAA;IACxB,2EAA2E;IAC3E,cAAc,CAAC,EAAE,iBAAiB,CAAA;IAClC,iEAAiE;IACjE,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,kDAAkD;IAClD,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,wDAAwD;IACxD,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,qDAAqD;IACrD,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB;;;;OAIG;IACH,UAAU,CAAC,EAAE,OAAO,CAAA;CACrB;AAED,4FAA4F;AAC5F,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,IAAI,EAAE,UAAU,EAAE,CAAA;IAC3B,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAA;IAC9B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;IAC3B,QAAQ,CAAC,KAAK,EAAE,cAAc,CAAA;IAC9B,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,CAAA;CACxB;AAqBD,sHAAsH;AACtH,wBAAgB,eAAe,CAAC,CAAC,EAAE,cAAc,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAEzE;AAsCD;;;;;;;;;;;;;;;;;;GAkBG;AACH,eAAO,MAAM,QAAQ;;;;;;;;;;IAYjB;;;;OAIG;;IAEH,oFAAoF;;IAEpF,+EAA+E;;;;;;;;;;;;;;;;;;;;;;;;;IAR/E;;;;OAIG;;IAEH,oFAAoF;;IAEpF,+EAA+E;;;;;;;;;;;;IAR/E;;;;OAIG;;IAEH,oFAAoF;;IAEpF,+EAA+E;;;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"pie-chart.d.ts","sourceRoot":"","sources":["../../src/pie-chart/pie-chart.ts"],"names":[],"mappings":"AAAA,OAAO,EAML,KAAK,UAAU,EACf,KAAK,MAAM,EAEX,KAAK,MAAM,EACX,KAAK,WAAW,EAEjB,MAAM,mBAAmB,CAAA;AAO1B,OAAO,EAKL,KAAK,cAAc,EACnB,KAAK,aAAa,EAClB,KAAK,YAAY,EACjB,KAAK,iBAAiB,EAEvB,MAAM,UAAU,CAAA;AAEjB,MAAM,WAAW,aAAc,SAAQ,WAAW;IAChD,iEAAiE;IACjE,IAAI,EAAE,UAAU,EAAE,CAAA;IAClB,kFAAkF;IAClF,aAAa,EAAE,MAAM,CAAA;IACrB,iFAAiF;IACjF,UAAU,EAAE,MAAM,CAAA;IAClB;;;;OAIG;IACH,KAAK,CAAC,EAAE,aAAa,CAAA;IACrB,kCAAkC;IAClC,SAAS,CAAC,EAAE,YAAY,CAAA;IACxB,2EAA2E;IAC3E,cAAc,CAAC,EAAE,iBAAiB,CAAA;IAClC,iEAAiE;IACjE,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,kDAAkD;IAClD,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,wDAAwD;IACxD,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,qDAAqD;IACrD,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB;;;;OAIG;IACH,UAAU,CAAC,EAAE,OAAO,CAAA;CACrB;AAED,4FAA4F;AAC5F,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,IAAI,EAAE,UAAU,EAAE,CAAA;IAC3B,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAA;IAC9B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;IAC3B,QAAQ,CAAC,KAAK,EAAE,cAAc,CAAA;IAC9B,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,CAAA;CACxB;AAqBD,sHAAsH;AACtH,wBAAgB,eAAe,CAAC,CAAC,EAAE,cAAc,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAEzE;AAsCD;;;;;;;;;;;;;;;;;;GAkBG;AACH,eAAO,MAAM,QAAQ;;;;;;;;;;IAYjB;;;;OAIG;;IAEH,oFAAoF;;IAEpF,+EAA+E;;;;;;;;;;;;;;;;;;;;;;;;;IAR/E;;;;OAIG;;IAEH,oFAAoF;;IAEpF,+EAA+E;;;;;;;;;;;;IAR/E;;;;OAIG;;IAEH,oFAAoF;;IAEpF,+EAA+E;;;;;;;;;;;;;;;yBAyHjF,CAAA;AAEF,MAAM,MAAM,QAAQ,GAAG,MAAM,CAAC,OAAO,QAAQ,CAAC,CAAA"}
|
|
@@ -107,6 +107,7 @@ export const PieChart = component2d({
|
|
|
107
107
|
height: "fill",
|
|
108
108
|
pops: (state) => slicesOf(state).map(() => 0),
|
|
109
109
|
},
|
|
110
|
+
allowedChildren: [],
|
|
110
111
|
// The slice *structure* (one label and one legend row per row) is read once;
|
|
111
112
|
// the slices themselves, their paint and the selection are bound, so a theme
|
|
112
113
|
// tween re-paints and a `set` of `data` re-cuts the wedges.
|
|
@@ -142,7 +143,7 @@ export const PieChart = component2d({
|
|
|
142
143
|
}));
|
|
143
144
|
}
|
|
144
145
|
const row = new Rect({ flow: "horizontal", width: "fill", height: "fill", gap: state.gap, align: "center", children: parts });
|
|
145
|
-
return asParts([
|
|
146
|
+
return asParts([row]);
|
|
146
147
|
},
|
|
147
148
|
commands: {
|
|
148
149
|
/**
|
|
@@ -153,6 +154,8 @@ export const PieChart = component2d({
|
|
|
153
154
|
*/
|
|
154
155
|
enter: {
|
|
155
156
|
args: {},
|
|
157
|
+
// Held from the chart's arrival, so it never shows finished ahead of its draw.
|
|
158
|
+
entrance: true,
|
|
156
159
|
easing: easeOut(),
|
|
157
160
|
run: (timeline, _state, children) => {
|
|
158
161
|
const parts = partsOf(children);
|