@pixerate/editor 0.165.0 → 0.166.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agent/index.cjs +34 -34
- package/dist/agent/index.js +5 -5
- package/dist/canvas/index.cjs +6 -6
- package/dist/canvas/index.js +2 -2
- package/dist/chart/controller.d.cts +29 -0
- package/dist/chart/controller.d.ts +29 -0
- package/dist/chart/index.cjs +301 -179
- package/dist/chart/index.d.cts +1 -0
- package/dist/chart/index.d.ts +1 -0
- package/dist/chart/index.js +132 -10
- package/dist/chart/layout-families.d.cts +7 -0
- package/dist/chart/layout-families.d.ts +7 -0
- package/dist/chart/layout-shared.d.cts +5 -0
- package/dist/chart/layout-shared.d.ts +5 -0
- package/dist/chart/race.d.cts +26 -0
- package/dist/chart/race.d.ts +26 -0
- package/dist/chart/schemas.d.cts +2 -0
- package/dist/chart/schemas.d.ts +2 -0
- package/dist/chart/spec.d.cts +1 -1
- package/dist/chart/spec.d.ts +1 -1
- package/dist/chart/types.d.cts +6 -2
- package/dist/chart/types.d.ts +6 -2
- package/dist/{chunk-FEU2XVQH.js → chunk-5UNQDC3Q.js} +5 -2
- package/dist/{chunk-64VWWR5U.cjs → chunk-6FYIFGBW.cjs} +16 -16
- package/dist/{chunk-UVXTOZ2B.cjs → chunk-BPX4Z3N3.cjs} +12 -3
- package/dist/{chunk-MKXK6E4O.cjs → chunk-CHLV7UFP.cjs} +51 -51
- package/dist/{chunk-X5W645RI.js → chunk-DFCAR7AW.js} +3 -3
- package/dist/{chunk-2ZRN43IN.js → chunk-FR432ROA.js} +12 -3
- package/dist/{chunk-ODFCS7HF.cjs → chunk-HXOBOHH2.cjs} +8 -8
- package/dist/{chunk-V5GSY3NC.js → chunk-ITANXMZD.js} +78 -2
- package/dist/{chunk-TVQW26AV.cjs → chunk-MZFZSVUJ.cjs} +26 -23
- package/dist/{chunk-N7NBGT2Y.js → chunk-NQQDGGXY.js} +2 -2
- package/dist/{chunk-Q25WAFTD.cjs → chunk-SZWVMB3B.cjs} +21 -18
- package/dist/{chunk-QO2T6KA5.cjs → chunk-UUUTEVX6.cjs} +116 -40
- package/dist/{chunk-IMRXC7OA.cjs → chunk-V5L2G22R.cjs} +153 -77
- package/dist/{chunk-2J5VLJHC.js → chunk-VB2CY6EG.js} +3 -3
- package/dist/{chunk-CRFSQWKQ.js → chunk-XNU45TYA.js} +4 -1
- package/dist/{chunk-FRBRLKNQ.js → chunk-YUFTVNLX.js} +78 -2
- package/dist/export/index.cjs +4 -4
- package/dist/export/index.js +3 -3
- package/dist/extensions/index.cjs +7 -7
- package/dist/extensions/index.js +6 -6
- package/dist/index.cjs +13 -13
- package/dist/index.js +7 -7
- package/package.json +1 -1
- package/skills/pixerate-chart/SKILL.md +20 -2
package/dist/chart/index.d.cts
CHANGED
package/dist/chart/index.d.ts
CHANGED
package/dist/chart/index.js
CHANGED
|
@@ -4,6 +4,7 @@ import {
|
|
|
4
4
|
HEIGHT,
|
|
5
5
|
LINK_INDEX,
|
|
6
6
|
LINK_PROPS,
|
|
7
|
+
RACE_TIME,
|
|
7
8
|
REFERENCE_BAND_PATCH,
|
|
8
9
|
REFERENCE_BAND_PROPS,
|
|
9
10
|
REFERENCE_INDEX,
|
|
@@ -16,7 +17,7 @@ import {
|
|
|
16
17
|
TRENDLINE_PROPS,
|
|
17
18
|
VALUE,
|
|
18
19
|
WIDTH
|
|
19
|
-
} from "../chunk-
|
|
20
|
+
} from "../chunk-5UNQDC3Q.js";
|
|
20
21
|
import {
|
|
21
22
|
CHART_OOXML_CONTENT_TYPE,
|
|
22
23
|
CHART_OOXML_NS,
|
|
@@ -24,7 +25,7 @@ import {
|
|
|
24
25
|
chartFormatToCode,
|
|
25
26
|
chartFromOoxml,
|
|
26
27
|
chartToOoxml
|
|
27
|
-
} from "../chunk-
|
|
28
|
+
} from "../chunk-XNU45TYA.js";
|
|
28
29
|
import {
|
|
29
30
|
CHART_COLOR_SCHEMES,
|
|
30
31
|
CHART_LAYOUT_PRESETS,
|
|
@@ -46,7 +47,7 @@ import {
|
|
|
46
47
|
monochromeChartPalette,
|
|
47
48
|
sparklineToSvg,
|
|
48
49
|
summarizeChart
|
|
49
|
-
} from "../chunk-
|
|
50
|
+
} from "../chunk-YUFTVNLX.js";
|
|
50
51
|
import "../chunk-KGRZMHZB.js";
|
|
51
52
|
import {
|
|
52
53
|
CHART_DATE_STEPS,
|
|
@@ -59,6 +60,9 @@ import {
|
|
|
59
60
|
chartHistogram,
|
|
60
61
|
chartMovingAverage,
|
|
61
62
|
chartQuantile,
|
|
63
|
+
chartRaceMoment,
|
|
64
|
+
chartRaceRanking,
|
|
65
|
+
chartRaceValueAt,
|
|
62
66
|
chartScaleFromPixel,
|
|
63
67
|
chartScaleToPixel,
|
|
64
68
|
chartSerialToDate,
|
|
@@ -87,7 +91,7 @@ import {
|
|
|
87
91
|
suggestChartReferences,
|
|
88
92
|
summarizeChartSeries,
|
|
89
93
|
trendNumberText
|
|
90
|
-
} from "../chunk-
|
|
94
|
+
} from "../chunk-ITANXMZD.js";
|
|
91
95
|
import {
|
|
92
96
|
CHART_AXIS_KINDS,
|
|
93
97
|
CHART_AXIS_SCALES,
|
|
@@ -181,7 +185,7 @@ import {
|
|
|
181
185
|
shadeChartColor,
|
|
182
186
|
simulateChartVision,
|
|
183
187
|
uniqueChartSeriesId
|
|
184
|
-
} from "../chunk-
|
|
188
|
+
} from "../chunk-FR432ROA.js";
|
|
185
189
|
import "../chunk-O6OGNDND.js";
|
|
186
190
|
import "../chunk-II2WIF5Z.js";
|
|
187
191
|
import {
|
|
@@ -396,6 +400,7 @@ function recommendForShape(shape) {
|
|
|
396
400
|
add("area", "Area", "Shows change over time with volume.");
|
|
397
401
|
add("bar", "Column", "Compares each period.");
|
|
398
402
|
if (shape.series > 1) add("area", "Stacked area", "Shows how the parts add up over time.", "stacked");
|
|
403
|
+
if (shape.series >= 5 && shape.points >= 3) add("barrace", "Bar race", "Many series over time: an animated ranking shows who leads when.");
|
|
399
404
|
return out;
|
|
400
405
|
}
|
|
401
406
|
if (shape.series === 1) {
|
|
@@ -430,6 +435,7 @@ function recommendForShape(shape) {
|
|
|
430
435
|
add("bar", "Stacked column", "Shows how the series add up.", "stacked");
|
|
431
436
|
add("line", "Line", "Shows the series in order.");
|
|
432
437
|
if (shape.points >= 3 && shape.series <= 6) add("radar", "Radar", "Compares several measures across the series.");
|
|
438
|
+
if (shape.nonNegative && shape.series >= 5 && shape.points >= 3) add("barrace", "Bar race", "Many series across ordered categories (such as years): an animated ranking shows who leads when.");
|
|
433
439
|
if (shape.nonNegative && shape.series >= 3 && shape.series <= 7) add("likert", "Likert", "Survey answers per question (columns from most negative to most positive): shows agreement against disagreement.");
|
|
434
440
|
}
|
|
435
441
|
return out;
|
|
@@ -475,6 +481,12 @@ function createChartCommands(controller, options = {}) {
|
|
|
475
481
|
if (index < 0 || index >= categories.length || !Number.isInteger(index)) fail(`There is no category ${JSON.stringify(ref)}; expected an index from 0 to ${categories.length - 1} or one of the labels.`);
|
|
476
482
|
return index;
|
|
477
483
|
};
|
|
484
|
+
const raceFrame = (time) => {
|
|
485
|
+
const cats = controller.getSpec().categories;
|
|
486
|
+
const frame = typeof time === "number" ? time : cats.indexOf(time);
|
|
487
|
+
if (!(Number.isFinite(frame) && frame >= 0 && frame <= cats.length - 1)) fail(`There is no time point ${JSON.stringify(time)}; expected an index from 0 to ${Math.max(0, cats.length - 1)} or a category label.`);
|
|
488
|
+
return frame;
|
|
489
|
+
};
|
|
478
490
|
const object = (properties, required) => ({ type: "object", properties, ...required ? { required } : {}, additionalProperties: false });
|
|
479
491
|
return [
|
|
480
492
|
{
|
|
@@ -887,6 +899,57 @@ function createChartCommands(controller, options = {}) {
|
|
|
887
899
|
return { links: controller.getSpec().links };
|
|
888
900
|
}
|
|
889
901
|
},
|
|
902
|
+
{
|
|
903
|
+
...base,
|
|
904
|
+
id: `${prefix}raceRanking`,
|
|
905
|
+
label: "Bar Race Ranking",
|
|
906
|
+
readOnly: true,
|
|
907
|
+
keywords: ["chart", "race", "ranking", "leader", "time"],
|
|
908
|
+
description: "Returns the top names of a bar race at a moment (default: the one shown).",
|
|
909
|
+
params: object({ time: RACE_TIME }),
|
|
910
|
+
run: (_ctx, params = {}) => {
|
|
911
|
+
const spec = controller.getSpec();
|
|
912
|
+
const frame = params?.time !== void 0 ? raceFrame(params.time) : controller.getState().raceFrame ?? spec.categories.length - 1;
|
|
913
|
+
return { frame, ranking: chartRaceRanking(spec, frame).slice(0, spec.raceTopN).map((e) => ({ rank: e.rank + 1, series: e.seriesId, name: e.name, value: e.value })) };
|
|
914
|
+
}
|
|
915
|
+
},
|
|
916
|
+
{
|
|
917
|
+
...base,
|
|
918
|
+
id: `${prefix}setRaceFrame`,
|
|
919
|
+
label: "Show Bar Race Moment\u2026",
|
|
920
|
+
keywords: ["chart", "race", "frame", "time", "scrub"],
|
|
921
|
+
description: "Shows the bar race at a time point (null for the last) and stops playback. View state, not an undo step.",
|
|
922
|
+
params: object({ time: { ...RACE_TIME, type: ["string", "number", "null"], description: `${RACE_TIME.description} null shows the last time point.` } }, ["time"]),
|
|
923
|
+
run: (_ctx, params) => {
|
|
924
|
+
const frame = params.time === null ? null : raceFrame(params.time);
|
|
925
|
+
check(controller.setRaceFrame(frame));
|
|
926
|
+
return { frame };
|
|
927
|
+
}
|
|
928
|
+
},
|
|
929
|
+
{
|
|
930
|
+
...base,
|
|
931
|
+
id: `${prefix}playRace`,
|
|
932
|
+
label: "Play Bar Race",
|
|
933
|
+
keywords: ["chart", "race", "play", "animate"],
|
|
934
|
+
description: "Plays the bar race from the moment shown, one time point every msPerStep ms.",
|
|
935
|
+
params: object({ msPerStep: { type: "number", minimum: 50, maximum: 1e4, description: "Milliseconds per time point (default 1000)." } }),
|
|
936
|
+
run: (_ctx, params = {}) => {
|
|
937
|
+
check(controller.playRace({ msPerStep: params?.msPerStep }));
|
|
938
|
+
return { playing: true };
|
|
939
|
+
}
|
|
940
|
+
},
|
|
941
|
+
{
|
|
942
|
+
...base,
|
|
943
|
+
id: `${prefix}pauseRace`,
|
|
944
|
+
label: "Pause Bar Race",
|
|
945
|
+
keywords: ["chart", "race", "pause", "stop"],
|
|
946
|
+
description: "Pauses bar race playback where it is.",
|
|
947
|
+
enabled: () => controller.getState().racePlaying || "The race is not playing",
|
|
948
|
+
run: () => {
|
|
949
|
+
controller.pauseRace();
|
|
950
|
+
return { frame: controller.getState().raceFrame };
|
|
951
|
+
}
|
|
952
|
+
},
|
|
890
953
|
{
|
|
891
954
|
...base,
|
|
892
955
|
id: `${prefix}applyPreset`,
|
|
@@ -1484,6 +1547,10 @@ function planChartToolPlayback(tool, args) {
|
|
|
1484
1547
|
return click(control("series.callout"));
|
|
1485
1548
|
case "highlight_chart":
|
|
1486
1549
|
return click(control("highlight"));
|
|
1550
|
+
case "set_chart_race_frame":
|
|
1551
|
+
return click(control("raceFrame"));
|
|
1552
|
+
case "play_chart_race":
|
|
1553
|
+
return click({ kind: "action", id: "race-play" });
|
|
1487
1554
|
case "render_chart":
|
|
1488
1555
|
return [{ type: "target", ref: { kind: "action", id: "download-png" } }];
|
|
1489
1556
|
case "undo_chart":
|
|
@@ -1548,6 +1615,22 @@ function createChartToolProvider(controller, options = {}) {
|
|
|
1548
1615
|
const depth = chartTreeDepth(spec().tree);
|
|
1549
1616
|
return [[...Array.from({ length: depth }, (_, k) => k === 0 ? "Group" : k === depth - 1 ? "Item" : `Level ${k + 1}`), "Value"], ...rows.map((r) => [...r.path, ...Array(depth - r.path.length).fill(""), r.value])];
|
|
1550
1617
|
};
|
|
1618
|
+
const raceFrameOf = (time) => {
|
|
1619
|
+
const cats = spec().categories;
|
|
1620
|
+
const frame = typeof time === "number" ? time : cats.indexOf(time);
|
|
1621
|
+
if (!(Number.isFinite(frame) && frame >= 0 && frame <= cats.length - 1))
|
|
1622
|
+
fail2(`There is no time point ${JSON.stringify(time)}; expected an index from 0 to ${Math.max(0, cats.length - 1)} or one of ${cats.slice(0, 20).map((c) => JSON.stringify(c)).join(", ")}.`);
|
|
1623
|
+
return frame;
|
|
1624
|
+
};
|
|
1625
|
+
const raceAt = (frame) => {
|
|
1626
|
+
const s = spec();
|
|
1627
|
+
const at = frame ?? s.categories.length - 1;
|
|
1628
|
+
return {
|
|
1629
|
+
frame: at,
|
|
1630
|
+
time: s.categories[Math.round(at)] ?? null,
|
|
1631
|
+
ranking: chartRaceRanking(s, at).slice(0, s.raceTopN).map((e) => ({ rank: e.rank + 1, series: e.seriesId, name: e.name, value: e.value }))
|
|
1632
|
+
};
|
|
1633
|
+
};
|
|
1551
1634
|
const linksSummary = () => ({ links: spec().links, nodes: spec().sankeyNodes.map((name, i) => ({ name, value: chartSankeyNodeValues(spec().links, spec().sankeyNodes)[i] })) });
|
|
1552
1635
|
const treeSummary = () => ({ tree: spec().tree, groups: spec().tree.map((n) => ({ name: n.name, total: chartTreeTotal(n) })), depth: chartTreeDepth(spec().tree) });
|
|
1553
1636
|
const Parser = () => options.DOMParser ?? globalThis.DOMParser;
|
|
@@ -1579,14 +1662,16 @@ function createChartToolProvider(controller, options = {}) {
|
|
|
1579
1662
|
properties: {
|
|
1580
1663
|
width: WIDTH,
|
|
1581
1664
|
height: HEIGHT,
|
|
1582
|
-
format: { type: "string", enum: ["svg", "png"], description: "svg (default): the SVG document as text. png: an image to look at (only when the host can rasterize; costs image tokens)." }
|
|
1665
|
+
format: { type: "string", enum: ["svg", "png"], description: "svg (default): the SVG document as text. png: an image to look at (only when the host can rasterize; costs image tokens)." },
|
|
1666
|
+
time: { ...RACE_TIME, description: `Bar race only: the moment to draw (default: the one shown). ${RACE_TIME.description}` }
|
|
1583
1667
|
},
|
|
1584
1668
|
additionalProperties: false
|
|
1585
1669
|
},
|
|
1586
1670
|
annotations: { title: "Render the chart", ...READ },
|
|
1587
|
-
handler: async ({ width = size.width, height = size.height, format = "svg" }) => {
|
|
1671
|
+
handler: async ({ width = size.width, height = size.height, format = "svg", time }) => {
|
|
1588
1672
|
const json = controller.toJSON();
|
|
1589
|
-
const
|
|
1673
|
+
const raceFrame = time !== void 0 ? raceFrameOf(time) : controller.getState().raceFrame;
|
|
1674
|
+
const scene = layoutChart(json, { width, height, selection: null, raceFrame });
|
|
1590
1675
|
const svg = chartSceneToSvg(scene, { ariaLabel: json.title || void 0, description: describeChart(json) });
|
|
1591
1676
|
const warnings = scene.warnings;
|
|
1592
1677
|
if (format === "png") {
|
|
@@ -1659,6 +1744,14 @@ function createChartToolProvider(controller, options = {}) {
|
|
|
1659
1744
|
return { trendline: line, coefficients: fit.coefficients, r2: fit.r2, equation: fit.equation, points: fit.points };
|
|
1660
1745
|
}
|
|
1661
1746
|
};
|
|
1747
|
+
const raceRanking = {
|
|
1748
|
+
name: "get_chart_race_ranking",
|
|
1749
|
+
title: "Read a bar race ranking",
|
|
1750
|
+
description: "Returns who leads a bar race at a moment without changing what is shown: the top raceTopN names with their rank, series id and value (eased between time points). Defaults to the moment shown. Works for any chart, reading categories as time points and series as names.",
|
|
1751
|
+
inputSchema: { type: "object", properties: { time: RACE_TIME }, additionalProperties: false },
|
|
1752
|
+
annotations: { title: "Read a bar race ranking", ...READ },
|
|
1753
|
+
handler: ({ time }) => raceAt(time !== void 0 ? raceFrameOf(time) : controller.getState().raceFrame)
|
|
1754
|
+
};
|
|
1662
1755
|
const listPresets = {
|
|
1663
1756
|
name: "list_chart_presets",
|
|
1664
1757
|
title: "List chart presets",
|
|
@@ -2150,6 +2243,30 @@ function createChartToolProvider(controller, options = {}) {
|
|
|
2150
2243
|
return { links: spec().links };
|
|
2151
2244
|
}
|
|
2152
2245
|
};
|
|
2246
|
+
const setRaceFrame = {
|
|
2247
|
+
name: "set_chart_race_frame",
|
|
2248
|
+
title: "Show a bar race moment",
|
|
2249
|
+
description: "Shows the bar race at a time point (or between two), and stops playback. This is view state like the selection: it is not an undo step and is not saved in the chart. Returns the moment and the ranking shown.",
|
|
2250
|
+
inputSchema: { type: "object", properties: { time: { ...RACE_TIME, type: ["string", "number", "null"], description: `${RACE_TIME.description} null shows the last time point.` } }, required: ["time"], additionalProperties: false },
|
|
2251
|
+
annotations: { title: "Show a bar race moment", ...WRITE_IDEMPOTENT },
|
|
2252
|
+
handler: ({ time }) => {
|
|
2253
|
+
const frame = time === null ? null : raceFrameOf(time);
|
|
2254
|
+
resolve(controller.setRaceFrame(frame));
|
|
2255
|
+
return raceAt(frame);
|
|
2256
|
+
}
|
|
2257
|
+
};
|
|
2258
|
+
const playRace = {
|
|
2259
|
+
name: "play_chart_race",
|
|
2260
|
+
title: "Play the bar race",
|
|
2261
|
+
description: "Starts playing the bar race for the user from the moment shown (from the start when it is at the end), one time point every msPerStep ms, and returns at once. set_chart_race_frame stops it. Nothing in the chart changes.",
|
|
2262
|
+
inputSchema: { type: "object", properties: { msPerStep: { type: "number", minimum: 50, maximum: 1e4, description: "Milliseconds per time point (default 1000)." } }, additionalProperties: false },
|
|
2263
|
+
annotations: { title: "Play the bar race", ...WRITE },
|
|
2264
|
+
handler: ({ msPerStep }) => {
|
|
2265
|
+
resolve(controller.playRace({ msPerStep }));
|
|
2266
|
+
const n = spec().categories.length;
|
|
2267
|
+
return { playing: true, from: controller.getState().raceFrame ?? 0, durationMs: Math.round((n - 1 - (controller.getState().raceFrame ?? 0)) * (msPerStep ?? 1e3)) };
|
|
2268
|
+
}
|
|
2269
|
+
};
|
|
2153
2270
|
const applyPreset = {
|
|
2154
2271
|
name: "apply_chart_preset",
|
|
2155
2272
|
title: "Apply a chart style",
|
|
@@ -2315,7 +2432,7 @@ function createChartToolProvider(controller, options = {}) {
|
|
|
2315
2432
|
return { redone, ...redone ? { label } : {} };
|
|
2316
2433
|
}
|
|
2317
2434
|
};
|
|
2318
|
-
const reads = [getChart, renderChart, checkColors, recommend, getTrendline, listPresets, exportMermaid, exportOoxml];
|
|
2435
|
+
const reads = [getChart, renderChart, checkColors, recommend, getTrendline, raceRanking, listPresets, exportMermaid, exportOoxml];
|
|
2319
2436
|
const writes = [
|
|
2320
2437
|
updateChart,
|
|
2321
2438
|
setData,
|
|
@@ -2347,6 +2464,8 @@ function createChartToolProvider(controller, options = {}) {
|
|
|
2347
2464
|
addLink,
|
|
2348
2465
|
updateLink,
|
|
2349
2466
|
removeLink,
|
|
2467
|
+
setRaceFrame,
|
|
2468
|
+
playRace,
|
|
2350
2469
|
applyPreset,
|
|
2351
2470
|
transpose,
|
|
2352
2471
|
select,
|
|
@@ -2359,7 +2478,7 @@ function createChartToolProvider(controller, options = {}) {
|
|
|
2359
2478
|
id: options.id ?? "chart",
|
|
2360
2479
|
namespace: options.namespace,
|
|
2361
2480
|
title: "Chart editor",
|
|
2362
|
-
description: "One chart: its spec, data and values, series and categories, trendlines, reference lines and bands, callouts, highlight, grouped data, flows and presets, CSV, Mermaid and OOXML import, rendering and colour checks.",
|
|
2481
|
+
description: "One chart: its spec, data and values, series and categories, trendlines, reference lines and bands, callouts, highlight, grouped data, flows, bar race playback and presets, CSV, Mermaid and OOXML import, rendering and colour checks.",
|
|
2363
2482
|
skill: "pixerate-chart",
|
|
2364
2483
|
tools: () => {
|
|
2365
2484
|
if (readOnlyReason()) return reads;
|
|
@@ -3112,6 +3231,9 @@ export {
|
|
|
3112
3231
|
chartPointRef,
|
|
3113
3232
|
chartPresetPatch,
|
|
3114
3233
|
chartQuantile,
|
|
3234
|
+
chartRaceMoment,
|
|
3235
|
+
chartRaceRanking,
|
|
3236
|
+
chartRaceValueAt,
|
|
3115
3237
|
chartRasterSize,
|
|
3116
3238
|
chartRgbToHex,
|
|
3117
3239
|
chartRgbToOklab,
|
|
@@ -45,3 +45,10 @@ export declare function layoutSunburst(ctx: LayoutCtx, area: ChartRect, series:
|
|
|
45
45
|
* in the order of the nodes at their other end, so they cross as little as the order allows.
|
|
46
46
|
*/
|
|
47
47
|
export declare function layoutSankey(ctx: LayoutCtx, area: ChartRect, series: ChartSeries | undefined): FamilyResult;
|
|
48
|
+
/**
|
|
49
|
+
* Bar race: the top `raceTopN` names at one moment (`frame`, a fractional category index;
|
|
50
|
+
* default the last time point) as ranked horizontal bars. Values ease between time points and
|
|
51
|
+
* places slide from one ranking to the next, so drawing frame after frame (or blending scenes,
|
|
52
|
+
* which match bars by series) animates the race. The time point is written large in a corner.
|
|
53
|
+
*/
|
|
54
|
+
export declare function layoutBarRace(ctx: LayoutCtx, area: ChartRect, frame: number | null | undefined): FamilyResult;
|
|
@@ -45,3 +45,10 @@ export declare function layoutSunburst(ctx: LayoutCtx, area: ChartRect, series:
|
|
|
45
45
|
* in the order of the nodes at their other end, so they cross as little as the order allows.
|
|
46
46
|
*/
|
|
47
47
|
export declare function layoutSankey(ctx: LayoutCtx, area: ChartRect, series: ChartSeries | undefined): FamilyResult;
|
|
48
|
+
/**
|
|
49
|
+
* Bar race: the top `raceTopN` names at one moment (`frame`, a fractional category index;
|
|
50
|
+
* default the last time point) as ranked horizontal bars. Values ease between time points and
|
|
51
|
+
* places slide from one ranking to the next, so drawing frame after frame (or blending scenes,
|
|
52
|
+
* which match bars by series) animates the race. The time point is written large in a corner.
|
|
53
|
+
*/
|
|
54
|
+
export declare function layoutBarRace(ctx: LayoutCtx, area: ChartRect, frame: number | null | undefined): FamilyResult;
|
|
@@ -34,6 +34,11 @@ export interface ChartLayoutOptions {
|
|
|
34
34
|
seriesId: string;
|
|
35
35
|
index: number;
|
|
36
36
|
} | null;
|
|
37
|
+
/**
|
|
38
|
+
* Bar race: the moment to draw, as a category index that may be fractional (2.5 is halfway
|
|
39
|
+
* between the third and fourth time points). Default: the last time point.
|
|
40
|
+
*/
|
|
41
|
+
raceFrame?: number | null;
|
|
37
42
|
}
|
|
38
43
|
/** A DOM-free text width estimate (average glyph ≈ 0.56 em, bold ≈ 0.6 em). */
|
|
39
44
|
export declare const estimateChartTextWidth: ChartTextMeasure;
|
|
@@ -34,6 +34,11 @@ export interface ChartLayoutOptions {
|
|
|
34
34
|
seriesId: string;
|
|
35
35
|
index: number;
|
|
36
36
|
} | null;
|
|
37
|
+
/**
|
|
38
|
+
* Bar race: the moment to draw, as a category index that may be fractional (2.5 is halfway
|
|
39
|
+
* between the third and fourth time points). Default: the last time point.
|
|
40
|
+
*/
|
|
41
|
+
raceFrame?: number | null;
|
|
37
42
|
}
|
|
38
43
|
/** A DOM-free text width estimate (average glyph ≈ 0.56 em, bold ≈ 0.6 em). */
|
|
39
44
|
export declare const estimateChartTextWidth: ChartTextMeasure;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { ChartSeries, ChartSpec } from './types.cjs';
|
|
2
|
+
/** A series' value at time point `index`: its own, else the last value before it (0 before the first). */
|
|
3
|
+
export declare function chartRaceValueAt(series: Pick<ChartSeries, 'values'>, index: number): number;
|
|
4
|
+
/** The moment `frame` stands for: the time points either side and how far between them (0–1). */
|
|
5
|
+
export declare function chartRaceMoment(count: number, frame: number | null | undefined): {
|
|
6
|
+
from: number;
|
|
7
|
+
to: number;
|
|
8
|
+
t: number;
|
|
9
|
+
at: number;
|
|
10
|
+
};
|
|
11
|
+
export interface ChartRaceEntry {
|
|
12
|
+
seriesId: string;
|
|
13
|
+
name: string;
|
|
14
|
+
/** The value at the moment (between time points, eased from one to the next). */
|
|
15
|
+
value: number;
|
|
16
|
+
/** 0-based place at the moment, fractional while two names swap. */
|
|
17
|
+
position: number;
|
|
18
|
+
/** 0-based place at the nearest time point. */
|
|
19
|
+
rank: number;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Every visible series at a moment, best first: its value between the two time points and its
|
|
23
|
+
* position, which slides from its rank at one time point to its rank at the next so bars swap
|
|
24
|
+
* smoothly. Ties keep the series order.
|
|
25
|
+
*/
|
|
26
|
+
export declare function chartRaceRanking(spec: Pick<ChartSpec, 'series' | 'categories'>, frame: number | null | undefined): ChartRaceEntry[];
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { ChartSeries, ChartSpec } from './types.js';
|
|
2
|
+
/** A series' value at time point `index`: its own, else the last value before it (0 before the first). */
|
|
3
|
+
export declare function chartRaceValueAt(series: Pick<ChartSeries, 'values'>, index: number): number;
|
|
4
|
+
/** The moment `frame` stands for: the time points either side and how far between them (0–1). */
|
|
5
|
+
export declare function chartRaceMoment(count: number, frame: number | null | undefined): {
|
|
6
|
+
from: number;
|
|
7
|
+
to: number;
|
|
8
|
+
t: number;
|
|
9
|
+
at: number;
|
|
10
|
+
};
|
|
11
|
+
export interface ChartRaceEntry {
|
|
12
|
+
seriesId: string;
|
|
13
|
+
name: string;
|
|
14
|
+
/** The value at the moment (between time points, eased from one to the next). */
|
|
15
|
+
value: number;
|
|
16
|
+
/** 0-based place at the moment, fractional while two names swap. */
|
|
17
|
+
position: number;
|
|
18
|
+
/** 0-based place at the nearest time point. */
|
|
19
|
+
rank: number;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Every visible series at a moment, best first: its value between the two time points and its
|
|
23
|
+
* position, which slides from its rank at one time point to its rank at the next so bars swap
|
|
24
|
+
* smoothly. Ties keep the series order.
|
|
25
|
+
*/
|
|
26
|
+
export declare function chartRaceRanking(spec: Pick<ChartSpec, 'series' | 'categories'>, frame: number | null | undefined): ChartRaceEntry[];
|
package/dist/chart/schemas.d.cts
CHANGED
|
@@ -22,6 +22,8 @@ export declare const TREE_DEFS: {
|
|
|
22
22
|
export declare const TREE_PATH: JsonSchema;
|
|
23
23
|
/** One Sankey flow's fields; source, target and value are required when adding. */
|
|
24
24
|
export declare const LINK_PROPS: Record<string, JsonSchema>;
|
|
25
|
+
/** A moment of a bar race: a time point by label, or a category index (fractional between time points). */
|
|
26
|
+
export declare const RACE_TIME: JsonSchema;
|
|
25
27
|
export declare const LINK_INDEX: JsonSchema;
|
|
26
28
|
export declare const ERROR_BARS: (what: string) => JsonSchema;
|
|
27
29
|
export declare const SERIES_PROPS: Record<string, JsonSchema>;
|
package/dist/chart/schemas.d.ts
CHANGED
|
@@ -22,6 +22,8 @@ export declare const TREE_DEFS: {
|
|
|
22
22
|
export declare const TREE_PATH: JsonSchema;
|
|
23
23
|
/** One Sankey flow's fields; source, target and value are required when adding. */
|
|
24
24
|
export declare const LINK_PROPS: Record<string, JsonSchema>;
|
|
25
|
+
/** A moment of a bar race: a time point by label, or a category index (fractional between time points). */
|
|
26
|
+
export declare const RACE_TIME: JsonSchema;
|
|
25
27
|
export declare const LINK_INDEX: JsonSchema;
|
|
26
28
|
export declare const ERROR_BARS: (what: string) => JsonSchema;
|
|
27
29
|
export declare const SERIES_PROPS: Record<string, JsonSchema>;
|
package/dist/chart/spec.d.cts
CHANGED
|
@@ -19,7 +19,7 @@ export declare const CHART_NUMBER_STYLES: readonly NonNullable<ChartNumberFormat
|
|
|
19
19
|
/** Labels for pickers, shared by the React and Svelte components. */
|
|
20
20
|
export declare const CHART_TYPE_LABELS: Readonly<Record<ChartType, string>>;
|
|
21
21
|
/** How a chart type is laid out. */
|
|
22
|
-
export type ChartFamily = 'cartesian' | 'xy' | 'pie' | 'radar' | 'waterfall' | 'histogram' | 'box' | 'funnel' | 'treemap' | 'slope' | 'likert' | 'parliament' | 'sunburst' | 'sankey';
|
|
22
|
+
export type ChartFamily = 'cartesian' | 'xy' | 'pie' | 'radar' | 'waterfall' | 'histogram' | 'box' | 'funnel' | 'treemap' | 'slope' | 'likert' | 'parliament' | 'sunburst' | 'sankey' | 'barrace';
|
|
23
23
|
/** A colour-blind-friendly categorical palette (Okabe–Ito order, tuned for light and dark backgrounds). */
|
|
24
24
|
export declare const DEFAULT_CHART_PALETTE: readonly string[];
|
|
25
25
|
export declare const DEFAULT_CHART_THEME: ChartTheme;
|
package/dist/chart/spec.d.ts
CHANGED
|
@@ -19,7 +19,7 @@ export declare const CHART_NUMBER_STYLES: readonly NonNullable<ChartNumberFormat
|
|
|
19
19
|
/** Labels for pickers, shared by the React and Svelte components. */
|
|
20
20
|
export declare const CHART_TYPE_LABELS: Readonly<Record<ChartType, string>>;
|
|
21
21
|
/** How a chart type is laid out. */
|
|
22
|
-
export type ChartFamily = 'cartesian' | 'xy' | 'pie' | 'radar' | 'waterfall' | 'histogram' | 'box' | 'funnel' | 'treemap' | 'slope' | 'likert' | 'parliament' | 'sunburst' | 'sankey';
|
|
22
|
+
export type ChartFamily = 'cartesian' | 'xy' | 'pie' | 'radar' | 'waterfall' | 'histogram' | 'box' | 'funnel' | 'treemap' | 'slope' | 'likert' | 'parliament' | 'sunburst' | 'sankey' | 'barrace';
|
|
23
23
|
/** A colour-blind-friendly categorical palette (Okabe–Ito order, tuned for light and dark backgrounds). */
|
|
24
24
|
export declare const DEFAULT_CHART_PALETTE: readonly string[];
|
|
25
25
|
export declare const DEFAULT_CHART_THEME: ChartTheme;
|
package/dist/chart/types.d.cts
CHANGED
|
@@ -17,8 +17,10 @@
|
|
|
17
17
|
* - `sunburst` draws `tree` as rings from the centre out (or, without a tree, the first series
|
|
18
18
|
* as one ring); a `treemap` with a `tree` nests each group's rectangles inside it.
|
|
19
19
|
* - `sankey` draws `links` as flows between columns of nodes.
|
|
20
|
+
* - `barrace` reads each category as a time point and each series as a name, and draws the
|
|
21
|
+
* top `raceTopN` names at one moment as ranked horizontal bars (an animated ranking).
|
|
20
22
|
*/
|
|
21
|
-
export type ChartType = 'bar' | 'line' | 'area' | 'scatter' | 'bubble' | 'pie' | 'donut' | 'radar' | 'waterfall' | 'histogram' | 'box' | 'funnel' | 'treemap' | 'slope' | 'likert' | 'parliament' | 'sunburst' | 'sankey';
|
|
23
|
+
export type ChartType = 'bar' | 'line' | 'area' | 'scatter' | 'bubble' | 'pie' | 'donut' | 'radar' | 'waterfall' | 'histogram' | 'box' | 'funnel' | 'treemap' | 'slope' | 'likert' | 'parliament' | 'sunburst' | 'sankey' | 'barrace';
|
|
22
24
|
/** How a series is drawn in a cartesian chart. */
|
|
23
25
|
export type ChartSeriesType = 'bar' | 'line' | 'area' | 'scatter';
|
|
24
26
|
/** One data value; `null` is a gap (missing value). */
|
|
@@ -299,6 +301,8 @@ export interface ChartSpec {
|
|
|
299
301
|
sankeyNodes: string[];
|
|
300
302
|
/** Sankey: what colours each flow. */
|
|
301
303
|
sankeyLinkColor: ChartSankeyLinkColor;
|
|
304
|
+
/** Bar race: how many bars each moment shows, 1–30. */
|
|
305
|
+
raceTopN: number;
|
|
302
306
|
}
|
|
303
307
|
/** What a click selects. */
|
|
304
308
|
export type ChartSelection = {
|
|
@@ -354,7 +358,7 @@ export interface ChartRect {
|
|
|
354
358
|
height: number;
|
|
355
359
|
}
|
|
356
360
|
/** What a mark is, for styling and tests. */
|
|
357
|
-
export type ChartMarkRole = 'background' | 'title' | 'subtitle' | 'grid' | 'axis' | 'tick' | 'tick-label' | 'axis-title' | 'bar' | 'line' | 'area' | 'point' | 'slice' | 'cell' | 'box' | 'whisker' | 'outlier' | 'connector' | 'trendline' | 'trendline-label' | 'error-bar' | 'data-label' | 'legend-swatch' | 'legend-label' | 'drag-readout' | 'reference-line' | 'reference-band' | 'reference-label' | 'callout' | 'node' | 'link' | 'note' | 'selection' | 'empty';
|
|
361
|
+
export type ChartMarkRole = 'background' | 'title' | 'subtitle' | 'grid' | 'axis' | 'tick' | 'tick-label' | 'axis-title' | 'bar' | 'line' | 'area' | 'point' | 'slice' | 'cell' | 'box' | 'whisker' | 'outlier' | 'connector' | 'trendline' | 'trendline-label' | 'error-bar' | 'data-label' | 'legend-swatch' | 'legend-label' | 'drag-readout' | 'reference-line' | 'reference-band' | 'reference-label' | 'callout' | 'node' | 'race-time' | 'link' | 'note' | 'selection' | 'empty';
|
|
358
362
|
interface ChartMarkBase {
|
|
359
363
|
/** Unique within the scene (a stable key for frameworks). */
|
|
360
364
|
key: string;
|
package/dist/chart/types.d.ts
CHANGED
|
@@ -17,8 +17,10 @@
|
|
|
17
17
|
* - `sunburst` draws `tree` as rings from the centre out (or, without a tree, the first series
|
|
18
18
|
* as one ring); a `treemap` with a `tree` nests each group's rectangles inside it.
|
|
19
19
|
* - `sankey` draws `links` as flows between columns of nodes.
|
|
20
|
+
* - `barrace` reads each category as a time point and each series as a name, and draws the
|
|
21
|
+
* top `raceTopN` names at one moment as ranked horizontal bars (an animated ranking).
|
|
20
22
|
*/
|
|
21
|
-
export type ChartType = 'bar' | 'line' | 'area' | 'scatter' | 'bubble' | 'pie' | 'donut' | 'radar' | 'waterfall' | 'histogram' | 'box' | 'funnel' | 'treemap' | 'slope' | 'likert' | 'parliament' | 'sunburst' | 'sankey';
|
|
23
|
+
export type ChartType = 'bar' | 'line' | 'area' | 'scatter' | 'bubble' | 'pie' | 'donut' | 'radar' | 'waterfall' | 'histogram' | 'box' | 'funnel' | 'treemap' | 'slope' | 'likert' | 'parliament' | 'sunburst' | 'sankey' | 'barrace';
|
|
22
24
|
/** How a series is drawn in a cartesian chart. */
|
|
23
25
|
export type ChartSeriesType = 'bar' | 'line' | 'area' | 'scatter';
|
|
24
26
|
/** One data value; `null` is a gap (missing value). */
|
|
@@ -299,6 +301,8 @@ export interface ChartSpec {
|
|
|
299
301
|
sankeyNodes: string[];
|
|
300
302
|
/** Sankey: what colours each flow. */
|
|
301
303
|
sankeyLinkColor: ChartSankeyLinkColor;
|
|
304
|
+
/** Bar race: how many bars each moment shows, 1–30. */
|
|
305
|
+
raceTopN: number;
|
|
302
306
|
}
|
|
303
307
|
/** What a click selects. */
|
|
304
308
|
export type ChartSelection = {
|
|
@@ -354,7 +358,7 @@ export interface ChartRect {
|
|
|
354
358
|
height: number;
|
|
355
359
|
}
|
|
356
360
|
/** What a mark is, for styling and tests. */
|
|
357
|
-
export type ChartMarkRole = 'background' | 'title' | 'subtitle' | 'grid' | 'axis' | 'tick' | 'tick-label' | 'axis-title' | 'bar' | 'line' | 'area' | 'point' | 'slice' | 'cell' | 'box' | 'whisker' | 'outlier' | 'connector' | 'trendline' | 'trendline-label' | 'error-bar' | 'data-label' | 'legend-swatch' | 'legend-label' | 'drag-readout' | 'reference-line' | 'reference-band' | 'reference-label' | 'callout' | 'node' | 'link' | 'note' | 'selection' | 'empty';
|
|
361
|
+
export type ChartMarkRole = 'background' | 'title' | 'subtitle' | 'grid' | 'axis' | 'tick' | 'tick-label' | 'axis-title' | 'bar' | 'line' | 'area' | 'point' | 'slice' | 'cell' | 'box' | 'whisker' | 'outlier' | 'connector' | 'trendline' | 'trendline-label' | 'error-bar' | 'data-label' | 'legend-swatch' | 'legend-label' | 'drag-readout' | 'reference-line' | 'reference-band' | 'reference-label' | 'callout' | 'node' | 'race-time' | 'link' | 'note' | 'selection' | 'empty';
|
|
358
362
|
interface ChartMarkBase {
|
|
359
363
|
/** Unique within the scene (a stable key for frameworks). */
|
|
360
364
|
key: string;
|
|
@@ -18,7 +18,7 @@ import {
|
|
|
18
18
|
CHART_STACKINGS,
|
|
19
19
|
CHART_TRENDLINE_TYPES,
|
|
20
20
|
CHART_TYPES
|
|
21
|
-
} from "./chunk-
|
|
21
|
+
} from "./chunk-FR432ROA.js";
|
|
22
22
|
|
|
23
23
|
// src/chart/schemas.ts
|
|
24
24
|
var VALUE = { type: ["number", "string", "null"], description: 'A number, numeric text ("1,200", "12%", "$40", "(3)") or null for a gap.' };
|
|
@@ -119,6 +119,7 @@ var LINK_PROPS = {
|
|
|
119
119
|
value: { type: "number", exclusiveMinimum: 0, description: "How much flows, above 0 (its width)." },
|
|
120
120
|
color: { type: "string", description: "CSS colour (default: by sankeyLinkColor)." }
|
|
121
121
|
};
|
|
122
|
+
var RACE_TIME = { type: ["string", "number"], description: 'Time point label (a category, e.g. "2023") or index from 0; an index may be fractional, 2.5 being halfway between the third and fourth time points.' };
|
|
122
123
|
var LINK_INDEX = { type: "integer", minimum: 0, description: "Flow index (0 = first), as get_chart lists them in spec.links." };
|
|
123
124
|
var ERROR_BARS = (what) => ({
|
|
124
125
|
type: ["object", "null"],
|
|
@@ -157,7 +158,7 @@ var SERIES_PROPS = {
|
|
|
157
158
|
xErrorBars: ERROR_BARS("Error bars along the x axis (scatter and bubble charts with numeric x values; amounts in x units).")
|
|
158
159
|
};
|
|
159
160
|
var CHART_UPDATE_PROPERTIES = {
|
|
160
|
-
type: { type: "string", enum: [...CHART_TYPES], description: "Chart type. slope joins each category from the first series (before) to the second (after); likert reads each category as a question and the series as answers from most negative to most positive; parliament draws the first series as seats; sunburst draws the grouped data (set_chart_tree) as rings, and a treemap with grouped data nests its groups; sankey draws the flows (set_chart_links)." },
|
|
161
|
+
type: { type: "string", enum: [...CHART_TYPES], description: "Chart type. slope joins each category from the first series (before) to the second (after); likert reads each category as a question and the series as answers from most negative to most positive; parliament draws the first series as seats; sunburst draws the grouped data (set_chart_tree) as rings, and a treemap with grouped data nests its groups; sankey draws the flows (set_chart_links); barrace reads categories as time points and series as names, and animates their ranking." },
|
|
161
162
|
title: { type: "string", description: 'Title ("" for none).' },
|
|
162
163
|
subtitle: { type: "string", description: 'Subtitle ("" for none).' },
|
|
163
164
|
xAxis: AXIS("Category axis (or numeric x axis of scatter / bubble charts)."),
|
|
@@ -195,6 +196,7 @@ var CHART_UPDATE_PROPERTIES = {
|
|
|
195
196
|
parliamentLabel: { type: "string", description: 'Parliament: caption under the seat total ("" writes "seats").' },
|
|
196
197
|
sunburstLabel: { type: "string", description: 'Sunburst: caption under the total in the centre ("" for none).' },
|
|
197
198
|
sankeyLinkColor: { type: "string", enum: [...CHART_SANKEY_LINK_COLORS], description: "Sankey: colour each flow by its source node (default), its target node, or grey." },
|
|
199
|
+
raceTopN: { type: "integer", minimum: 1, maximum: 30, description: "Bar race: how many bars each moment shows (default 10)." },
|
|
198
200
|
sankeyNodes: { type: "array", items: { type: "string" }, description: "Sankey: node names in the order to stack them within their columns (reorder to untangle crossing flows); nodes left out follow in the order the flows name them." }
|
|
199
201
|
};
|
|
200
202
|
|
|
@@ -213,6 +215,7 @@ export {
|
|
|
213
215
|
TREE_DEFS,
|
|
214
216
|
TREE_PATH,
|
|
215
217
|
LINK_PROPS,
|
|
218
|
+
RACE_TIME,
|
|
216
219
|
LINK_INDEX,
|
|
217
220
|
SERIES_PROPS,
|
|
218
221
|
CHART_UPDATE_PROPERTIES
|