@pixerate/editor 0.165.0 → 0.167.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.
Files changed (55) hide show
  1. package/THIRD_PARTY_NOTICES.md +11 -0
  2. package/dist/agent/index.cjs +34 -34
  3. package/dist/agent/index.js +5 -5
  4. package/dist/canvas/index.cjs +6 -6
  5. package/dist/canvas/index.js +2 -2
  6. package/dist/chart/controller.d.cts +29 -0
  7. package/dist/chart/controller.d.ts +29 -0
  8. package/dist/chart/index.cjs +352 -179
  9. package/dist/chart/index.d.cts +2 -0
  10. package/dist/chart/index.d.ts +2 -0
  11. package/dist/chart/index.js +183 -10
  12. package/dist/chart/layout-families.d.cts +15 -0
  13. package/dist/chart/layout-families.d.ts +15 -0
  14. package/dist/chart/layout-shared.d.cts +5 -0
  15. package/dist/chart/layout-shared.d.ts +5 -0
  16. package/dist/chart/maps.d.cts +43 -0
  17. package/dist/chart/maps.d.ts +43 -0
  18. package/dist/chart/race.d.cts +26 -0
  19. package/dist/chart/race.d.ts +26 -0
  20. package/dist/chart/schemas.d.cts +2 -0
  21. package/dist/chart/schemas.d.ts +2 -0
  22. package/dist/chart/spec.d.cts +1 -1
  23. package/dist/chart/spec.d.ts +1 -1
  24. package/dist/chart/types.d.cts +14 -2
  25. package/dist/chart/types.d.ts +14 -2
  26. package/dist/chart-maps/europe.d.cts +7 -0
  27. package/dist/chart-maps/europe.d.ts +7 -0
  28. package/dist/chart-maps/index.cjs +66 -0
  29. package/dist/chart-maps/index.d.cts +1 -0
  30. package/dist/chart-maps/index.d.ts +1 -0
  31. package/dist/chart-maps/index.js +66 -0
  32. package/dist/{chunk-IMRXC7OA.cjs → chunk-2F4GAZL5.cjs} +186 -96
  33. package/dist/{chunk-FEU2XVQH.js → chunk-34UCPHYO.js} +8 -2
  34. package/dist/{chunk-ODFCS7HF.cjs → chunk-E45AIIWY.cjs} +8 -8
  35. package/dist/{chunk-N7NBGT2Y.js → chunk-FKYGM35R.js} +2 -2
  36. package/dist/{chunk-64VWWR5U.cjs → chunk-GD34ICEX.cjs} +16 -16
  37. package/dist/{chunk-TVQW26AV.cjs → chunk-GTF4RYXJ.cjs} +29 -23
  38. package/dist/{chunk-V5GSY3NC.js → chunk-M52UCHVZ.js} +203 -3
  39. package/dist/{chunk-FRBRLKNQ.js → chunk-N3ACT6VJ.js} +92 -2
  40. package/dist/{chunk-CRFSQWKQ.js → chunk-OLCHKGGO.js} +7 -1
  41. package/dist/{chunk-2ZRN43IN.js → chunk-ORZF4JOO.js} +32 -4
  42. package/dist/{chunk-UVXTOZ2B.cjs → chunk-OUO3DSRT.cjs} +32 -4
  43. package/dist/{chunk-MKXK6E4O.cjs → chunk-SBAPXFPB.cjs} +51 -51
  44. package/dist/{chunk-2J5VLJHC.js → chunk-T62BRXMS.js} +3 -3
  45. package/dist/{chunk-Q25WAFTD.cjs → chunk-VKHJJUBK.cjs} +24 -18
  46. package/dist/{chunk-QO2T6KA5.cjs → chunk-WOIXNDHV.cjs} +247 -47
  47. package/dist/{chunk-X5W645RI.js → chunk-ZUPP4NKM.js} +3 -3
  48. package/dist/export/index.cjs +4 -4
  49. package/dist/export/index.js +3 -3
  50. package/dist/extensions/index.cjs +7 -7
  51. package/dist/extensions/index.js +6 -6
  52. package/dist/index.cjs +13 -13
  53. package/dist/index.js +7 -7
  54. package/package.json +11 -1
  55. package/skills/pixerate-chart/SKILL.md +36 -2
