@opendata-ai/openchart-engine 7.11.0 → 8.0.0-rc.2
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 +123 -14
- package/dist/index.js +16166 -10027
- package/dist/index.js.map +1 -1
- package/package.json +11 -4
- package/src/__tests__/__snapshots__/compile-snapshot.test.ts.snap +170 -56
- package/src/__tests__/annotation-behavior.test.ts +721 -0
- package/src/__tests__/axes.test.ts +50 -3
- package/src/__tests__/compile-chart.test.ts +30 -0
- package/src/__tests__/compile-footnotes.test.ts +277 -0
- package/src/__tests__/compile-layer.test.ts +120 -1
- package/src/__tests__/helpers/invariants.ts +54 -20
- package/src/__tests__/known-bugs.test.ts +455 -2
- package/src/__tests__/legend.test.ts +69 -4
- package/src/__tests__/ranking-recipes.test.ts +260 -0
- package/src/__tests__/scales.test.ts +9 -3
- package/src/__tests__/series-search.test.ts +92 -0
- package/src/__tests__/spec-sugar.test.ts +801 -0
- package/src/__tests__/you-draw-it.test.ts +160 -0
- package/src/annotations/__tests__/compute.test.ts +207 -92
- package/src/annotations/__tests__/geometry.test.ts +66 -0
- package/src/annotations/__tests__/resolve-text.test.ts +527 -27
- package/src/annotations/__tests__/rich-text.test.ts +91 -0
- package/src/annotations/__tests__/thinning.test.ts +148 -0
- package/src/annotations/collisions.ts +130 -84
- package/src/annotations/compute.ts +83 -85
- package/src/annotations/constants.ts +116 -6
- package/src/annotations/geometry.ts +222 -77
- package/src/annotations/move.ts +135 -0
- package/src/annotations/placement.ts +62 -14
- package/src/annotations/resolve-range.ts +2 -0
- package/src/annotations/resolve-refline.ts +2 -0
- package/src/annotations/resolve-text.ts +312 -111
- package/src/annotations/rich-text.ts +65 -0
- package/src/annotations/thinning.ts +84 -10
- package/src/barlist/compile-barlist.ts +16 -6
- package/src/charts/_shared/format-label-value.ts +9 -8
- package/src/charts/bar/__tests__/compute.test.ts +57 -10
- package/src/charts/bar/__tests__/labels.test.ts +5 -4
- package/src/charts/bar/compute.ts +2 -6
- package/src/charts/bar/index.ts +8 -1
- package/src/charts/bar/labels.ts +3 -3
- package/src/charts/beeswarm/__tests__/compute.test.ts +280 -0
- package/src/charts/beeswarm/__tests__/dodge.test.ts +148 -0
- package/src/charts/beeswarm/compute.ts +203 -0
- package/src/charts/beeswarm/dodge.ts +155 -0
- package/src/charts/beeswarm/index.ts +32 -0
- package/src/charts/builtin.ts +12 -1
- package/src/charts/calendar/__tests__/compute.test.ts +417 -0
- package/src/charts/calendar/compute.ts +319 -0
- package/src/charts/calendar/index.ts +32 -0
- package/src/charts/column/__tests__/compute.test.ts +21 -7
- package/src/charts/column/__tests__/labels.test.ts +76 -1
- package/src/charts/column/compute.ts +2 -6
- package/src/charts/column/index.ts +10 -2
- package/src/charts/column/labels.ts +95 -21
- package/src/charts/dot/index.ts +8 -1
- package/src/charts/dot/labels.ts +3 -3
- package/src/charts/line/__tests__/compute.test.ts +15 -19
- package/src/charts/line/area.ts +8 -23
- package/src/charts/line/compute.ts +32 -2
- package/src/charts/parliament/__tests__/compute.test.ts +411 -0
- package/src/charts/parliament/compute.ts +313 -0
- package/src/charts/parliament/index.ts +32 -0
- package/src/charts/pie/__tests__/compute.test.ts +103 -0
- package/src/charts/pie/compute.ts +63 -8
- package/src/charts/pie/labels.ts +1 -0
- package/src/charts/range/__tests__/compute.test.ts +486 -0
- package/src/charts/range/compute.ts +273 -0
- package/src/charts/range/index.ts +82 -0
- package/src/charts/range/labels.ts +169 -0
- package/src/charts/rect/__tests__/compute.test.ts +120 -0
- package/src/charts/rect/index.ts +127 -0
- package/src/charts/scatter/compute.ts +7 -21
- package/src/charts/text/__tests__/compute.test.ts +307 -0
- package/src/charts/text/index.ts +44 -7
- package/src/charts/tick/__tests__/compute.test.ts +75 -0
- package/src/charts/tick/index.ts +7 -4
- package/src/charts/utils.ts +5 -3
- package/src/charts/waffle/__tests__/compute.test.ts +305 -0
- package/src/charts/waffle/compute.ts +197 -0
- package/src/charts/waffle/index.ts +31 -0
- package/src/compile/__tests__/color-scale-reverse.test.ts +89 -0
- package/src/compile/__tests__/data-clip.test.ts +68 -0
- package/src/compile/__tests__/fill-patterns.test.ts +154 -0
- package/src/compile/__tests__/size-scale.test.ts +108 -0
- package/src/compile/color-scale-range.ts +54 -33
- package/src/compile/data-clip.ts +21 -6
- package/src/compile/fill-patterns.ts +74 -0
- package/src/compile/layer.ts +117 -21
- package/src/compile/size-scale.ts +139 -0
- package/src/compile/spec-sugar.ts +758 -0
- package/src/compile/you-draw-it.ts +123 -0
- package/src/compile.ts +310 -103
- package/src/compiler/__tests__/a11y-warnings.test.ts +148 -0
- package/src/compiler/__tests__/fixtures/vl-parity/axis-null.json +19 -0
- package/src/compiler/__tests__/fixtures/vl-parity/color-value.json +20 -0
- package/src/compiler/__tests__/fixtures/vl-parity/count-aggregate.json +22 -0
- package/src/compiler/__tests__/fixtures/vl-parity/data-values.json +19 -0
- package/src/compiler/__tests__/fixtures/vl-parity/layer-axis-null.json +14 -0
- package/src/compiler/__tests__/fixtures/vl-parity/layer-count.json +34 -0
- package/src/compiler/__tests__/fixtures/vl-parity/layer-data-values.json +22 -0
- package/src/compiler/__tests__/fixtures/vl-parity/layer-legend-null.json +41 -0
- package/src/compiler/__tests__/fixtures/vl-parity/layer-scheme.json +38 -0
- package/src/compiler/__tests__/fixtures/vl-parity/layer-sort.json +28 -0
- package/src/compiler/__tests__/fixtures/vl-parity/layer-theta.json +28 -0
- package/src/compiler/__tests__/fixtures/vl-parity/layer-title.json +30 -0
- package/src/compiler/__tests__/fixtures/vl-parity/layer-value-def.json +29 -0
- package/src/compiler/__tests__/fixtures/vl-parity/legend-null.json +32 -0
- package/src/compiler/__tests__/fixtures/vl-parity/scheme.json +25 -0
- package/src/compiler/__tests__/fixtures/vl-parity/sort-by-value.json +19 -0
- package/src/compiler/__tests__/fixtures/vl-parity/theta-arc.json +19 -0
- package/src/compiler/__tests__/fixtures/vl-parity/title-subtitle.json +21 -0
- package/src/compiler/__tests__/fixtures/vl-parity/width-height.json +23 -0
- package/src/compiler/__tests__/keys.test.ts +3 -9
- package/src/compiler/__tests__/normalize.test.ts +65 -1
- package/src/compiler/__tests__/validate-did-you-mean.test.ts +86 -0
- package/src/compiler/__tests__/validate-near-miss.test.ts +89 -0
- package/src/compiler/__tests__/validate.test.ts +156 -0
- package/src/compiler/__tests__/vl-parity.test.ts +68 -0
- package/src/compiler/a11y-warnings.ts +110 -0
- package/src/compiler/keys.ts +5 -4
- package/src/compiler/normalize.ts +150 -7
- package/src/compiler/types.ts +11 -0
- package/src/compiler/validate.ts +664 -18
- package/src/endpoint-labels/__tests__/compute.test.ts +88 -0
- package/src/endpoint-labels/compute.ts +40 -12
- package/src/endpoint-labels/format.ts +45 -15
- package/src/endpoint-labels/predict.ts +50 -36
- package/src/format/__tests__/field-format.test.ts +164 -0
- package/src/format/field-format.ts +27 -0
- package/src/geo/__tests__/compile-map.test.ts +621 -0
- package/src/geo/compile-map.ts +856 -0
- package/src/geo/join.ts +115 -0
- package/src/geo/projections.ts +45 -0
- package/src/geo/types.ts +24 -0
- package/src/graphs/__tests__/compile-graph.test.ts +25 -0
- package/src/graphs/compile-graph.ts +27 -18
- package/src/index.ts +20 -2
- package/src/layout/axes/ticks.ts +59 -10
- package/src/layout/axes.ts +35 -6
- package/src/layout/dimensions.ts +139 -83
- package/src/layout/facet.ts +14 -3
- package/src/layout/plan.ts +83 -33
- package/src/layout/scales.ts +132 -15
- package/src/legend/__tests__/continuous.test.ts +318 -0
- package/src/legend/__tests__/size.test.ts +348 -0
- package/src/legend/__tests__/suppression.test.ts +17 -1
- package/src/legend/compute.ts +119 -13
- package/src/legend/continuous.ts +327 -0
- package/src/legend/size.ts +407 -0
- package/src/legend/suppression.ts +8 -7
- package/src/sankey/compile-sankey.ts +31 -19
- package/src/tables/format-cells.ts +16 -7
- package/src/tilemap/__tests__/compile-tilemap.test.ts +39 -0
- package/src/tilemap/compile-tilemap.ts +24 -7
- package/src/tooltips/__tests__/compute.test.ts +2 -2
- package/src/tooltips/compute.ts +422 -41
- package/src/transforms/__tests__/conditional.test.ts +18 -0
- package/src/transforms/aggregate.ts +2 -1
|
@@ -20,6 +20,8 @@ import type {
|
|
|
20
20
|
GraphSpec,
|
|
21
21
|
LabelSpec,
|
|
22
22
|
LayerSpec,
|
|
23
|
+
MapSpec,
|
|
24
|
+
MarkDef,
|
|
23
25
|
SankeySpec,
|
|
24
26
|
TableSpec,
|
|
25
27
|
TileMapSpec,
|
|
@@ -30,6 +32,7 @@ import {
|
|
|
30
32
|
isChartSpec,
|
|
31
33
|
isGraphSpec,
|
|
32
34
|
isLayerSpec,
|
|
35
|
+
isMapSpec,
|
|
33
36
|
isSankeySpec,
|
|
34
37
|
isTableSpec,
|
|
35
38
|
isTileMapSpec,
|
|
@@ -37,6 +40,7 @@ import {
|
|
|
37
40
|
resolveMarkType,
|
|
38
41
|
} from '@opendata-ai/openchart-core';
|
|
39
42
|
import type { NormalizedBarListSpec } from '../barlist/types';
|
|
43
|
+
import type { NormalizedMapSpec } from '../geo/types';
|
|
40
44
|
import type { NormalizedSankeySpec } from '../sankey/types';
|
|
41
45
|
import { STATE_CODE_SET } from '../tilemap/layout';
|
|
42
46
|
import type { NormalizedTileMapSpec } from '../tilemap/types';
|
|
@@ -138,6 +142,9 @@ function inferEncodingTypes(encoding: Encoding, data: DataRow[], warnings: strin
|
|
|
138
142
|
|
|
139
143
|
// Skip conditional value definitions - they don't have field/type at the top level
|
|
140
144
|
if ('condition' in spec) continue;
|
|
145
|
+
// Skip bare value defs (no field). The sugar expansion moves these to
|
|
146
|
+
// mark-level properties before normalize runs on the compile path.
|
|
147
|
+
if (!('field' in spec)) continue;
|
|
141
148
|
|
|
142
149
|
if (!spec.type) {
|
|
143
150
|
const inferred = inferFieldType(data, spec.field);
|
|
@@ -168,13 +175,20 @@ function inferEncodingTypes(encoding: Encoding, data: DataRow[], warnings: strin
|
|
|
168
175
|
function normalizeAnnotations(annotations: Annotation[] | undefined): Annotation[] {
|
|
169
176
|
if (!annotations || annotations.length === 0) return [];
|
|
170
177
|
|
|
178
|
+
// The spec-sugar pass rewrites the deprecated `type: 'rule'` annotation
|
|
179
|
+
// alias to `'refline'` (with a warning) before validation/normalization
|
|
180
|
+
// ever runs, so by this point every annotation is in canonical form.
|
|
171
181
|
return annotations.map((ann) => {
|
|
172
182
|
switch (ann.type) {
|
|
173
183
|
case 'text':
|
|
184
|
+
// Deliberately does NOT default fontSize/fontWeight. The annotation
|
|
185
|
+
// layer owns those (DEFAULT_ANNOTATION_FONT_SIZE, and the lede rule
|
|
186
|
+
// that promotes a subtitle-bearing primary line to bold). Stamping
|
|
187
|
+
// them here makes `annotation.fontWeight` always defined, so
|
|
188
|
+
// `resolveLedeFontWeight` can never fire and the size default can
|
|
189
|
+
// never apply — both features become dead code.
|
|
174
190
|
return {
|
|
175
191
|
...ann,
|
|
176
|
-
fontSize: ann.fontSize ?? 12,
|
|
177
|
-
fontWeight: ann.fontWeight ?? 400,
|
|
178
192
|
opacity: ann.opacity ?? 1,
|
|
179
193
|
};
|
|
180
194
|
case 'range':
|
|
@@ -184,10 +198,8 @@ function normalizeAnnotations(annotations: Annotation[] | undefined): Annotation
|
|
|
184
198
|
fill: ann.fill ?? '#000000',
|
|
185
199
|
};
|
|
186
200
|
case 'refline':
|
|
187
|
-
case 'rule':
|
|
188
201
|
return {
|
|
189
202
|
...ann,
|
|
190
|
-
type: 'refline' as const,
|
|
191
203
|
style: ann.style ?? 'dashed',
|
|
192
204
|
strokeWidth: ann.strokeWidth ?? 1,
|
|
193
205
|
stroke: ann.stroke ?? '#666666',
|
|
@@ -254,10 +266,104 @@ function normalizeHighlight(encoding: Encoding, data: DataRow[], warnings: strin
|
|
|
254
266
|
return highlight;
|
|
255
267
|
}
|
|
256
268
|
|
|
269
|
+
// ---------------------------------------------------------------------------
|
|
270
|
+
// Series search normalization
|
|
271
|
+
// ---------------------------------------------------------------------------
|
|
272
|
+
|
|
273
|
+
/**
|
|
274
|
+
* Normalize `seriesSearch` to a config object, or undefined when disabled.
|
|
275
|
+
* Search needs a categorical color encoding to enumerate series values;
|
|
276
|
+
* warns and disables when there isn't one.
|
|
277
|
+
*/
|
|
278
|
+
function normalizeSeriesSearch(
|
|
279
|
+
spec: ChartSpec,
|
|
280
|
+
encoding: Encoding,
|
|
281
|
+
warnings: string[],
|
|
282
|
+
): import('@opendata-ai/openchart-core').SeriesSearchConfig | undefined {
|
|
283
|
+
if (!spec.seriesSearch) return undefined;
|
|
284
|
+
const color = encoding.color;
|
|
285
|
+
const hasCategoricalColor =
|
|
286
|
+
!!color &&
|
|
287
|
+
!('condition' in color) &&
|
|
288
|
+
'field' in color &&
|
|
289
|
+
!!color.field &&
|
|
290
|
+
color.type !== 'quantitative';
|
|
291
|
+
if (!hasCategoricalColor) {
|
|
292
|
+
warnings.push(
|
|
293
|
+
'[openchart] seriesSearch requires a categorical color encoding (encoding.color.field with a nominal/ordinal type); ignoring seriesSearch.',
|
|
294
|
+
);
|
|
295
|
+
return undefined;
|
|
296
|
+
}
|
|
297
|
+
return typeof spec.seriesSearch === 'object' ? { ...spec.seriesSearch } : {};
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
// ---------------------------------------------------------------------------
|
|
301
|
+
// You draw it normalization
|
|
302
|
+
// ---------------------------------------------------------------------------
|
|
303
|
+
|
|
304
|
+
/**
|
|
305
|
+
* Normalize `youDrawIt` to a config object with defaults filled in, or
|
|
306
|
+
* undefined when disabled. Mark type, single-series, and `from` presence are
|
|
307
|
+
* enforced by validateSpec before normalize runs; this only fills defaults.
|
|
308
|
+
*/
|
|
309
|
+
function normalizeYouDrawIt(
|
|
310
|
+
spec: ChartSpec,
|
|
311
|
+
): import('@opendata-ai/openchart-core').YouDrawItConfig | undefined {
|
|
312
|
+
if (!spec.youDrawIt) return undefined;
|
|
313
|
+
return {
|
|
314
|
+
prompt: 'Draw your guess',
|
|
315
|
+
revealLabel: 'Show me',
|
|
316
|
+
...spec.youDrawIt,
|
|
317
|
+
};
|
|
318
|
+
}
|
|
319
|
+
|
|
257
320
|
// ---------------------------------------------------------------------------
|
|
258
321
|
// Spec-level normalization
|
|
259
322
|
// ---------------------------------------------------------------------------
|
|
260
323
|
|
|
324
|
+
/**
|
|
325
|
+
* Beeswarm point budget. Past this count the dodge layout still resolves
|
|
326
|
+
* every collision, but the swarm piles into a solid band that reads no
|
|
327
|
+
* better than an overplotted strip, and layout cost keeps growing.
|
|
328
|
+
*/
|
|
329
|
+
const BEESWARM_POINT_BUDGET = 2000;
|
|
330
|
+
|
|
331
|
+
/**
|
|
332
|
+
* Warn when a parliament `majorityLine.seats` override lands outside the chamber
|
|
333
|
+
* (below 1 or above the seat total). The mark falls back to a simple majority in
|
|
334
|
+
* that case, so this is a non-fatal warning routed through the shared warnings
|
|
335
|
+
* array (dedup + single emit boundary) rather than a raw console.warn in mark
|
|
336
|
+
* computation. Only the object form of majorityLine carries a seat count.
|
|
337
|
+
*/
|
|
338
|
+
function warnParliamentMajorityRange(
|
|
339
|
+
markDef: MarkDef,
|
|
340
|
+
encoding: Encoding,
|
|
341
|
+
data: DataRow[],
|
|
342
|
+
warnings: string[],
|
|
343
|
+
): void {
|
|
344
|
+
const majorityLine = markDef.majorityLine;
|
|
345
|
+
if (!majorityLine || typeof majorityLine !== 'object') return;
|
|
346
|
+
const requested = majorityLine.seats;
|
|
347
|
+
if (requested === undefined) return;
|
|
348
|
+
|
|
349
|
+
const valueField = encoding.theta?.field ?? encoding.y?.field;
|
|
350
|
+
if (!valueField) return;
|
|
351
|
+
|
|
352
|
+
let totalSeats = 0;
|
|
353
|
+
for (const row of data) {
|
|
354
|
+
const v = Number(row[valueField]);
|
|
355
|
+
if (Number.isFinite(v)) totalSeats += v;
|
|
356
|
+
}
|
|
357
|
+
if (totalSeats <= 0) return;
|
|
358
|
+
|
|
359
|
+
if (!Number.isFinite(requested) || requested < 1 || requested > totalSeats) {
|
|
360
|
+
const fallback = Math.floor(totalSeats / 2) + 1;
|
|
361
|
+
warnings.push(
|
|
362
|
+
`[openchart] parliament mark.majorityLine.seats (${requested}) is outside the valid range 1..${totalSeats}; using the default majority threshold of ${fallback}.`,
|
|
363
|
+
);
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
|
|
261
367
|
function normalizeChartSpec(spec: ChartSpec, warnings: string[]): NormalizedChartSpec {
|
|
262
368
|
const encoding = inferEncodingTypes(spec.encoding, spec.data, warnings);
|
|
263
369
|
const markType = resolveMarkType(spec.mark);
|
|
@@ -276,6 +382,16 @@ function normalizeChartSpec(spec: ChartSpec, warnings: string[]): NormalizedChar
|
|
|
276
382
|
);
|
|
277
383
|
}
|
|
278
384
|
|
|
385
|
+
if (markType === 'beeswarm' && spec.data.length > BEESWARM_POINT_BUDGET) {
|
|
386
|
+
warnings.push(
|
|
387
|
+
`[openchart] beeswarm received ${spec.data.length} data points, past the ~${BEESWARM_POINT_BUDGET}-point budget where individual dots stop being readable and the swarm collapses into a solid band. Sample the data down, or summarize the distribution with mark: 'tick' (strip plot) or a binned histogram (bin transform + mark: 'bar').`,
|
|
388
|
+
);
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
if (markType === 'parliament') {
|
|
392
|
+
warnParliamentMajorityRange(markDef, encoding, spec.data, warnings);
|
|
393
|
+
}
|
|
394
|
+
|
|
279
395
|
return {
|
|
280
396
|
markType,
|
|
281
397
|
markDef,
|
|
@@ -283,6 +399,8 @@ function normalizeChartSpec(spec: ChartSpec, warnings: string[]): NormalizedChar
|
|
|
283
399
|
encoding,
|
|
284
400
|
chrome: normalizeChrome(spec.chrome),
|
|
285
401
|
metrics: spec.metrics,
|
|
402
|
+
seriesSearch: normalizeSeriesSearch(spec, encoding, warnings),
|
|
403
|
+
youDrawIt: normalizeYouDrawIt(spec),
|
|
286
404
|
annotations: normalizeAnnotations(spec.annotations),
|
|
287
405
|
labels: normalizeLabels(spec.labels),
|
|
288
406
|
legend: spec.legend,
|
|
@@ -298,6 +416,7 @@ function normalizeChartSpec(spec: ChartSpec, warnings: string[]): NormalizedChar
|
|
|
298
416
|
seriesStyles: spec.seriesStyles ?? {},
|
|
299
417
|
watermark: spec.watermark ?? true,
|
|
300
418
|
highlight: normalizeHighlight(encoding, spec.data, warnings),
|
|
419
|
+
a11y: spec.a11y,
|
|
301
420
|
display,
|
|
302
421
|
resolve: spec.resolve,
|
|
303
422
|
// Default empty userExplicit; compileChart overwrites this with the real
|
|
@@ -358,7 +477,7 @@ function normalizeSankeySpec(spec: SankeySpec, _warnings: string[]): NormalizedS
|
|
|
358
477
|
};
|
|
359
478
|
}
|
|
360
479
|
|
|
361
|
-
function normalizeGraphSpec(spec: GraphSpec
|
|
480
|
+
function normalizeGraphSpec(spec: GraphSpec): NormalizedGraphSpec {
|
|
362
481
|
// Default layout with chargeStrength and linkDistance
|
|
363
482
|
const defaultLayout = {
|
|
364
483
|
type: 'force' as const,
|
|
@@ -458,6 +577,27 @@ function normalizeTileMapSpec(spec: TileMapSpec, warnings: string[]): Normalized
|
|
|
458
577
|
};
|
|
459
578
|
}
|
|
460
579
|
|
|
580
|
+
function normalizeMapSpec(spec: MapSpec, _warnings: string[]): NormalizedMapSpec {
|
|
581
|
+
return {
|
|
582
|
+
type: 'map',
|
|
583
|
+
geo: {
|
|
584
|
+
features: spec.geo.features,
|
|
585
|
+
idField: spec.geo.idField ?? 'id',
|
|
586
|
+
projection: spec.geo.projection ?? 'albersUsa',
|
|
587
|
+
focus: spec.geo.focus ?? null,
|
|
588
|
+
},
|
|
589
|
+
data: spec.data,
|
|
590
|
+
encoding: spec.encoding,
|
|
591
|
+
chrome: normalizeChrome(spec.chrome),
|
|
592
|
+
legend: spec.legend,
|
|
593
|
+
theme: spec.theme ?? {},
|
|
594
|
+
darkMode: spec.darkMode ?? 'off',
|
|
595
|
+
watermark: spec.watermark ?? true,
|
|
596
|
+
animation: spec.animation,
|
|
597
|
+
valueFormat: spec.valueFormat,
|
|
598
|
+
};
|
|
599
|
+
}
|
|
600
|
+
|
|
461
601
|
function normalizeBarListSpec(spec: BarListSpec, _warnings: string[]): NormalizedBarListSpec {
|
|
462
602
|
return {
|
|
463
603
|
type: 'barlist',
|
|
@@ -504,7 +644,7 @@ export function normalizeSpec(spec: VizSpec, warnings: string[] = []): Normalize
|
|
|
504
644
|
return normalizeTableSpec(spec, warnings);
|
|
505
645
|
}
|
|
506
646
|
if (isGraphSpec(spec)) {
|
|
507
|
-
return normalizeGraphSpec(spec
|
|
647
|
+
return normalizeGraphSpec(spec);
|
|
508
648
|
}
|
|
509
649
|
if (isSankeySpec(spec)) {
|
|
510
650
|
return normalizeSankeySpec(spec, warnings);
|
|
@@ -512,12 +652,15 @@ export function normalizeSpec(spec: VizSpec, warnings: string[] = []): Normalize
|
|
|
512
652
|
if (isTileMapSpec(spec)) {
|
|
513
653
|
return normalizeTileMapSpec(spec, warnings);
|
|
514
654
|
}
|
|
655
|
+
if (isMapSpec(spec)) {
|
|
656
|
+
return normalizeMapSpec(spec, warnings);
|
|
657
|
+
}
|
|
515
658
|
if (isBarListSpec(spec)) {
|
|
516
659
|
return normalizeBarListSpec(spec, warnings);
|
|
517
660
|
}
|
|
518
661
|
// Should never happen after validation
|
|
519
662
|
throw new Error(
|
|
520
|
-
`Unknown spec shape. Expected mark (chart), layer, type: 'table', type: 'graph', type: 'sankey', type: 'tilemap', or type: 'barlist'.`,
|
|
663
|
+
`Unknown spec shape. Expected mark (chart), layer, type: 'table', type: 'graph', type: 'sankey', type: 'tilemap', type: 'map', or type: 'barlist'.`,
|
|
521
664
|
);
|
|
522
665
|
}
|
|
523
666
|
|
package/src/compiler/types.ts
CHANGED
|
@@ -30,6 +30,7 @@ import type {
|
|
|
30
30
|
ThemeConfig,
|
|
31
31
|
} from '@opendata-ai/openchart-core';
|
|
32
32
|
import type { NormalizedBarListSpec } from '../barlist/types';
|
|
33
|
+
import type { NormalizedMapSpec } from '../geo/types';
|
|
33
34
|
import type { NormalizedSankeySpec } from '../sankey/types';
|
|
34
35
|
import type { NormalizedTileMapSpec } from '../tilemap/types';
|
|
35
36
|
|
|
@@ -107,6 +108,13 @@ export interface NormalizedChartSpec {
|
|
|
107
108
|
chrome: NormalizedChrome;
|
|
108
109
|
/** Optional KPI metric cells, passed through unchanged. */
|
|
109
110
|
metrics?: import('@opendata-ai/openchart-core').Metric[];
|
|
111
|
+
/**
|
|
112
|
+
* Searchable series highlight config. Present only when `seriesSearch` is
|
|
113
|
+
* enabled AND the spec has a categorical color encoding to search over.
|
|
114
|
+
*/
|
|
115
|
+
seriesSearch?: import('@opendata-ai/openchart-core').SeriesSearchConfig;
|
|
116
|
+
/** Resolved "you draw it" config with defaults filled in. Present only when `youDrawIt` is enabled. */
|
|
117
|
+
youDrawIt?: import('@opendata-ai/openchart-core').YouDrawItConfig;
|
|
110
118
|
annotations: Annotation[];
|
|
111
119
|
/** Normalized label configuration with defaults applied. density, format, and prefix are always set; offsets and color stay optional. */
|
|
112
120
|
labels: Required<Pick<LabelConfig, 'density' | 'format' | 'prefix'>> &
|
|
@@ -126,6 +134,8 @@ export interface NormalizedChartSpec {
|
|
|
126
134
|
hiddenSeries: string[];
|
|
127
135
|
/** Per-series visual style overrides. */
|
|
128
136
|
seriesStyles: Record<string, import('@opendata-ai/openchart-core').SeriesStyle>;
|
|
137
|
+
/** Author accessibility overrides (alt-text description, aria-hidden opt-out). */
|
|
138
|
+
a11y?: import('@opendata-ai/openchart-core').A11yConfig;
|
|
129
139
|
/** Display mode controlling chrome/axes/legend stripping. Defaults to `'full'`. */
|
|
130
140
|
display: Display;
|
|
131
141
|
/** Resolve configuration for independent/shared scales in faceted charts. */
|
|
@@ -184,6 +194,7 @@ export type NormalizedSpec =
|
|
|
184
194
|
| NormalizedGraphSpec
|
|
185
195
|
| NormalizedSankeySpec
|
|
186
196
|
| NormalizedTileMapSpec
|
|
197
|
+
| NormalizedMapSpec
|
|
187
198
|
| NormalizedBarListSpec;
|
|
188
199
|
|
|
189
200
|
// ---------------------------------------------------------------------------
|