@opendata-ai/openchart-core 8.0.0-rc.2 → 8.0.0-rc.20

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 (82) hide show
  1. package/dist/index.d.ts +490 -25
  2. package/dist/index.js +57 -19
  3. package/dist/index.js.map +1 -1
  4. package/dist/styles.css +1 -1
  5. package/dist/styles.css.map +1 -1
  6. package/package.json +1 -2
  7. package/schema/chart.schema.json +485 -35
  8. package/schema/table.schema.json +35 -1
  9. package/schema/vizspec.schema.json +1305 -120
  10. package/src/accessibility/__tests__/alt-text.test.ts +0 -110
  11. package/src/accessibility/__tests__/aria.test.ts +0 -125
  12. package/src/accessibility/alt-text.ts +0 -155
  13. package/src/accessibility/aria.ts +0 -75
  14. package/src/accessibility/index.ts +0 -6
  15. package/src/colors/__tests__/colorblind.test.ts +0 -75
  16. package/src/colors/__tests__/contrast.test.ts +0 -119
  17. package/src/colors/__tests__/palettes.test.ts +0 -74
  18. package/src/colors/colorblind.ts +0 -131
  19. package/src/colors/contrast.ts +0 -143
  20. package/src/colors/index.ts +0 -36
  21. package/src/colors/palettes.ts +0 -206
  22. package/src/helpers/__tests__/deep-merge.test.ts +0 -54
  23. package/src/helpers/__tests__/spec-builders.test.ts +0 -338
  24. package/src/helpers/deep-merge.ts +0 -29
  25. package/src/helpers/spec-builders.ts +0 -479
  26. package/src/index.ts +0 -215
  27. package/src/labels/__tests__/collision.test.ts +0 -310
  28. package/src/labels/collision.ts +0 -249
  29. package/src/labels/index.ts +0 -13
  30. package/src/layout/__tests__/chrome.test.ts +0 -208
  31. package/src/layout/__tests__/text-measure.test.ts +0 -57
  32. package/src/layout/chrome.ts +0 -470
  33. package/src/layout/index.ts +0 -18
  34. package/src/layout/text-measure.ts +0 -404
  35. package/src/layout/text-wrap.ts +0 -93
  36. package/src/locale/__tests__/format.test.ts +0 -606
  37. package/src/locale/format.ts +0 -459
  38. package/src/locale/index.ts +0 -21
  39. package/src/responsive/__tests__/breakpoints.test.ts +0 -146
  40. package/src/responsive/__tests__/metrics.test.ts +0 -52
  41. package/src/responsive/breakpoints.ts +0 -172
  42. package/src/responsive/index.ts +0 -53
  43. package/src/responsive/metrics.ts +0 -299
  44. package/src/schema/__tests__/generated-artifacts.test.ts +0 -42
  45. package/src/schema/__tests__/schema.test.ts +0 -179
  46. package/src/styles/__tests__/reduced-motion-selectors.test.ts +0 -28
  47. package/src/styles/animation.css +0 -199
  48. package/src/styles/base.css +0 -102
  49. package/src/styles/chrome.css +0 -174
  50. package/src/styles/dark.css +0 -44
  51. package/src/styles/graph.css +0 -135
  52. package/src/styles/index.css +0 -28
  53. package/src/styles/keyframes.css +0 -135
  54. package/src/styles/legend.css +0 -18
  55. package/src/styles/reduced-motion.css +0 -67
  56. package/src/styles/series-search.css +0 -153
  57. package/src/styles/sparkline.css +0 -16
  58. package/src/styles/table-animation.css +0 -93
  59. package/src/styles/table.css +0 -398
  60. package/src/styles/token-definitions.ts +0 -199
  61. package/src/styles/tokens.css +0 -156
  62. package/src/styles/tooltip.css +0 -126
  63. package/src/styles/you-draw-it.css +0 -126
  64. package/src/theme/__tests__/dark-mode.test.ts +0 -232
  65. package/src/theme/__tests__/defaults.test.ts +0 -73
  66. package/src/theme/__tests__/resolve.test.ts +0 -277
  67. package/src/theme/dark-mode.ts +0 -258
  68. package/src/theme/defaults.ts +0 -110
  69. package/src/theme/index.ts +0 -8
  70. package/src/theme/presets.ts +0 -64
  71. package/src/theme/resolve.ts +0 -312
  72. package/src/types/__tests__/encoding.test.ts +0 -368
  73. package/src/types/__tests__/gradient.test.ts +0 -95
  74. package/src/types/__tests__/spec.test.ts +0 -499
  75. package/src/types/encoding.ts +0 -280
  76. package/src/types/events.ts +0 -154
  77. package/src/types/index.ts +0 -287
  78. package/src/types/layout.ts +0 -1966
  79. package/src/types/schema-roots.ts +0 -32
  80. package/src/types/spec.ts +0 -2867
  81. package/src/types/table.ts +0 -108
  82. package/src/types/theme.ts +0 -209
@@ -152,8 +152,15 @@
152
152
  "description": "Clip marks to the chart area."
153
153
  },
154
154
  "trendline": {
155
- "type": "boolean",
156
- "description": "Overlay a least-squares regression line on scatter (point) marks. Defaults to true. Set `mark: { type: 'point', trendline: false }` to suppress it when the chart already carries its own reference line (e.g. a manual x=y diagonal in a separate layer), which would otherwise produce two competing diagonals."
155
+ "anyOf": [
156
+ {
157
+ "type": "boolean"
158
+ },
159
+ {
160
+ "$ref": "#/definitions/TrendlineConfig"
161
+ }
162
+ ],
163
+ "description": "Overlay a least-squares regression line on scatter (point) marks. Defaults to true. Set `mark: { type: 'point', trendline: false }` to suppress it when the chart already carries its own reference line (e.g. a manual x=y diagonal in a separate layer), which would otherwise produce two competing diagonals.\n\nPass an object to control stacking order: the line renders `below` the points by default, but a dense scatter (thousands of overlapping dots) fully occludes a line drawn underneath, so `{ layer: 'above' }` lifts the reference line over the cloud."
157
164
  },
158
165
  "dx": {
159
166
  "type": "number",
@@ -193,6 +200,15 @@
193
200
  ],
194
201
  "description": "Pattern-fill reinforcement for filled marks (bar, area, arc).\n\n- `'auto'`: assign a per-series SVG pattern (diagonal hatch, dots, crosshatch, vertical lines) layered over each series color so series remain distinguishable without color vision. Marks too small to show a legible pattern keep their solid fill.\n- `'none'` (default): solid fills only."
195
202
  },
203
+ "render": {
204
+ "type": "string",
205
+ "enum": [
206
+ "auto",
207
+ "svg",
208
+ "canvas"
209
+ ],
210
+ "description": "Rendering backend for point marks. High-cardinality scatter plots draw thousands of SVG circles, which is what makes their entrance and update transitions stutter; a canvas layer draws the same dots in a handful of batched paint calls.\n\n- `'auto'` (default): canvas above 1,000 compiled point marks, SVG below.\n- `'svg'`: always SVG, whatever the point count.\n- `'canvas'`: always canvas, whatever the point count.\n\nCanvas mode trades per-mark keyboard focus and edit-mode point selection (the screen-reader data table still carries every row), and draws the trendline above the dots even when `trendline.layer` is `'below'`. Tooltips, hover, and click callbacks work the same in both modes.\n\nIgnored with a console warning for non-point marks, and for faceted, layered, and sparkline charts."
211
+ },
196
212
  "style": {
197
213
  "type": "string",
198
214
  "enum": [
@@ -421,8 +437,15 @@
421
437
  "description": "Clip marks to the chart area."
422
438
  },
423
439
  "trendline": {
424
- "type": "boolean",
425
- "description": "Overlay a least-squares regression line on scatter (point) marks. Defaults to true. Set `mark: { type: 'point', trendline: false }` to suppress it when the chart already carries its own reference line (e.g. a manual x=y diagonal in a separate layer), which would otherwise produce two competing diagonals."
440
+ "anyOf": [
441
+ {
442
+ "type": "boolean"
443
+ },
444
+ {
445
+ "$ref": "#/definitions/TrendlineConfig"
446
+ }
447
+ ],
448
+ "description": "Overlay a least-squares regression line on scatter (point) marks. Defaults to true. Set `mark: { type: 'point', trendline: false }` to suppress it when the chart already carries its own reference line (e.g. a manual x=y diagonal in a separate layer), which would otherwise produce two competing diagonals.\n\nPass an object to control stacking order: the line renders `below` the points by default, but a dense scatter (thousands of overlapping dots) fully occludes a line drawn underneath, so `{ layer: 'above' }` lifts the reference line over the cloud."
426
449
  },
427
450
  "dx": {
428
451
  "type": "number",
@@ -462,6 +485,15 @@
462
485
  ],
463
486
  "description": "Pattern-fill reinforcement for filled marks (bar, area, arc).\n\n- `'auto'`: assign a per-series SVG pattern (diagonal hatch, dots, crosshatch, vertical lines) layered over each series color so series remain distinguishable without color vision. Marks too small to show a legible pattern keep their solid fill.\n- `'none'` (default): solid fills only."
464
487
  },
