@opendata-ai/openchart-core 8.0.0-rc.9 → 8.0.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 (82) hide show
  1. package/dist/index.d.ts +363 -43
  2. package/dist/index.js +39 -18
  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 +373 -67
  8. package/schema/table.schema.json +35 -1
  9. package/schema/vizspec.schema.json +950 -152
  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 -177
  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 -213
  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 -151
  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 -236
  77. package/src/types/index.ts +0 -290
  78. package/src/types/layout.ts +0 -2024
  79. package/src/types/schema-roots.ts +0 -32
  80. package/src/types/spec.ts +0 -2925
  81. package/src/types/table.ts +0 -108
  82. package/src/types/theme.ts +0 -209
@@ -1,2024 +0,0 @@
1
- /**
2
- * Layout types: the engine output contract.
3
- *
4
- * These are the structured layout objects that the engine produces after
5
- * compiling a spec. Framework adapters consume these to render real DOM.
6
- *
7
- * The key distinction: spec.ts types are USER INPUT, layout.ts types are
8
- * ENGINE OUTPUT. Input types have optionals and unions. Output types are
9
- * fully resolved with computed positions, colors, and dimensions.
10
- */
11
-
12
- import type { GradientDef } from './spec';
13
- import type { ResolvedTheme } from './theme';
14
-
15
- // ---------------------------------------------------------------------------
16
- // Geometry primitives
17
- // ---------------------------------------------------------------------------
18
-
19
- /** A rectangle defined by position and dimensions. */
20
- export interface Rect {
21
- x: number;
22
- y: number;
23
- width: number;
24
- height: number;
25
- }
26
-
27
- /** Margins around a region (top, right, bottom, left). */
28
- export interface Margins {
29
- top: number;
30
- right: number;
31
- bottom: number;
32
- left: number;
33
- }
34
-
35
- /** A 2D point. */
36
- export interface Point {
37
- x: number;
38
- y: number;
39
- }
40
-
41
- // ---------------------------------------------------------------------------
42
- // Text styling
43
- // ---------------------------------------------------------------------------
44
-
45
- /** Resolved text style with all computed values. */
46
- export interface TextStyle {
47
- /** Font family. */
48
- fontFamily: string;
49
- /** Font size in pixels. */
50
- fontSize: number;
51
- /** Font weight. */
52
- fontWeight: number;
53
- /** Text color (CSS color string). */
54
- fill: string;
55
- /** Line height multiplier. */
56
- lineHeight: number;
57
- /** Text anchor for SVG: start, middle, or end. */
58
- textAnchor?: 'start' | 'middle' | 'end';
59
- /** Dominant baseline for SVG text vertical alignment. */
60
- dominantBaseline?: 'auto' | 'hanging' | 'central' | 'text-after-edge';
61
- /** Font variant (e.g. "tabular-nums" for fixed-width digits). */
62
- fontVariant?: string;
63
- }
64
-
65
- /** Cell style for table cells. */
66
- export interface CellStyle {
67
- /** Background color. */
68
- backgroundColor?: string;
69
- /** Text color. */
70
- color?: string;
71
- /** Font weight. */
72
- fontWeight?: number;
73
- /** Font variant. */
74
- fontVariant?: string;
75
- }
76
-
77
- // ---------------------------------------------------------------------------
78
- // Chrome (resolved)
79
- // ---------------------------------------------------------------------------
80
-
81
- /** A single resolved chrome text element with computed position and style. */
82
- export interface ResolvedChromeElement {
83
- /** The text content. */
84
- text: string;
85
- /** X position in the layout coordinate system. */
86
- x: number;
87
- /** Y position (baseline) in the layout coordinate system. */
88
- y: number;
89
- /** Maximum width for line wrapping. */
90
- maxWidth: number;
91
- /** Computed text style. */
92
- style: TextStyle;
93
- }
94
-
95
- /**
96
- * Fully resolved chrome with computed positions for all elements.
97
- * Only present elements are included (no undefined checks needed at render time).
98
- */
99
- export interface ResolvedChrome {
100
- /** Total height consumed by chrome elements above the chart area. */
101
- topHeight: number;
102
- /** Total height consumed by chrome elements below the chart area. */
103
- bottomHeight: number;
104
- /** Resolved chrome elements. Only present if specified in the spec. */
105
- eyebrow?: ResolvedChromeElement;
106
- title?: ResolvedChromeElement;
107
- subtitle?: ResolvedChromeElement;
108
- source?: ResolvedChromeElement;
109
- byline?: ResolvedChromeElement;
110
- footer?: ResolvedChromeElement;
111
- brand?: ResolvedChromeElement;
112
- /** Annotation footnotes generated by auto-thinning. Rendered as a numbered list above the source line. */
113
- footnotes?: AnnotationFootnote[];
114
- /** Absolute y at which bottom-chrome relative offsets are anchored: area.y + area.height + x-axis extent. */
115
- bottomAnchorY?: number;
116
- }
117
-
118
- // ---------------------------------------------------------------------------
119
- // Axes
120
- // ---------------------------------------------------------------------------
121
-
122
- /** A single axis tick with computed position and formatted label. */
123
- export interface AxisTick {
124
- /** The raw data value at this tick. */
125
- value: unknown;
126
- /** Pixel position along the axis. */
127
- position: number;
128
- /** Formatted label string for display. */
129
- label: string;
130
- /**
131
- * The untruncated label, set only when `label` was shortened with an ellipsis
132
- * to fit the rotated-tick reservation. Renderers should surface this as the
133
- * tick's accessible/tooltip text so the full category name is never lost.
134
- */
135
- fullLabel?: string;
136
- /** Secondary label text from axis.labelField. */
137
- subtitle?: string;
138
- }
139
-
140
- /** A single gridline with computed positions. */
141
- export interface Gridline {
142
- /** Pixel position along the axis. */
143
- position: number;
144
- /** Whether this is a major or minor gridline. */
145
- major: boolean;
146
- }
147
-
148
- /** Resolved axis layout with computed tick positions and labels. */
149
- export interface AxisLayout {
150
- /** Axis ticks with positions and labels. */
151
- ticks: AxisTick[];
152
- /** Gridlines at tick positions. */
153
- gridlines: Gridline[];
154
- /** Axis label text (e.g. "GDP Growth (%)"). */
155
- label?: string;
156
- /** Label style. */
157
- labelStyle?: TextStyle;
158
- /** Tick label style. */
159
- tickLabelStyle: TextStyle;
160
- /** Rotation angle in degrees for tick labels. */
161
- tickAngle?: number;
162
- /** Axis line start position. */
163
- start: Point;
164
- /** Axis line end position. */
165
- end: Point;
166
- /** Axis orientation (which side it appears on). */
167
- orient?: 'top' | 'bottom' | 'left' | 'right';
168
- /** Whether to show the axis domain line. Defaults to true. */
169
- domainLine?: boolean;
170
- /** Whether to show tick marks. Defaults to true. */
171
- tickMarks?: boolean;
172
- /** Axis position offset in pixels. */
173
- offset?: number;
174
- /** Padding between axis title and axis in pixels. */
175
- titlePadding?: number;
176
- /** Padding between tick labels and axis in pixels. */
177
- labelPadding?: number;
178
- /** How overlapping labels should be handled. */
179
- labelOverlap?: boolean | 'parity' | 'greedy';
180
- /** Whether to flush labels to the axis edges. */
181
- labelFlush?: boolean;
182
- /**
183
- * Where tick labels render relative to the chart area.
184
- * `'inline'` puts y-axis labels above their gridlines at chart-area x and
185
- * suppresses the axis line and tick marks. `'gutter'` (default) keeps the
186
- * classic outside-the-area placement.
187
- */
188
- tickPosition?: 'inline' | 'gutter';
189
- /** Extent in px beyond the chart-area edge occupied by tick labels + title. Engine-resolved from the final (post-thinning) tick set. */
190
- extent?: number;
191
- /** Absolute anchor for the axis title. Replaces renderer-side offset math. */
192
- titlePosition?: { x: number; y: number; angle?: number };
193
- }
194
-
195
- // ---------------------------------------------------------------------------
196
- // Marks (data visual elements)
197
- // ---------------------------------------------------------------------------
198
-
199
- /** The four built-in fill pattern shapes for series reinforcement. */
200
- export type FillPatternType = 'diagonal' | 'dot' | 'crosshatch' | 'vertical';
201
-
202
- /**
203
- * A resolved per-mark fill pattern (engine output for `mark.fillPattern: 'auto'`).
204
- *
205
- * The renderer builds one SVG `<pattern>` per unique (type, base, line)
206
- * combination: a tile of `base` color overlaid with `line`-colored pattern
207
- * geometry. Marks referencing the same resolved pattern share one def.
208
- */
209
- export interface ResolvedFillPattern {
210
- /** Pattern shape assigned to this mark's series. */
211
- type: FillPatternType;
212
- /** Base tile color: the series' solid color. */
213
- base: string;
214
- /** Pattern line/dot color, contrast-picked against `base`. */
215
- line: string;
216
- }
217
-
218
- /** Accessibility attributes for a mark. */
219
- export interface MarkAria {
220
- /** ARIA label for the mark. Optional when `decorative: true` — decorative
221
- * marks render with `aria-hidden="true"` and don't need a label. */
222
- label?: string;
223
- /** Optional longer description. */
224
- description?: string;
225
- /** ARIA role override. */
226
- role?: string;
227
- /** When true, the mark is purely decorative (e.g. a sparkline endpoint dot
228
- * that duplicates an existing data point). Renderers translate this into
229
- * `aria-hidden="true"` and skip the mark from the screen-reader data table. */
230
- decorative?: boolean;
231
- }
232
-
233
- /**
234
- * Line mark: a series of connected points.
235
- * Used by line charts and area chart boundaries.
236
- */
237
- export interface LineMark {
238
- type: 'line';
239
- /** Stable identity key for data-update transitions. */
240
- key?: string;
241
- /** Per-point identity keys parallel to `points`, for data-update transitions. */
242
- pointKeys?: string[];
243
- /** Ordered array of points defining the line path. */
244
- points: Point[];
245
- /** Pre-computed SVG path string (D3 monotone curve). When present, renderers
246
- * should use this instead of reconstructing straight M/L segments from points. */
247
- path?: string;
248
- /** Curve interpolation method used to build the path. Stored so the transition
249
- * driver can reconstruct paths from interpolated point positions. */
250
- interpolate?: string;
251
- /** Stroke color. */
252
- stroke: string;
253
- /** Stroke width in pixels. */
254
- strokeWidth: number;
255
- /** Line dash pattern (empty for solid). */
256
- strokeDasharray?: string;
257
- /** Overall opacity for the line (0-1). */
258
- opacity?: number;
259
- /** Series identifier (for multi-series charts). */
260
- seriesKey?: string;
261
- /** Original data rows for this series. */
262
- data: Record<string, unknown>[];
263
- /**
264
- * Pixel-coordinate data points for spatial tooltip lookup (voronoi overlay).
265
- * Each entry pairs a pixel position with its original data row.
266
- */
267
- dataPoints?: Array<{
268
- x: number;
269
- y: number;
270
- datum: Record<string, unknown>;
271
- tooltip?: TooltipContent;
272
- }>;
273
- /** Resolved label after collision detection. */
274
- label?: ResolvedLabel;
275
- /** Accessibility attributes. */
276
- aria: MarkAria;
277
- /** Index for stagger animation ordering. */
278
- animationIndex?: number;
279
- /** Which y-scale produced this mark ('y' = left, 'y2' = right). */
280
- yScale?: 'y' | 'y2';
281
- }
282
-
283
- /**
284
- * Area mark: a filled region bounded by a top line and a baseline.
285
- * Used by area charts.
286
- */
287
- export interface AreaMark {
288
- type: 'area';
289
- /** Stable identity key for data-update transitions. */
290
- key?: string;
291
- /** Per-point identity keys parallel to `topPoints`, for data-update transitions. */
292
- pointKeys?: string[];
293
- /** Upper boundary points. */
294
- topPoints: Point[];
295
- /** Lower boundary points (baseline, usually y=0). */
296
- bottomPoints: Point[];
297
- /** SVG path string for the complete area shape. */
298
- path: string;
299
- /** SVG path string for just the top boundary (for stroking the data line only). */
300
- topPath: string;
301
- /** Curve interpolation method used to build the path. */
302
- interpolate?: string;
303
- /** Fill color or gradient. */
304
- fill: string | GradientDef;
305
- /** Resolved fill pattern. Present only when `mark.fillPattern: 'auto'` assigned one. */
306
- pattern?: ResolvedFillPattern;
307
- /** Fill opacity. */
308
- fillOpacity: number;
309
- /** Optional stroke for the top boundary. */
310
- stroke?: string;
311
- /** Stroke width. */
312
- strokeWidth?: number;
313
- /** Series identifier. */
314
- seriesKey?: string;
315
- /** Original data rows. */
316
- data: Record<string, unknown>[];
317
- /**
318
- * Pixel-coordinate data points for spatial tooltip lookup (voronoi overlay).
319
- * Each entry pairs a pixel position with its original data row.
320
- */
321
- dataPoints?: Array<{
322
- x: number;
323
- y: number;
324
- datum: Record<string, unknown>;
325
- tooltip?: TooltipContent;
326
- }>;
327
- /** Accessibility attributes. */
328
- aria: MarkAria;
329
- /** Index for stagger animation ordering. */
330
- animationIndex?: number;
331
- /** Which y-scale produced this mark ('y' = left, 'y2' = right). */
332
- yScale?: 'y' | 'y2';
333
- }
334
-
335
- /**
336
- * Rect mark: a rectangle.
337
- * Used by bar charts, column charts, and heatmap cells.
338
- */
339
- export interface RectMark {
340
- type: 'rect';
341
- /** Stable identity key for data-update transitions. */
342
- key?: string;
343
- /** X position. */
344
- x: number;
345
- /** Y position. */
346
- y: number;
347
- /** Width. */
348
- width: number;
349
- /** Height. */
350
- height: number;
351
- /** Fill color or gradient. */
352
- fill: string | GradientDef;
353
- /** Resolved fill pattern. Present only when `mark.fillPattern: 'auto'` assigned one. */
354
- pattern?: ResolvedFillPattern;
355
- /** Stroke color. */
356
- stroke?: string;
357
- /** Stroke width. */
358
- strokeWidth?: number;
359
- /** Corner radius. */
360
- cornerRadius?: number;
361
- /**
362
- * Which corners receive `cornerRadius`. Defaults to all four when unset.
363
- * Used by stacked bars/columns to round only the leading edge of the
364
- * topmost (vertical) or rightmost (horizontal) segment so the seams
365
- * between stacked segments stay square and visually contiguous.
366
- */
367
- cornerRadiusSides?: { tl?: boolean; tr?: boolean; br?: boolean; bl?: boolean };
368
- /** Original data row. */
369
- data: Record<string, unknown>;
370
- /** Resolved label. */
371
- label?: ResolvedLabel;
372
- /** Accessibility attributes. */
373
- aria: MarkAria;
374
- /** Index for stagger animation ordering. */
375
- animationIndex?: number;
376
- /** Bar orientation for animation direction. Set by the engine based on encoding. */
377
- orient?: 'horizontal' | 'vertical';
378
- /** Stacking group key (e.g. category name). Segments sharing this key animate together. */
379
- stackGroup?: string;
380
- /** Position of this segment within its stack group (0, 1, 2...). Set by engine for stacked bars. */
381
- stackPos?: number;
382
- /** Which y-scale produced this mark ('y' = left, 'y2' = right). */
383
- yScale?: 'y' | 'y2';
384
- }
385
-
386
- /**
387
- * Arc mark: a pie/donut slice.
388
- * Used by pie and donut charts.
389
- */
390
- export interface ArcMark {
391
- type: 'arc';
392
- /** SVG path string for the arc. */
393
- path: string;
394
- /** Centroid point (center of the arc, for label positioning). */
395
- centroid: Point;
396
- /** Center of the pie/donut chart (for SVG translate). */
397
- center: Point;
398
- /** Inner radius (0 for pie, >0 for donut). */
399
- innerRadius: number;
400
- /** Outer radius. */
401
- outerRadius: number;
402
- /** Start angle in radians. */
403
- startAngle: number;
404
- /** End angle in radians. */
405
- endAngle: number;
406
- /** Fill color or gradient. */
407
- fill: string | GradientDef;
408
- /** Resolved fill pattern. Present only when `mark.fillPattern: 'auto'` assigned one. */
409
- pattern?: ResolvedFillPattern;
410
- /** Stroke color (usually white for slice separation). */
411
- stroke: string;
412
- /** Stroke width. */
413
- strokeWidth: number;
414
- /** Original data row. */
415
- data: Record<string, unknown>;
416
- /** Resolved label. */
417
- label?: ResolvedLabel;
418
- /** Accessibility attributes. */
419
- aria: MarkAria;
420
- /** Stable identity key for data-update transitions. */
421
- key?: string;
422
- /** Index for stagger animation ordering. */
423
- animationIndex?: number;
424
- }
425
-
426
- /**
427
- * Point mark: a circle or dot.
428
- * Used by scatter/bubble charts and dot plots.
429
- */
430
- export interface PointMark {
431
- type: 'point';
432
- /** Stable identity key for data-update transitions. */
433
- key?: string;
434
- /** Center x position. */
435
- cx: number;
436
- /** Center y position. */
437
- cy: number;
438
- /** Radius in pixels. */
439
- r: number;
440
- /** Fill color or gradient. */
441
- fill: string | GradientDef;
442
- /** Stroke color. */
443
- stroke: string;
444
- /** Stroke width. */
445
- strokeWidth: number;
446
- /** Fill opacity. */
447
- fillOpacity?: number;
448
- /** Original data row. */
449
- data: Record<string, unknown>;
450
- /** Resolved label. */
451
- label?: ResolvedLabel;
452
- /** Accessibility attributes. */
453
- aria: MarkAria;
454
- /** Index for stagger animation ordering. */
455
- animationIndex?: number;
456
- /** Which y-scale produced this mark ('y' = left, 'y2' = right). */
457
- yScale?: 'y' | 'y2';
458
- }
459
-
460
- /**
461
- * Text mark: data-positioned text label.
462
- * Used by text charts for showing values directly at data coordinates.
463
- */
464
- export interface TextMarkLayout {
465
- type: 'textMark';
466
- /** Stable identity key for data-update transitions. */
467
- key?: string;
468
- /** X position, including any `dx` offset. */
469
- x: number;
470
- /** Y position, including any `dy` offset. */
471
- y: number;
472
- /** Data-space anchor before `dx` was applied. Set only when the mark is offset. */
473
- anchorX?: number;
474
- /** Data-space anchor before `dy` was applied. Set only when the mark is offset. */
475
- anchorY?: number;
476
- /** Text content to display. */
477
- text: string;
478
- /** Fill color. */
479
- fill: string;
480
- /** Font size in pixels. */
481
- fontSize: number;
482
- /** Font weight. */
483
- fontWeight?: number;
484
- /** Font family override. */
485
- fontFamily?: string;
486
- /** Horizontal text alignment. */
487
- textAnchor: 'start' | 'middle' | 'end';
488
- /**
489
- * Vertical baseline. Omit for the SVG default (alphabetic), which the calendar
490
- * and parliament marks rely on — they hand-compute baseline-relative offsets.
491
- */
492
- dominantBaseline?: 'auto' | 'hanging' | 'central' | 'text-after-edge';
493
- /** Rotation angle in degrees. */
494
- angle?: number;
495
- /** Original data row. */
496
- data: Record<string, unknown>;
497
- /** Resolved label. */
498
- label?: ResolvedLabel;
499
- /** Accessibility attributes. */
500
- aria: MarkAria;
501
- /** Index for stagger animation ordering. */
502
- animationIndex?: number;
503
- /** Which y-scale produced this mark ('y' = left, 'y2' = right). */
504
- yScale?: 'y' | 'y2';
505
- }
506
-
507
- /**
508
- * Rule mark: a line segment between two points.
509
- * Used for reference lines rendered as data marks.
510
- */
511
- export interface RuleMarkLayout {
512
- type: 'rule';
513
- /** Stable identity key for data-update transitions. */
514
- key?: string;
515
- /** Start x position. */
516
- x1: number;
517
- /** Start y position. */
518
- y1: number;
519
- /** End x position. */
520
- x2: number;
521
- /** End y position. */
522
- y2: number;
523
- /** Stroke color. */
524
- stroke: string;
525
- /** Stroke width in pixels. */
526
- strokeWidth: number;
527
- /** Stroke dash pattern (e.g. "4 2"). */
528
- strokeDasharray?: string;
529
- /** Opacity (0-1). */
530
- opacity?: number;
531
- /** Original data row. */
532
- data: Record<string, unknown>;
533
- /** Accessibility attributes. */
534
- aria: MarkAria;
535
- /** Index for stagger animation ordering. */
536
- animationIndex?: number;
537
- /** Which y-scale produced this mark ('y' = left, 'y2' = right). */
538
- yScale?: 'y' | 'y2';
539
- }
540
-
541
- /**
542
- * Tick mark: a short line segment at a data coordinate.
543
- * Used for strip plots and rug plots.
544
- */
545
- export interface TickMarkLayout {
546
- type: 'tick';
547
- /** Stable identity key for data-update transitions. */
548
- key?: string;
549
- /** X position. */
550
- x: number;
551
- /** Y position. */
552
- y: number;
553
- /** Length of the tick mark in pixels. */
554
- length: number;
555
- /** Whether the tick is horizontal or vertical. */
556
- orient: 'horizontal' | 'vertical';
557
- /** Stroke color. */
558
- stroke: string;
559
- /** Stroke width in pixels. */
560
- strokeWidth: number;
561
- /** Opacity (0-1). */
562
- opacity?: number;
563
- /** Original data row. */
564
- data: Record<string, unknown>;
565
- /** Accessibility attributes. */
566
- aria: MarkAria;
567
- /** Index for stagger animation ordering. */
568
- animationIndex?: number;
569
- /** Which y-scale produced this mark ('y' = left, 'y2' = right). */
570
- yScale?: 'y' | 'y2';
571
- }
572
-
573
- /** Discriminated union of all mark types. */
574
- export type Mark =
575
- | LineMark
576
- | AreaMark
577
- | RectMark
578
- | ArcMark
579
- | PointMark
580
- | TextMarkLayout
581
- | RuleMarkLayout
582
- | TickMarkLayout;
583
-
584
- // ---------------------------------------------------------------------------
585
- // Labels
586
- // ---------------------------------------------------------------------------
587
-
588
- /**
589
- * A resolved label: text with a computed position after collision detection.
590
- * The collision engine determines whether labels are visible or demoted to tooltip-only.
591
- */
592
- export interface ResolvedLabel {
593
- /** Label text content. */
594
- text: string;
595
- /** Computed x position. */
596
- x: number;
597
- /** Computed y position (baseline). */
598
- y: number;
599
- /** Text style. */
600
- style: TextStyle;
601
- /** Whether this label is visible or was demoted to tooltip-only by collision detection. */
602
- visible: boolean;
603
- /** Maximum available width for the label text. When set, the renderer should wrap or truncate. */
604
- maxWidth?: number;
605
- /** If not at the anchor point, draw a connector line from label to anchor. */
606
- connector?: {
607
- /** Connector start (at the label). */
608
- from: Point;
609
- /** Connector end (pulled back from the data point so the line doesn't touch it). */
610
- to: Point;
611
- /** Actual data point the connector is calling out. Renderer uses this for the endpoint marker. */
612
- endpoint?: Point;
613
- /** Author's from-end nudge, re-applied on every geometry rebuild (mirrors `endpoint` for `to`). */
614
- fromOffset?: { dx: number; dy: number };
615
- /** Connector line color. */
616
- stroke: string;
617
- /** Connector style: straight line, curved arrow, or vertical drop-line through the data point. */
618
- style: 'straight' | 'curve' | 'drop-line';
619
- /** Whether to draw an arrowhead at the data-point end. */
620
- arrow: boolean;
621
- /**
622
- * Which edge of the label block the connector leaves from. Renderers use it
623
- * to shape the curve's control point. Internal; not part of the spec.
624
- */
625
- exit?: 'horizontal' | 'vertical';
626
- };
627
- /** Background color behind the label text. */
628
- background?: string;
629
- /** Whether to show the paint-order stroke halo. Default true. */
630
- halo?: boolean;
631
- /** Engine-measured text-block bounds. Renderers should use this for background rects instead of re-estimating. */
632
- bounds?: Rect;
633
- /** Source index carried through from the LabelCandidate, if the caller set one. */
634
- index?: number;
635
- }
636
-
637
- // ---------------------------------------------------------------------------
638
- // Annotations (resolved)
639
- // ---------------------------------------------------------------------------
640
-
641
- /** A resolved annotation with computed pixel positions. */
642
- export interface ResolvedAnnotation {
643
- /** Original annotation type. */
644
- type: 'text' | 'range' | 'refline';
645
- /** Stable identifier from the spec annotation, for selection/edit callbacks. */
646
- id?: string;
647
- /**
648
- * Index of the originating annotation in `spec.annotations`.
649
- *
650
- * The resolved array is a *filtered* view of the spec array -- an annotation
651
- * whose position falls outside the scale domain resolves to nothing and is
652
- * dropped -- so a resolved array index is NOT a spec index. Anything that has
653
- * to reach back to the authored annotation (thinning's priority/responsive
654
- * lookup, faceted footnote numbering) must key on this.
655
- */
656
- specIndex?: number;
657
- /** Label text (if any). */
658
- label?: ResolvedLabel;
659
- /** For range: the highlighted rectangle in pixel coordinates. */
660
- rect?: Rect;
661
- /** For refline: the line start and end in pixel coordinates. */
662
- line?: { start: Point; end: Point };
663
- /** Fill color. */
664
- fill?: string;
665
- /** Stroke color. */
666
- stroke?: string;
667
- /** Opacity. */
668
- opacity?: number;
669
- /** Line dash pattern for reflines. */
670
- strokeDasharray?: string;
671
- /** Stroke width. */
672
- strokeWidth?: number;
673
- /** Z-index for render ordering. Higher values render on top. */
674
- zIndex?: number;
675
- /**
676
- * For text annotations: the endpoint marker drawn at the data point.
677
- * Coordinates sit on the data point itself (plus any `connectorOffset.to`),
678
- * not on the pulled-back `label.connector.to`.
679
- */
680
- dot?: {
681
- x: number;
682
- y: number;
683
- radius: number;
684
- fill: string;
685
- stroke: string;
686
- strokeWidth: number;
687
- };
688
- /**
689
- * For text annotations: optional muted subtitle rendered below the primary
690
- * label. Positioned `lineHeight * primaryLineCount + gap` below `label.y`.
691
- */
692
- subtitle?: {
693
- text: string;
694
- x: number;
695
- y: number;
696
- style: TextStyle;
697
- };
698
- /** Full placed extent: label bounds unioned with subtitle bounds. Collision and placement source of truth. */
699
- bounds?: Rect;
700
- /**
701
- * When set, this annotation was demoted to a footnote marker by auto-thinning.
702
- * The label is replaced by a numbered dot at the data point; the original text
703
- * appears in the chrome footnote band. 1-indexed.
704
- */
705
- footnoteIndex?: number;
706
- }
707
-
708
- /** A footnote entry generated by annotation auto-thinning. */
709
- export interface AnnotationFootnote {
710
- /** 1-indexed footnote number matching the dot marker on the chart. */
711
- index: number;
712
- /** The original annotation text that was demoted. */
713
- text: string;
714
- }
715
-
716
- // ---------------------------------------------------------------------------
717
- // Legend
718
- // ---------------------------------------------------------------------------
719
-
720
- /** A single entry in a categorical legend. */
721
- export interface LegendEntry {
722
- /** The label text (category name or range description). */
723
- label: string;
724
- /** The color swatch. */
725
- color: string;
726
- /** Shape of the swatch (matches the mark type). */
727
- shape: 'circle' | 'square' | 'line';
728
- /** Whether this entry is currently highlighted/active. */
729
- active?: boolean;
730
- /** True for overflow indicator entries ("+N more"). Not interactive. */
731
- overflow?: boolean;
732
- }
733
-
734
- /** The encoding channel a legend keys. */
735
- export type LegendChannel = 'color' | 'size';
736
-
737
- /** Base legend layout fields shared by all legend types. */
738
- export interface BaseLegendLayout {
739
- /**
740
- * Which encoding channel this legend keys. Omitted means `'color'` (every
741
- * legend was a color legend before size legends existed).
742
- *
743
- * This is the identity that makes plural legends safe: click-to-toggle-series
744
- * must fire for color entries and never for size circles, and selection/drag
745
- * must be able to tell two legends apart. Without it, `.oc-legend` and
746
- * `data-legend-index` are ambiguous across legends and the DOM queries that
747
- * read them silently pick whichever comes first.
748
- */
749
- channel?: LegendChannel;
750
- /** Where the legend is positioned relative to the chart area. `'top-left'`
751
- * is a map-only overlay position (floats inside the map area). */
752
- position: 'top' | 'top-left' | 'right' | 'bottom' | 'bottom-right' | 'inline';
753
- /** Bounding box for the legend (pixel coordinates). */
754
- bounds: Rect;
755
- /** Entry label style. */
756
- labelStyle: TextStyle;
757
- }
758
-
759
- /** Engine-resolved absolute position for a single legend entry. */
760
- export interface LegendEntryPosition {
761
- x: number;
762
- y: number;
763
- labelX: number;
764
- labelY: number;
765
- width: number;
766
- row: number;
767
- }
768
-
769
- /** Categorical legend with discrete swatch entries. */
770
- export interface CategoricalLegendLayout extends BaseLegendLayout {
771
- /** Discriminant for legend type. Omitted means categorical (backwards compat). */
772
- type?: 'categorical';
773
- /** Legend entries. */
774
- entries: LegendEntry[];
775
- /** Swatch size in pixels. */
776
- swatchSize: number;
777
- /** Gap between swatch and label. */
778
- swatchGap: number;
779
- /** Gap between entries. */
780
- entryGap: number;
781
- /** Fill color for the rounded chip background behind the colored bar. */
782
- swatchChipFill: string;
783
- /** Engine-resolved absolute positions, parallel to `entries`. */
784
- entryPositions?: LegendEntryPosition[];
785
- /** Row advance used to build entryPositions (single source of truth). */
786
- rowHeight?: number;
787
- }
788
-
789
- /** A color stop in a gradient legend. */
790
- export interface GradientColorStop {
791
- /** Position along the gradient (0 to 1). */
792
- offset: number;
793
- /** CSS color value. */
794
- color: string;
795
- /** Optional stop-opacity (0 to 1). */
796
- opacity?: number;
797
- }
798
-
799
- /** Gradient legend for continuous color scales. */
800
- export interface GradientLegendLayout extends BaseLegendLayout {
801
- /** Discriminant for legend type. */
802
- type: 'gradient';
803
- /** Color stops for the gradient bar. */
804
- colorStops: GradientColorStop[];
805
- /** Formatted minimum value label. */
806
- minLabel: string;
807
- /** Formatted maximum value label. */
808
- maxLabel: string;
809
- }
810
-
811
- /** A positioned value label on a continuous/binned color legend. */
812
- export interface ContinuousLegendTick {
813
- /** The data value this label marks. */
814
- value: number;
815
- /** Formatted label text (channel format applied). */
816
- label: string;
817
- /** Label x position (pixel coordinates). */
818
- x: number;
819
- /** Horizontal text anchor for the label. */
820
- anchor: 'start' | 'middle' | 'end';
821
- }
822
-
823
- /** A discrete class swatch in a binned continuous legend. */
824
- export interface ContinuousLegendBin {
825
- /** Swatch x position (pixel coordinates). */
826
- x: number;
827
- /** Swatch width in pixels. */
828
- width: number;
829
- /** Fill color. */
830
- color: string;
831
- }
832
-
833
- /**
834
- * Continuous color legend for quantitative color scales on charts.
835
- *
836
- * Two rendering modes, resolved from the color channel's scale type:
837
- * - `gradient`: a single gradient-filled bar with min/max labels (plus a
838
- * midpoint label at the neutral value for diverging ramps).
839
- * - `binned`: a contiguous swatch row (quantile/quantize/threshold scales)
840
- * with boundary value labels between swatches at the class breaks.
841
- */
842
- export interface ContinuousLegendLayout extends BaseLegendLayout {
843
- /** Discriminant for legend type. */
844
- type: 'continuous';
845
- /** Rendering mode: gradient bar or binned swatch row. */
846
- mode: 'gradient' | 'binned';
847
- /** The color bar rectangle (pixel coordinates). */
848
- bar: Rect;
849
- /** Gradient color stops (empty in binned mode). */
850
- colorStops: GradientColorStop[];
851
- /** Class swatches, left to right (empty in gradient mode). */
852
- bins: ContinuousLegendBin[];
853
- /** Value labels rendered below the bar. */
854
- ticks: ContinuousLegendTick[];
855
- /** Text baseline y for the value labels (pixel coordinates). */
856
- labelY: number;
857
- }
858
-
859
- /**
860
- * One graduated circle in a size legend: a representative value from the size
861
- * scale's domain, drawn at the radius that value actually resolves to.
862
- */
863
- export interface SizeLegendCircle {
864
- /** The data value this circle stands for. */
865
- value: number;
866
- /** Formatted label text. */
867
- label: string;
868
- /** Radius in pixels -- the *same* scale the marks use, never a re-derivation. */
869
- radius: number;
870
- /** Center x, relative to the legend bounds. */
871
- cx: number;
872
- /** Center y, relative to the legend bounds. Circles sit on a common baseline. */
873
- cy: number;
874
- /** Label baseline y, relative to the legend bounds. */
875
- labelY: number;
876
- }
877
-
878
- /**
879
- * Size legend: graduated circles keying a quantitative `size` encoding.
880
- *
881
- * The circles are drawn nested (concentric, sharing a bottom edge) rather than
882
- * side by side -- the newsroom convention, and it makes the *ratio* between
883
- * magnitudes legible instead of just their order.
884
- *
885
- * The keyed values come from the scale's DOMAIN, not the data extent. The size
886
- * scale clamps, so with an explicit `scale.domain` every datum past `domain[1]`
887
- * renders at max radius; keying the data extent would imply the biggest circle
888
- * equals the biggest datum when it may not.
889
- */
890
- export interface SizeLegendLayout extends BaseLegendLayout {
891
- /** Discriminant for legend type. */
892
- type: 'size';
893
- /** Graduated circles, smallest first. */
894
- circles: SizeLegendCircle[];
895
- /** Stroke color for the circle outlines. */
896
- stroke: string;
897
- }
898
-
899
- /**
900
- * Resolved legend layout: categorical (swatches), gradient (tilemap bar),
901
- * continuous (chart color bar), or size (graduated circles).
902
- */
903
- export type LegendLayout =
904
- | CategoricalLegendLayout
905
- | GradientLegendLayout
906
- | ContinuousLegendLayout
907
- | SizeLegendLayout;
908
-
909
- // ---------------------------------------------------------------------------
910
- // Endpoint labels (right-side per-series column for line/area charts)
911
- // ---------------------------------------------------------------------------
912
-
913
- /** A single resolved endpoint-label entry, fully positioned. */
914
- export interface EndpointLabelEntry {
915
- /** Series identifier (matches mark.seriesKey). */
916
- seriesKey: string;
917
- /** Pre-wrapped label text lines. */
918
- labelLines: string[];
919
- /** Formatted value string for the last data point. */
920
- value: string;
921
- /** Series color. */
922
- color: string;
923
- /** True pixel y of the last data point on the line. */
924
- dataY: number;
925
- /** Displaced y after the bidirectional collision sweep. */
926
- labelY: number;
927
- /** True when |labelY - dataY| exceeds the threshold (renderer draws a leader line). */
928
- showLeader: boolean;
929
- /** Optional anchor circle drawn on the line at the chart's right edge. */
930
- marker?: {
931
- /** Rendered cx (offset right by radius so the line terminates at the circle edge). */
932
- x: number;
933
- y: number;
934
- /** Original data point x (used to suppress the underlying point mark). */
935
- dataX: number;
936
- fill: string;
937
- stroke: string;
938
- strokeWidth: number;
939
- radius: number;
940
- };
941
- }
942
-
943
- /** Resolved layout for the endpoint labels column. */
944
- export interface EndpointLabelsLayout {
945
- /** Per-series resolved entries. */
946
- entries: EndpointLabelEntry[];
947
- /** Bounding box for the column. */
948
- bounds: Rect;
949
- /** Style for the series-name text. */
950
- labelStyle: TextStyle;
951
- /** Style for the formatted value text. */
952
- valueStyle: TextStyle;
953
- /** Width of the colored swatch line drawn left of the label. */
954
- swatchSize: number;
955
- /** Horizontal gap between swatch and label text. */
956
- gap: number;
957
- /**
958
- * Vertical gap between the last wrapped label line and the value text
959
- * directly below it. Resolved by the engine so the renderer can't drift
960
- * away from the height the collision sweep budgeted for each entry.
961
- */
962
- valueGap: number;
963
- /** Fill color for the rounded chip background behind the colored bar. */
964
- swatchChipFill: string;
965
- /** Leading-edge (left side) entries when `ends: 'both'`. Empty when trailing only. */
966
- leading?: EndpointLabelEntry[];
967
- /** Bounding box for the leading column. Only set when `ends: 'both'`. */
968
- leadingBounds?: Rect;
969
- }
970
-
971
- // ---------------------------------------------------------------------------
972
- // Tooltips
973
- // ---------------------------------------------------------------------------
974
-
975
- /** A single field-value pair in a tooltip. */
976
- export interface TooltipField {
977
- /** Field label (e.g. "GDP Growth"). */
978
- label: string;
979
- /** Formatted value (e.g. "4.2%"). */
980
- value: string;
981
- /** Optional color swatch for series identification. */
982
- color?: string;
983
- }
984
-
985
- /** Tooltip content descriptor for a data point. */
986
- export interface TooltipContent {
987
- /** Title line (e.g. the x-axis value like "2020-Q1"). */
988
- title?: string;
989
- /** Field-value pairs to display. */
990
- fields: TooltipField[];
991
- }
992
-
993
- // ---------------------------------------------------------------------------
994
- // Accessibility
995
- // ---------------------------------------------------------------------------
996
-
997
- /** Accessibility metadata for the entire visualization. */
998
- export interface A11yMetadata {
999
- /** Alt text describing the visualization: the author's `a11y.description` / `description` when set, auto-generated otherwise. */
1000
- altText: string;
1001
- /** Tabular data fallback for screen readers. Each inner array is a row. */
1002
- dataTableFallback: unknown[][];
1003
- /** ARIA role for the visualization root element. */
1004
- role: string;
1005
- /** Whether the visualization is keyboard-navigable. */
1006
- keyboardNavigable: boolean;
1007
- /**
1008
- * Hide the visualization from assistive technology (`aria-hidden="true"`,
1009
- * no screen-reader table, no keyboard mark navigation). Optional because
1010
- * only chart compilation sets it, and only on author opt-out via
1011
- * `a11y.hidden`.
1012
- */
1013
- hidden?: boolean;
1014
- }
1015
-
1016
- // ---------------------------------------------------------------------------
1017
- // Animation (resolved)
1018
- // ---------------------------------------------------------------------------
1019
-
1020
- /** One fully-resolved animation phase. */
1021
- export interface ResolvedAnimationPhase {
1022
- /** Duration in ms. */
1023
- duration: number;
1024
- /** Easing preset name. */
1025
- ease: import('./spec').AnimationEase;
1026
- /** Stagger delay between elements in ms. */
1027
- staggerDelay: number;
1028
- /** Stagger ordering. */
1029
- staggerOrder: 'index' | 'value' | 'reverse';
1030
- }
1031
-
1032
- /** Resolved animation config. A phase is present iff that phase is enabled. */
1033
- export interface ResolvedAnimation {
1034
- /** Entrance animation phase. Present when enter animation is enabled. */
1035
- enter?: ResolvedAnimationPhase;
1036
- /** Data-update transition phase. Present when update animation is enabled. */
1037
- update?: ResolvedAnimationPhase;
1038
- /** Exit animation phase. Present when exit animation is enabled. */
1039
- exit?: ResolvedAnimationPhase;
1040
- /** Delay before annotations animate in (ms after marks). */
1041
- annotationDelay: number;
1042
- }
1043
-
1044
- // ---------------------------------------------------------------------------
1045
- // Metric bar (resolved)
1046
- // ---------------------------------------------------------------------------
1047
-
1048
- /**
1049
- * A resolved KPI metric cell with computed positions for label, value, and
1050
- * supplementary text spans. Cells render as a row above the chart area.
1051
- */
1052
- export interface ResolvedMetricCell {
1053
- /** Cell left x in layout coordinates. */
1054
- x: number;
1055
- /** Cell width. */
1056
- cellWidth: number;
1057
- /** Baseline y for the uppercase label. */
1058
- labelY: number;
1059
- /** Baseline y for the primary value. */
1060
- valueY: number;
1061
- /** The original metric spec (label/value/delta/etc.). */
1062
- metric: import('./spec').Metric;
1063
- /** True if value+delta+secondary would overflow cellWidth. Set by layout for diagnostics. */
1064
- overflowed: boolean;
1065
- }
1066
-
1067
- /**
1068
- * The full metric-bar layout. Present only when spec.metrics is supplied
1069
- * and the bar fits the container.
1070
- */
1071
- export interface ResolvedMetricBar {
1072
- /** Top y of the metric row in layout coordinates. */
1073
- y: number;
1074
- /** Total reserved height of the row. */
1075
- height: number;
1076
- /** Cells laid out evenly across the chart width. */
1077
- cells: ResolvedMetricCell[];
1078
- }
1079
-
1080
- // ---------------------------------------------------------------------------
1081
- // Series search (resolved)
1082
- // ---------------------------------------------------------------------------
1083
-
1084
- /**
1085
- * Reserved band for the series search input (`seriesSearch`). The band is
1086
- * empty SVG space between the chrome/metrics block and the top legend; the
1087
- * vanilla adapter overlays an absolutely-positioned DOM combobox aligned to
1088
- * this rect, so mounting it never changes the container's size.
1089
- */
1090
- export interface ResolvedSeriesSearch {
1091
- /** Band left x in layout coordinates. */
1092
- x: number;
1093
- /** Band top y in layout coordinates. */
1094
- y: number;
1095
- /** Band width. */
1096
- width: number;
1097
- /** Input row height (the reservation adds a gap below this). */
1098
- height: number;
1099
- /** Resolved input placeholder text. */
1100
- placeholder: string;
1101
- /** Distinct color-channel values available for search, in data order. */
1102
- values: string[];
1103
- }
1104
-
1105
- // ---------------------------------------------------------------------------
1106
- // You draw it (resolved)
1107
- // ---------------------------------------------------------------------------
1108
-
1109
- /**
1110
- * One x-sample the reader's drawing snaps to: a pixel x position paired with
1111
- * its data-x value. `xValue` is the value reported by `onReveal`; it falls
1112
- * back to the pixel x when the data value can't be recovered.
1113
- */
1114
- export interface YouDrawItSample {
1115
- /** Pixel x position within the chart area. */
1116
- px: number;
1117
- /** Data-coordinate x value at this sample (from the target line's data). */
1118
- xValue: string | number;
1119
- }
1120
-
1121
- /**
1122
- * Linear y pixel-to-data anchors, so the vanilla layer can map a drawn pixel
1123
- * y back to a data value for `onReveal` without holding the scale object.
1124
- * Present only when the y scale is invertible (continuous scales).
1125
- */
1126
- export interface YouDrawItYInvert {
1127
- /** Top pixel of the drawing area. */
1128
- topPixel: number;
1129
- /** Bottom pixel of the drawing area. */
1130
- bottomPixel: number;
1131
- /** Data value at the top pixel. */
1132
- topData: number;
1133
- /** Data value at the bottom pixel. */
1134
- bottomData: number;
1135
- }
1136
-
1137
- /**
1138
- * Scale inversion anchors serialized from the engine so the vanilla layer
1139
- * can convert pixel positions to data-space values without holding d3
1140
- * scale objects. Generalizes the YouDrawItYInvert pattern to both axes.
1141
- */
1142
- export interface ScaleInvert {
1143
- /** For continuous scales: two reference pixel-to-data anchor points. */
1144
- topPixel: number;
1145
- bottomPixel: number;
1146
- topData: number;
1147
- bottomData: number;
1148
- /** Scale type so the vanilla layer applies the correct inverse transform. */
1149
- scaleType?: 'linear' | 'log' | 'pow' | 'sqrt' | 'symlog' | 'time';
1150
- /** For band/point scales: ordered domain values and their pixel centers. */
1151
- domain?: (string | number)[];
1152
- positions?: number[];
1153
- }
1154
-
1155
- /**
1156
- * Resolved geometry and config for the "you draw it" interactive format
1157
- * (`youDrawIt`). The vanilla adapter uses this to render the hatched drawing
1158
- * region, capture pointer input, and mask/reveal the real line. Present only
1159
- * when the spec enables `youDrawIt` on a valid single-series line chart.
1160
- */
1161
- export interface ResolvedYouDrawIt {
1162
- /** Pixel x position of `from` within the chart area (drawing starts here). */
1163
- fromX: number;
1164
- /** The chart drawing area, for clamping pointer input and sizing the hatch region. */
1165
- area: Rect;
1166
- /** X samples (pixel + data value) at or after `from`, ascending by pixel x. Drawing snaps to these. */
1167
- samples: YouDrawItSample[];
1168
- /** Resolved prompt text for the hatched region. */
1169
- prompt: string;
1170
- /** Resolved skip-to-reveal button label. */
1171
- revealLabel: string;
1172
- /** Stroke color of the target line (the reader's guess uses a distinct pen style, but shares the palette for continuity). */
1173
- lineColor: string;
1174
- /** seriesKey of the target line mark, so the vanilla layer can find its DOM element. Undefined for a single-series line with no color encoding. */
1175
- targetSeriesKey?: string;
1176
- /** Pixel-to-data y anchors for reporting the guess in data coordinates. Absent when the y scale isn't invertible. */
1177
- yInvert?: YouDrawItYInvert;
1178
- /** Optional comparison line, resolved to pixel points parallel to the target line's points. */
1179
- comparisonPoints?: Point[];
1180
- }
1181
-
1182
- // ---------------------------------------------------------------------------
1183
- // ChartLayout (the main engine output for charts)
1184
- // ---------------------------------------------------------------------------
1185
-
1186
- /**
1187
- * A single panel in a faceted (small-multiples) layout.
1188
- * Each panel has its own marks, axes, and drawing area but typically
1189
- * shares scales with sibling panels.
1190
- */
1191
- export interface FacetPanelLayout {
1192
- /** Facet value that produced this panel. */
1193
- key: string;
1194
- /** Panel drawing area in SVG coordinates. */
1195
- area: Rect;
1196
- /** Data marks for this panel. */
1197
- marks: Mark[];
1198
- /** Per-panel axis layouts. Inner panels may have ticks suppressed. */
1199
- axes: { x?: AxisLayout; y?: AxisLayout };
1200
- /** Per-panel annotations. */
1201
- annotations: ResolvedAnnotation[];
1202
- /** Panel header label (facet value) positioned above the panel. */
1203
- header: { text: string; x: number; y: number; fontSize: number; fontWeight: number };
1204
- }
1205
-
1206
- /** Layout for a faceted (small-multiples) chart. */
1207
- export interface FacetLayout {
1208
- /** Ordered array of panel layouts. */
1209
- panels: FacetPanelLayout[];
1210
- /** The data field used for faceting. */
1211
- facetField: string;
1212
- /** Number of columns in the wrap grid. */
1213
- columns: number;
1214
- /** Whether scales are shared across panels. */
1215
- sharedScales: boolean;
1216
- }
1217
-
1218
- /**
1219
- * ChartLayout: the complete engine output for chart visualizations.
1220
- *
1221
- * Contains everything an adapter needs to render the chart: dimensions,
1222
- * chrome text, axes, data marks, annotations, legend, tooltip descriptors,
1223
- * and accessibility metadata. All values are fully computed pixel positions
1224
- * and resolved colors.
1225
- */
1226
- export interface ChartLayout {
1227
- /** The chart drawing area (after chrome, axes, and legend are subtracted). */
1228
- area: Rect;
1229
- /** Resolved chrome text elements with positions and styles. */
1230
- chrome: ResolvedChrome;
1231
- /** Resolved KPI metric bar. Present only when spec.metrics is supplied and fits. */
1232
- metrics?: ResolvedMetricBar;
1233
- /** Reserved series-search band. Present only when spec.seriesSearch is enabled. */
1234
- seriesSearch?: ResolvedSeriesSearch;
1235
- /** Resolved "you draw it" config. Present only when spec.youDrawIt is enabled and valid. */
1236
- youDrawIt?: ResolvedYouDrawIt;
1237
- /** Resolved axis layouts. */
1238
- axes: {
1239
- x?: AxisLayout;
1240
- y?: AxisLayout;
1241
- /** Right-side y-axis for independent-scale layers (dual-axis charts). */
1242
- y2?: AxisLayout;
1243
- };
1244
- /** Data marks: the visual representation of data points. */
1245
- marks: Mark[];
1246
- /** Resolved annotations with pixel positions. */
1247
- annotations: ResolvedAnnotation[];
1248
- /**
1249
- * Primary legend (the color legend). Kept as a singular slot: it is what every
1250
- * existing consumer reads, and a chart's legend is a color legend unless it
1251
- * says otherwise.
1252
- */
1253
- legend: LegendLayout;
1254
- /**
1255
- * Every legend on the chart, in render order -- the color legend plus, when a
1256
- * quantitative `size` channel is encoded, a size legend.
1257
- *
1258
- * `legend` is `legends[0]` when a color legend exists. Consumers that reserve
1259
- * space or hit-test **must** iterate this array: a bubble chart keys both
1260
- * continent (color) and population (size), and reserving margin for only the
1261
- * first leaves the second drawing on top of the plot.
1262
- */
1263
- legends: LegendLayout[];
1264
- /**
1265
- * Right-side endpoint labels column for multi-series line/area charts.
1266
- * Empty `entries` means the column is suppressed (single-series, opt-out, or
1267
- * auto-suppressed by the truth table).
1268
- */
1269
- endpointLabels?: EndpointLabelsLayout;
1270
- /** Tooltip descriptors keyed by a mark identifier. */
1271
- tooltipDescriptors: Map<string, TooltipContent>;
1272
- /** Accessibility metadata. */
1273
- a11y: A11yMetadata;
1274
- /** The resolved theme used for rendering. */
1275
- theme: ResolvedTheme;
1276
- /** Total SVG dimensions. */
1277
- dimensions: { width: number; height: number };
1278
- /** Resolved animation config. Present only when animation is enabled. */
1279
- animation?: ResolvedAnimation;
1280
- /** Whether the tryOpenData.ai watermark is enabled. */
1281
- watermark: boolean;
1282
- /** Display mode controlling chrome/axes/legend stripping. `'sparkline'` produces an edge-to-edge mini chart. */
1283
- display: import('./spec').Display;
1284
- /** Whether the crosshair (vertical snap line) is enabled. */
1285
- crosshair: boolean;
1286
- /** Real text measurement function from the adapter (for accurate SVG text wrapping). */
1287
- measureText?: MeasureTextFn;
1288
- /** Scale inversion anchors for the x axis. Used by anchor drag to convert pixel to data-space. */
1289
- xInvert?: ScaleInvert;
1290
- /** Scale inversion anchors for the y axis. Used by anchor drag to convert pixel to data-space. */
1291
- yInvert?: ScaleInvert;
1292
- /** Faceted (small-multiples) layout. When present, renderers iterate panels instead of using top-level marks/axes. */
1293
- facet?: FacetLayout;
1294
- }
1295
-
1296
- // ---------------------------------------------------------------------------
1297
- // TableLayout (engine output for tables)
1298
- // ---------------------------------------------------------------------------
1299
-
1300
- /** A resolved column definition with computed properties. */
1301
- export interface ResolvedColumn {
1302
- /** Column key (data field name). */
1303
- key: string;
1304
- /** Display label. */
1305
- label: string;
1306
- /** Computed width in pixels. */
1307
- width: number;
1308
- /** Whether sorting is enabled. */
1309
- sortable: boolean;
1310
- /** Text alignment. */
1311
- align: 'left' | 'center' | 'right';
1312
- /** Column cell type (determines rendering strategy). */
1313
- cellType: 'text' | 'heatmap' | 'category' | 'bar' | 'sparkline' | 'image' | 'flag';
1314
- }
1315
-
1316
- /** Base properties for all table cell types. */
1317
- export interface TableCellBase {
1318
- /** Raw value from the data. */
1319
- value: unknown;
1320
- /** Formatted display value. */
1321
- formattedValue: string;
1322
- /** Computed cell style. */
1323
- style: CellStyle;
1324
- /** ARIA label for the cell. */
1325
- aria?: string;
1326
- }
1327
-
1328
- /** Plain text cell. */
1329
- export interface TextTableCell extends TableCellBase {
1330
- cellType: 'text';
1331
- }
1332
-
1333
- /** Heatmap-colored cell. */
1334
- export interface HeatmapTableCell extends TableCellBase {
1335
- cellType: 'heatmap';
1336
- }
1337
-
1338
- /** Category-colored cell. */
1339
- export interface CategoryTableCell extends TableCellBase {
1340
- cellType: 'category';
1341
- }
1342
-
1343
- /** Cell with an inline bar visualization. */
1344
- export interface BarTableCell extends TableCellBase {
1345
- cellType: 'bar';
1346
- /** Bar width as a proportion (0 to 1) of available cell width. */
1347
- barWidth: number;
1348
- /** Bar left-edge offset as a proportion (0 to 1). 0 = left edge. */
1349
- barOffset: number;
1350
- /** Bar fill color. */
1351
- barColor: string;
1352
- /** Whether this bar represents a negative value. */
1353
- isNegative: boolean;
1354
- }
1355
-
1356
- /** Normalized sparkline data ready for rendering. */
1357
- export interface SparklineData {
1358
- /** Sparkline type. */
1359
- type: 'line' | 'bar' | 'column';
1360
- /** Normalized points in 0-1 range (for line type: x/y coordinates). */
1361
- points: Array<{ x: number; y: number }>;
1362
- /** For bar/column: widths or heights as 0-1 proportions. */
1363
- bars: number[];
1364
- /** Sparkline stroke/fill color. */
1365
- color: string;
1366
- /** Number of data points. */
1367
- count: number;
1368
- /** Raw value of the first data point. */
1369
- startValue: number;
1370
- /** Raw value of the last data point. */
1371
- endValue: number;
1372
- }
1373
-
1374
- /** Cell with an inline sparkline. */
1375
- export interface SparklineTableCell extends TableCellBase {
1376
- cellType: 'sparkline';
1377
- /** Sparkline rendering data (normalized points, color, type). Null when no valid data. */
1378
- sparklineData: SparklineData | null;
1379
- }
1380
-
1381
- /** Cell with an image. */
1382
- export interface ImageTableCell extends TableCellBase {
1383
- cellType: 'image';
1384
- /** Image URL. */
1385
- src: string;
1386
- /** Image width. */
1387
- imageWidth: number;
1388
- /** Image height. */
1389
- imageHeight: number;
1390
- /** Whether to apply rounded styling. */
1391
- rounded: boolean;
1392
- }
1393
-
1394
- /** Cell displaying a flag. */
1395
- export interface FlagTableCell extends TableCellBase {
1396
- cellType: 'flag';
1397
- /** Country code or flag identifier. */
1398
- countryCode: string;
1399
- }
1400
-
1401
- /** Discriminated union of all table cell types. */
1402
- export type TableCell =
1403
- | TextTableCell
1404
- | HeatmapTableCell
1405
- | CategoryTableCell
1406
- | BarTableCell
1407
- | SparklineTableCell
1408
- | ImageTableCell
1409
- | FlagTableCell;
1410
-
1411
- /** A resolved table row. */
1412
- export interface TableRow {
1413
- /** Unique row identifier. */
1414
- id: string;
1415
- /** Resolved cells in column order. */
1416
- cells: TableCell[];
1417
- /** Original data row. */
1418
- data: Record<string, unknown>;
1419
- }
1420
-
1421
- /** Pagination state for the table. */
1422
- export interface PaginationState {
1423
- /** Current page (0-indexed). */
1424
- page: number;
1425
- /** Rows per page. */
1426
- pageSize: number;
1427
- /** Total number of rows. */
1428
- totalRows: number;
1429
- /** Total number of pages. */
1430
- totalPages: number;
1431
- }
1432
-
1433
- /** Sort state for the table. */
1434
- export interface SortState {
1435
- /** Column key being sorted. */
1436
- column: string;
1437
- /** Sort direction. */
1438
- direction: 'asc' | 'desc';
1439
- }
1440
-
1441
- /**
1442
- * TableLayout: the complete engine output for table visualizations.
1443
- *
1444
- * Contains resolved columns, rows with computed cell values and styles,
1445
- * pagination, sort, search state, and accessibility metadata.
1446
- */
1447
- export interface TableLayout {
1448
- /** Resolved chrome text elements. */
1449
- chrome: ResolvedChrome;
1450
- /** Resolved column definitions. */
1451
- columns: ResolvedColumn[];
1452
- /** Resolved table rows with computed cell values and styles. */
1453
- rows: TableRow[];
1454
- /** Current sort state. */
1455
- sort?: SortState;
1456
- /** Pagination state. */
1457
- pagination?: PaginationState;
1458
- /** Whether search is enabled. */
1459
- search: { enabled: boolean; placeholder: string; query: string };
1460
- /** Whether the first column is sticky. */
1461
- stickyFirstColumn: boolean;
1462
- /** Whether compact mode is active. */
1463
- compact: boolean;
1464
- /** Accessibility metadata. */
1465
- a11y: { caption: string; summary: string };
1466
- /** The resolved theme. */
1467
- theme: ResolvedTheme;
1468
- /** Resolved animation config. Present only when animation is enabled. */
1469
- animation?: ResolvedAnimation;
1470
- /** Whether the tryOpenData.ai watermark is enabled. */
1471
- watermark: boolean;
1472
- }
1473
-
1474
- // ---------------------------------------------------------------------------
1475
- // GraphLayout (engine output for network graphs)
1476
- // ---------------------------------------------------------------------------
1477
-
1478
- /** A resolved graph node with computed position and visual properties. */
1479
- export interface GraphNodeLayout {
1480
- /** Node id. */
1481
- id: string;
1482
- /** Computed x position. */
1483
- x: number;
1484
- /** Computed y position. */
1485
- y: number;
1486
- /** Node radius in pixels. */
1487
- radius: number;
1488
- /** Fill color. */
1489
- fill: string;
1490
- /** Stroke color. */
1491
- stroke: string;
1492
- /** Stroke width. */
1493
- strokeWidth: number;
1494
- /** Node label. */
1495
- label?: ResolvedLabel;
1496
- /** Original node data. */
1497
- data: Record<string, unknown>;
1498
- /** Community/cluster identifier (from clustering config). */
1499
- community?: string;
1500
- /** Accessibility attributes. */
1501
- aria: MarkAria;
1502
- }
1503
-
1504
- /** A resolved graph edge with computed positions and visual properties. */
1505
- export interface GraphEdgeLayout {
1506
- /** Source node id. */
1507
- source: string;
1508
- /** Target node id. */
1509
- target: string;
1510
- /** Source x position. */
1511
- x1: number;
1512
- /** Source y position. */
1513
- y1: number;
1514
- /** Target x position. */
1515
- x2: number;
1516
- /** Target y position. */
1517
- y2: number;
1518
- /** Stroke color. */
1519
- stroke: string;
1520
- /** Stroke width. */
1521
- strokeWidth: number;
1522
- /** Line style. */
1523
- style: 'solid' | 'dashed' | 'dotted';
1524
- /** Original edge data. */
1525
- data: Record<string, unknown>;
1526
- }
1527
-
1528
- /**
1529
- * GraphLayout: the complete engine output for network graph visualizations.
1530
- *
1531
- * Note: GraphLayout is defined here for forward compatibility but the engine
1532
- * won't produce it until the graph renderer is implemented in a future phase.
1533
- */
1534
- export interface GraphLayout {
1535
- /** The graph drawing area. */
1536
- area: Rect;
1537
- /** Resolved chrome text. */
1538
- chrome: ResolvedChrome;
1539
- /** Resolved node positions and visual properties. */
1540
- nodes: GraphNodeLayout[];
1541
- /** Resolved edge positions and visual properties. */
1542
- edges: GraphEdgeLayout[];
1543
- /** Legend layout. */
1544
- legend: LegendLayout;
1545
- /** Tooltip descriptors. */
1546
- tooltipDescriptors: Map<string, TooltipContent>;
1547
- /** Accessibility metadata. */
1548
- a11y: A11yMetadata;
1549
- /** The resolved theme. */
1550
- theme: ResolvedTheme;
1551
- /** Total dimensions. */
1552
- dimensions: { width: number; height: number };
1553
- }
1554
-
1555
- // ---------------------------------------------------------------------------
1556
- // SankeyLayout (engine output for sankey diagrams)
1557
- // ---------------------------------------------------------------------------
1558
-
1559
- /** A resolved sankey node with computed position and visual properties. */
1560
- export interface SankeyNodeMark {
1561
- type: 'sankeyNode';
1562
- /** Left edge x position. */
1563
- x: number;
1564
- /** Top edge y position. */
1565
- y: number;
1566
- /** Node rectangle width. */
1567
- width: number;
1568
- /** Node rectangle height (proportional to throughput). */
1569
- height: number;
1570
- /** Fill color. */
1571
- fill: string;
1572
- /** Stroke color. */
1573
- stroke?: string;
1574
- /** Stroke width. */
1575
- strokeWidth?: number;
1576
- /** Corner radius for subtle rounding. */
1577
- cornerRadius: number;
1578
- /** Node label positioned outside the node. */
1579
- label: ResolvedLabel;
1580
- /** Node identifier (unique across the diagram). */
1581
- nodeId: string;
1582
- /** Total value flowing through this node. */
1583
- value: number;
1584
- /** Depth column (0 = leftmost). */
1585
- depth: number;
1586
- /** Original data associated with this node. */
1587
- data: Record<string, unknown>;
1588
- /** Accessibility attributes. */
1589
- aria: MarkAria;
1590
- /** Index for stagger animation ordering. */
1591
- animationIndex?: number;
1592
- }
1593
-
1594
- /** A resolved sankey link with computed path and visual properties. */
1595
- export interface SankeyLinkMark {
1596
- type: 'sankeyLink';
1597
- /** SVG path string for the curved ribbon. */
1598
- path: string;
1599
- /** Source node color (for gradient start). */
1600
- sourceColor: string;
1601
- /** Target node color (for gradient end). */
1602
- targetColor: string;
1603
- /** Fill opacity (0.35 default, increases on hover). */
1604
- fillOpacity: number;
1605
- /** Source node identifier. */
1606
- sourceId: string;
1607
- /** Target node identifier. */
1608
- targetId: string;
1609
- /** Link ribbon width at its thinnest point. */
1610
- width: number;
1611
- /** Flow value this link represents. */
1612
- value: number;
1613
- /** Original data row for this link. */
1614
- data: Record<string, unknown>;
1615
- /** Accessibility attributes. */
1616
- aria: MarkAria;
1617
- /** Index for stagger animation ordering. */
1618
- animationIndex?: number;
1619
- }
1620
-
1621
- /**
1622
- * SankeyLayout: the complete engine output for sankey diagram visualizations.
1623
- *
1624
- * Contains everything an adapter needs to render the sankey: dimensions,
1625
- * chrome, nodes, links, legend, tooltip descriptors, and accessibility metadata.
1626
- * No axes (sankey has no traditional axis system).
1627
- */
1628
- export interface SankeyLayout {
1629
- /** The sankey drawing area (after chrome and legend are subtracted). */
1630
- area: Rect;
1631
- /** Resolved chrome text elements with positions and styles. */
1632
- chrome: ResolvedChrome;
1633
- /** Resolved sankey node marks with positions and colors. */
1634
- nodes: SankeyNodeMark[];
1635
- /** Resolved sankey link marks with paths and gradient colors. */
1636
- links: SankeyLinkMark[];
1637
- /** Legend layout (position, entries, bounds). */
1638
- legend: LegendLayout;
1639
- /** Tooltip descriptors keyed by node/link identifier. */
1640
- tooltipDescriptors: Map<string, TooltipContent>;
1641
- /** Accessibility metadata. */
1642
- a11y: A11yMetadata;
1643
- /** The resolved theme used for rendering. */
1644
- theme: ResolvedTheme;
1645
- /** Total SVG dimensions. */
1646
- dimensions: { width: number; height: number };
1647
- /** Resolved animation config. Present only when animation is enabled. */
1648
- animation?: ResolvedAnimation;
1649
- /** Whether the tryOpenData.ai watermark is enabled. */
1650
- watermark: boolean;
1651
- /** Real text measurement function from the adapter (for accurate SVG text wrapping). */
1652
- measureText?: MeasureTextFn;
1653
- }
1654
-
1655
- // ---------------------------------------------------------------------------
1656
- // TileMapLayout (engine output for tile map visualizations)
1657
- // ---------------------------------------------------------------------------
1658
-
1659
- /** A resolved tile map tile with computed position and visual properties. */
1660
- export interface TileMapTileMark {
1661
- type: 'tile';
1662
- /** Left edge x position. */
1663
- x: number;
1664
- /** Top edge y position. */
1665
- y: number;
1666
- /** Tile width and height (tiles are square). */
1667
- size: number;
1668
- /** Fill color from the sequential color scale. */
1669
- fill: string;
1670
- /** Fill opacity (0-1). Used for opacity-based encoding. */
1671
- fillOpacity: number;
1672
- /** Tile border color. */
1673
- stroke: string;
1674
- /** Tile border width. */
1675
- strokeWidth: number;
1676
- /** Corner radius. */
1677
- cornerRadius: number;
1678
- /** US state abbreviation (e.g. "CA", "TX"). */
1679
- stateCode: string;
1680
- /** Numeric value (null if state has no data). */
1681
- value: number | null;
1682
- /** Formatted value string (e.g. "12,000" or "–" for missing). */
1683
- formattedValue: string;
1684
- /** Whether this state has data. False for missing states. */
1685
- hasData: boolean;
1686
- /** State code text label (positioned inside tile). */
1687
- label: ResolvedLabel;
1688
- /** Value text label (positioned inside tile, below state code). */
1689
- valueLabel: ResolvedLabel;
1690
- /** Accessibility attributes. */
1691
- aria: MarkAria;
1692
- /** Index for stagger animation ordering. */
1693
- animationIndex?: number;
1694
- /** Original data associated with this tile. */
1695
- data: Record<string, unknown>;
1696
- }
1697
-
1698
- /**
1699
- * TileMapLayout: the complete engine output for tile map visualizations.
1700
- *
1701
- * Contains everything an adapter needs to render the tile map: dimensions,
1702
- * chrome, tiles, gradient legend, tooltip descriptors, and accessibility metadata.
1703
- */
1704
- export interface TileMapLayout {
1705
- /** The tile map drawing area (after chrome and legend are subtracted). */
1706
- area: Rect;
1707
- /** Resolved chrome text elements with positions and styles. */
1708
- chrome: ResolvedChrome;
1709
- /** Resolved tile marks with positions, colors, and labels. */
1710
- tiles: TileMapTileMark[];
1711
- /** Gradient color legend for quantitative mode (null if hidden or categorical). */
1712
- gradientLegend: GradientLegendLayout | null;
1713
- /** Categorical swatch legend for nominal mode (null if hidden or quantitative). */
1714
- categoricalLegend: CategoricalLegendLayout | null;
1715
- /** Tooltip content descriptors keyed by state code. */
1716
- tooltipDescriptors: Map<string, TooltipContent>;
1717
- /** Accessibility metadata for the tile map. */
1718
- a11y: A11yMetadata;
1719
- /** Resolved theme. */
1720
- theme: ResolvedTheme;
1721
- /** Total SVG width in pixels. */
1722
- width: number;
1723
- /** Total SVG height in pixels. */
1724
- height: number;
1725
- /** Resolved animation config (undefined if animation is disabled). */
1726
- animation: ResolvedAnimation | undefined;
1727
- /** Whether to render the watermark. */
1728
- watermark: boolean;
1729
- /** Text measurement function for the rendering adapter. */
1730
- measureText: MeasureTextFn;
1731
- }
1732
-
1733
- // ---------------------------------------------------------------------------
1734
- // MapLayout (engine output for map visualizations)
1735
- // ---------------------------------------------------------------------------
1736
-
1737
- /** A structured compile warning with a code and context. */
1738
- export interface CompileWarning {
1739
- code: string;
1740
- message: string;
1741
- context?: Record<string, unknown>;
1742
- }
1743
-
1744
- /** Resolved focus target for map camera framing. */
1745
- export interface MapFocusLayout {
1746
- target: { x: number; y: number; width: number; height: number; padding: number };
1747
- ids: Array<string | number>;
1748
- }
1749
-
1750
- /** A resolved map feature mark with computed SVG path and fill. */
1751
- export interface MapFeatureMark {
1752
- type: 'map-feature';
1753
- /** SVG path `d` attribute for this feature's shape. */
1754
- path: string;
1755
- /** CSS fill color. */
1756
- fill: string;
1757
- /** CSS stroke color (border). */
1758
- stroke: string;
1759
- /** Stroke width in px. */
1760
- strokeWidth: number;
1761
- /** Feature ID (from TopoJSON). */
1762
- id: string | number;
1763
- /** Feature name (from properties, if available). */
1764
- name?: string;
1765
- /** Original joined data row (null if no data matched this feature). */
1766
- data: Record<string, unknown> | null;
1767
- /** Accessibility attributes. */
1768
- aria: MarkAria;
1769
- /** Index for stagger animation ordering. */
1770
- animationIndex: number;
1771
- /** Bounding box in map-local coordinates. */
1772
- bounds: { x: number; y: number; width: number; height: number };
1773
- /** Centroid in map-local coordinates. */
1774
- centroid: [number, number];
1775
- }
1776
-
1777
- /** A resolved map point mark with projected coordinates and visual properties. */
1778
- export interface MapPointMark {
1779
- type: 'map-point';
1780
- /** Projected center x in map-local coordinates. */
1781
- cx: number;
1782
- /** Projected center y in map-local coordinates. */
1783
- cy: number;
1784
- /** Radius in pixels (base radius before camera counter-scaling). */
1785
- r: number;
1786
- /** CSS fill color. */
1787
- fill: string;
1788
- /** CSS stroke color. */
1789
- stroke: string;
1790
- /** Stroke width in px. */
1791
- strokeWidth: number;
1792
- /** Fill opacity (0-1). */
1793
- fillOpacity: number;
1794
- /** Stable key for events. */
1795
- key: string;
1796
- /** Original data row. */
1797
- data: Record<string, unknown>;
1798
- /** Accessibility attributes. */
1799
- aria: MarkAria;
1800
- /** Index for stagger animation ordering. */
1801
- animationIndex: number;
1802
- }
1803
-
1804
- /** Border paths for the map (interior borders and coastline/outline). */
1805
- export interface MapBorders {
1806
- /** SVG path `d` for interior borders between features. */
1807
- interiorPath: string;
1808
- /** SVG path `d` for the outer boundary / coastline. */
1809
- outlinePath: string;
1810
- /** Stroke color for interior borders. */
1811
- interiorStroke: string;
1812
- /** Stroke color for outer boundary. */
1813
- outlineStroke: string;
1814
- }
1815
-
1816
- /**
1817
- * MapLayout: the complete engine output for map visualizations.
1818
- *
1819
- * Contains everything an adapter needs to render the map: dimensions,
1820
- * chrome, feature paths, borders, legend, tooltip descriptors, and
1821
- * accessibility metadata.
1822
- */
1823
- export interface MapLayout {
1824
- /** The map drawing area (after chrome and legend are subtracted). */
1825
- area: Rect;
1826
- /** Resolved chrome text elements with positions and styles. */
1827
- chrome: ResolvedChrome;
1828
- /** Resolved feature marks with paths, fills, and joined data. */
1829
- features: MapFeatureMark[];
1830
- /** Border paths (interior mesh and outline). */
1831
- borders: MapBorders;
1832
- /** Resolved point marks for the symbol layer (empty array if no points layer). */
1833
- pointMarks: MapPointMark[];
1834
- /** Categorical legend for the point color channel (null if no point color). */
1835
- pointCategoricalLegend: CategoricalLegendLayout | null;
1836
- /** Continuous legend for the point color channel (null if no point color). */
1837
- pointContinuousLegend: ContinuousLegendLayout | null;
1838
- /** Continuous color legend for quantitative mode (null if hidden or categorical). */
1839
- continuousLegend: ContinuousLegendLayout | null;
1840
- /** Categorical swatch legend for nominal mode (null if hidden or quantitative). */
1841
- categoricalLegend: CategoricalLegendLayout | null;
1842
- /** Tooltip content descriptors keyed by feature ID. */
1843
- tooltipDescriptors: Map<string, TooltipContent>;
1844
- /** Accessibility metadata for the map. */
1845
- a11y: A11yMetadata;
1846
- /** Resolved theme. */
1847
- theme: ResolvedTheme;
1848
- /** Total SVG width in pixels. */
1849
- width: number;
1850
- /** Total SVG height in pixels. */
1851
- height: number;
1852
- /** Resolved animation config (undefined if animation is disabled). */
1853
- animation: ResolvedAnimation | undefined;
1854
- /** Whether to render the watermark. */
1855
- watermark: boolean;
1856
- /** Text measurement function for the rendering adapter. */
1857
- measureText: MeasureTextFn;
1858
- /** Structured compile warnings (unmatched keys, missing data, winding issues). */
1859
- warnings: CompileWarning[];
1860
- /** The (width, height) passed to the projection's fitSize -- camera fits against this, not the SVG viewBox. */
1861
- mapSize: { width: number; height: number };
1862
- /** Resolved focus target for camera framing (null if no focus). */
1863
- focus: MapFocusLayout | null;
1864
- }
1865
-
1866
- // ---------------------------------------------------------------------------
1867
- // BarListLayout (engine output for bar list visualizations)
1868
- // ---------------------------------------------------------------------------
1869
-
1870
- /** A resolved bar list row with computed positions and visual properties. */
1871
- export interface BarListRowMark {
1872
- type: 'barlist-row';
1873
- /** Row index (0-based). */
1874
- index: number;
1875
- /** Row top y position. */
1876
- y: number;
1877
- /** Row height (includes spacing). */
1878
- height: number;
1879
- /** Label text for this row. */
1880
- label: ResolvedLabel;
1881
- /** Optional subtitle text. */
1882
- subtitle?: ResolvedLabel;
1883
- /** Track rectangle (the muted background bar). */
1884
- track: { x: number; y: number; width: number; height: number; cornerRadius: number };
1885
- /** Fill bar rectangle (the colored bar proportional to value). */
1886
- bar: { x: number; y: number; width: number; height: number; cornerRadius: number; fill: string };
1887
- /** Formatted value label (right-aligned). */
1888
- valueLabel: ResolvedLabel;
1889
- /** Raw numeric value. */
1890
- value: number;
1891
- /** Formatted value string. */
1892
- formattedValue: string;
1893
- /** Accessibility attributes. */
1894
- aria: MarkAria;
1895
- /** Index for stagger animation ordering. */
1896
- animationIndex: number;
1897
- /** Original data row. */
1898
- data: Record<string, unknown>;
1899
- }
1900
-
1901
- /**
1902
- * BarListLayout: the complete engine output for bar list visualizations.
1903
- *
1904
- * Contains everything an adapter needs to render the bar list: dimensions,
1905
- * chrome, row marks, tooltip descriptors, and accessibility metadata.
1906
- */
1907
- export interface BarListLayout {
1908
- /** The bar list drawing area. */
1909
- area: Rect;
1910
- /** Resolved chrome text elements with positions and styles. */
1911
- chrome: ResolvedChrome;
1912
- /** Resolved row marks with positions, colors, and labels. */
1913
- rows: BarListRowMark[];
1914
- /** Tooltip content descriptors keyed by row index. */
1915
- tooltipDescriptors: Map<string, TooltipContent>;
1916
- /** Accessibility metadata. */
1917
- a11y: A11yMetadata;
1918
- /** Resolved theme. */
1919
- theme: ResolvedTheme;
1920
- /** Total SVG width in pixels. */
1921
- width: number;
1922
- /** Total SVG height in pixels. */
1923
- height: number;
1924
- /** Resolved animation config (undefined if animation is disabled). */
1925
- animation: ResolvedAnimation | undefined;
1926
- /** Whether to render the watermark. */
1927
- watermark: boolean;
1928
- /** Text measurement function for the rendering adapter. */
1929
- measureText: MeasureTextFn;
1930
- }
1931
-
1932
- // ---------------------------------------------------------------------------
1933
- // Compile options (engine input)
1934
- // ---------------------------------------------------------------------------
1935
-
1936
- /** Function signature for text measurement provided by adapters. */
1937
- export type MeasureTextFn = (
1938
- text: string,
1939
- fontSize: number,
1940
- fontWeight?: number,
1941
- ) => { width: number; height: number };
1942
-
1943
- /**
1944
- * Options passed to the engine's compile functions.
1945
- *
1946
- * Width and height define the total available space. The engine subtracts
1947
- * chrome, axes, and legend to compute the chart drawing area.
1948
- */
1949
- export interface CompileOptions {
1950
- /** Total available width in pixels. */
1951
- width: number;
1952
- /** Total available height in pixels. */
1953
- height: number;
1954
- /** Theme overrides. */
1955
- theme?: import('./spec').ThemeConfig;
1956
- /**
1957
- * Resolved dark mode boolean.
1958
- *
1959
- * Note: this is a boolean, not the DarkMode union ("auto" | "force" | "off").
1960
- * Adapters resolve "auto" by checking window.matchMedia('(prefers-color-scheme: dark)')
1961
- * before calling compile. The engine always receives a resolved boolean.
1962
- */
1963
- darkMode?: boolean;
1964
- /** Whether to show the tryOpenData.ai watermark. Defaults to true. */
1965
- watermark?: boolean;
1966
- /**
1967
- * Enable development-time diagnostics (WCAG contrast warnings via
1968
- * `console.warn`). The engine is isomorphic, so it never sniffs
1969
- * `process.env`; the host decides what "dev" means and passes this flag.
1970
- * Warnings are advisory only and never throw. Defaults to false.
1971
- */
1972
- dev?: boolean;
1973
- /**
1974
- * Sink for advisory spec warnings (deprecations, did-you-mean suggestions,
1975
- * unknown scheme names, overplotting/beeswarm budget notes, etc.). The engine
1976
- * is isomorphic and side-effect-free by default: rather than writing to the
1977
- * global `console`, it routes every advisory warning through this callback so
1978
- * a host can collect, reroute, or silence them (e.g. suppress under SSR, fail
1979
- * a test on any warning, surface them in a dev overlay). When omitted, the
1980
- * engine defaults to `console.warn`. Never called with fatal errors, which are
1981
- * thrown instead.
1982
- */
1983
- onWarn?: (message: string) => void;
1984
- /**
1985
- * Real text measurement function provided by the adapter.
1986
- * Uses a hidden canvas or DOM element for accurate text dimensions.
1987
- * If not provided, the engine falls back to heuristic estimation.
1988
- */
1989
- measureText?: MeasureTextFn;
1990
- /** Extra pixels to reserve on the right margin for a secondary y-axis. Set by compileLayer when resolve.scale.y is 'independent'. */
1991
- rightAxisReserve?: number;
1992
- /**
1993
- * Extra pixels to reserve below the plot for the auto-thinning footnote list.
1994
- * Chicken-and-egg: thinning needs the chart area to decide what to demote, but
1995
- * the footnotes it produces need space carved out of that same area. compileChart
1996
- * resolves it by compiling once to learn the footnote count, then recompiling with
1997
- * this set. Callers should not set it; it is internal to that second pass.
1998
- */
1999
- footnoteReserve?: number;
2000
- /** Recursion depth of the footnote-reserve convergence pass. Internal to compileChart. */
2001
- footnotePass?: number;
2002
- /** Set after facet height growth to prevent unbounded recursion. Internal to compileFaceted. */
2003
- facetHeightGrown?: boolean;
2004
- /**
2005
- * Use this chart drawing area instead of computing one from chrome, axes,
2006
- * and legend reservations. Set by compileLayer when compiling leaf layers so
2007
- * their marks land in the primary layout's coordinate space; leaf specs lack
2008
- * the layer-level chrome/legend/theme and would otherwise compute a
2009
- * different area than the one the axes are rendered in.
2010
- */
2011
- frozenChartArea?: Rect;
2012
- }
2013
-
2014
- /** Extended compile options for table visualizations. */
2015
- export interface CompileTableOptions extends CompileOptions {
2016
- /** Current sort state to apply. */
2017
- sort?: SortState;
2018
- /** Search query to filter rows. */
2019
- search?: string;
2020
- /** Current page (0-indexed). */
2021
- page?: number;
2022
- /** Rows per page. */
2023
- pageSize?: number;
2024
- }