@@ -2,6 +2,8 @@ export * from './types.cjs';
2
2
  export * from './spec.cjs';
3
3
  export * from './tree.cjs';
4
4
  export * from './links.cjs';
5
+ export * from './race.cjs';
6
+ export * from './maps.cjs';
5
7
  export * from './scale.cjs';
6
8
  export * from './numfmt.cjs';
7
9
  export * from './color.cjs';
@@ -2,6 +2,8 @@ export * from './types.js';
2
2
  export * from './spec.js';
3
3
  export * from './tree.js';
4
4
  export * from './links.js';
5
+ export * from './race.js';
6
+ export * from './maps.js';
5
7
  export * from './scale.js';
6
8
  export * from './numfmt.js';
7
9
  export * from './color.js';
@@ -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-FEU2XVQH.js";
20
+ } from "../chunk-34UCPHYO.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-CRFSQWKQ.js";
28
+ } from "../chunk-OLCHKGGO.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-FRBRLKNQ.js";
50
+ } from "../chunk-N3ACT6VJ.js";
50
51
  import "../chunk-KGRZMHZB.js";
51
52
  import {
52
53
  CHART_DATE_STEPS,
@@ -57,8 +58,14 @@ import {
57
58
  chartDateLabels,
58
59
  chartDateToSerial,
59
60
  chartHistogram,
61
+ chartMapBreaks,
62
+ chartMapClass,
63
+ chartMapRamp,
60
64
  chartMovingAverage,
61
65
  chartQuantile,
66
+ chartRaceMoment,
67
+ chartRaceRanking,
68
+ chartRaceValueAt,
62
69
  chartScaleFromPixel,
63
70
  chartScaleToPixel,
64
71
  chartSerialToDate,
@@ -75,19 +82,23 @@ import {
75
82
  formatChartDate,
76
83
  formatChartNumber,
77
84
  formatChartValueWithCode,
85
+ getChartMap,
78
86
  layoutChart,
79
87
  linearMap,
88
+ listChartMaps,
89
+ matchChartMapRegions,
80
90
  niceLogScale,
81
91
  niceScale,
82
92
  niceStep,
83
93
  parseChartDate,
94
+ registerChartMap,
84
95
  sameChartSelection,
85
96
  snapChartValue,
86
97
  stepDecimals,
87
98
  suggestChartReferences,
88
99
  summarizeChartSeries,
89
100
  trendNumberText
90
- } from "../chunk-V5GSY3NC.js";
101
+ } from "../chunk-M52UCHVZ.js";
91
102
  import {
92
103
  CHART_AXIS_KINDS,
93
104
  CHART_AXIS_SCALES,
@@ -181,7 +192,7 @@ import {
181
192
  shadeChartColor,
182
193
  simulateChartVision,
183
194
  uniqueChartSeriesId
184
- } from "../chunk-2ZRN43IN.js";
195
+ } from "../chunk-ORZF4JOO.js";
185
196
  import "../chunk-O6OGNDND.js";
186
197
  import "../chunk-II2WIF5Z.js";
187
198
  import {
@@ -396,6 +407,7 @@ function recommendForShape(shape) {
396
407
  add("area", "Area", "Shows change over time with volume.");
397
408
  add("bar", "Column", "Compares each period.");
398
409
  if (shape.series > 1) add("area", "Stacked area", "Shows how the parts add up over time.", "stacked");
410
+ if (shape.series >= 5 && shape.points >= 3) add("barrace", "Bar race", "Many series over time: an animated ranking shows who leads when.");
399
411
  return out;
400
412
  }
401
413
  if (shape.series === 1) {
@@ -430,6 +442,7 @@ function recommendForShape(shape) {
430
442
  add("bar", "Stacked column", "Shows how the series add up.", "stacked");
431
443
  add("line", "Line", "Shows the series in order.");
432
444
  if (shape.points >= 3 && shape.series <= 6) add("radar", "Radar", "Compares several measures across the series.");
445
+ 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
446
  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
447
  }
435
448
  return out;
@@ -475,6 +488,12 @@ function createChartCommands(controller, options = {}) {
475
488
  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
489
  return index;
477
490
  };
491
+ const raceFrame = (time) => {
492
+ const cats = controller.getSpec().categories;
493
+ const frame = typeof time === "number" ? time : cats.indexOf(time);
494
+ 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.`);
495
+ return frame;
496
+ };
478
497
  const object = (properties, required) => ({ type: "object", properties, ...required ? { required } : {}, additionalProperties: false });
479
498
  return [
480
499
  {
@@ -887,6 +906,73 @@ function createChartCommands(controller, options = {}) {
887
906
  return { links: controller.getSpec().links };
888
907
  }
889
908
  },
909
+ {
910
+ ...base,
911
+ id: `${prefix}mapRegions`,
912
+ label: "Map Regions",
913
+ readOnly: true,
914
+ keywords: ["chart", "map", "choropleth", "regions", "countries", "codes"],
915
+ description: "Lists the regions of the chart's map (or another registered map) and which categories match none.",
916
+ params: object({ map: { type: "string", description: "Map id (default: the chart's map)." } }),
917
+ run: (_ctx, params = {}) => {
918
+ const id = params?.map ?? controller.getSpec().map;
919
+ const geometry = getChartMap(id);
920
+ if (!geometry) fail(`There is no map "${id}"; register it with registerChartMap.`);
921
+ const matches = matchChartMapRegions(geometry, controller.getSpec().categories);
922
+ return { regions: geometry.regions.map((r) => ({ id: r.id, name: r.name })), unmatched: controller.getSpec().categories.filter((_, i) => !matches[i]) };
923
+ }
924
+ },
925
+ {
926
+ ...base,
927
+ id: `${prefix}raceRanking`,
928
+ label: "Bar Race Ranking",
929
+ readOnly: true,
930
+ keywords: ["chart", "race", "ranking", "leader", "time"],
931
+ description: "Returns the top names of a bar race at a moment (default: the one shown).",
932
+ params: object({ time: RACE_TIME }),
933
+ run: (_ctx, params = {}) => {
934
+ const spec = controller.getSpec();
935
+ const frame = params?.time !== void 0 ? raceFrame(params.time) : controller.getState().raceFrame ?? spec.categories.length - 1;
936
+ 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 })) };
937
+ }
938
+ },
939
+ {
940
+ ...base,
941
+ id: `${prefix}setRaceFrame`,
942
+ label: "Show Bar Race Moment\u2026",
943
+ keywords: ["chart", "race", "frame", "time", "scrub"],
944
+ description: "Shows the bar race at a time point (null for the last) and stops playback. View state, not an undo step.",
945
+ params: object({ time: { ...RACE_TIME, type: ["string", "number", "null"], description: `${RACE_TIME.description} null shows the last time point.` } }, ["time"]),
946
+ run: (_ctx, params) => {
947
+ const frame = params.time === null ? null : raceFrame(params.time);
948
+ check(controller.setRaceFrame(frame));
949
+ return { frame };
950
+ }
951
+ },
952
+ {
953
+ ...base,
954
+ id: `${prefix}playRace`,
955
+ label: "Play Bar Race",
956
+ keywords: ["chart", "race", "play", "animate"],
957
+ description: "Plays the bar race from the moment shown, one time point every msPerStep ms.",
958
+ params: object({ msPerStep: { type: "number", minimum: 50, maximum: 1e4, description: "Milliseconds per time point (default 1000)." } }),
959
+ run: (_ctx, params = {}) => {
960
+ check(controller.playRace({ msPerStep: params?.msPerStep }));
961
+ return { playing: true };
962
+ }
963
+ },
964
+ {
965
+ ...base,
966
+ id: `${prefix}pauseRace`,
967
+ label: "Pause Bar Race",
968
+ keywords: ["chart", "race", "pause", "stop"],
969
+ description: "Pauses bar race playback where it is.",
970
+ enabled: () => controller.getState().racePlaying || "The race is not playing",
971
+ run: () => {
972
+ controller.pauseRace();
973
+ return { frame: controller.getState().raceFrame };
974
+ }
975
+ },
890
976
  {
891
977
  ...base,
892
978
  id: `${prefix}applyPreset`,
@@ -1484,6 +1570,10 @@ function planChartToolPlayback(tool, args) {
1484
1570
  return click(control("series.callout"));
1485
1571
  case "highlight_chart":
1486
1572
  return click(control("highlight"));
1573
+ case "set_chart_race_frame":
1574
+ return click(control("raceFrame"));
1575
+ case "play_chart_race":
1576
+ return click({ kind: "action", id: "race-play" });
1487
1577
  case "render_chart":
1488
1578
  return [{ type: "target", ref: { kind: "action", id: "download-png" } }];
1489
1579
  case "undo_chart":
@@ -1548,6 +1638,22 @@ function createChartToolProvider(controller, options = {}) {
1548
1638
  const depth = chartTreeDepth(spec().tree);
1549
1639
  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
1640
  };
1641
+ const raceFrameOf = (time) => {
1642
+ const cats = spec().categories;
1643
+ const frame = typeof time === "number" ? time : cats.indexOf(time);
1644
+ if (!(Number.isFinite(frame) && frame >= 0 && frame <= cats.length - 1))
1645
+ 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(", ")}.`);
1646
+ return frame;
1647
+ };
1648
+ const raceAt = (frame) => {
1649
+ const s = spec();
1650
+ const at = frame ?? s.categories.length - 1;
1651
+ return {
1652
+ frame: at,
1653
+ time: s.categories[Math.round(at)] ?? null,
1654
+ ranking: chartRaceRanking(s, at).slice(0, s.raceTopN).map((e) => ({ rank: e.rank + 1, series: e.seriesId, name: e.name, value: e.value }))
1655
+ };
1656
+ };
1551
1657
  const linksSummary = () => ({ links: spec().links, nodes: spec().sankeyNodes.map((name, i) => ({ name, value: chartSankeyNodeValues(spec().links, spec().sankeyNodes)[i] })) });
1552
1658
  const treeSummary = () => ({ tree: spec().tree, groups: spec().tree.map((n) => ({ name: n.name, total: chartTreeTotal(n) })), depth: chartTreeDepth(spec().tree) });
1553
1659
  const Parser = () => options.DOMParser ?? globalThis.DOMParser;
@@ -1579,14 +1685,16 @@ function createChartToolProvider(controller, options = {}) {
1579
1685
  properties: {
1580
1686
  width: WIDTH,
1581
1687
  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)." }
1688
+ 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)." },
1689
+ time: { ...RACE_TIME, description: `Bar race only: the moment to draw (default: the one shown). ${RACE_TIME.description}` }
1583
1690
  },
1584
1691
  additionalProperties: false
1585
1692
  },