488
+ "render": {
489
+ "type": "string",
490
+ "enum": [
491
+ "auto",
492
+ "svg",
493
+ "canvas"
494
+ ],
495
+ "description": "Rendering backend for point marks. High-cardinality scatter plots draw thousands of SVG circles, which is what makes their entrance and update transitions stutter; a canvas layer draws the same dots in a handful of batched paint calls.\n\n- `'auto'` (default): canvas above 1,000 compiled point marks, SVG below.\n- `'svg'`: always SVG, whatever the point count.\n- `'canvas'`: always canvas, whatever the point count.\n\nCanvas mode trades per-mark keyboard focus and edit-mode point selection (the screen-reader data table still carries every row), and draws the trendline above the dots even when `trendline.layer` is `'below'`. Tooltips, hover, and click callbacks work the same in both modes.\n\nIgnored with a console warning for non-point marks, and for faceted, layered, and sparkline charts."
496
+ },
465
497
  "style": {
466
498
  "type": "string",
467
499
  "enum": [
@@ -690,8 +722,15 @@
690
722
  "description": "Clip marks to the chart area."
691
723
  },
692
724
  "trendline": {
693
- "type": "boolean",
694
- "description": "Overlay a least-squares regression line on scatter (point) marks. Defaults to true. Set `mark: { type: 'point', trendline: false }` to suppress it when the chart already carries its own reference line (e.g. a manual x=y diagonal in a separate layer), which would otherwise produce two competing diagonals."
725
+ "anyOf": [
726
+ {
727
+ "type": "boolean"
728
+ },
729
+ {
730
+ "$ref": "#/definitions/TrendlineConfig"
731
+ }
732
+ ],
733
+ "description": "Overlay a least-squares regression line on scatter (point) marks. Defaults to true. Set `mark: { type: 'point', trendline: false }` to suppress it when the chart already carries its own reference line (e.g. a manual x=y diagonal in a separate layer), which would otherwise produce two competing diagonals.\n\nPass an object to control stacking order: the line renders `below` the points by default, but a dense scatter (thousands of overlapping dots) fully occludes a line drawn underneath, so `{ layer: 'above' }` lifts the reference line over the cloud."
695
734
  },
696
735
  "dx": {
697
736
  "type": "number",
@@ -731,6 +770,15 @@
731
770
  ],
732
771
  "description": "Pattern-fill reinforcement for filled marks (bar, area, arc).\n\n- `'auto'`: assign a per-series SVG pattern (diagonal hatch, dots, crosshatch, vertical lines) layered over each series color so series remain distinguishable without color vision. Marks too small to show a legible pattern keep their solid fill.\n- `'none'` (default): solid fills only."
733
772
  },
773
+ "render": {
774
+ "type": "string",
775
+ "enum": [
776
+ "auto",
777
+ "svg",
778
+ "canvas"
779
+ ],
780
+ "description": "Rendering backend for point marks. High-cardinality scatter plots draw thousands of SVG circles, which is what makes their entrance and update transitions stutter; a canvas layer draws the same dots in a handful of batched paint calls.\n\n- `'auto'` (default): canvas above 1,000 compiled point marks, SVG below.\n- `'svg'`: always SVG, whatever the point count.\n- `'canvas'`: always canvas, whatever the point count.\n\nCanvas mode trades per-mark keyboard focus and edit-mode point selection (the screen-reader data table still carries every row), and draws the trendline above the dots even when `trendline.layer` is `'below'`. Tooltips, hover, and click callbacks work the same in both modes.\n\nIgnored with a console warning for non-point marks, and for faceted, layered, and sparkline charts."
781
+ },
734
782
  "style": {
735
783
  "type": "string",
736
784
  "enum": [
@@ -959,8 +1007,15 @@
959
1007
  "description": "Clip marks to the chart area."
960
1008
  },
961
1009
  "trendline": {
962
- "type": "boolean",
963
- "description": "Overlay a least-squares regression line on scatter (point) marks. Defaults to true. Set `mark: { type: 'point', trendline: false }` to suppress it when the chart already carries its own reference line (e.g. a manual x=y diagonal in a separate layer), which would otherwise produce two competing diagonals."
1010
+ "anyOf": [
1011
+ {
1012
+ "type": "boolean"
1013
+ },
1014
+ {
1015
+ "$ref": "#/definitions/TrendlineConfig"
1016
+ }
1017
+ ],
1018
+ "description": "Overlay a least-squares regression line on scatter (point) marks. Defaults to true. Set `mark: { type: 'point', trendline: false }` to suppress it when the chart already carries its own reference line (e.g. a manual x=y diagonal in a separate layer), which would otherwise produce two competing diagonals.\n\nPass an object to control stacking order: the line renders `below` the points by default, but a dense scatter (thousands of overlapping dots) fully occludes a line drawn underneath, so `{ layer: 'above' }` lifts the reference line over the cloud."
964
1019
  },
965
1020
  "dx": {
966
1021
  "type": "number",
@@ -1000,6 +1055,15 @@
1000
1055
  ],
1001
1056
  "description": "Pattern-fill reinforcement for filled marks (bar, area, arc).\n\n- `'auto'`: assign a per-series SVG pattern (diagonal hatch, dots, crosshatch, vertical lines) layered over each series color so series remain distinguishable without color vision. Marks too small to show a legible pattern keep their solid fill.\n- `'none'` (default): solid fills only."
1002
1057
  },
1058
+ "render": {
1059
+ "type": "string",
1060
+ "enum": [
1061
+ "auto",
1062
+ "svg",
1063
+ "canvas"
1064
+ ],
1065
+ "description": "Rendering backend for point marks. High-cardinality scatter plots draw thousands of SVG circles, which is what makes their entrance and update transitions stutter; a canvas layer draws the same dots in a handful of batched paint calls.\n\n- `'auto'` (default): canvas above 1,000 compiled point marks, SVG below.\n- `'svg'`: always SVG, whatever the point count.\n- `'canvas'`: always canvas, whatever the point count.\n\nCanvas mode trades per-mark keyboard focus and edit-mode point selection (the screen-reader data table still carries every row), and draws the trendline above the dots even when `trendline.layer` is `'below'`. Tooltips, hover, and click callbacks work the same in both modes.\n\nIgnored with a console warning for non-point marks, and for faceted, layered, and sparkline charts."
1066
+ },
1003
1067
  "style": {
1004
1068
  "type": "string",
1005
1069
  "enum": [
@@ -1228,8 +1292,15 @@
1228
1292
  "description": "Clip marks to the chart area."
1229
1293
  },
1230
1294
  "trendline": {
1231
- "type": "boolean",
1232
- "description": "Overlay a least-squares regression line on scatter (point) marks. Defaults to true. Set `mark: { type: 'point', trendline: false }` to suppress it when the chart already carries its own reference line (e.g. a manual x=y diagonal in a separate layer), which would otherwise produce two competing diagonals."
1295
+ "anyOf": [
1296
+ {
1297
+ "type": "boolean"
1298
+ },
1299
+ {
1300
+ "$ref": "#/definitions/TrendlineConfig"
1301
+ }
1302
+ ],
1303
+ "description": "Overlay a least-squares regression line on scatter (point) marks. Defaults to true. Set `mark: { type: 'point', trendline: false }` to suppress it when the chart already carries its own reference line (e.g. a manual x=y diagonal in a separate layer), which would otherwise produce two competing diagonals.\n\nPass an object to control stacking order: the line renders `below` the points by default, but a dense scatter (thousands of overlapping dots) fully occludes a line drawn underneath, so `{ layer: 'above' }` lifts the reference line over the cloud."
1233
1304
  },
1234
1305
  "dx": {
1235
1306
  "type": "number",
@@ -1269,6 +1340,15 @@
1269
1340
  ],
1270
1341
  "description": "Pattern-fill reinforcement for filled marks (bar, area, arc).\n\n- `'auto'`: assign a per-series SVG pattern (diagonal hatch, dots, crosshatch, vertical lines) layered over each series color so series remain distinguishable without color vision. Marks too small to show a legible pattern keep their solid fill.\n- `'none'` (default): solid fills only."
1271
1342
  },
