@opendata-ai/openchart-core 7.10.0 → 8.0.0-rc.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +1154 -119
- package/dist/index.js +530 -41
- package/dist/index.js.map +1 -1
- package/dist/styles.css +2 -1
- package/dist/styles.css.map +1 -0
- package/package.json +9 -3
- package/schema/chart.schema.json +8957 -0
- package/schema/table.schema.json +861 -0
- package/schema/vizspec.schema.json +17694 -0
- package/src/accessibility/alt-text.ts +39 -1
- package/src/accessibility/aria.ts +4 -2
- package/src/colors/__tests__/colorblind.test.ts +12 -0
- package/src/colors/colorblind.ts +11 -2
- package/src/colors/contrast.ts +11 -0
- package/src/colors/index.ts +9 -1
- package/src/colors/palettes.ts +47 -0
- package/src/helpers/__tests__/deep-merge.test.ts +54 -0
- package/src/helpers/__tests__/spec-builders.test.ts +3 -3
- package/src/helpers/deep-merge.ts +29 -0
- package/src/helpers/spec-builders.ts +7 -7
- package/src/index.ts +29 -1
- package/src/labels/collision.ts +1 -0
- package/src/layout/chrome.ts +24 -0
- package/src/layout/index.ts +1 -1
- package/src/locale/__tests__/format.test.ts +347 -11
- package/src/locale/format.ts +243 -18
- package/src/locale/index.ts +10 -1
- package/src/responsive/index.ts +2 -0
- package/src/responsive/metrics.ts +74 -9
- package/src/schema/__tests__/generated-artifacts.test.ts +42 -0
- package/src/schema/__tests__/schema.test.ts +179 -0
- package/src/styles/__tests__/reduced-motion-selectors.test.ts +28 -0
- package/src/styles/animation.css +197 -168
- package/src/styles/base.css +89 -62
- package/src/styles/chrome.css +173 -179
- package/src/styles/dark.css +38 -35
- package/src/styles/graph.css +116 -111
- package/src/styles/index.css +5 -0
- package/src/styles/keyframes.css +115 -100
- package/src/styles/legend.css +14 -12
- package/src/styles/reduced-motion.css +61 -40
- package/src/styles/series-search.css +153 -0
- package/src/styles/sparkline.css +14 -12
- package/src/styles/table-animation.css +82 -80
- package/src/styles/table.css +314 -302
- package/src/styles/token-definitions.ts +199 -0
- package/src/styles/tokens.css +132 -128
- package/src/styles/tooltip.css +109 -115
- package/src/styles/you-draw-it.css +126 -0
- package/src/types/__tests__/encoding.test.ts +86 -17
- package/src/types/__tests__/spec.test.ts +16 -12
- package/src/types/encoding.ts +69 -25
- package/src/types/events.ts +12 -0
- package/src/types/index.ts +39 -3
- package/src/types/layout.ts +414 -8
- package/src/types/schema-roots.ts +32 -0
- package/src/types/spec.ts +643 -84
- package/src/types/table.ts +3 -2
package/src/types/spec.ts
CHANGED
|
@@ -32,6 +32,10 @@ import type { SeriesStrategy, TokenValue } from './theme';
|
|
|
32
32
|
* - 'rule': reference lines as data marks
|
|
33
33
|
* - 'tick': strip/rug plot marks
|
|
34
34
|
* - 'rect': heatmaps and 2D binned plots
|
|
35
|
+
* - 'range': dumbbell / arrow / range-bar plots spanning two values per category
|
|
36
|
+
* - 'waffle': unit grids ("x of 100") for part-to-whole counts
|
|
37
|
+
* - 'calendar': GitHub-style calendar heatmap (weeks x weekdays, daily dates)
|
|
38
|
+
* - 'parliament': hemicycle seat-dot chart for election/legislature results
|
|
35
39
|
*/
|
|
36
40
|
export type MarkType =
|
|
37
41
|
| 'bar'
|
|
@@ -44,10 +48,12 @@ export type MarkType =
|
|
|
44
48
|
| 'rule'
|
|
45
49
|
| 'tick'
|
|
46
50
|
| 'rect'
|
|
47
|
-
| 'lollipop'
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
+
| 'lollipop'
|
|
52
|
+
| 'beeswarm'
|
|
53
|
+
| 'range'
|
|
54
|
+
| 'waffle'
|
|
55
|
+
| 'calendar'
|
|
56
|
+
| 'parliament';
|
|
51
57
|
|
|
52
58
|
// ---------------------------------------------------------------------------
|
|
53
59
|
// Gradient definitions (Vega-aligned)
|
|
@@ -174,6 +180,19 @@ export interface MarkDef {
|
|
|
174
180
|
innerRadius?: number;
|
|
175
181
|
/** Outer radius for arc marks. */
|
|
176
182
|
outerRadius?: number;
|
|
183
|
+
/**
|
|
184
|
+
* Start angle in radians for arc marks. Defaults to 0 (full pie/donut).
|
|
185
|
+
* Combined with `endAngle`, restricts the pie/donut to a partial sweep,
|
|
186
|
+
* e.g. `startAngle: -Math.PI / 2, endAngle: Math.PI / 2` for a half-donut
|
|
187
|
+
* (election-style results donut). Angles follow d3's convention: 0 is
|
|
188
|
+
* straight up, increasing clockwise. Only meaningful when `type` is `'arc'`.
|
|
189
|
+
*/
|
|
190
|
+
startAngle?: number;
|
|
191
|
+
/**
|
|
192
|
+
* End angle in radians for arc marks. Defaults to 2*Math.PI (full pie/donut).
|
|
193
|
+
* See `startAngle`. Only meaningful when `type` is `'arc'`.
|
|
194
|
+
*/
|
|
195
|
+
endAngle?: number;
|
|
177
196
|
/** Corner radius for rect/bar marks. 'pill' sets rx to half the bar thickness. */
|
|
178
197
|
cornerRadius?: number | 'pill';
|
|
179
198
|
/** Fixed bar thickness in pixels for bar/column marks. When set, bars are this height (horizontal) or width (vertical), centered within the band. */
|
|
@@ -200,6 +219,99 @@ export interface MarkDef {
|
|
|
200
219
|
* two competing diagonals.
|
|
201
220
|
*/
|
|
202
221
|
trendline?: boolean;
|
|
222
|
+
/**
|
|
223
|
+
* Horizontal pixel offset from the data anchor. Only meaningful when `type`
|
|
224
|
+
* is `'text'`. Use it to lift a label clear of the mark it annotates instead
|
|
225
|
+
* of shifting the underlying data value.
|
|
226
|
+
*/
|
|
227
|
+
dx?: number;
|
|
228
|
+
/**
|
|
229
|
+
* Vertical pixel offset from the data anchor (negative = up). Only meaningful
|
|
230
|
+
* when `type` is `'text'`. `{ type: 'text', dy: -10 }` floats each label ten
|
|
231
|
+
* pixels above its point.
|
|
232
|
+
*/
|
|
233
|
+
dy?: number;
|
|
234
|
+
/** Horizontal alignment of text marks relative to their anchor. Defaults to `'center'`. */
|
|
235
|
+
align?: 'left' | 'center' | 'right';
|
|
236
|
+
/** Vertical alignment of text marks relative to their anchor. Defaults to `'middle'`. */
|
|
237
|
+
baseline?: 'top' | 'middle' | 'bottom';
|
|
238
|
+
/**
|
|
239
|
+
* Font size in pixels for text marks. Ignored when the `size` encoding channel
|
|
240
|
+
* is present (which scales font size from a data field). `size` is already
|
|
241
|
+
* taken by bar thickness, hence the distinct name.
|
|
242
|
+
*/
|
|
243
|
+
fontSize?: number;
|
|
244
|
+
/**
|
|
245
|
+
* Pattern-fill reinforcement for filled marks (bar, area, arc).
|
|
246
|
+
*
|
|
247
|
+
* - `'auto'`: assign a per-series SVG pattern (diagonal hatch, dots,
|
|
248
|
+
* crosshatch, vertical lines) layered over each series color so series
|
|
249
|
+
* remain distinguishable without color vision. Marks too small to show
|
|
250
|
+
* a legible pattern keep their solid fill.
|
|
251
|
+
* - `'none'` (default): solid fills only.
|
|
252
|
+
*/
|
|
253
|
+
fillPattern?: 'auto' | 'none';
|
|
254
|
+
/**
|
|
255
|
+
* Visual style for range marks. Only meaningful when `type` is `'range'`.
|
|
256
|
+
* - 'dumbbell' (default): a dot at each end joined by a connector line.
|
|
257
|
+
* The start dot is muted, the end dot carries the accent color.
|
|
258
|
+
* - 'arrow': a line with an arrowhead at the x2/y2 end, the strongest
|
|
259
|
+
* "change between two points in time" form.
|
|
260
|
+
* - 'bar': a plain floating range bar spanning start to end.
|
|
261
|
+
*/
|
|
262
|
+
style?: 'dumbbell' | 'arrow' | 'bar';
|
|
263
|
+
/**
|
|
264
|
+
* Color range marks by direction of change. Only meaningful when `type` is
|
|
265
|
+
* `'range'`. When true, increases (x2 > x, or y2 > y) use the theme's
|
|
266
|
+
* `positive` semantic color and decreases use `negative`. A field-based
|
|
267
|
+
* `encoding.color` takes precedence over direction coloring.
|
|
268
|
+
*/
|
|
269
|
+
colorByDirection?: boolean;
|
|
270
|
+
/**
|
|
271
|
+
* Total number of cells in a waffle grid. Only meaningful when `type` is
|
|
272
|
+
* `'waffle'`. Category values normalize to this many cells via
|
|
273
|
+
* largest-remainder rounding so the grid always sums exactly. Default 100.
|
|
274
|
+
*/
|
|
275
|
+
units?: number;
|
|
276
|
+
/**
|
|
277
|
+
* Number of columns in a waffle grid. Only meaningful when `type` is
|
|
278
|
+
* `'waffle'`. Rows derive from `units / columns`. Default 10.
|
|
279
|
+
*/
|
|
280
|
+
columns?: number;
|
|
281
|
+
/**
|
|
282
|
+
* First day of the week for calendar marks. Only meaningful when `type` is
|
|
283
|
+
* `'calendar'`. Controls which weekday occupies the top row of each band.
|
|
284
|
+
* Defaults to 'monday' (ISO week convention).
|
|
285
|
+
*/
|
|
286
|
+
weekStart?: 'monday' | 'sunday';
|
|
287
|
+
/**
|
|
288
|
+
* Corner radius in pixels for calendar day cells. Only meaningful when
|
|
289
|
+
* `type` is `'calendar'`. Defaults to 1.
|
|
290
|
+
*/
|
|
291
|
+
cellRadius?: number;
|
|
292
|
+
/**
|
|
293
|
+
* Seat layout shape for parliament marks. Only meaningful when `type` is
|
|
294
|
+
* `'parliament'`. `'hemicycle'` (default, and currently the only shape)
|
|
295
|
+
* packs seats into concentric semicircular arcs, party-grouped left to
|
|
296
|
+
* right.
|
|
297
|
+
*/
|
|
298
|
+
shape?: 'hemicycle';
|
|
299
|
+
/**
|
|
300
|
+
* Seat dot radius in pixels for parliament marks. `'auto'` (default) sizes
|
|
301
|
+
* dots to fill the available hemicycle rings for the given seat count.
|
|
302
|
+
* Only meaningful when `type` is `'parliament'`.
|
|
303
|
+
*/
|
|
304
|
+
seatRadius?: number | 'auto';
|
|
305
|
+
/**
|
|
306
|
+
* The majority-threshold line and "N to win" label on parliament marks. Only
|
|
307
|
+
* meaningful when `type` is `'parliament'`. `true` (default) draws the line at
|
|
308
|
+
* a simple majority (half the seats plus one); `false` hides it. The object
|
|
309
|
+
* form overrides the threshold and label: `{ seats }` sets a custom seat count
|
|
310
|
+
* (e.g. a two-thirds supermajority) and `{ label }` overrides the default
|
|
311
|
+
* "N to win" text. A `seats` value outside `1..totalSeats` warns and falls
|
|
312
|
+
* back to the simple-majority default.
|
|
313
|
+
*/
|
|
314
|
+
majorityLine?: boolean | { seats?: number; label?: string };
|
|
203
315
|
}
|
|
204
316
|
|
|
205
317
|
// ---------------------------------------------------------------------------
|
|
@@ -227,7 +339,11 @@ export type AggregateOp =
|
|
|
227
339
|
export interface AxisConfig {
|
|
228
340
|
/** Axis title text. If omitted, the field name is used. */
|
|
229
341
|
title?: string;
|
|
230
|
-
/**
|
|
342
|
+
/**
|
|
343
|
+
* Number format: d3-format string (e.g. ",.0f"), or semantic keyword
|
|
344
|
+
* `'percent'` / `'currency'`. When omitted, compact notation (1k, 2.5M)
|
|
345
|
+
* is applied automatically.
|
|
346
|
+
*/
|
|
231
347
|
format?: string;
|
|
232
348
|
/** Override tick count. Engine picks a sensible default if omitted. */
|
|
233
349
|
tickCount?: number;
|
|
@@ -271,8 +387,12 @@ export interface AxisConfig {
|
|
|
271
387
|
|
|
272
388
|
/** Scale configuration for an encoding channel. */
|
|
273
389
|
export interface ScaleConfig {
|
|
274
|
-
/**
|
|
275
|
-
|
|
390
|
+
/**
|
|
391
|
+
* Explicit domain override. Auto-derived from data if omitted.
|
|
392
|
+
* Continuous scales take `[min, max]`; threshold scales take the full
|
|
393
|
+
* list of class break values; categorical scales take the value list.
|
|
394
|
+
*/
|
|
395
|
+
domain?: number[] | string[];
|
|
276
396
|
/** Scale type override. Usually inferred from field type. */
|
|
277
397
|
type?: ScaleType;
|
|
278
398
|
/** Whether to nice-ify the domain for clean tick values. Defaults to true. */
|
|
@@ -283,6 +403,15 @@ export interface ScaleConfig {
|
|
|
283
403
|
clip?: boolean;
|
|
284
404
|
/** Explicit range override. */
|
|
285
405
|
range?: unknown[];
|
|
406
|
+
/**
|
|
407
|
+
* Named color scheme (Vega-Lite aligned). Resolved against the core palette
|
|
408
|
+
* registry (sequential: blue, green, orange, purple, teal; diverging:
|
|
409
|
+
* redBlue, brownTeal; categorical) during the pre-validation sugar
|
|
410
|
+
* expansion; common VL names (blues, greens, category10, ...) are accepted
|
|
411
|
+
* as aliases. Unknown names fail validation with the supported list.
|
|
412
|
+
* An explicit `range` wins over `scheme`.
|
|
413
|
+
*/
|
|
414
|
+
scheme?: string;
|
|
286
415
|
/** Reverse the range direction. */
|
|
287
416
|
reverse?: boolean;
|
|
288
417
|
/** Clamp output to the range. */
|
|
@@ -317,6 +446,30 @@ export type ScaleType =
|
|
|
317
446
|
| 'quantize'
|
|
318
447
|
| 'threshold';
|
|
319
448
|
|
|
449
|
+
/**
|
|
450
|
+
* Sort a categorical domain by the aggregated values of another field
|
|
451
|
+
* (Vega-Lite EncodingSortField).
|
|
452
|
+
*/
|
|
453
|
+
export interface SortByField {
|
|
454
|
+
/** Data field whose values determine the category order. */
|
|
455
|
+
field: string;
|
|
456
|
+
/** Aggregate applied per category before comparing. Defaults to 'sum'. */
|
|
457
|
+
op?: AggregateOp;
|
|
458
|
+
/** Sort direction. Defaults to 'ascending'. */
|
|
459
|
+
order?: 'ascending' | 'descending';
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
/**
|
|
463
|
+
* A constant value definition for an encoding channel (Vega-Lite aligned).
|
|
464
|
+
* The VL idiom for a fixed visual property, e.g. `color: { value: '#1b7fa3' }`.
|
|
465
|
+
* Expanded to the matching mark-level property (fill/stroke, size, opacity)
|
|
466
|
+
* during the pre-validation sugar expansion.
|
|
467
|
+
*/
|
|
468
|
+
export interface ValueDef {
|
|
469
|
+
/** The constant value: CSS color string, size number, opacity (0-1), or gradient. */
|
|
470
|
+
value: string | number | boolean | null | GradientDef;
|
|
471
|
+
}
|
|
472
|
+
|
|
320
473
|
/**
|
|
321
474
|
* A single encoding channel mapping a data field to a visual property.
|
|
322
475
|
*
|
|
@@ -348,8 +501,11 @@ export interface EncodingChannel<TData extends DataRow = DataRow> {
|
|
|
348
501
|
type: FieldType;
|
|
349
502
|
/** Optional aggregate to apply before encoding. */
|
|
350
503
|
aggregate?: AggregateOp;
|
|
351
|
-
/**
|
|
352
|
-
|
|
504
|
+
/**
|
|
505
|
+
* Axis configuration. Set to `false` to suppress axis entirely (no space
|
|
506
|
+
* reserved). `null` is accepted as a VL-aligned alias for `false`.
|
|
507
|
+
*/
|
|
508
|
+
axis?: AxisConfig | false | null;
|
|
353
509
|
/** Scale configuration. */
|
|
354
510
|
scale?: ScaleConfig;
|
|
355
511
|
/**
|
|
@@ -361,26 +517,28 @@ export interface EncodingChannel<TData extends DataRow = DataRow> {
|
|
|
361
517
|
* The string forms are still the canonical input — the boolean shorthand is
|
|
362
518
|
* normalized to the matching string before reaching layout.
|
|
363
519
|
*
|
|
364
|
-
* - undefined: chart-type default (see below)
|
|
520
|
+
* - undefined: chart-type default (see below) -- stacked for bar/column/area
|
|
365
521
|
* - true | 'zero': stack from zero baseline
|
|
366
522
|
* - 'normalize': stack and normalize to fraction of total (0-1 per category)
|
|
367
523
|
* - 'center': center stacks around zero (streamgraph style)
|
|
368
|
-
* - null | false: no stacking -- renders
|
|
524
|
+
* - null | false: no stacking -- renders grouped/dodged (bar) or overlap (area)
|
|
369
525
|
*
|
|
370
526
|
* **Defaults differ by chart type:**
|
|
371
|
-
* - **Bar/Column**: defaults to
|
|
372
|
-
*
|
|
373
|
-
*
|
|
374
|
-
*
|
|
527
|
+
* - **Bar/Column**: defaults to stacked (`'zero'`), Vega-Lite aligned. Use
|
|
528
|
+
* `stack: null` (or `false`) for grouped/side-by-side bars.
|
|
529
|
+
* - **Area**: defaults to stacked (`'zero'`), Vega-Lite aligned. Use
|
|
530
|
+
* `stack: null` (or `false`) to opt into overlap rendering, where each
|
|
531
|
+
* series renders as a translucent gradient band anchored at the
|
|
532
|
+
* y-domain baseline.
|
|
375
533
|
* - **Line**: stacking is not applied (lines always overlap).
|
|
376
534
|
*
|
|
377
535
|
* @example
|
|
378
|
-
* //
|
|
379
|
-
* "x": { "field": "revenue", "type": "quantitative", "stack":
|
|
536
|
+
* // Grouped horizontal bars (opt-out; default is stacked):
|
|
537
|
+
* "x": { "field": "revenue", "type": "quantitative", "stack": null }
|
|
380
538
|
*
|
|
381
539
|
* @example
|
|
382
|
-
* //
|
|
383
|
-
* "y": { "field": "value", "type": "quantitative", "stack":
|
|
540
|
+
* // Overlap area (opt-out; default is stacked):
|
|
541
|
+
* "y": { "field": "value", "type": "quantitative", "stack": null }
|
|
384
542
|
*/
|
|
385
543
|
stack?: boolean | 'zero' | 'normalize' | 'center' | null;
|
|
386
544
|
/**
|
|
@@ -403,8 +561,22 @@ export interface EncodingChannel<TData extends DataRow = DataRow> {
|
|
|
403
561
|
* - 'descending': sort domain values descending
|
|
404
562
|
* - null: use data order (no sorting)
|
|
405
563
|
* - undefined: ascending (VL default)
|
|
564
|
+
* - 'x' | '-x' | 'y' | '-y': sort by another channel's values ('-' prefix
|
|
565
|
+
* for descending). The VL ranked-bar idiom: `sort: '-y'` orders categories
|
|
566
|
+
* by value, largest first. Resolved into an explicit domain during the
|
|
567
|
+
* pre-validation sugar expansion.
|
|
568
|
+
* - string[]: explicit value order. Listed values come first (in the given
|
|
569
|
+
* order); unlisted data values follow in data order.
|
|
570
|
+
* - SortByField: sort by the aggregated values of another field.
|
|
406
571
|
*/
|
|
407
|
-
sort?: 'ascending' | 'descending' | null;
|
|
572
|
+
sort?: 'ascending' | 'descending' | null | 'x' | '-x' | 'y' | '-y' | string[] | SortByField;
|
|
573
|
+
/**
|
|
574
|
+
* Legend configuration for this channel (Vega-Lite aligned).
|
|
575
|
+
* Only meaningful on the `color` channel. `null` hides the legend (the VL
|
|
576
|
+
* idiom for `legend.show = false`); a config object merges into the
|
|
577
|
+
* top-level `legend` (top-level keys win on conflict).
|
|
578
|
+
*/
|
|
579
|
+
legend?: LegendConfig | null;
|
|
408
580
|
/**
|
|
409
581
|
* Display title override (Vega-Lite aligned).
|
|
410
582
|
* Used as the label in tooltips instead of the raw field name.
|
|
@@ -413,7 +585,8 @@ export interface EncodingChannel<TData extends DataRow = DataRow> {
|
|
|
413
585
|
title?: string;
|
|
414
586
|
/**
|
|
415
587
|
* Format string for values (Vega-Lite aligned).
|
|
416
|
-
* For quantitative fields: d3-format string (e.g. ",.0f", "$,.2f")
|
|
588
|
+
* For quantitative fields: d3-format string (e.g. ",.0f", "$,.2f"),
|
|
589
|
+
* or semantic keyword `'percent'` / `'currency'`.
|
|
417
590
|
* For temporal fields: d3-time-format string (e.g. "%Y", "%b %d").
|
|
418
591
|
* Used in tooltips; `axis.format` takes precedence for axis tick labels.
|
|
419
592
|
*/
|
|
@@ -475,14 +648,16 @@ export interface Encoding<TData extends DataRow = DataRow> {
|
|
|
475
648
|
/**
|
|
476
649
|
* Color channel. Required for arc marks (determines pie/donut slice coloring).
|
|
477
650
|
* Optional for all other marks -- used for series differentiation on multi-series charts,
|
|
478
|
-
* or heatmap intensity. Accepts a conditional definition to apply colors based on data predicates
|
|
651
|
+
* or heatmap intensity. Accepts a conditional definition to apply colors based on data predicates,
|
|
652
|
+
* or a bare `{ value }` constant (VL aligned; expanded to the mark-level fill/stroke).
|
|
479
653
|
*/
|
|
480
|
-
color?: EncodingChannel<TData> | ConditionalValueDef<TData
|
|
654
|
+
color?: EncodingChannel<TData> | ConditionalValueDef<TData> | ValueDef;
|
|
481
655
|
/**
|
|
482
656
|
* Size channel. Used by point/bubble charts to scale dot area by a quantitative field.
|
|
483
|
-
* Accepts a conditional definition to vary size based on data predicates
|
|
657
|
+
* Accepts a conditional definition to vary size based on data predicates,
|
|
658
|
+
* or a bare `{ value }` constant (VL aligned; expanded to `mark.size`).
|
|
484
659
|
*/
|
|
485
|
-
size?: EncodingChannel<TData> | ConditionalValueDef<TData
|
|
660
|
+
size?: EncodingChannel<TData> | ConditionalValueDef<TData> | ValueDef;
|
|
486
661
|
/**
|
|
487
662
|
* Detail channel. Groups data into multiple series without mapping to a visual property.
|
|
488
663
|
* Useful when you want separate lines per category but don't need the color to differ.
|
|
@@ -506,17 +681,14 @@ export interface Encoding<TData extends DataRow = DataRow> {
|
|
|
506
681
|
y2?: EncodingChannel<TData>;
|
|
507
682
|
/**
|
|
508
683
|
* Data-driven opacity (0-1 range). Accepts a conditional definition to vary opacity
|
|
509
|
-
* based on data predicates (e.g., highlight selected points)
|
|
510
|
-
|
|
511
|
-
opacity?: EncodingChannel<TData> | ConditionalValueDef<TData>;
|
|
512
|
-
/**
|
|
513
|
-
* Point shape encoding. Valid values: 'circle', 'square', 'diamond', 'triangle-up',
|
|
514
|
-
* 'triangle-down', 'cross'. Used on point/scatter marks to differentiate series by shape.
|
|
684
|
+
* based on data predicates (e.g., highlight selected points), or a bare `{ value }`
|
|
685
|
+
* constant (VL aligned; expanded to `mark.opacity`).
|
|
515
686
|
*/
|
|
516
|
-
|
|
687
|
+
opacity?: EncodingChannel<TData> | ConditionalValueDef<TData> | ValueDef;
|
|
517
688
|
/**
|
|
518
|
-
* Stroke dash pattern encoding. Maps a nominal field to different
|
|
519
|
-
* on line marks. Useful when color alone doesn't
|
|
689
|
+
* Stroke dash pattern encoding. Maps a nominal/ordinal field to different
|
|
690
|
+
* dash patterns on line and rule marks. Useful when color alone doesn't
|
|
691
|
+
* distinguish series well.
|
|
520
692
|
*/
|
|
521
693
|
strokeDash?: EncodingChannel<TData>;
|
|
522
694
|
/** Rotation angle encoding for point marks. Maps a quantitative field to 0-360 degrees. */
|
|
@@ -531,25 +703,15 @@ export interface Encoding<TData extends DataRow = DataRow> {
|
|
|
531
703
|
* multi-field tooltips. Independent of the x/y/color encoding.
|
|
532
704
|
*/
|
|
533
705
|
tooltip?: EncodingChannel<TData> | EncodingChannel<TData>[];
|
|
534
|
-
/** Hyperlink encoding. Maps a field containing URLs to clickable marks. */
|
|
535
|
-
href?: EncodingChannel<TData>;
|
|
536
706
|
/**
|
|
537
|
-
*
|
|
538
|
-
*
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
*
|
|
543
|
-
* Optional -- defaults to the `y` channel value when omitted.
|
|
544
|
-
* Not used by any other mark type.
|
|
707
|
+
* Angular position (slice value) for arc marks (pie/donut), the canonical
|
|
708
|
+
* value channel in v8. Waffle and parliament marks accept it too (the same
|
|
709
|
+
* part-to-whole value channel). `y` is still accepted on these marks as a
|
|
710
|
+
* deprecated alias for backward compatibility (a compile warning is emitted
|
|
711
|
+
* and `y` is populated from `theta` internally). Not used by any other mark
|
|
712
|
+
* type.
|
|
545
713
|
*/
|
|
546
714
|
theta?: EncodingChannel<TData>;
|
|
547
|
-
/**
|
|
548
|
-
* Radial distance from center for arc marks.
|
|
549
|
-
* Optional -- only meaningful on donut charts (controls inner radius boundary).
|
|
550
|
-
* Not used by any other mark type.
|
|
551
|
-
*/
|
|
552
|
-
radius?: EncodingChannel<TData>;
|
|
553
715
|
/**
|
|
554
716
|
* Facet channel: partitions data into a grid of small-multiple panels.
|
|
555
717
|
* Each unique value of the facet field produces one panel. Panels share
|
|
@@ -682,15 +844,26 @@ export interface AnnotationOffset {
|
|
|
682
844
|
/** Anchor direction for annotation label placement relative to the data point. */
|
|
683
845
|
export type AnnotationAnchor = 'top' | 'bottom' | 'left' | 'right' | 'auto';
|
|
684
846
|
|
|
685
|
-
/**
|
|
847
|
+
/** Connector type for annotation labels. */
|
|
848
|
+
export type ConnectorType = 'straight' | 'curve' | 'drop-line';
|
|
849
|
+
|
|
850
|
+
/** Object form of the connector config, allowing arrow control. */
|
|
851
|
+
export interface ConnectorConfig {
|
|
852
|
+
/** Connector style. */
|
|
853
|
+
type: ConnectorType;
|
|
854
|
+
/** Whether to draw an arrowhead at the data-point end. Default: true for curve, false for straight. Drop-line never takes a head. */
|
|
855
|
+
arrow?: boolean;
|
|
856
|
+
}
|
|
857
|
+
|
|
858
|
+
/** Style overrides for the dot marker drawn at the data point. */
|
|
686
859
|
export interface AnnotationDot {
|
|
687
|
-
/** Circle radius in pixels. Default
|
|
860
|
+
/** Circle radius in pixels. Default 4. */
|
|
688
861
|
radius?: number;
|
|
689
862
|
/** Fill color. Defaults to theme background for an "open ring" look. */
|
|
690
863
|
fill?: string;
|
|
691
|
-
/** Stroke color. Defaults to
|
|
864
|
+
/** Stroke color. Defaults to the connector's resolved stroke, so marker and leader read as one system. */
|
|
692
865
|
stroke?: string;
|
|
693
|
-
/** Stroke width in pixels. Default
|
|
866
|
+
/** Stroke width in pixels. Default 1.5. */
|
|
694
867
|
strokeWidth?: number;
|
|
695
868
|
}
|
|
696
869
|
|
|
@@ -722,7 +895,13 @@ export interface TextAnnotation extends AnnotationBase {
|
|
|
722
895
|
x: string | number;
|
|
723
896
|
/** Y-axis data value or position. */
|
|
724
897
|
y: string | number;
|
|
725
|
-
/**
|
|
898
|
+
/**
|
|
899
|
+
* The annotation text. Required for text annotations.
|
|
900
|
+
*
|
|
901
|
+
* Supports inline `**bold**` spans, so emphasis lands on the key phrase rather
|
|
902
|
+
* than the whole block: `'Inflation peaked at **8.5%**'`. Unmatched `**` (and
|
|
903
|
+
* empty `****`) render literally. `\n` starts a new line.
|
|
904
|
+
*/
|
|
726
905
|
text: string;
|
|
727
906
|
/** Thinning priority (lower = kept longer at narrow widths). When omitted, spec order is used. */
|
|
728
907
|
priority?: number;
|
|
@@ -730,12 +909,23 @@ export interface TextAnnotation extends AnnotationBase {
|
|
|
730
909
|
* Optional muted second-tone text rendered below the primary `text`.
|
|
731
910
|
* Used for supporting context (e.g. methodology, source). Newlines in
|
|
732
911
|
* `text` still produce multi-line primary; subtitle is a separate block.
|
|
912
|
+
*
|
|
913
|
+
* Supports the same inline `**bold**` spans as `text`. When a subtitle is
|
|
914
|
+
* present and no `fontWeight` is set, the primary `text` resolves to weight
|
|
915
|
+
* 700 — the lede + context stack.
|
|
733
916
|
*/
|
|
734
917
|
subtitle?: string;
|
|
735
918
|
/**
|
|
736
|
-
*
|
|
737
|
-
*
|
|
738
|
-
*
|
|
919
|
+
* Open-ring marker drawn on the data point itself (not on the pulled-back
|
|
920
|
+
* connector tip).
|
|
921
|
+
*
|
|
922
|
+
* Left unset, a default marker appears whenever a connector is enabled and
|
|
923
|
+
* carries no arrowhead — the leader points, the ring lands. An arrowed
|
|
924
|
+
* connector gets no marker unless you ask for one: the head already marks the
|
|
925
|
+
* spot. `dot: false` is always bare; an explicit `dot` always wins.
|
|
926
|
+
*
|
|
927
|
+
* `true` uses the default style; pass an object to override radius, fill,
|
|
928
|
+
* stroke, or strokeWidth.
|
|
739
929
|
*/
|
|
740
930
|
dot?: boolean | AnnotationDot;
|
|
741
931
|
/** Font size override. */
|
|
@@ -748,13 +938,19 @@ export interface TextAnnotation extends AnnotationBase {
|
|
|
748
938
|
anchor?: AnnotationAnchor;
|
|
749
939
|
/**
|
|
750
940
|
* Connector from label to anchor point.
|
|
751
|
-
* - `true` (default): straight line
|
|
752
|
-
* - `'straight'`: straight line
|
|
941
|
+
* - `true` (default): straight line, no arrow
|
|
942
|
+
* - `'straight'`: straight line, no arrow
|
|
753
943
|
* - `'curve'`: curved arrow with arrowhead
|
|
754
|
-
* - `'drop-line'`: vertical line through the data point's x
|
|
944
|
+
* - `'drop-line'`: vertical line through the data point's x
|
|
945
|
+
* - `{ type, arrow? }`: object form for explicit arrow control
|
|
755
946
|
* - `false`: no connector
|
|
947
|
+
*
|
|
948
|
+
* The connector leaves the text block on the side facing the data point, with
|
|
949
|
+
* a small standoff gap. A leader shorter than 8px is dropped as noise (the
|
|
950
|
+
* marker alone reads better), as is a connector whose target sits inside the
|
|
951
|
+
* text block. Widen `offset` if you want the line back.
|
|
756
952
|
*/
|
|
757
|
-
connector?: boolean |
|
|
953
|
+
connector?: boolean | ConnectorType | ConnectorConfig;
|
|
758
954
|
/** Per-endpoint offsets for the connector line. Allows fine-tuning where the connector starts and ends. */
|
|
759
955
|
connectorOffset?: {
|
|
760
956
|
/** Offset for the label-end of the connector. */
|
|
@@ -762,8 +958,14 @@ export interface TextAnnotation extends AnnotationBase {
|
|
|
762
958
|
/** Offset for the data-point-end of the connector. */
|
|
763
959
|
to?: AnnotationOffset;
|
|
764
960
|
};
|
|
765
|
-
/**
|
|
766
|
-
|
|
961
|
+
/**
|
|
962
|
+
* Background plate behind the text, for readability over chart lines.
|
|
963
|
+
*
|
|
964
|
+
* `true` uses the theme surface, so the plate follows light/dark mode. A
|
|
965
|
+
* color string sets it explicitly. Prefer `true`: a hardcoded '#ffffff' stays
|
|
966
|
+
* white in dark mode and the text turns light-gray-on-white.
|
|
967
|
+
*/
|
|
968
|
+
background?: string | true;
|
|
767
969
|
/** Whether to show the paint-order stroke halo behind text. Default true. Set false for white text on colored backgrounds. */
|
|
768
970
|
halo?: boolean;
|
|
769
971
|
}
|
|
@@ -807,7 +1009,14 @@ export interface RangeAnnotation extends AnnotationBase {
|
|
|
807
1009
|
* Useful for baselines (zero), targets, or thresholds.
|
|
808
1010
|
*/
|
|
809
1011
|
export interface RefLineAnnotation extends AnnotationBase {
|
|
810
|
-
|
|
1012
|
+
/**
|
|
1013
|
+
* Discriminant. `'refline'` is canonical and the only value in the type.
|
|
1014
|
+
* `'rule'` (it collides with the `rule` mark type) is still accepted at
|
|
1015
|
+
* runtime for backward compatibility -- the spec-sugar pass rewrites it to
|
|
1016
|
+
* `'refline'` with a deprecation warning before validation -- but it is not
|
|
1017
|
+
* part of this type. Use `'refline'`.
|
|
1018
|
+
*/
|
|
1019
|
+
type: 'refline';
|
|
811
1020
|
/** X-axis value for a vertical reference line. */
|
|
812
1021
|
x?: string | number;
|
|
813
1022
|
/** Y-axis value for a horizontal reference line. */
|
|
@@ -1007,7 +1216,11 @@ export interface LabelConfig {
|
|
|
1007
1216
|
suffix?: string;
|
|
1008
1217
|
/** Fixed CSS color for all labels. Overrides the default fill-derived color. */
|
|
1009
1218
|
color?: string;
|
|
1010
|
-
/**
|
|
1219
|
+
/**
|
|
1220
|
+
* Per-series pixel offsets for fine-tuning label positions, keyed by series name.
|
|
1221
|
+
* @deprecated Per-series pixel offsets are a workaround for collision bugs
|
|
1222
|
+
* now fixed by the layout engine. Will be removed in a future version.
|
|
1223
|
+
*/
|
|
1011
1224
|
offsets?: Record<string, AnnotationOffset>;
|
|
1012
1225
|
/** Font size in pixels for bar/column value labels. */
|
|
1013
1226
|
fontSize?: number;
|
|
@@ -1038,6 +1251,46 @@ export interface LegendConfig {
|
|
|
1038
1251
|
exclude?: string[];
|
|
1039
1252
|
}
|
|
1040
1253
|
|
|
1254
|
+
/**
|
|
1255
|
+
* Configuration for the searchable series highlight input (`seriesSearch`).
|
|
1256
|
+
* The boolean form (`seriesSearch: true`) uses the defaults.
|
|
1257
|
+
*/
|
|
1258
|
+
export interface SeriesSearchConfig {
|
|
1259
|
+
/** Placeholder text for the search input. Defaults to "Find a series". */
|
|
1260
|
+
placeholder?: string;
|
|
1261
|
+
}
|
|
1262
|
+
|
|
1263
|
+
/**
|
|
1264
|
+
* Configuration for the "you draw it" interactive engagement format
|
|
1265
|
+
* (`youDrawIt`). The reader draws their guess of the trend from `from` to the
|
|
1266
|
+
* right edge before the real line reveals. Line marks only, single-series only.
|
|
1267
|
+
*/
|
|
1268
|
+
export interface YouDrawItConfig {
|
|
1269
|
+
/**
|
|
1270
|
+
* The x value (matching `encoding.x`'s domain) where drawing starts. Data
|
|
1271
|
+
* before this point renders normally; data at or after it is hidden behind
|
|
1272
|
+
* a hatched "draw here" region until reveal.
|
|
1273
|
+
*/
|
|
1274
|
+
from: string | number;
|
|
1275
|
+
/** Prompt text shown in the hatched drawing region. Defaults to "Draw your guess". */
|
|
1276
|
+
prompt?: string;
|
|
1277
|
+
/** Label for the skip-to-reveal button. Defaults to "Show me". */
|
|
1278
|
+
revealLabel?: string;
|
|
1279
|
+
/**
|
|
1280
|
+
* Optional extra comparison line (e.g. "what everyone else guessed"),
|
|
1281
|
+
* supplied by the host app. Rendered in a third, visually distinct style
|
|
1282
|
+
* alongside the reader's guess and the real line after reveal.
|
|
1283
|
+
*/
|
|
1284
|
+
comparisonLine?: Array<{ x: string | number; y: number }>;
|
|
1285
|
+
}
|
|
1286
|
+
|
|
1287
|
+
/**
|
|
1288
|
+
* Content composition for an endpoint-label entry: the series name, the
|
|
1289
|
+
* formatted value, or both joined on one line. See
|
|
1290
|
+
* {@link EndpointLabelsConfig.content}.
|
|
1291
|
+
*/
|
|
1292
|
+
export type EndpointLabelContent = 'label' | 'value' | 'label value';
|
|
1293
|
+
|
|
1041
1294
|
/**
|
|
1042
1295
|
* Configuration for the endpoint labels column rendered at the chart's right edge
|
|
1043
1296
|
* for multi-series line/area charts. Each entry pairs the series name with its
|
|
@@ -1075,6 +1328,20 @@ export interface EndpointLabelsConfig {
|
|
|
1075
1328
|
* - `'both'`: labels on both left (leading) and right (trailing) edges.
|
|
1076
1329
|
*/
|
|
1077
1330
|
ends?: 'end' | 'both';
|
|
1331
|
+
/**
|
|
1332
|
+
* What each entry renders.
|
|
1333
|
+
* - `'label'`: series name only.
|
|
1334
|
+
* - `'value'`: formatted value only.
|
|
1335
|
+
* - `'label value'`: series name and value joined on one line.
|
|
1336
|
+
*
|
|
1337
|
+
* When omitted, entries render the series name with the formatted value on
|
|
1338
|
+
* a second line (the classic endpoint column). Pass an object to set the
|
|
1339
|
+
* leading and trailing columns independently, e.g. the classic slope-chart
|
|
1340
|
+
* look is `{ leading: 'label value', trailing: 'value' }`.
|
|
1341
|
+
*/
|
|
1342
|
+
content?:
|
|
1343
|
+
| EndpointLabelContent
|
|
1344
|
+
| { leading?: EndpointLabelContent; trailing?: EndpointLabelContent };
|
|
1078
1345
|
/** Field to read the displayed value from. Defaults to `encoding.y.field`. */
|
|
1079
1346
|
valueField?: string;
|
|
1080
1347
|
/** d3-format string for the value. Defaults to `encoding.y.axis.format`. */
|
|
@@ -1250,14 +1517,14 @@ export interface Metric {
|
|
|
1250
1517
|
|
|
1251
1518
|
/**
|
|
1252
1519
|
* Encoding for arc marks (pie/donut charts).
|
|
1253
|
-
* - `
|
|
1520
|
+
* - `theta`: required (quantitative — the canonical slice value channel)
|
|
1254
1521
|
* - `color`: required (nominal/ordinal — the category)
|
|
1255
|
-
* - `
|
|
1256
|
-
* - `radius`: optional (donut inner radius)
|
|
1522
|
+
* - `y`: deprecated alias for `theta`, accepted for backward compatibility
|
|
1257
1523
|
*/
|
|
1258
1524
|
export interface ArcEncoding<TData extends DataRow = DataRow> extends Encoding<TData> {
|
|
1259
|
-
|
|
1260
|
-
|
|
1525
|
+
/** Canonical value channel for arc marks (quantitative — the slice value). */
|
|
1526
|
+
theta: EncodingChannel<TData>;
|
|
1527
|
+
color: EncodingChannel<TData> | ConditionalValueDef<TData>;
|
|
1261
1528
|
}
|
|
1262
1529
|
|
|
1263
1530
|
/**
|
|
@@ -1320,6 +1587,67 @@ export interface LollipopEncoding<TData extends DataRow = DataRow> extends Encod
|
|
|
1320
1587
|
y: EncodingChannel<TData>;
|
|
1321
1588
|
}
|
|
1322
1589
|
|
|
1590
|
+
/**
|
|
1591
|
+
* Encoding for beeswarm marks (dodged distribution dots).
|
|
1592
|
+
* - Exactly one positional channel is quantitative: the value axis
|
|
1593
|
+
* (x = horizontal swarm, y = vertical swarm).
|
|
1594
|
+
* - The other positional channel is optional (nominal/ordinal): grouped
|
|
1595
|
+
* swarms, one lane per category. The cross axis has no scale; the dodge
|
|
1596
|
+
* layout computes pixel offsets around each lane center.
|
|
1597
|
+
*/
|
|
1598
|
+
export interface BeeswarmEncoding<TData extends DataRow = DataRow> extends Encoding<TData> {
|
|
1599
|
+
x?: EncodingChannel<TData>;
|
|
1600
|
+
y?: EncodingChannel<TData>;
|
|
1601
|
+
}
|
|
1602
|
+
|
|
1603
|
+
/**
|
|
1604
|
+
* Encoding for range marks (dumbbell / arrow / range-bar plots).
|
|
1605
|
+
* - Horizontal (the common editorial form): `y` nominal/ordinal category,
|
|
1606
|
+
* `x` quantitative start, `x2` quantitative end.
|
|
1607
|
+
* - Vertical: `x` nominal/ordinal category, `y` quantitative start,
|
|
1608
|
+
* `y2` quantitative end.
|
|
1609
|
+
*/
|
|
1610
|
+
export interface RangeEncoding<TData extends DataRow = DataRow> extends Encoding<TData> {
|
|
1611
|
+
x: EncodingChannel<TData>;
|
|
1612
|
+
y: EncodingChannel<TData>;
|
|
1613
|
+
}
|
|
1614
|
+
|
|
1615
|
+
/**
|
|
1616
|
+
* Encoding for waffle marks (unit grids for part-to-whole counts).
|
|
1617
|
+
* - `color`: required (nominal/ordinal, the category)
|
|
1618
|
+
* - `theta`: the canonical quantitative share, the same part-to-whole value
|
|
1619
|
+
* channel arc marks use. `y` is a deprecated alias, accepted for backward
|
|
1620
|
+
* compatibility.
|
|
1621
|
+
*/
|
|
1622
|
+
export interface WaffleEncoding<TData extends DataRow = DataRow> extends Encoding<TData> {
|
|
1623
|
+
color: EncodingChannel<TData> | ConditionalValueDef<TData>;
|
|
1624
|
+
}
|
|
1625
|
+
|
|
1626
|
+
/**
|
|
1627
|
+
* Encoding for parliament marks (hemicycle seat-dot charts).
|
|
1628
|
+
* - `color`: required (nominal/ordinal, the party)
|
|
1629
|
+
* - `theta`: the canonical quantitative seat count, the same part-to-whole
|
|
1630
|
+
* value channel arc/waffle marks use. `y` is a deprecated alias, accepted
|
|
1631
|
+
* for backward compatibility.
|
|
1632
|
+
*/
|
|
1633
|
+
export interface ParliamentEncoding<TData extends DataRow = DataRow> extends Encoding<TData> {
|
|
1634
|
+
color: EncodingChannel<TData> | ConditionalValueDef<TData>;
|
|
1635
|
+
}
|
|
1636
|
+
|
|
1637
|
+
/**
|
|
1638
|
+
* Encoding for calendar marks (GitHub-style calendar heatmaps).
|
|
1639
|
+
* - `x`: required (temporal, daily dates, one row per day)
|
|
1640
|
+
* - `color`: required (quantitative, the per-day value)
|
|
1641
|
+
*
|
|
1642
|
+
* The calendar computes its own weeks-x-weekdays geometry: no positional
|
|
1643
|
+
* scales or axes. Multi-year data partitions into one stacked band per year,
|
|
1644
|
+
* all bands sharing a single color scale and legend.
|
|
1645
|
+
*/
|
|
1646
|
+
export interface CalendarEncoding<TData extends DataRow = DataRow> extends Encoding<TData> {
|
|
1647
|
+
x: EncodingChannel<TData>;
|
|
1648
|
+
color: EncodingChannel<TData>;
|
|
1649
|
+
}
|
|
1650
|
+
|
|
1323
1651
|
/**
|
|
1324
1652
|
* Encoding for text marks (data-positioned labels).
|
|
1325
1653
|
* - `text`: required (the field to render as text)
|
|
@@ -1349,6 +1677,33 @@ export interface RectEncoding<TData extends DataRow = DataRow> extends Encoding<
|
|
|
1349
1677
|
y: EncodingChannel<TData>;
|
|
1350
1678
|
}
|
|
1351
1679
|
|
|
1680
|
+
// ---------------------------------------------------------------------------
|
|
1681
|
+
// Accessibility configuration
|
|
1682
|
+
// ---------------------------------------------------------------------------
|
|
1683
|
+
|
|
1684
|
+
/**
|
|
1685
|
+
* Author-facing accessibility overrides.
|
|
1686
|
+
*
|
|
1687
|
+
* Everything here is optional; when omitted, openchart auto-generates alt
|
|
1688
|
+
* text, ARIA labels, and a screen-reader data table from the spec and data.
|
|
1689
|
+
*/
|
|
1690
|
+
export interface A11yConfig {
|
|
1691
|
+
/**
|
|
1692
|
+
* Alt text announced by screen readers for the chart as a whole. Replaces
|
|
1693
|
+
* the auto-generated description. Also settable via the top-level
|
|
1694
|
+
* `description` field (Vega-Lite convention); this field wins when both
|
|
1695
|
+
* are present.
|
|
1696
|
+
*/
|
|
1697
|
+
description?: string;
|
|
1698
|
+
/**
|
|
1699
|
+
* Hide the chart from assistive technology entirely (`aria-hidden`).
|
|
1700
|
+
* Use only when the chart is decorative or the surrounding content
|
|
1701
|
+
* already conveys the same information. Also suppresses the hidden
|
|
1702
|
+
* screen-reader data table and keyboard mark navigation.
|
|
1703
|
+
*/
|
|
1704
|
+
hidden?: boolean;
|
|
1705
|
+
}
|
|
1706
|
+
|
|
1352
1707
|
// ---------------------------------------------------------------------------
|
|
1353
1708
|
// Shared (non-mark-specific) ChartSpec properties
|
|
1354
1709
|
// ---------------------------------------------------------------------------
|
|
@@ -1360,12 +1715,44 @@ export interface RectEncoding<TData extends DataRow = DataRow> extends Encoding<
|
|
|
1360
1715
|
* @internal
|
|
1361
1716
|
*/
|
|
1362
1717
|
interface BaseChartSpec<TData extends DataRow = DataRow> {
|
|
1363
|
-
/**
|
|
1718
|
+
/**
|
|
1719
|
+
* Data array: each element is a row with field values.
|
|
1720
|
+
* The Vega-Lite object form `{ values: [...] }` is also accepted at runtime
|
|
1721
|
+
* and unwrapped during the pre-validation sugar expansion. `{ url }` is not
|
|
1722
|
+
* supported (openchart does not fetch data).
|
|
1723
|
+
*/
|
|
1364
1724
|
data: TData[];
|
|
1365
1725
|
/** Data transforms applied in order before encoding (filter, bin, calculate, timeUnit). */
|
|
1366
1726
|
transform?: Transform[];
|
|
1367
1727
|
/** Editorial chrome (title, subtitle, source, etc.). */
|
|
1368
1728
|
chrome?: Chrome;
|
|
1729
|
+
/**
|
|
1730
|
+
* Top-level title sugar (Vega-Lite aligned). Expanded into `chrome.title`
|
|
1731
|
+
* (and `chrome.subtitle` for the object form). `chrome.title` wins when
|
|
1732
|
+
* both are set.
|
|
1733
|
+
*/
|
|
1734
|
+
title?: string | { text: string; subtitle?: string };
|
|
1735
|
+
/** Top-level subtitle sugar. Expanded into `chrome.subtitle`; `chrome.subtitle` wins. */
|
|
1736
|
+
subtitle?: string;
|
|
1737
|
+
/**
|
|
1738
|
+
* Alt text for the rendered chart (Vega-Lite aligned). Sugar for
|
|
1739
|
+
* `a11y.description`; `a11y.description` wins when both are set.
|
|
1740
|
+
* When absent, alt text is auto-generated from the spec and data.
|
|
1741
|
+
*/
|
|
1742
|
+
description?: string;
|
|
1743
|
+
/** Accessibility overrides. See {@link A11yConfig}. */
|
|
1744
|
+
a11y?: A11yConfig;
|
|
1745
|
+
/**
|
|
1746
|
+
* Fixed render width in pixels (Vega-Lite aligned). Overrides the
|
|
1747
|
+
* container-derived width. When both `width` and `height` are set,
|
|
1748
|
+
* `responsive: false` is implied unless `responsive` is set explicitly.
|
|
1749
|
+
* Omit for the default container-driven sizing.
|
|
1750
|
+
*/
|
|
1751
|
+
width?: number;
|
|
1752
|
+
/** Fixed render height in pixels (Vega-Lite aligned). See `width`. */
|
|
1753
|
+
height?: number;
|
|
1754
|
+
/** Accepted for Vega-Lite compatibility and ignored (with a compile warning). */
|
|
1755
|
+
$schema?: string;
|
|
1369
1756
|
/**
|
|
1370
1757
|
* KPI/metric cells rendered as a horizontal row between subtitle and chart
|
|
1371
1758
|
* area. Each cell shows a label/value pair with optional delta and secondary
|
|
@@ -1426,6 +1813,22 @@ interface BaseChartSpec<TData extends DataRow = DataRow> {
|
|
|
1426
1813
|
* explicitly set.
|
|
1427
1814
|
*/
|
|
1428
1815
|
crosshair?: boolean;
|
|
1816
|
+
/**
|
|
1817
|
+
* Searchable series highlight ("find your country"). Renders a compact
|
|
1818
|
+
* search input above the chart with typeahead over the color channel's
|
|
1819
|
+
* distinct values. Selecting a value adds it to the highlight set
|
|
1820
|
+
* (multi-select chips, removable); clearing restores the authored
|
|
1821
|
+
* `encoding.color.highlight` baseline. Requires a categorical color
|
|
1822
|
+
* encoding. Mutually exclusive with edit mode (search wins).
|
|
1823
|
+
*/
|
|
1824
|
+
seriesSearch?: boolean | SeriesSearchConfig;
|
|
1825
|
+
/**
|
|
1826
|
+
* "You draw it" interactive engagement format: the reader draws their
|
|
1827
|
+
* guess of the trend before the real line reveals. Line marks only,
|
|
1828
|
+
* single-series only. Mutually exclusive with edit mode (validation
|
|
1829
|
+
* warning if both are enabled; youDrawIt is disabled).
|
|
1830
|
+
*/
|
|
1831
|
+
youDrawIt?: YouDrawItConfig;
|
|
1429
1832
|
/**
|
|
1430
1833
|
* Display mode controlling how much chart chrome is rendered.
|
|
1431
1834
|
*
|
|
@@ -1521,6 +1924,18 @@ export type ChartSpec<TData extends DataRow = DataRow> =
|
|
|
1521
1924
|
mark: 'lollipop' | (MarkDef & { type: 'lollipop' });
|
|
1522
1925
|
encoding: LollipopEncoding<TData>;
|
|
1523
1926
|
})
|
|
1927
|
+
| (BaseChartSpec<TData> & {
|
|
1928
|
+
mark: 'beeswarm' | (MarkDef & { type: 'beeswarm' });
|
|
1929
|
+
encoding: BeeswarmEncoding<TData>;
|
|
1930
|
+
})
|
|
1931
|
+
| (BaseChartSpec<TData> & {
|
|
1932
|
+
mark: 'range' | (MarkDef & { type: 'range' });
|
|
1933
|
+
encoding: RangeEncoding<TData>;
|
|
1934
|
+
})
|
|
1935
|
+
| (BaseChartSpec<TData> & {
|
|
1936
|
+
mark: 'waffle' | (MarkDef & { type: 'waffle' });
|
|
1937
|
+
encoding: WaffleEncoding<TData>;
|
|
1938
|
+
})
|
|
1524
1939
|
| (BaseChartSpec<TData> & {
|
|
1525
1940
|
mark: 'text' | (MarkDef & { type: 'text' });
|
|
1526
1941
|
encoding: TextEncoding<TData>;
|
|
@@ -1536,6 +1951,14 @@ export type ChartSpec<TData extends DataRow = DataRow> =
|
|
|
1536
1951
|
| (BaseChartSpec<TData> & {
|
|
1537
1952
|
mark: 'rule' | (MarkDef & { type: 'rule' });
|
|
1538
1953
|
encoding: Encoding<TData>;
|
|
1954
|
+
})
|
|
1955
|
+
| (BaseChartSpec<TData> & {
|
|
1956
|
+
mark: 'calendar' | (MarkDef & { type: 'calendar' });
|
|
1957
|
+
encoding: CalendarEncoding<TData>;
|
|
1958
|
+
})
|
|
1959
|
+
| (BaseChartSpec<TData> & {
|
|
1960
|
+
mark: 'parliament' | (MarkDef & { type: 'parliament' });
|
|
1961
|
+
encoding: ParliamentEncoding<TData>;
|
|
1539
1962
|
});
|
|
1540
1963
|
|
|
1541
1964
|
/**
|
|
@@ -1676,6 +2099,16 @@ export interface LayerSpec<TData extends DataRow = DataRow> {
|
|
|
1676
2099
|
transform?: Transform[];
|
|
1677
2100
|
/** Editorial chrome (title, subtitle, source, etc.). */
|
|
1678
2101
|
chrome?: Chrome;
|
|
2102
|
+
/** Top-level title sugar (VL aligned). Expanded into `chrome.title`; `chrome.title` wins. */
|
|
2103
|
+
title?: string | { text: string; subtitle?: string };
|
|
2104
|
+
/** Top-level subtitle sugar. Expanded into `chrome.subtitle`; `chrome.subtitle` wins. */
|
|
2105
|
+
subtitle?: string;
|
|
2106
|
+
/** Fixed render width in pixels (VL aligned). Overrides the container-derived width. */
|
|
2107
|
+
width?: number;
|
|
2108
|
+
/** Fixed render height in pixels (VL aligned). Overrides the container-derived height. */
|
|
2109
|
+
height?: number;
|
|
2110
|
+
/** Accepted for Vega-Lite compatibility and ignored (with a compile warning). */
|
|
2111
|
+
$schema?: string;
|
|
1679
2112
|
/** Annotations on the layered view. */
|
|
1680
2113
|
annotations?: Annotation[];
|
|
1681
2114
|
/** Label display configuration. `false` disables all labels, `true` uses defaults. */
|
|
@@ -1774,6 +2207,8 @@ export interface SankeySpec {
|
|
|
1774
2207
|
* number (data value 28 renders as "28%"). For currency: "$,.0f" or "$~s".
|
|
1775
2208
|
* For SI suffixes: "~s" (renders 1000 as "1k"). When not set, values use
|
|
1776
2209
|
* the default number formatter.
|
|
2210
|
+
* @deprecated Use the encoding channel's `format` field instead. This
|
|
2211
|
+
* property is expanded into the encoding during compilation.
|
|
1777
2212
|
*/
|
|
1778
2213
|
valueFormat?: string;
|
|
1779
2214
|
}
|
|
@@ -1840,6 +2275,72 @@ export interface TileMapSpec {
|
|
|
1840
2275
|
/**
|
|
1841
2276
|
* d3-format string applied to tile values, legend labels, and tooltips.
|
|
1842
2277
|
* Examples: ".1f" for one decimal, "$,.0f" for currency, "~s" for SI.
|
|
2278
|
+
* @deprecated Use the encoding channel's `format` field instead. This
|
|
2279
|
+
* property is expanded into the encoding during compilation.
|
|
2280
|
+
*/
|
|
2281
|
+
valueFormat?: string;
|
|
2282
|
+
}
|
|
2283
|
+
|
|
2284
|
+
// ---------------------------------------------------------------------------
|
|
2285
|
+
// Map spec (choropleth / symbol maps)
|
|
2286
|
+
// ---------------------------------------------------------------------------
|
|
2287
|
+
|
|
2288
|
+
/** Supported map projections. */
|
|
2289
|
+
export type MapProjection = 'albersUsa' | 'mercator' | 'equalEarth' | 'identity';
|
|
2290
|
+
|
|
2291
|
+
/** Focus target for map camera: feature id(s) to zoom/pan to. */
|
|
2292
|
+
export type MapFocus =
|
|
2293
|
+
| string
|
|
2294
|
+
| number
|
|
2295
|
+
| Array<string | number>
|
|
2296
|
+
| { features: string | number | Array<string | number>; padding?: number };
|
|
2297
|
+
|
|
2298
|
+
/** Geo configuration for map specs. */
|
|
2299
|
+
export interface MapGeo {
|
|
2300
|
+
/** TopoJSON topology object. User imports this from us-atlas, world-atlas, or their own source. */
|
|
2301
|
+
features: unknown;
|
|
2302
|
+
/** Field in the TopoJSON feature properties to use as the join key. Defaults to 'id'. */
|
|
2303
|
+
idField?: string;
|
|
2304
|
+
/** Map projection. Defaults to 'albersUsa'. */
|
|
2305
|
+
projection?: MapProjection;
|
|
2306
|
+
/** Focus on specific feature(s). null clears focus from a prior story step. */
|
|
2307
|
+
focus?: MapFocus | null;
|
|
2308
|
+
}
|
|
2309
|
+
|
|
2310
|
+
/** Encoding channels specific to map visualizations. */
|
|
2311
|
+
export interface MapEncoding {
|
|
2312
|
+
/** Join key field in the data (required). Maps data rows to geo features via geo.idField. */
|
|
2313
|
+
key: EncodingChannel;
|
|
2314
|
+
/** Color encoding (required, quantitative or nominal). Drives fill color of features. */
|
|
2315
|
+
color: EncodingChannel;
|
|
2316
|
+
/** Tooltip encoding (optional). */
|
|
2317
|
+
tooltip?: EncodingChannel | EncodingChannel[];
|
|
2318
|
+
}
|
|
2319
|
+
|
|
2320
|
+
export interface MapSpec {
|
|
2321
|
+
/** Discriminant: always "map". */
|
|
2322
|
+
type: 'map';
|
|
2323
|
+
/** Geo configuration: TopoJSON features, join key, and projection. */
|
|
2324
|
+
geo: MapGeo;
|
|
2325
|
+
/** Tabular data to join to geo features. */
|
|
2326
|
+
data: DataRow[];
|
|
2327
|
+
/** Encoding channels mapping data fields to visual properties. */
|
|
2328
|
+
encoding: MapEncoding;
|
|
2329
|
+
/** Editorial chrome (title, subtitle, source, byline, footer). */
|
|
2330
|
+
chrome?: Chrome;
|
|
2331
|
+
/** Legend display configuration. */
|
|
2332
|
+
legend?: LegendConfig;
|
|
2333
|
+
/** Theme configuration overrides. */
|
|
2334
|
+
theme?: ThemeConfig;
|
|
2335
|
+
/** Dark mode behavior. Defaults to "off". */
|
|
2336
|
+
darkMode?: DarkMode;
|
|
2337
|
+
/** Whether to show the tryOpenData.ai watermark. Defaults to true. */
|
|
2338
|
+
watermark?: boolean;
|
|
2339
|
+
/** Animation configuration for entrance animations. */
|
|
2340
|
+
animation?: AnimationSpec;
|
|
2341
|
+
/**
|
|
2342
|
+
* d3-format string applied to color values in tooltips and legend.
|
|
2343
|
+
* @deprecated Use the encoding channel's `format` field instead.
|
|
1843
2344
|
*/
|
|
1844
2345
|
valueFormat?: string;
|
|
1845
2346
|
}
|
|
@@ -1877,6 +2378,8 @@ export interface BarListSpec {
|
|
|
1877
2378
|
/**
|
|
1878
2379
|
* d3-format string applied to bar values and tooltips.
|
|
1879
2380
|
* Examples: ".1f" for one decimal, "$,.0f" for currency, "~s" for SI.
|
|
2381
|
+
* @deprecated Use the encoding channel's `format` field instead. This
|
|
2382
|
+
* property is expanded into the encoding during compilation.
|
|
1880
2383
|
*/
|
|
1881
2384
|
valueFormat?: string;
|
|
1882
2385
|
}
|
|
@@ -1904,7 +2407,15 @@ export interface BarListEncoding {
|
|
|
1904
2407
|
* - GraphSpec: has `type: 'graph'`
|
|
1905
2408
|
* - SankeySpec: has `type: 'sankey'`
|
|
1906
2409
|
* - TileMapSpec: has `type: 'tilemap'`
|
|
2410
|
+
* - MapSpec: has `type: 'map'`
|
|
1907
2411
|
* - BarListSpec: has `type: 'barlist'`
|
|
2412
|
+
*
|
|
2413
|
+
* Election parliament (hemicycle) charts are `ChartSpec` with `mark:
|
|
2414
|
+
* 'parliament'`, not a separate top-level type: seat data (party + seats)
|
|
2415
|
+
* maps naturally onto encoding.color/y like arc and waffle, and riding the
|
|
2416
|
+
* existing chart pipeline gets scales, legend, tooltips, a11y, and dark mode
|
|
2417
|
+
* for free instead of a second bespoke compile path (see
|
|
2418
|
+
* `packages/engine/src/charts/parliament/`).
|
|
1908
2419
|
*/
|
|
1909
2420
|
export type VizSpec =
|
|
1910
2421
|
| ChartSpec
|
|
@@ -1913,6 +2424,7 @@ export type VizSpec =
|
|
|
1913
2424
|
| GraphSpec
|
|
1914
2425
|
| SankeySpec
|
|
1915
2426
|
| TileMapSpec
|
|
2427
|
+
| MapSpec
|
|
1916
2428
|
| BarListSpec;
|
|
1917
2429
|
|
|
1918
2430
|
/**
|
|
@@ -1928,6 +2440,8 @@ export type GraphSpecWithoutData = Omit<GraphSpec, 'nodes' | 'edges'>;
|
|
|
1928
2440
|
export type SankeySpecWithoutData = Omit<SankeySpec, 'data'>;
|
|
1929
2441
|
/** TileMap spec without runtime data, for persistence/storage. */
|
|
1930
2442
|
export type TileMapSpecWithoutData = Omit<TileMapSpec, 'data'>;
|
|
2443
|
+
/** Map spec without runtime data, for persistence/storage. */
|
|
2444
|
+
export type MapSpecWithoutData = Omit<MapSpec, 'data'>;
|
|
1931
2445
|
/** BarList spec without runtime data, for persistence/storage. */
|
|
1932
2446
|
export type BarListSpecWithoutData = Omit<BarListSpec, 'data'>;
|
|
1933
2447
|
/** Union of data-stripped spec types for persistence/storage. */
|
|
@@ -1937,6 +2451,7 @@ export type StoredVizSpec =
|
|
|
1937
2451
|
| GraphSpecWithoutData
|
|
1938
2452
|
| SankeySpecWithoutData
|
|
1939
2453
|
| TileMapSpecWithoutData
|
|
2454
|
+
| MapSpecWithoutData
|
|
1940
2455
|
| BarListSpecWithoutData;
|
|
1941
2456
|
|
|
1942
2457
|
// ---------------------------------------------------------------------------
|
|
@@ -2144,9 +2659,10 @@ export interface Condition<TData extends DataRow = DataRow> {
|
|
|
2144
2659
|
test: FilterPredicate;
|
|
2145
2660
|
/**
|
|
2146
2661
|
* Static value to use when the condition is true.
|
|
2147
|
-
* Accepted values: CSS color string, opacity (0-1), size number,
|
|
2662
|
+
* Accepted values: CSS color string, opacity (0-1), size number, boolean flag,
|
|
2663
|
+
* or a gradient definition for color channels.
|
|
2148
2664
|
*/
|
|
2149
|
-
value?: string | number | boolean | null;
|
|
2665
|
+
value?: string | number | boolean | null | GradientDef;
|
|
2150
2666
|
/**
|
|
2151
2667
|
* Data field to use when the condition is true.
|
|
2152
2668
|
* Constrained to column names of `TData` when using `ChartSpec<TData>`.
|
|
@@ -2167,18 +2683,19 @@ export interface ConditionalValueDef<TData extends DataRow = DataRow> {
|
|
|
2167
2683
|
condition: Condition<TData> | Condition<TData>[];
|
|
2168
2684
|
/**
|
|
2169
2685
|
* Default value when no condition matches.
|
|
2170
|
-
* Accepted values: CSS color string, opacity (0-1), size number,
|
|
2686
|
+
* Accepted values: CSS color string, opacity (0-1), size number, boolean flag,
|
|
2687
|
+
* or a gradient definition for color channels.
|
|
2171
2688
|
*/
|
|
2172
|
-
value?: string | number | boolean | null;
|
|
2689
|
+
value?: string | number | boolean | null | GradientDef;
|
|
2173
2690
|
}
|
|
2174
2691
|
|
|
2175
2692
|
/**
|
|
2176
2693
|
* Check if a channel definition is a regular EncodingChannel (has 'field' at top level).
|
|
2177
|
-
* Use this to narrow `EncodingChannel | ConditionalValueDef` in encoding
|
|
2178
|
-
* that support conditional encoding (color, size, opacity).
|
|
2694
|
+
* Use this to narrow `EncodingChannel | ConditionalValueDef | ValueDef` in encoding
|
|
2695
|
+
* channels that support conditional encoding (color, size, opacity).
|
|
2179
2696
|
*/
|
|
2180
2697
|
export function isEncodingChannel<TData extends DataRow = DataRow>(
|
|
2181
|
-
def: EncodingChannel<TData> | ConditionalValueDef<TData> | undefined,
|
|
2698
|
+
def: EncodingChannel<TData> | ConditionalValueDef<TData> | ValueDef | undefined,
|
|
2182
2699
|
): def is EncodingChannel<TData> {
|
|
2183
2700
|
if (!def) return false;
|
|
2184
2701
|
return 'field' in def && !('condition' in def);
|
|
@@ -2188,12 +2705,24 @@ export function isEncodingChannel<TData extends DataRow = DataRow>(
|
|
|
2188
2705
|
* Check if a channel definition is a ConditionalValueDef.
|
|
2189
2706
|
*/
|
|
2190
2707
|
export function isConditionalDef<TData extends DataRow = DataRow>(
|
|
2191
|
-
def: EncodingChannel<TData> | ConditionalValueDef<TData> | undefined,
|
|
2708
|
+
def: EncodingChannel<TData> | ConditionalValueDef<TData> | ValueDef | undefined,
|
|
2192
2709
|
): def is ConditionalValueDef<TData> {
|
|
2193
2710
|
if (!def) return false;
|
|
2194
2711
|
return 'condition' in def;
|
|
2195
2712
|
}
|
|
2196
2713
|
|
|
2714
|
+
/**
|
|
2715
|
+
* Check if a channel definition is a bare ValueDef (constant value, no field
|
|
2716
|
+
* or condition). These are expanded to mark-level properties during the
|
|
2717
|
+
* pre-validation sugar expansion.
|
|
2718
|
+
*/
|
|
2719
|
+
export function isValueDef<TData extends DataRow = DataRow>(
|
|
2720
|
+
def: EncodingChannel<TData> | ConditionalValueDef<TData> | ValueDef | undefined,
|
|
2721
|
+
): def is ValueDef {
|
|
2722
|
+
if (!def) return false;
|
|
2723
|
+
return 'value' in def && !('condition' in def) && !('field' in def);
|
|
2724
|
+
}
|
|
2725
|
+
|
|
2197
2726
|
// ---------------------------------------------------------------------------
|
|
2198
2727
|
// Mark type helpers
|
|
2199
2728
|
// ---------------------------------------------------------------------------
|
|
@@ -2211,10 +2740,25 @@ export const MARK_TYPES: ReadonlySet<string> = new Set<MarkType>([
|
|
|
2211
2740
|
'tick',
|
|
2212
2741
|
'rect',
|
|
2213
2742
|
'lollipop',
|
|
2743
|
+
'beeswarm',
|
|
2744
|
+
'range',
|
|
2745
|
+
'waffle',
|
|
2746
|
+
'calendar',
|
|
2747
|
+
'parliament',
|
|
2214
2748
|
]);
|
|
2215
2749
|
|
|
2216
|
-
/**
|
|
2217
|
-
|
|
2750
|
+
/**
|
|
2751
|
+
* Mark types that lay out inside the chart area without positional axes
|
|
2752
|
+
* (no axis or gridline computation; margins shrink to padding).
|
|
2753
|
+
*/
|
|
2754
|
+
export function isAxislessMark(markType: MarkType): boolean {
|
|
2755
|
+
return (
|
|
2756
|
+
markType === 'arc' ||
|
|
2757
|
+
markType === 'waffle' ||
|
|
2758
|
+
markType === 'calendar' ||
|
|
2759
|
+
markType === 'parliament'
|
|
2760
|
+
);
|
|
2761
|
+
}
|
|
2218
2762
|
|
|
2219
2763
|
/**
|
|
2220
2764
|
* Extract the mark type string from a mark field (string or MarkDef).
|
|
@@ -2269,6 +2813,11 @@ export function isBarListSpec(spec: VizSpec | Record<string, unknown>): spec is
|
|
|
2269
2813
|
return 'type' in spec && (spec as Record<string, unknown>).type === 'barlist';
|
|
2270
2814
|
}
|
|
2271
2815
|
|
|
2816
|
+
/** Check if a spec is a MapSpec. */
|
|
2817
|
+
export function isMapSpec(spec: VizSpec | Record<string, unknown>): spec is MapSpec {
|
|
2818
|
+
return 'type' in spec && (spec as Record<string, unknown>).type === 'map';
|
|
2819
|
+
}
|
|
2820
|
+
|
|
2272
2821
|
// ---------------------------------------------------------------------------
|
|
2273
2822
|
// Annotation type guards
|
|
2274
2823
|
// ---------------------------------------------------------------------------
|
|
@@ -2283,9 +2832,14 @@ export function isRangeAnnotation(annotation: Annotation): annotation is RangeAn
|
|
|
2283
2832
|
return annotation.type === 'range';
|
|
2284
2833
|
}
|
|
2285
2834
|
|
|
2286
|
-
/**
|
|
2835
|
+
/**
|
|
2836
|
+
* Check if an annotation is a RefLineAnnotation. Also accepts the deprecated
|
|
2837
|
+
* `'rule'` type at runtime (pre-sugar-expansion input), since `annotation.type`
|
|
2838
|
+
* may not yet be narrowed to the canonical `'refline'` form.
|
|
2839
|
+
*/
|
|
2287
2840
|
export function isRefLineAnnotation(annotation: Annotation): annotation is RefLineAnnotation {
|
|
2288
|
-
|
|
2841
|
+
const type: string = annotation.type;
|
|
2842
|
+
return type === 'refline' || type === 'rule';
|
|
2289
2843
|
}
|
|
2290
2844
|
|
|
2291
2845
|
// ---------------------------------------------------------------------------
|
|
@@ -2305,4 +2859,9 @@ export const MARK_DISPLAY_NAMES: Record<MarkType, string> = {
|
|
|
2305
2859
|
tick: 'Tick plot',
|
|
2306
2860
|
rect: 'Heatmap',
|
|
2307
2861
|
lollipop: 'Lollipop chart',
|
|
2862
|
+
beeswarm: 'Beeswarm chart',
|
|
2863
|
+
range: 'Range plot',
|
|
2864
|
+
waffle: 'Waffle chart',
|
|
2865
|
+
calendar: 'Calendar heatmap',
|
|
2866
|
+
parliament: 'Parliament chart',
|
|
2308
2867
|
};
|