1586
1693
  annotations: { title: "Render the chart", ...READ },
1587
- handler: async ({ width = size.width, height = size.height, format = "svg" }) => {
1694
+ handler: async ({ width = size.width, height = size.height, format = "svg", time }) => {
1588
1695
  const json = controller.toJSON();
1589
- const scene = layoutChart(json, { width, height, selection: null });
1696
+ const raceFrame = time !== void 0 ? raceFrameOf(time) : controller.getState().raceFrame;
1697
+ const scene = layoutChart(json, { width, height, selection: null, raceFrame });
1590
1698
  const svg = chartSceneToSvg(scene, { ariaLabel: json.title || void 0, description: describeChart(json) });
1591
1699
  const warnings = scene.warnings;
1592
1700
  if (format === "png") {
@@ -1659,6 +1767,35 @@ function createChartToolProvider(controller, options = {}) {
1659
1767
  return { trendline: line, coefficients: fit.coefficients, r2: fit.r2, equation: fit.equation, points: fit.points };
1660
1768
  }
1661
1769
  };
1770
+ const raceRanking = {
1771
+ name: "get_chart_race_ranking",
1772
+ title: "Read a bar race ranking",
1773
+ 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.",
1774
+ inputSchema: { type: "object", properties: { time: RACE_TIME }, additionalProperties: false },
1775
+ annotations: { title: "Read a bar race ranking", ...READ },
1776
+ handler: ({ time }) => raceAt(time !== void 0 ? raceFrameOf(time) : controller.getState().raceFrame)
1777
+ };
1778
+ const mapRegions = {
1779
+ name: "list_chart_map_regions",
1780
+ title: "List map regions",
1781
+ description: "Lists the maps a choropleth can draw and the regions of one (default: the chart's map), each with the id and name that categories may use, and how the chart's categories match them: matched (category \u2192 region id) and unmatched. Use it to pick category labels before set_chart_data, and to fix unmatched ones.",
1782
+ inputSchema: { type: "object", properties: { map: { type: "string", description: "Map id (default: the chart's map)." } }, additionalProperties: false },
1783
+ annotations: { title: "List map regions", ...READ },
1784
+ handler: ({ map }) => {
1785
+ const id = map ?? spec().map;
1786
+ const maps = listChartMaps().map((m) => ({ id: m.id, name: m.name, regions: m.regions.length }));
1787
+ const geometry = getChartMap(id);
1788
+ if (!geometry) fail2(maps.length ? `There is no map "${id}"; the host has ${maps.map((m) => `"${m.id}"`).join(", ")}.` : `There is no map "${id}": the host has not registered any maps (EUROPE_CHART_MAP in @pixerate/editor/chart-maps).`);
1789
+ const matches = matchChartMapRegions(geometry, spec().categories);
1790
+ return {
1791
+ maps,
1792
+ map: id,
1793
+ regions: geometry.regions.map((r) => ({ id: r.id, name: r.name })),
1794
+ matched: spec().categories.flatMap((c, i) => matches[i] ? [{ category: c, region: matches[i].id }] : []),
1795
+ unmatched: spec().categories.filter((_, i) => !matches[i])
1796
+ };
1797
+ }
1798
+ };
1662
1799
  const listPresets = {
1663
1800
  name: "list_chart_presets",
1664
1801
  title: "List chart presets",
@@ -2150,6 +2287,30 @@ function createChartToolProvider(controller, options = {}) {
2150
2287
  return { links: spec().links };
2151
2288
  }
2152
2289
  };
2290
+ const setRaceFrame = {
2291
+ name: "set_chart_race_frame",
2292
+ title: "Show a bar race moment",
2293
+ 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.",
2294
+ 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 },
2295
+ annotations: { title: "Show a bar race moment", ...WRITE_IDEMPOTENT },
2296
+ handler: ({ time }) => {
2297
+ const frame = time === null ? null : raceFrameOf(time);
2298
+ resolve(controller.setRaceFrame(frame));
2299
+ return raceAt(frame);
2300
+ }
2301
+ };
2302
+ const playRace = {
2303
+ name: "play_chart_race",
2304
+ title: "Play the bar race",
2305
+ 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.",
2306
+ inputSchema: { type: "object", properties: { msPerStep: { type: "number", minimum: 50, maximum: 1e4, description: "Milliseconds per time point (default 1000)." } }, additionalProperties: false },
2307
+ annotations: { title: "Play the bar race", ...WRITE },
2308
+ handler: ({ msPerStep }) => {
2309
+ resolve(controller.playRace({ msPerStep }));
2310
+ const n = spec().categories.length;
2311
+ return { playing: true, from: controller.getState().raceFrame ?? 0, durationMs: Math.round((n - 1 - (controller.getState().raceFrame ?? 0)) * (msPerStep ?? 1e3)) };
2312
+ }
2313
+ };
2153
2314
  const applyPreset = {
2154
2315
  name: "apply_chart_preset",
2155
2316
  title: "Apply a chart style",
@@ -2315,7 +2476,7 @@ function createChartToolProvider(controller, options = {}) {
2315
2476
  return { redone, ...redone ? { label } : {} };
2316
2477
  }
2317
2478
  };
2318
- const reads = [getChart, renderChart, checkColors, recommend, getTrendline, listPresets, exportMermaid, exportOoxml];
2479
+ const reads = [getChart, renderChart, checkColors, recommend, getTrendline, raceRanking, mapRegions, listPresets, exportMermaid, exportOoxml];
2319
2480
  const writes = [
2320
2481
  updateChart,
2321
2482
  setData,
@@ -2347,6 +2508,8 @@ function createChartToolProvider(controller, options = {}) {
2347
2508
  addLink,
2348
2509
  updateLink,
2349
2510
  removeLink,
2511
+ setRaceFrame,
2512
+ playRace,
2350
2513
  applyPreset,
2351
2514
  transpose,
2352
2515
  select,
@@ -2359,7 +2522,7 @@ function createChartToolProvider(controller, options = {}) {
2359
2522
  id: options.id ?? "chart",
2360
2523
  namespace: options.namespace,
2361
2524
  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.",
2525
+ 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
2526
  skill: "pixerate-chart",
2364
2527
  tools: () => {
2365
2528
  if (readOnlyReason()) return reads;
@@ -3105,6 +3268,9 @@ export {
3105
3268
  chartLikertColor,
3106
3269
  chartLinksFromTable,
3107
3270
  chartLuminance,
3271
+ chartMapBreaks,
3272
+ chartMapClass,
3273
+ chartMapRamp,
3108
3274
  chartMermaidFamily,
3109
3275
  chartMovingAverage,
3110
3276
  chartPointAnchor,
@@ -3112,6 +3278,9 @@ export {
3112
3278
  chartPointRef,
3113
3279
  chartPresetPatch,
3114
3280
  chartQuantile,
3281
+ chartRaceMoment,
3282
+ chartRaceRanking,
3283
+ chartRaceValueAt,
3115
3284
  chartRasterSize,
3116
3285
  chartRgbToHex,
3117
3286
  chartRgbToOklab,
@@ -3184,13 +3353,16 @@ export {
3184
3353
  formatChartDate,
3185
3354
  formatChartNumber,
3186
3355
  formatChartValueWithCode,
3356
+ getChartMap,
3187
3357
  handleChartKey,
3188
3358
  isCartesianChart,
3189
3359
  isXyChart,
3190
3360
  layoutChart,
3191
3361
  layoutSparkline,
3192
3362
  linearMap,
3363
+ listChartMaps,
3193
3364
  locateChartPoint,
3365
+ matchChartMapRegions,
3194
3366
  monochromeChartPalette,
3195
3367
  niceLogScale,
3196
3368
  niceScale,
@@ -3215,6 +3387,7 @@ export {
3215
3387
  realChartClock,
3216
3388
  recommendChartTypes,
3217
3389
  recommendForShape,
3390
+ registerChartMap,
3218
3391
  removeChartTreeRow,
3219
3392
  resolveChartSvgPaints,
3220
3393
  sameChartSelection,
@@ -45,3 +45,18 @@ 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;
55
+ /**
56
+ * Choropleth: the regions of a registered map (`spec.map`) shaded by the first series, one class
57
+ * per `mapSteps` (or `mapThresholds`), light to dark. Each category names a region by id or name;
58
+ * regions without data are grey and neighbouring land is drawn behind. Regions too small to see
59
+ * get a marker at their centre. The class legend runs along the bottom. The map must be
60
+ * registered and match a category (`layoutChart` draws bars otherwise).
61
+ */
62
+ export declare function layoutChoropleth(ctx: LayoutCtx, area: ChartRect, series: ChartSeries): FamilyResult;
@@ -45,3 +45,18 @@ 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;
55
+ /**
56
+ * Choropleth: the regions of a registered map (`spec.map`) shaded by the first series, one class
57
+ * per `mapSteps` (or `mapThresholds`), light to dark. Each category names a region by id or name;
58
+ * regions without data are grey and neighbouring land is drawn behind. Regions too small to see
59
+ * get a marker at their centre. The class legend runs along the bottom. The map must be
60
+ * registered and match a category (`layoutChart` draws bars otherwise).
61
+ */
62
+ export declare function layoutChoropleth(ctx: LayoutCtx, area: ChartRect, series: ChartSeries): 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,43 @@
1
+ /** One region of a map: an id (ISO 3166-1 alpha-3 for countries), a name and its outline. */
2
+ export interface ChartMapRegion {
3
+ id: string;
4
+ name: string;
5
+ /** SVG path data in the map's box (absolute M / L / Z commands). */
6
+ d: string;
7
+ /** Where a label or a marker goes, in the map's box. */
8
+ center: [number, number];
9
+ /** Area in square box units (0 for a region too small to outline, drawn as a marker). */
10
+ area: number;
11
+ }
12
+ export interface ChartMapGeometry {
13
+ /** What `spec.map` names, e.g. `europe`. */
14
+ id: string;
15
+ name: string;
16
+ width: number;
17
+ height: number;
18
+ regions: ChartMapRegion[];
19
+ /** Land in the frame that is not a region (neighbouring countries), drawn as background. */
20
+ land?: string;
21
+ /** Credit to show with the map (Natural Earth asks for none, but welcomes it). */
22
+ attribution?: string;
23
+ }
24
+ /** Makes a map available to choropleth charts (`spec.map` = its id). Registering an id again replaces it. */
25
+ export declare function registerChartMap(map: ChartMapGeometry): void;
26
+ /** A registered map by id, or undefined. */
27
+ export declare function getChartMap(id: string): ChartMapGeometry | undefined;
28
+ /** Every registered map. */
29
+ export declare function listChartMaps(): ChartMapGeometry[];
30
+ /**
31
+ * The region each category names, matched by id (any case) or by name (ignoring case and
32
+ * accents), or null. Several categories may not name the same region: the first wins.
33
+ */
34
+ export declare function matchChartMapRegions(map: ChartMapGeometry, categories: readonly string[]): (ChartMapRegion | null)[];
35
+ /**
36
+ * Class breaks for a choropleth: `thresholds` when given (ascending), else `steps` equal
37
+ * intervals between the smallest and largest value. Returns the inner breaks (one fewer than the classes).
38
+ */
39
+ export declare function chartMapBreaks(values: readonly number[], steps: number, thresholds: readonly number[]): number[];
40
+ /** The class (0-based) a value falls in: the number of breaks at or below it. */
41
+ export declare const chartMapClass: (value: number, breaks: readonly number[]) => number;
42
+ /** A light-to-dark ramp of `count` shades of `base`, one per class. */
43
+ export declare function chartMapRamp(base: string, count: number): string[];
@@ -0,0 +1,43 @@
1
+ /** One region of a map: an id (ISO 3166-1 alpha-3 for countries), a name and its outline. */
2
+ export interface ChartMapRegion {
3
+ id: string;
4
+ name: string;
5
+ /** SVG path data in the map's box (absolute M / L / Z commands). */
6
+ d: string;
7
+ /** Where a label or a marker goes, in the map's box. */
8
+ center: [number, number];
9
+ /** Area in square box units (0 for a region too small to outline, drawn as a marker). */
10
+ area: number;
11
+ }
12
+ export interface ChartMapGeometry {
13
+ /** What `spec.map` names, e.g. `europe`. */
14
+ id: string;
15
+ name: string;
16
+ width: number;
17
+ height: number;
18
+ regions: ChartMapRegion[];
19
+ /** Land in the frame that is not a region (neighbouring countries), drawn as background. */
20
+ land?: string;
21
+ /** Credit to show with the map (Natural Earth asks for none, but welcomes it). */
22
+ attribution?: string;
23
+ }
24
+ /** Makes a map available to choropleth charts (`spec.map` = its id). Registering an id again replaces it. */
25
+ export declare function registerChartMap(map: ChartMapGeometry): void;
26
+ /** A registered map by id, or undefined. */
27
+ export declare function getChartMap(id: string): ChartMapGeometry | undefined;
28
+ /** Every registered map. */
29
+ export declare function listChartMaps(): ChartMapGeometry[];
30
+ /**
31
+ * The region each category names, matched by id (any case) or by name (ignoring case and
32
+ * accents), or null. Several categories may not name the same region: the first wins.
33
+ */
34
+ export declare function matchChartMapRegions(map: ChartMapGeometry, categories: readonly string[]): (ChartMapRegion | null)[];
35
+ /**
36
+ * Class breaks for a choropleth: `thresholds` when given (ascending), else `steps` equal
37
+ * intervals between the smallest and largest value. Returns the inner breaks (one fewer than the classes).
38
+ */
39
+ export declare function chartMapBreaks(values: readonly number[], steps: number, thresholds: readonly number[]): number[];
40
+ /** The class (0-based) a value falls in: the number of breaks at or below it. */
41
+ export declare const chartMapClass: (value: number, breaks: readonly number[]) => number;
42
+ /** A light-to-dark ramp of `count` shades of `base`, one per class. */
43
+ export declare function chartMapRamp(base: string, count: number): string[];
@@ -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[];
@@ -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>;
@@ -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>;
@@ -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' | 'choropleth';
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;
@@ -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' | 'choropleth';
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;