1343
+ "render": {
1344
+ "type": "string",
1345
+ "enum": [
1346
+ "auto",
1347
+ "svg",
1348
+ "canvas"
1349
+ ],
1350
+ "description": "Rendering backend for point marks. High-cardinality scatter plots draw thousands of SVG circles, which is what makes their entrance and update transitions stutter; a canvas layer draws the same dots in a handful of batched paint calls.\n\n- `'auto'` (default): canvas above 1,000 compiled point marks, SVG below.\n- `'svg'`: always SVG, whatever the point count.\n- `'canvas'`: always canvas, whatever the point count.\n\nCanvas mode trades per-mark keyboard focus and edit-mode point selection (the screen-reader data table still carries every row), and draws the trendline above the dots even when `trendline.layer` is `'below'`. Tooltips, hover, and click callbacks work the same in both modes.\n\nIgnored with a console warning for non-point marks, and for faceted, layered, and sparkline charts."
1351
+ },
1272
1352
  "style": {
1273
1353
  "type": "string",
1274
1354
  "enum": [
@@ -1497,8 +1577,15 @@
1497
1577
  "description": "Clip marks to the chart area."
1498
1578
  },
1499
1579
  "trendline": {
1500
- "type": "boolean",
1501
- "description": "Overlay a least-squares regression line on scatter (point) marks. Defaults to true. Set `mark: { type: 'point', trendline: false }` to suppress it when the chart already carries its own reference line (e.g. a manual x=y diagonal in a separate layer), which would otherwise produce two competing diagonals."
1580
+ "anyOf": [
1581
+ {
1582
+ "type": "boolean"
1583
+ },
1584
+ {
1585
+ "$ref": "#/definitions/TrendlineConfig"
1586
+ }
1587
+ ],
1588
+ "description": "Overlay a least-squares regression line on scatter (point) marks. Defaults to true. Set `mark: { type: 'point', trendline: false }` to suppress it when the chart already carries its own reference line (e.g. a manual x=y diagonal in a separate layer), which would otherwise produce two competing diagonals.\n\nPass an object to control stacking order: the line renders `below` the points by default, but a dense scatter (thousands of overlapping dots) fully occludes a line drawn underneath, so `{ layer: 'above' }` lifts the reference line over the cloud."
1502
1589
  },
1503
1590
  "dx": {
1504
1591
  "type": "number",
@@ -1538,6 +1625,15 @@
1538
1625
  ],
1539
1626
  "description": "Pattern-fill reinforcement for filled marks (bar, area, arc).\n\n- `'auto'`: assign a per-series SVG pattern (diagonal hatch, dots, crosshatch, vertical lines) layered over each series color so series remain distinguishable without color vision. Marks too small to show a legible pattern keep their solid fill.\n- `'none'` (default): solid fills only."
1540
1627
  },
1628
+ "render": {
1629
+ "type": "string",
1630
+ "enum": [
1631
+ "auto",
1632
+ "svg",
1633
+ "canvas"
1634
+ ],
1635
+ "description": "Rendering backend for point marks. High-cardinality scatter plots draw thousands of SVG circles, which is what makes their entrance and update transitions stutter; a canvas layer draws the same dots in a handful of batched paint calls.\n\n- `'auto'` (default): canvas above 1,000 compiled point marks, SVG below.\n- `'svg'`: always SVG, whatever the point count.\n- `'canvas'`: always canvas, whatever the point count.\n\nCanvas mode trades per-mark keyboard focus and edit-mode point selection (the screen-reader data table still carries every row), and draws the trendline above the dots even when `trendline.layer` is `'below'`. Tooltips, hover, and click callbacks work the same in both modes.\n\nIgnored with a console warning for non-point marks, and for faceted, layered, and sparkline charts."
1636
+ },
1541
1637
  "style": {
1542
1638
  "type": "string",
1543
1639
  "enum": [
@@ -1766,8 +1862,15 @@
1766
1862
  "description": "Clip marks to the chart area."
1767
1863
  },
1768
1864
  "trendline": {
1769
- "type": "boolean",
1770
- "description": "Overlay a least-squares regression line on scatter (point) marks. Defaults to true. Set `mark: { type: 'point', trendline: false }` to suppress it when the chart already carries its own reference line (e.g. a manual x=y diagonal in a separate layer), which would otherwise produce two competing diagonals."
1865
+ "anyOf": [
1866
+ {
1867
+ "type": "boolean"
1868
+ },
1869
+ {
1870
+ "$ref": "#/definitions/TrendlineConfig"
1871
+ }
1872
+ ],
1873
+ "description": "Overlay a least-squares regression line on scatter (point) marks. Defaults to true. Set `mark: { type: 'point', trendline: false }` to suppress it when the chart already carries its own reference line (e.g. a manual x=y diagonal in a separate layer), which would otherwise produce two competing diagonals.\n\nPass an object to control stacking order: the line renders `below` the points by default, but a dense scatter (thousands of overlapping dots) fully occludes a line drawn underneath, so `{ layer: 'above' }` lifts the reference line over the cloud."
1771
1874
  },
1772
1875
  "dx": {
1773
1876
  "type": "number",
@@ -1807,6 +1910,15 @@
1807
1910
  ],
1808
1911
  "description": "Pattern-fill reinforcement for filled marks (bar, area, arc).\n\n- `'auto'`: assign a per-series SVG pattern (diagonal hatch, dots, crosshatch, vertical lines) layered over each series color so series remain distinguishable without color vision. Marks too small to show a legible pattern keep their solid fill.\n- `'none'` (default): solid fills only."
1809
1912
  },
1913
+ "render": {
1914
+ "type": "string",
1915
+ "enum": [
1916
+ "auto",
1917
+ "svg",
1918
+ "canvas"
1919
+ ],
1920
+ "description": "Rendering backend for point marks. High-cardinality scatter plots draw thousands of SVG circles, which is what makes their entrance and update transitions stutter; a canvas layer draws the same dots in a handful of batched paint calls.\n\n- `'auto'` (default): canvas above 1,000 compiled point marks, SVG below.\n- `'svg'`: always SVG, whatever the point count.\n- `'canvas'`: always canvas, whatever the point count.\n\nCanvas mode trades per-mark keyboard focus and edit-mode point selection (the screen-reader data table still carries every row), and draws the trendline above the dots even when `trendline.layer` is `'below'`. Tooltips, hover, and click callbacks work the same in both modes.\n\nIgnored with a console warning for non-point marks, and for faceted, layered, and sparkline charts."
1921
+ },
1810
1922
  "style": {
1811
1923
  "type": "string",
1812
1924
  "enum": [
@@ -2035,8 +2147,15 @@
2035
2147
  "description": "Clip marks to the chart area."
2036
2148
  },
2037
2149
  "trendline": {
2038
- "type": "boolean",
2039
- "description": "Overlay a least-squares regression line on scatter (point) marks. Defaults to true. Set `mark: { type: 'point', trendline: false }` to suppress it when the chart already carries its own reference line (e.g. a manual x=y diagonal in a separate layer), which would otherwise produce two competing diagonals."
2150
+ "anyOf": [
2151
+ {
2152
+ "type": "boolean"
2153
+ },
2154
+ {
2155
+ "$ref": "#/definitions/TrendlineConfig"
2156
+ }
2157
+ ],
2158
+ "description": "Overlay a least-squares regression line on scatter (point) marks. Defaults to true. Set `mark: { type: 'point', trendline: false }` to suppress it when the chart already carries its own reference line (e.g. a manual x=y diagonal in a separate layer), which would otherwise produce two competing diagonals.\n\nPass an object to control stacking order: the line renders `below` the points by default, but a dense scatter (thousands of overlapping dots) fully occludes a line drawn underneath, so `{ layer: 'above' }` lifts the reference line over the cloud."
2040
2159
  },
2041
2160
  "dx": {
2042
2161
  "type": "number",
@@ -2076,6 +2195,15 @@
2076
2195
  ],
2077
2196
  "description": "Pattern-fill reinforcement for filled marks (bar, area, arc).\n\n- `'auto'`: assign a per-series SVG pattern (diagonal hatch, dots, crosshatch, vertical lines) layered over each series color so series remain distinguishable without color vision. Marks too small to show a legible pattern keep their solid fill.\n- `'none'` (default): solid fills only."
2078
2197
  },
2198
+ "render": {
2199
+ "type": "string",
2200
+ "enum": [
2201
+ "auto",
2202
+ "svg",
2203
+ "canvas"
2204
+ ],
2205
+ "description": "Rendering backend for point marks. High-cardinality scatter plots draw thousands of SVG circles, which is what makes their entrance and update transitions stutter; a canvas layer draws the same dots in a handful of batched paint calls.\n\n- `'auto'` (default): canvas above 1,000 compiled point marks, SVG below.\n- `'svg'`: always SVG, whatever the point count.\n- `'canvas'`: always canvas, whatever the point count.\n\nCanvas mode trades per-mark keyboard focus and edit-mode point selection (the screen-reader data table still carries every row), and draws the trendline above the dots even when `trendline.layer` is `'below'`. Tooltips, hover, and click callbacks work the same in both modes.\n\nIgnored with a console warning for non-point marks, and for faceted, layered, and sparkline charts."
2206
+ },
2079
2207
  "style": {
2080
2208
  "type": "string",
2081
2209
  "enum": [
@@ -2304,8 +2432,15 @@
2304
2432
  "description": "Clip marks to the chart area."
2305
2433
  },
2306
2434
  "trendline": {
2307
- "type": "boolean",
2308
- "description": "Overlay a least-squares regression line on scatter (point) marks. Defaults to true. Set `mark: { type: 'point', trendline: false }` to suppress it when the chart already carries its own reference line (e.g. a manual x=y diagonal in a separate layer), which would otherwise produce two competing diagonals."
2435
+ "anyOf": [
2436
+ {
2437
+ "type": "boolean"
2438
+ },
2439
+ {
2440
+ "$ref": "#/definitions/TrendlineConfig"
2441
+ }
2442
+ ],
2443
+ "description": "Overlay a least-squares regression line on scatter (point) marks. Defaults to true. Set `mark: { type: 'point', trendline: false }` to suppress it when the chart already carries its own reference line (e.g. a manual x=y diagonal in a separate layer), which would otherwise produce two competing diagonals.\n\nPass an object to control stacking order: the line renders `below` the points by default, but a dense scatter (thousands of overlapping dots) fully occludes a line drawn underneath, so `{ layer: 'above' }` lifts the reference line over the cloud."
2309
2444
  },
2310
2445
  "dx": {
2311
2446
  "type": "number",
@@ -2345,6 +2480,15 @@
2345
2480
  ],
2346
2481
  "description": "Pattern-fill reinforcement for filled marks (bar, area, arc).\n\n- `'auto'`: assign a per-series SVG pattern (diagonal hatch, dots, crosshatch, vertical lines) layered over each series color so series remain distinguishable without color vision. Marks too small to show a legible pattern keep their solid fill.\n- `'none'` (default): solid fills only."
2347
2482
  },
2483
+ "render": {
2484
+ "type": "string",
2485
+ "enum": [
2486
+ "auto",
2487
+ "svg",
2488
+ "canvas"
2489
+ ],
2490
+ "description": "Rendering backend for point marks. High-cardinality scatter plots draw thousands of SVG circles, which is what makes their entrance and update transitions stutter; a canvas layer draws the same dots in a handful of batched paint calls.\n\n- `'auto'` (default): canvas above 1,000 compiled point marks, SVG below.\n- `'svg'`: always SVG, whatever the point count.\n- `'canvas'`: always canvas, whatever the point count.\n\nCanvas mode trades per-mark keyboard focus and edit-mode point selection (the screen-reader data table still carries every row), and draws the trendline above the dots even when `trendline.layer` is `'below'`. Tooltips, hover, and click callbacks work the same in both modes.\n\nIgnored with a console warning for non-point marks, and for faceted, layered, and sparkline charts."
2491
+ },
2348
2492
  "style": {
2349
2493
  "type": "string",
2350
2494
  "enum": [
@@ -2573,8 +2717,15 @@
2573
2717
  "description": "Clip marks to the chart area."
2574
2718
  },
2575
2719
  "trendline": {
2576
- "type": "boolean",
2577
- "description": "Overlay a least-squares regression line on scatter (point) marks. Defaults to true. Set `mark: { type: 'point', trendline: false }` to suppress it when the chart already carries its own reference line (e.g. a manual x=y diagonal in a separate layer), which would otherwise produce two competing diagonals."
2720
+ "anyOf": [
2721
+ {
2722
+ "type": "boolean"
2723
+ },
2724
+ {
2725
+ "$ref": "#/definitions/TrendlineConfig"
2726
+ }
2727
+ ],
2728
+ "description": "Overlay a least-squares regression line on scatter (point) marks. Defaults to true. Set `mark: { type: 'point', trendline: false }` to suppress it when the chart already carries its own reference line (e.g. a manual x=y diagonal in a separate layer), which would otherwise produce two competing diagonals.\n\nPass an object to control stacking order: the line renders `below` the points by default, but a dense scatter (thousands of overlapping dots) fully occludes a line drawn underneath, so `{ layer: 'above' }` lifts the reference line over the cloud."
2578
2729
  },
2579
2730
  "dx": {
2580
2731
  "type": "number",
@@ -2614,6 +2765,15 @@
2614
2765
  ],
2615
2766
  "description": "Pattern-fill reinforcement for filled marks (bar, area, arc).\n\n- `'auto'`: assign a per-series SVG pattern (diagonal hatch, dots, crosshatch, vertical lines) layered over each series color so series remain distinguishable without color vision. Marks too small to show a legible pattern keep their solid fill.\n- `'none'` (default): solid fills only."
2616
2767
  },
2768
+ "render": {
2769
+ "type": "string",
2770
+ "enum": [
2771
+ "auto",
2772
+ "svg",
2773
+ "canvas"
2774
+ ],
2775
+ "description": "Rendering backend for point marks. High-cardinality scatter plots draw thousands of SVG circles, which is what makes their entrance and update transitions stutter; a canvas layer draws the same dots in a handful of batched paint calls.\n\n- `'auto'` (default): canvas above 1,000 compiled point marks, SVG below.\n- `'svg'`: always SVG, whatever the point count.\n- `'canvas'`: always canvas, whatever the point count.\n\nCanvas mode trades per-mark keyboard focus and edit-mode point selection (the screen-reader data table still carries every row), and draws the trendline above the dots even when `trendline.layer` is `'below'`. Tooltips, hover, and click callbacks work the same in both modes.\n\nIgnored with a console warning for non-point marks, and for faceted, layered, and sparkline charts."
2776
+ },
2617
2777
  "style": {
2618
2778
  "type": "string",
2619
2779
  "enum": [
@@ -2842,8 +3002,15 @@
2842
3002
  "description": "Clip marks to the chart area."
2843
3003
  },
2844
3004
  "trendline": {
2845
- "type": "boolean",
2846
- "description": "Overlay a least-squares regression line on scatter (point) marks. Defaults to true. Set `mark: { type: 'point', trendline: false }` to suppress it when the chart already carries its own reference line (e.g. a manual x=y diagonal in a separate layer), which would otherwise produce two competing diagonals."
3005
+ "anyOf": [
3006
+ {
3007
+ "type": "boolean"
3008
+ },
3009
+ {
3010
+ "$ref": "#/definitions/TrendlineConfig"
3011
+ }
3012
+ ],
3013
+ "description": "Overlay a least-squares regression line on scatter (point) marks. Defaults to true. Set `mark: { type: 'point', trendline: false }` to suppress it when the chart already carries its own reference line (e.g. a manual x=y diagonal in a separate layer), which would otherwise produce two competing diagonals.\n\nPass an object to control stacking order: the line renders `below` the points by default, but a dense scatter (thousands of overlapping dots) fully occludes a line drawn underneath, so `{ layer: 'above' }` lifts the reference line over the cloud."
2847
3014
  },
2848
3015
  "dx": {
2849
3016
  "type": "number",
@@ -2883,6 +3050,15 @@
2883
3050
  ],
2884
3051
  "description": "Pattern-fill reinforcement for filled marks (bar, area, arc).\n\n- `'auto'`: assign a per-series SVG pattern (diagonal hatch, dots, crosshatch, vertical lines) layered over each series color so series remain distinguishable without color vision. Marks too small to show a legible pattern keep their solid fill.\n- `'none'` (default): solid fills only."
2885
3052
  },
3053
+ "render": {
3054
+ "type": "string",
3055
+ "enum": [
3056
+ "auto",
3057
+ "svg",
3058
+ "canvas"
3059
+ ],
3060
+ "description": "Rendering backend for point marks. High-cardinality scatter plots draw thousands of SVG circles, which is what makes their entrance and update transitions stutter; a canvas layer draws the same dots in a handful of batched paint calls.\n\n- `'auto'` (default): canvas above 1,000 compiled point marks, SVG below.\n- `'svg'`: always SVG, whatever the point count.\n- `'canvas'`: always canvas, whatever the point count.\n\nCanvas mode trades per-mark keyboard focus and edit-mode point selection (the screen-reader data table still carries every row), and draws the trendline above the dots even when `trendline.layer` is `'below'`. Tooltips, hover, and click callbacks work the same in both modes.\n\nIgnored with a console warning for non-point marks, and for faceted, layered, and sparkline charts."
3061
+ },
2886
3062
  "style": {
2887
3063
  "type": "string",
2888
3064
  "enum": [
@@ -3111,8 +3287,15 @@
3111
3287
  "description": "Clip marks to the chart area."
3112
3288
  },
3113
3289
  "trendline": {
3114
- "type": "boolean",
3115
- "description": "Overlay a least-squares regression line on scatter (point) marks. Defaults to true. Set `mark: { type: 'point', trendline: false }` to suppress it when the chart already carries its own reference line (e.g. a manual x=y diagonal in a separate layer), which would otherwise produce two competing diagonals."
3290
+ "anyOf": [
3291
+ {
3292
+ "type": "boolean"
3293
+ },
3294
+ {
3295
+ "$ref": "#/definitions/TrendlineConfig"
3296
+ }
3297
+ ],
3298
+ "description": "Overlay a least-squares regression line on scatter (point) marks. Defaults to true. Set `mark: { type: 'point', trendline: false }` to suppress it when the chart already carries its own reference line (e.g. a manual x=y diagonal in a separate layer), which would otherwise produce two competing diagonals.\n\nPass an object to control stacking order: the line renders `below` the points by default, but a dense scatter (thousands of overlapping dots) fully occludes a line drawn underneath, so `{ layer: 'above' }` lifts the reference line over the cloud."
3116
3299
  },
3117
3300
  "dx": {
3118
3301
  "type": "number",
@@ -3152,6 +3335,15 @@
3152
3335
  ],
3153
3336
  "description": "Pattern-fill reinforcement for filled marks (bar, area, arc).\n\n- `'auto'`: assign a per-series SVG pattern (diagonal hatch, dots, crosshatch, vertical lines) layered over each series color so series remain distinguishable without color vision. Marks too small to show a legible pattern keep their solid fill.\n- `'none'` (default): solid fills only."
3154
3337
  },
3338
+ "render": {
3339
+ "type": "string",
3340
+ "enum": [
3341
+ "auto",
3342
+ "svg",
3343
+ "canvas"
3344
+ ],
3345
+ "description": "Rendering backend for point marks. High-cardinality scatter plots draw thousands of SVG circles, which is what makes their entrance and update transitions stutter; a canvas layer draws the same dots in a handful of batched paint calls.\n\n- `'auto'` (default): canvas above 1,000 compiled point marks, SVG below.\n- `'svg'`: always SVG, whatever the point count.\n- `'canvas'`: always canvas, whatever the point count.\n\nCanvas mode trades per-mark keyboard focus and edit-mode point selection (the screen-reader data table still carries every row), and draws the trendline above the dots even when `trendline.layer` is `'below'`. Tooltips, hover, and click callbacks work the same in both modes.\n\nIgnored with a console warning for non-point marks, and for faceted, layered, and sparkline charts."
3346
+ },
3155
3347
  "style": {
3156
3348
  "type": "string",
3157
3349
  "enum": [
@@ -3380,8 +3572,15 @@
3380
3572
  "description": "Clip marks to the chart area."
3381
3573
  },
3382
3574
  "trendline": {
3383
- "type": "boolean",
3384
- "description": "Overlay a least-squares regression line on scatter (point) marks. Defaults to true. Set `mark: { type: 'point', trendline: false }` to suppress it when the chart already carries its own reference line (e.g. a manual x=y diagonal in a separate layer), which would otherwise produce two competing diagonals."
3575
+ "anyOf": [
3576
+ {
3577
+ "type": "boolean"
3578
+ },
3579
+ {
3580
+ "$ref": "#/definitions/TrendlineConfig"
3581
+ }
3582
+ ],
3583
+ "description": "Overlay a least-squares regression line on scatter (point) marks. Defaults to true. Set `mark: { type: 'point', trendline: false }` to suppress it when the chart already carries its own reference line (e.g. a manual x=y diagonal in a separate layer), which would otherwise produce two competing diagonals.\n\nPass an object to control stacking order: the line renders `below` the points by default, but a dense scatter (thousands of overlapping dots) fully occludes a line drawn underneath, so `{ layer: 'above' }` lifts the reference line over the cloud."
3385
3584
  },
3386
3585
  "dx": {
3387
3586
  "type": "number",
@@ -3421,6 +3620,15 @@
3421
3620
  ],
3422
3621
  "description": "Pattern-fill reinforcement for filled marks (bar, area, arc).\n\n- `'auto'`: assign a per-series SVG pattern (diagonal hatch, dots, crosshatch, vertical lines) layered over each series color so series remain distinguishable without color vision. Marks too small to show a legible pattern keep their solid fill.\n- `'none'` (default): solid fills only."
3423
3622
  },
3623
+ "render": {
3624
+ "type": "string",
3625
+ "enum": [
3626
+ "auto",
3627
+ "svg",
3628
+ "canvas"
3629
+ ],
3630
+ "description": "Rendering backend for point marks. High-cardinality scatter plots draw thousands of SVG circles, which is what makes their entrance and update transitions stutter; a canvas layer draws the same dots in a handful of batched paint calls.\n\n- `'auto'` (default): canvas above 1,000 compiled point marks, SVG below.\n- `'svg'`: always SVG, whatever the point count.\n- `'canvas'`: always canvas, whatever the point count.\n\nCanvas mode trades per-mark keyboard focus and edit-mode point selection (the screen-reader data table still carries every row), and draws the trendline above the dots even when `trendline.layer` is `'below'`. Tooltips, hover, and click callbacks work the same in both modes.\n\nIgnored with a console warning for non-point marks, and for faceted, layered, and sparkline charts."
3631
+ },
3424
3632
  "style": {
3425
3633
  "type": "string",
3426
3634
  "enum": [
@@ -3649,8 +3857,15 @@
3649
3857
  "description": "Clip marks to the chart area."
3650
3858
  },
3651
3859
  "trendline": {
3652
- "type": "boolean",
3653
- "description": "Overlay a least-squares regression line on scatter (point) marks. Defaults to true. Set `mark: { type: 'point', trendline: false }` to suppress it when the chart already carries its own reference line (e.g. a manual x=y diagonal in a separate layer), which would otherwise produce two competing diagonals."
3860
+ "anyOf": [
3861
+ {
3862
+ "type": "boolean"
3863
+ },
3864
+ {
3865
+ "$ref": "#/definitions/TrendlineConfig"
3866
+ }
3867
+ ],
3868
+ "description": "Overlay a least-squares regression line on scatter (point) marks. Defaults to true. Set `mark: { type: 'point', trendline: false }` to suppress it when the chart already carries its own reference line (e.g. a manual x=y diagonal in a separate layer), which would otherwise produce two competing diagonals.\n\nPass an object to control stacking order: the line renders `below` the points by default, but a dense scatter (thousands of overlapping dots) fully occludes a line drawn underneath, so `{ layer: 'above' }` lifts the reference line over the cloud."
3654
3869
  },
3655
3870
  "dx": {
3656
3871
  "type": "number",
@@ -3690,6 +3905,15 @@
3690
3905
  ],
3691
3906
  "description": "Pattern-fill reinforcement for filled marks (bar, area, arc).\n\n- `'auto'`: assign a per-series SVG pattern (diagonal hatch, dots, crosshatch, vertical lines) layered over each series color so series remain distinguishable without color vision. Marks too small to show a legible pattern keep their solid fill.\n- `'none'` (default): solid fills only."
3692
3907
  },
3908
+ "render": {
3909
+ "type": "string",
3910
+ "enum": [
3911
+ "auto",
3912
+ "svg",
3913
+ "canvas"
3914
+ ],
3915
+ "description": "Rendering backend for point marks. High-cardinality scatter plots draw thousands of SVG circles, which is what makes their entrance and update transitions stutter; a canvas layer draws the same dots in a handful of batched paint calls.\n\n- `'auto'` (default): canvas above 1,000 compiled point marks, SVG below.\n- `'svg'`: always SVG, whatever the point count.\n- `'canvas'`: always canvas, whatever the point count.\n\nCanvas mode trades per-mark keyboard focus and edit-mode point selection (the screen-reader data table still carries every row), and draws the trendline above the dots even when `trendline.layer` is `'below'`. Tooltips, hover, and click callbacks work the same in both modes.\n\nIgnored with a console warning for non-point marks, and for faceted, layered, and sparkline charts."
3916
+ },
3693
3917
  "style": {
3694
3918
  "type": "string",
3695
3919
  "enum": [
@@ -3918,8 +4142,15 @@
3918
4142
  "description": "Clip marks to the chart area."
3919
4143
  },
3920
4144
  "trendline": {
3921
- "type": "boolean",
3922
- "description": "Overlay a least-squares regression line on scatter (point) marks. Defaults to true. Set `mark: { type: 'point', trendline: false }` to suppress it when the chart already carries its own reference line (e.g. a manual x=y diagonal in a separate layer), which would otherwise produce two competing diagonals."
4145
+ "anyOf": [
4146
+ {
4147
+ "type": "boolean"
4148
+ },
4149
+ {
4150
+ "$ref": "#/definitions/TrendlineConfig"
4151
+ }
4152
+ ],
4153
+ "description": "Overlay a least-squares regression line on scatter (point) marks. Defaults to true. Set `mark: { type: 'point', trendline: false }` to suppress it when the chart already carries its own reference line (e.g. a manual x=y diagonal in a separate layer), which would otherwise produce two competing diagonals.\n\nPass an object to control stacking order: the line renders `below` the points by default, but a dense scatter (thousands of overlapping dots) fully occludes a line drawn underneath, so `{ layer: 'above' }` lifts the reference line over the cloud."
3923
4154
  },
3924
4155
  "dx": {
3925
4156
  "type": "number",
@@ -3959,6 +4190,15 @@
3959
4190
  ],
3960
4191
  "description": "Pattern-fill reinforcement for filled marks (bar, area, arc).\n\n- `'auto'`: assign a per-series SVG pattern (diagonal hatch, dots, crosshatch, vertical lines) layered over each series color so series remain distinguishable without color vision. Marks too small to show a legible pattern keep their solid fill.\n- `'none'` (default): solid fills only."
3961
4192
  },
4193
+ "render": {
4194
+ "type": "string",
4195
+ "enum": [
4196
+ "auto",
4197
+ "svg",
4198
+ "canvas"
4199
+ ],
4200
+ "description": "Rendering backend for point marks. High-cardinality scatter plots draw thousands of SVG circles, which is what makes their entrance and update transitions stutter; a canvas layer draws the same dots in a handful of batched paint calls.\n\n- `'auto'` (default): canvas above 1,000 compiled point marks, SVG below.\n- `'svg'`: always SVG, whatever the point count.\n- `'canvas'`: always canvas, whatever the point count.\n\nCanvas mode trades per-mark keyboard focus and edit-mode point selection (the screen-reader data table still carries every row), and draws the trendline above the dots even when `trendline.layer` is `'below'`. Tooltips, hover, and click callbacks work the same in both modes.\n\nIgnored with a console warning for non-point marks, and for faceted, layered, and sparkline charts."
4201
+ },
3962
4202
  "style": {
3963
4203
  "type": "string",
3964
4204
  "enum": [
@@ -4187,8 +4427,15 @@
4187
4427
  "description": "Clip marks to the chart area."
4188
4428
  },
4189
4429
  "trendline": {
4190
- "type": "boolean",
4191
- "description": "Overlay a least-squares regression line on scatter (point) marks. Defaults to true. Set `mark: { type: 'point', trendline: false }` to suppress it when the chart already carries its own reference line (e.g. a manual x=y diagonal in a separate layer), which would otherwise produce two competing diagonals."
4430
+ "anyOf": [
4431
+ {
4432
+ "type": "boolean"
4433
+ },
4434
+ {
4435
+ "$ref": "#/definitions/TrendlineConfig"
4436
+ }
4437
+ ],
4438
+ "description": "Overlay a least-squares regression line on scatter (point) marks. Defaults to true. Set `mark: { type: 'point', trendline: false }` to suppress it when the chart already carries its own reference line (e.g. a manual x=y diagonal in a separate layer), which would otherwise produce two competing diagonals.\n\nPass an object to control stacking order: the line renders `below` the points by default, but a dense scatter (thousands of overlapping dots) fully occludes a line drawn underneath, so `{ layer: 'above' }` lifts the reference line over the cloud."
4192
4439
  },
4193
4440
  "dx": {
4194
4441
  "type": "number",
@@ -4228,6 +4475,15 @@
4228
4475
  ],
4229
4476
  "description": "Pattern-fill reinforcement for filled marks (bar, area, arc).\n\n- `'auto'`: assign a per-series SVG pattern (diagonal hatch, dots, crosshatch, vertical lines) layered over each series color so series remain distinguishable without color vision. Marks too small to show a legible pattern keep their solid fill.\n- `'none'` (default): solid fills only."
4230
4477
  },
4478
+ "render": {
4479
+ "type": "string",
4480
+ "enum": [
4481
+ "auto",
4482
+ "svg",
4483
+ "canvas"
4484
+ ],
4485
+ "description": "Rendering backend for point marks. High-cardinality scatter plots draw thousands of SVG circles, which is what makes their entrance and update transitions stutter; a canvas layer draws the same dots in a handful of batched paint calls.\n\n- `'auto'` (default): canvas above 1,000 compiled point marks, SVG below.\n- `'svg'`: always SVG, whatever the point count.\n- `'canvas'`: always canvas, whatever the point count.\n\nCanvas mode trades per-mark keyboard focus and edit-mode point selection (the screen-reader data table still carries every row), and draws the trendline above the dots even when `trendline.layer` is `'below'`. Tooltips, hover, and click callbacks work the same in both modes.\n\nIgnored with a console warning for non-point marks, and for faceted, layered, and sparkline charts."
4486
+ },
4231
4487
  "style": {
4232
4488
  "type": "string",
4233
4489
  "enum": [
@@ -4455,6 +4711,29 @@
4455
4711
  "additionalProperties": false,
4456
4712
  "description": "Radial gradient definition. Coordinates are in [0,1] normalized space relative to the mark's bounding box."
4457
4713
  },
4714
+ "TrendlineConfig": {
4715
+ "type": "object",
4716
+ "properties": {
4717
+ "layer": {
4718
+ "type": "string",
4719
+ "enum": [
4720
+ "above",
4721
+ "below"
4722
+ ],
4723
+ "description": "Stacking order relative to the point marks. `'below'` (default) draws the line behind the dots; `'above'` draws it on top so it stays visible over a dense cloud."
4724
+ },
4725
+ "stroke": {
4726
+ "type": "string",
4727
+ "description": "Stroke color. Defaults to the theme's high-contrast text color so the line reads on both light and dark grounds. Set an explicit CSS color to override."
4728
+ },
4729
+ "strokeWidth": {
4730
+ "type": "number",
4731
+ "description": "Stroke width in pixels. Defaults to 1.5. Over a dense cloud with `layer: 'above'`, a heavier line (e.g. 2.5) stays legible where the thin default disappears into the dots."
4732
+ }
4733
+ },
4734
+ "additionalProperties": false,
4735
+ "description": "Configuration for the scatter regression trend line. Passed as the object form of `MarkDef.trendline`."
4736
+ },
4458
4737
  "ArcEncoding<DataRow>": {
4459
4738
  "type": "object",
4460
4739
  "properties": {
@@ -4554,6 +4833,14 @@
4554
4833
  "facet": {
4555
4834
  "$ref": "#/definitions/FacetChannel%3CDataRow%3E",
4556
4835
  "description": "Facet channel: partitions data into a grid of small-multiple panels. Each unique value of the facet field produces one panel. Panels share scales by default; use `resolve: { scale: { y: 'independent' } }` for per-panel axes."
4836
+ },
4837
+ "row": {
4838
+ "$ref": "#/definitions/FacetChannel%3CDataRow%3E",
4839
+ "description": "Row facet channel: partitions data into vertically-stacked panels. Each unique value of the row field produces one panel, arranged in a single column. Shares the x-axis scale by default; y-axis is independent. Mutually exclusive with `facet` and `column`."
4840
+ },
4841
+ "column": {
4842
+ "$ref": "#/definitions/FacetChannel%3CDataRow%3E",
4843
+ "description": "Column facet channel: partitions data into side-by-side panels. Each unique value of the column field produces one panel, arranged in a single row. Shares the y-axis scale by default; x-axis is independent. Mutually exclusive with `facet` and `row`."
4557
4844
  }
4558
4845
  },
4559
4846
  "required": [
@@ -5063,12 +5350,13 @@
5063
5350
  "type": "string",
5064
5351
  "enum": [
5065
5352
  "top",
5353
+ "top-left",
5066
5354
  "right",
5067
5355
  "bottom",
5068
5356
  "bottom-right",
5069
5357
  "inline"
5070
5358
  ],
5071
- "description": "Legend position at a given breakpoint."
5359
+ "description": "Legend position at a given breakpoint. `'top-left'` is a map-only overlay position: the legend floats inside the map area's top-left corner (with its own backdrop) instead of reserving a block of figure height. Charts treat it as the default position."
5072
5360
  },
5073
5361
  "AnnotationOffset": {
5074
5362
  "type": "object",
@@ -5860,6 +6148,10 @@
5860
6148
  "color": {
5861
6149
  "type": "string",
5862
6150
  "description": "Text color (CSS color string)."
6151
+ },
6152
+ "maxLines": {
6153
+ "type": "number",
6154
+ "description": "Maximum number of lines this chrome text may wrap to. Additional lines are dropped and the last kept line is truncated with an ellipsis. Bounds the chrome's contribution to layout height at any container width. Applies whether the font size comes from the theme default or an explicit override. Caps height only, not horizontal overflow of a single unbreakable word."
5863
6155
  }
5864
6156
  },
5865
6157
  "additionalProperties": false,
@@ -6912,7 +7204,7 @@
6912
7204
  "update": {
6913
7205
  "anyOf": [
6914
7206
  {
6915
- "$ref": "#/definitions/AnimationPhaseConfig"
7207
+ "$ref": "#/definitions/UpdatePhaseConfig"
6916
7208
  },
6917
7209
  {
6918
7210
  "type": "boolean"
@@ -6993,6 +7285,36 @@
6993
7285
  "additionalProperties": false,
6994
7286
  "description": "Stagger configuration for sequential element reveal."
6995
7287
  },
7288
+ "UpdatePhaseConfig": {
7289
+ "type": "object",
7290
+ "properties": {
7291
+ "duration": {
7292
+ "type": "number",
7293
+ "description": "Duration in ms. Default: 500 for enter."
7294
+ },
7295
+ "ease": {
7296
+ "$ref": "#/definitions/AnimationEase",
7297
+ "description": "Easing preset. Default: 'smooth'."
7298
+ },
7299
+ "stagger": {
7300
+ "anyOf": [
7301
+ {
7302
+ "$ref": "#/definitions/AnimationStagger"
7303
+ },
7304
+ {
7305
+ "type": "boolean"
7306
+ }
7307
+ ],
7308
+ "description": "Stagger config. true = defaults, false = no stagger. Default: true for enter."
7309
+ },
7310
+ "maxMarks": {
7311
+ "type": "number",
7312
+ "description": "Maximum mark count that still runs a tweened data-update transition. Default: 500. Above the cap the chart swaps instantly instead, because per-frame SVG attribute writes on thousands of elements drop frames on low-end devices. Raise it deliberately when the audience is desktop-heavy and you have measured the frame budget."
7313
+ }
7314
+ },
7315
+ "additionalProperties": false,
7316
+ "description": "Data-update phase config. Adds `maxMarks` on top of the shared phase options; the cap is meaningless for enter/exit, which animate via CSS."
7317
+ },
6996
7318
  "Display": {
6997
7319
  "type": "string",
6998
7320
  "enum": [
@@ -7219,6 +7541,14 @@
7219
7541
  "facet": {
7220
7542
  "$ref": "#/definitions/FacetChannel%3CDataRow%3E",
7221
7543
  "description": "Facet channel: partitions data into a grid of small-multiple panels. Each unique value of the facet field produces one panel. Panels share scales by default; use `resolve: { scale: { y: 'independent' } }` for per-panel axes."
7544
+ },
7545
+ "row": {
7546
+ "$ref": "#/definitions/FacetChannel%3CDataRow%3E",
7547
+ "description": "Row facet channel: partitions data into vertically-stacked panels. Each unique value of the row field produces one panel, arranged in a single column. Shares the x-axis scale by default; y-axis is independent. Mutually exclusive with `facet` and `column`."
7548
+ },
7549
+ "column": {
7550
+ "$ref": "#/definitions/FacetChannel%3CDataRow%3E",
7551
+ "description": "Column facet channel: partitions data into side-by-side panels. Each unique value of the column field produces one panel, arranged in a single row. Shares the y-axis scale by default; x-axis is independent. Mutually exclusive with `facet` and `row`."
7222
7552
  }
7223
7553
  },
7224
7554
  "required": [
@@ -7330,6 +7660,14 @@
7330
7660
  "facet": {
7331
7661
  "$ref": "#/definitions/FacetChannel%3CDataRow%3E",
7332
7662
  "description": "Facet channel: partitions data into a grid of small-multiple panels. Each unique value of the facet field produces one panel. Panels share scales by default; use `resolve: { scale: { y: 'independent' } }` for per-panel axes."
7663
+ },
7664
+ "row": {
7665
+ "$ref": "#/definitions/FacetChannel%3CDataRow%3E",
7666
+ "description": "Row facet channel: partitions data into vertically-stacked panels. Each unique value of the row field produces one panel, arranged in a single column. Shares the x-axis scale by default; y-axis is independent. Mutually exclusive with `facet` and `column`."
7667
+ },
7668
+ "column": {
7669
+ "$ref": "#/definitions/FacetChannel%3CDataRow%3E",
7670
+ "description": "Column facet channel: partitions data into side-by-side panels. Each unique value of the column field produces one panel, arranged in a single row. Shares the y-axis scale by default; x-axis is independent. Mutually exclusive with `facet` and `row`."
7333
7671
  }
7334
7672
  },
7335
7673
  "required": [
@@ -7441,6 +7779,14 @@
7441
7779
  "facet": {
7442
7780
  "$ref": "#/definitions/FacetChannel%3CDataRow%3E",
7443
7781
  "description": "Facet channel: partitions data into a grid of small-multiple panels. Each unique value of the facet field produces one panel. Panels share scales by default; use `resolve: { scale: { y: 'independent' } }` for per-panel axes."
7782
+ },
7783
+ "row": {
7784
+ "$ref": "#/definitions/FacetChannel%3CDataRow%3E",
7785
+ "description": "Row facet channel: partitions data into vertically-stacked panels. Each unique value of the row field produces one panel, arranged in a single column. Shares the x-axis scale by default; y-axis is independent. Mutually exclusive with `facet` and `column`."
7786
+ },
7787
+ "column": {
7788
+ "$ref": "#/definitions/FacetChannel%3CDataRow%3E",
7789
+ "description": "Column facet channel: partitions data into side-by-side panels. Each unique value of the column field produces one panel, arranged in a single row. Shares the y-axis scale by default; x-axis is independent. Mutually exclusive with `facet` and `row`."
7444
7790
  }
7445
7791
  },
7446
7792
  "required": [
@@ -7552,6 +7898,14 @@
7552
7898
  "facet": {
7553
7899
  "$ref": "#/definitions/FacetChannel%3CDataRow%3E",
7554
7900
  "description": "Facet channel: partitions data into a grid of small-multiple panels. Each unique value of the facet field produces one panel. Panels share scales by default; use `resolve: { scale: { y: 'independent' } }` for per-panel axes."
7901
+ },
7902
+ "row": {
7903
+ "$ref": "#/definitions/FacetChannel%3CDataRow%3E",
7904
+ "description": "Row facet channel: partitions data into vertically-stacked panels. Each unique value of the row field produces one panel, arranged in a single column. Shares the x-axis scale by default; y-axis is independent. Mutually exclusive with `facet` and `column`."
7905
+ },
7906
+ "column": {
7907
+ "$ref": "#/definitions/FacetChannel%3CDataRow%3E",
7908
+ "description": "Column facet channel: partitions data into side-by-side panels. Each unique value of the column field produces one panel, arranged in a single row. Shares the y-axis scale by default; x-axis is independent. Mutually exclusive with `facet` and `row`."
7555
7909
  }
7556
7910
  },
7557
7911
  "required": [
@@ -7663,6 +8017,14 @@
7663
8017
  "facet": {
7664
8018
  "$ref": "#/definitions/FacetChannel%3CDataRow%3E",
7665
8019
  "description": "Facet channel: partitions data into a grid of small-multiple panels. Each unique value of the facet field produces one panel. Panels share scales by default; use `resolve: { scale: { y: 'independent' } }` for per-panel axes."
8020
+ },
8021
+ "row": {
8022
+ "$ref": "#/definitions/FacetChannel%3CDataRow%3E",
8023
+ "description": "Row facet channel: partitions data into vertically-stacked panels. Each unique value of the row field produces one panel, arranged in a single column. Shares the x-axis scale by default; y-axis is independent. Mutually exclusive with `facet` and `column`."
8024
+ },
8025
+ "column": {
8026
+ "$ref": "#/definitions/FacetChannel%3CDataRow%3E",
8027
+ "description": "Column facet channel: partitions data into side-by-side panels. Each unique value of the column field produces one panel, arranged in a single row. Shares the y-axis scale by default; x-axis is independent. Mutually exclusive with `facet` and `row`."
7666
8028
  }
7667
8029
  },
7668
8030
  "required": [
@@ -7774,6 +8136,14 @@
7774
8136
  "facet": {
7775
8137
  "$ref": "#/definitions/FacetChannel%3CDataRow%3E",
7776
8138
  "description": "Facet channel: partitions data into a grid of small-multiple panels. Each unique value of the facet field produces one panel. Panels share scales by default; use `resolve: { scale: { y: 'independent' } }` for per-panel axes."
8139
+ },
8140
+ "row": {
8141
+ "$ref": "#/definitions/FacetChannel%3CDataRow%3E",
8142
+ "description": "Row facet channel: partitions data into vertically-stacked panels. Each unique value of the row field produces one panel, arranged in a single column. Shares the x-axis scale by default; y-axis is independent. Mutually exclusive with `facet` and `column`."
8143
+ },
8144
+ "column": {
8145
+ "$ref": "#/definitions/FacetChannel%3CDataRow%3E",
8146
+ "description": "Column facet channel: partitions data into side-by-side panels. Each unique value of the column field produces one panel, arranged in a single row. Shares the y-axis scale by default; x-axis is independent. Mutually exclusive with `facet` and `row`."
7777
8147
  }
7778
8148
  },
7779
8149
  "required": [
@@ -7885,6 +8255,14 @@
7885
8255
  "facet": {
7886
8256
  "$ref": "#/definitions/FacetChannel%3CDataRow%3E",
7887
8257
  "description": "Facet channel: partitions data into a grid of small-multiple panels. Each unique value of the facet field produces one panel. Panels share scales by default; use `resolve: { scale: { y: 'independent' } }` for per-panel axes."
8258
+ },
8259
+ "row": {
8260
+ "$ref": "#/definitions/FacetChannel%3CDataRow%3E",
8261
+ "description": "Row facet channel: partitions data into vertically-stacked panels. Each unique value of the row field produces one panel, arranged in a single column. Shares the x-axis scale by default; y-axis is independent. Mutually exclusive with `facet` and `column`."
8262
+ },
8263
+ "column": {
8264
+ "$ref": "#/definitions/FacetChannel%3CDataRow%3E",
8265
+ "description": "Column facet channel: partitions data into side-by-side panels. Each unique value of the column field produces one panel, arranged in a single row. Shares the y-axis scale by default; x-axis is independent. Mutually exclusive with `facet` and `row`."
7888
8266
  }
7889
8267
  },
7890
8268
  "additionalProperties": false,
@@ -7992,6 +8370,14 @@
7992
8370
  "facet": {
7993
8371
  "$ref": "#/definitions/FacetChannel%3CDataRow%3E",
7994
8372
  "description": "Facet channel: partitions data into a grid of small-multiple panels. Each unique value of the facet field produces one panel. Panels share scales by default; use `resolve: { scale: { y: 'independent' } }` for per-panel axes."
8373
+ },
8374
+ "row": {
8375
+ "$ref": "#/definitions/FacetChannel%3CDataRow%3E",
8376
+ "description": "Row facet channel: partitions data into vertically-stacked panels. Each unique value of the row field produces one panel, arranged in a single column. Shares the x-axis scale by default; y-axis is independent. Mutually exclusive with `facet` and `column`."
8377
+ },
8378
+ "column": {
8379
+ "$ref": "#/definitions/FacetChannel%3CDataRow%3E",
8380
+ "description": "Column facet channel: partitions data into side-by-side panels. Each unique value of the column field produces one panel, arranged in a single row. Shares the y-axis scale by default; x-axis is independent. Mutually exclusive with `facet` and `row`."
7995
8381
  }
7996
8382
  },
7997
8383
  "required": [
@@ -8100,6 +8486,14 @@
8100
8486
  "facet": {
8101
8487
  "$ref": "#/definitions/FacetChannel%3CDataRow%3E",
8102
8488
  "description": "Facet channel: partitions data into a grid of small-multiple panels. Each unique value of the facet field produces one panel. Panels share scales by default; use `resolve: { scale: { y: 'independent' } }` for per-panel axes."
8489
+ },
8490
+ "row": {
8491
+ "$ref": "#/definitions/FacetChannel%3CDataRow%3E",
8492
+ "description": "Row facet channel: partitions data into vertically-stacked panels. Each unique value of the row field produces one panel, arranged in a single column. Shares the x-axis scale by default; y-axis is independent. Mutually exclusive with `facet` and `column`."
8493
+ },
8494
+ "column": {
8495
+ "$ref": "#/definitions/FacetChannel%3CDataRow%3E",
8496
+ "description": "Column facet channel: partitions data into side-by-side panels. Each unique value of the column field produces one panel, arranged in a single row. Shares the y-axis scale by default; x-axis is independent. Mutually exclusive with `facet` and `row`."
8103
8497
  }
8104
8498
  },
8105
8499
  "required": [
@@ -8210,6 +8604,14 @@
8210
8604
  "facet": {
8211
8605
  "$ref": "#/definitions/FacetChannel%3CDataRow%3E",
8212
8606
  "description": "Facet channel: partitions data into a grid of small-multiple panels. Each unique value of the facet field produces one panel. Panels share scales by default; use `resolve: { scale: { y: 'independent' } }` for per-panel axes."
8607
+ },
8608
+ "row": {
8609
+ "$ref": "#/definitions/FacetChannel%3CDataRow%3E",
8610
+ "description": "Row facet channel: partitions data into vertically-stacked panels. Each unique value of the row field produces one panel, arranged in a single column. Shares the x-axis scale by default; y-axis is independent. Mutually exclusive with `facet` and `column`."
8611
+ },
8612
+ "column": {
8613
+ "$ref": "#/definitions/FacetChannel%3CDataRow%3E",
8614
+ "description": "Column facet channel: partitions data into side-by-side panels. Each unique value of the column field produces one panel, arranged in a single row. Shares the y-axis scale by default; x-axis is independent. Mutually exclusive with `facet` and `row`."
8213
8615
  }
8214
8616
  },
8215
8617
  "required": [
@@ -8320,6 +8722,14 @@
8320
8722
  "facet": {
8321
8723
  "$ref": "#/definitions/FacetChannel%3CDataRow%3E",
8322
8724
  "description": "Facet channel: partitions data into a grid of small-multiple panels. Each unique value of the facet field produces one panel. Panels share scales by default; use `resolve: { scale: { y: 'independent' } }` for per-panel axes."
8725
+ },
8726
+ "row": {
8727
+ "$ref": "#/definitions/FacetChannel%3CDataRow%3E",
8728
+ "description": "Row facet channel: partitions data into vertically-stacked panels. Each unique value of the row field produces one panel, arranged in a single column. Shares the x-axis scale by default; y-axis is independent. Mutually exclusive with `facet` and `column`."
8729
+ },
8730
+ "column": {
8731
+ "$ref": "#/definitions/FacetChannel%3CDataRow%3E",
8732
+ "description": "Column facet channel: partitions data into side-by-side panels. Each unique value of the column field produces one panel, arranged in a single row. Shares the y-axis scale by default; x-axis is independent. Mutually exclusive with `facet` and `row`."
8323
8733
  }
8324
8734
  },
8325
8735
  "required": [
@@ -8431,6 +8841,14 @@
8431
8841
  "facet": {
8432
8842
  "$ref": "#/definitions/FacetChannel%3CDataRow%3E",
8433
8843
  "description": "Facet channel: partitions data into a grid of small-multiple panels. Each unique value of the facet field produces one panel. Panels share scales by default; use `resolve: { scale: { y: 'independent' } }` for per-panel axes."
8844
+ },
8845
+ "row": {
8846
+ "$ref": "#/definitions/FacetChannel%3CDataRow%3E",
8847
+ "description": "Row facet channel: partitions data into vertically-stacked panels. Each unique value of the row field produces one panel, arranged in a single column. Shares the x-axis scale by default; y-axis is independent. Mutually exclusive with `facet` and `column`."
8848
+ },
8849
+ "column": {
8850
+ "$ref": "#/definitions/FacetChannel%3CDataRow%3E",
8851
+ "description": "Column facet channel: partitions data into side-by-side panels. Each unique value of the column field produces one panel, arranged in a single row. Shares the y-axis scale by default; x-axis is independent. Mutually exclusive with `facet` and `row`."
8434
8852
  }
8435
8853
  },
8436
8854
  "required": [
@@ -8542,6 +8960,14 @@
8542
8960
  "facet": {
8543
8961
  "$ref": "#/definitions/FacetChannel%3CDataRow%3E",
8544
8962
  "description": "Facet channel: partitions data into a grid of small-multiple panels. Each unique value of the facet field produces one panel. Panels share scales by default; use `resolve: { scale: { y: 'independent' } }` for per-panel axes."
8963
+ },
8964
+ "row": {
8965
+ "$ref": "#/definitions/FacetChannel%3CDataRow%3E",
8966
+ "description": "Row facet channel: partitions data into vertically-stacked panels. Each unique value of the row field produces one panel, arranged in a single column. Shares the x-axis scale by default; y-axis is independent. Mutually exclusive with `facet` and `column`."
8967
+ },
8968
+ "column": {
8969
+ "$ref": "#/definitions/FacetChannel%3CDataRow%3E",
8970
+ "description": "Column facet channel: partitions data into side-by-side panels. Each unique value of the column field produces one panel, arranged in a single row. Shares the y-axis scale by default; x-axis is independent. Mutually exclusive with `facet` and `row`."
8545
8971
  }
8546
8972
  },
8547
8973
  "additionalProperties": false,
@@ -8639,6 +9065,14 @@
8639
9065
  "facet": {
8640
9066
  "$ref": "#/definitions/FacetChannel%3CDataRow%3E",
8641
9067
  "description": "Facet channel: partitions data into a grid of small-multiple panels. Each unique value of the facet field produces one panel. Panels share scales by default; use `resolve: { scale: { y: 'independent' } }` for per-panel axes."
9068
+ },
9069
+ "row": {
9070
+ "$ref": "#/definitions/FacetChannel%3CDataRow%3E",
9071
+ "description": "Row facet channel: partitions data into vertically-stacked panels. Each unique value of the row field produces one panel, arranged in a single column. Shares the x-axis scale by default; y-axis is independent. Mutually exclusive with `facet` and `column`."
9072
+ },
9073
+ "column": {
9074
+ "$ref": "#/definitions/FacetChannel%3CDataRow%3E",
9075
+ "description": "Column facet channel: partitions data into side-by-side panels. Each unique value of the column field produces one panel, arranged in a single row. Shares the y-axis scale by default; x-axis is independent. Mutually exclusive with `facet` and `row`."
8642
9076
  }
8643
9077
  },
8644
9078
  "required": [
@@ -8747,6 +9181,14 @@
8747
9181
  "facet": {
8748
9182
  "$ref": "#/definitions/FacetChannel%3CDataRow%3E",
8749
9183
  "description": "Facet channel: partitions data into a grid of small-multiple panels. Each unique value of the facet field produces one panel. Panels share scales by default; use `resolve: { scale: { y: 'independent' } }` for per-panel axes."
9184
+ },
9185
+ "row": {
9186
+ "$ref": "#/definitions/FacetChannel%3CDataRow%3E",
9187
+ "description": "Row facet channel: partitions data into vertically-stacked panels. Each unique value of the row field produces one panel, arranged in a single column. Shares the x-axis scale by default; y-axis is independent. Mutually exclusive with `facet` and `column`."
9188
+ },
9189
+ "column": {
9190
+ "$ref": "#/definitions/FacetChannel%3CDataRow%3E",
9191
+ "description": "Column facet channel: partitions data into side-by-side panels. Each unique value of the column field produces one panel, arranged in a single row. Shares the y-axis scale by default; x-axis is independent. Mutually exclusive with `facet` and `row`."
8750
9192
  }
8751
9193
  },
8752
9194
  "required": [
@@ -8783,6 +9225,14 @@
8783
9225
  "$ref": "#/definitions/Chrome",
8784
9226
  "description": "Editorial chrome (title, subtitle, source, etc.)."
8785
9227
  },
9228
+ "chromeLayout": {
9229
+ "type": "string",
9230
+ "enum": [
9231
+ "subtract",
9232
+ "grow"
9233
+ ],
9234
+ "description": "How chrome height interacts with the container height budget.\n\n- `'subtract'` (default): the container height is fixed and chrome text (title/subtitle/source) is subtracted from it, shrinking the plot. This is the historical behavior.\n- `'grow'`: the container height is treated as the *plot* budget, and the rendered SVG grows taller by the measured chrome height. The plot keeps its full budget (minus axis/padding overhead) regardless of how many lines the title wraps to.\n\n`'grow'` is a no-op for faceted specs in this version."
9235
+ },
8786
9236
  "title": {
8787
9237
  "anyOf": [
8788
9238
  {
@@ -8891,7 +9341,7 @@
8891
9341
  "items": {
8892
9342
  "type": "string"
8893
9343
  },
8894
- "description": "Series names to hide from rendering. Hidden series remain in the legend but are visually dimmed."
9344
+ "description": "Series names to hide from rendering by default. This is the authored persistence target for legend visibility. Runtime legend toggles (legend-toggle edit events) layer on top of this via ephemeral runtime sets but never modify it."
8895
9345
  },
8896
9346
  "seriesStyles": {
8897
9347
  "type": "object",