@opendata-ai/openchart-engine 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 +142 -7
- package/dist/index.js +16182 -10032
- 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__/dimensions.test.ts +49 -4
- package/src/__tests__/helpers/invariants.ts +54 -20
- package/src/__tests__/known-bugs.test.ts +455 -2
- package/src/__tests__/legend.test.ts +120 -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 +315 -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__/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/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 +28 -2
- package/src/layout/axes/ticks.ts +59 -10
- package/src/layout/axes.ts +30 -2
- package/src/layout/dimensions.ts +178 -95
- package/src/layout/facet.ts +14 -3
- package/src/layout/plan.ts +86 -35
- 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 +126 -14
- package/src/legend/continuous.ts +327 -0
- package/src/legend/size.ts +407 -0
- package/src/legend/suppression.ts +8 -7
- package/src/legend/wrap.ts +8 -0
- 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
|
@@ -533,5 +533,44 @@ describe('compileTileMap', () => {
|
|
|
533
533
|
const caTile = result.tiles.find((t) => t.stateCode === 'CA')!;
|
|
534
534
|
expect(caTile.formattedValue).toBe('Medical Only');
|
|
535
535
|
});
|
|
536
|
+
|
|
537
|
+
it('suppresses value labels in categorical mode (showValueLabels: false)', () => {
|
|
538
|
+
const result = compileTileMap(categoricalRecordSpec, defaultOptions);
|
|
539
|
+
|
|
540
|
+
// All tiles should have valueLabel.visible = false in categorical mode
|
|
541
|
+
const dataTiles = result.tiles.filter((t) => t.hasData);
|
|
542
|
+
for (const tile of dataTiles) {
|
|
543
|
+
expect(tile.valueLabel.visible).toBe(false);
|
|
544
|
+
}
|
|
545
|
+
});
|
|
546
|
+
});
|
|
547
|
+
|
|
548
|
+
describe('value label visibility', () => {
|
|
549
|
+
it('shows value labels by default in quantitative mode (when tile size permits)', () => {
|
|
550
|
+
const result = compileTileMap(basicSpec, defaultOptions);
|
|
551
|
+
|
|
552
|
+
// Tiles should have valueLabel.visible = true when tileSize >= 24 in quantitative mode
|
|
553
|
+
const dataTiles = result.tiles.filter((t) => t.hasData);
|
|
554
|
+
const tilesWithVisibleLabels = dataTiles.filter((t) => t.valueLabel.visible);
|
|
555
|
+
|
|
556
|
+
// At least some tiles should have visible value labels (depends on computed tile size)
|
|
557
|
+
// If tileSize is large enough (>= 24), all data tiles should show value labels
|
|
558
|
+
if (dataTiles.length > 0 && dataTiles[0].size >= 24) {
|
|
559
|
+
expect(tilesWithVisibleLabels.length).toBe(dataTiles.length);
|
|
560
|
+
}
|
|
561
|
+
});
|
|
562
|
+
|
|
563
|
+
it('hides value labels when tile size is too small (< 24px)', () => {
|
|
564
|
+
// Use a very narrow container to force small tiles
|
|
565
|
+
const result = compileTileMap(basicSpec, { width: 200, height: 400 });
|
|
566
|
+
|
|
567
|
+
const dataTiles = result.tiles.filter((t) => t.hasData);
|
|
568
|
+
if (dataTiles.length > 0 && dataTiles[0].size < 24) {
|
|
569
|
+
// When tiles are small, value labels should be hidden
|
|
570
|
+
for (const tile of dataTiles) {
|
|
571
|
+
expect(tile.valueLabel.visible).toBe(false);
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
});
|
|
536
575
|
});
|
|
537
576
|
});
|
|
@@ -33,11 +33,9 @@ import type {
|
|
|
33
33
|
} from '@opendata-ai/openchart-core';
|
|
34
34
|
import {
|
|
35
35
|
adaptTheme,
|
|
36
|
-
buildD3Formatter,
|
|
37
36
|
CATEGORICAL_PALETTE,
|
|
38
37
|
computeChrome,
|
|
39
38
|
estimateTextWidth,
|
|
40
|
-
formatNumber,
|
|
41
39
|
getBreakpoint,
|
|
42
40
|
HPAD_COMPACT_FRACTION,
|
|
43
41
|
HPAD_COMPACT_MIN,
|
|
@@ -46,9 +44,10 @@ import {
|
|
|
46
44
|
SEQUENTIAL_PALETTES,
|
|
47
45
|
} from '@opendata-ai/openchart-core';
|
|
48
46
|
import { scaleLinear } from 'd3-scale';
|
|
49
|
-
|
|
47
|
+
import { emitSpecWarnings, expandSpecSugar } from '../compile/spec-sugar';
|
|
50
48
|
import { resolveAnimation } from '../compiler/animation';
|
|
51
49
|
import { compile as compileSpec } from '../compiler/index';
|
|
50
|
+
import { resolveFieldFormatter } from '../format/field-format';
|
|
52
51
|
import { computeTilePositions, STATE_CODE_SET, STATE_NAMES, US_STATE_TILES } from './layout';
|
|
53
52
|
import type { NormalizedTileMapSpec } from './types';
|
|
54
53
|
|
|
@@ -79,8 +78,19 @@ function clamp(value: number, min: number, max: number): number {
|
|
|
79
78
|
* @throws Error if spec is invalid or not a tilemap type.
|
|
80
79
|
*/
|
|
81
80
|
export function compileTileMap(spec: unknown, options: CompileOptions): TileMapLayout {
|
|
82
|
-
// 1.
|
|
83
|
-
|
|
81
|
+
// 1. Expand deprecated top-level sugar (valueFormat -> encoding.value.format)
|
|
82
|
+
// before validation, then validate + normalize via the shared compiler
|
|
83
|
+
// pipeline. Surface any normalize warnings (e.g. "only N of M rows have
|
|
84
|
+
// valid US state codes", mixed-type coercion) the same way the chart path
|
|
85
|
+
// does; without this the primary "your data did not map" diagnostic is
|
|
86
|
+
// computed and then dropped.
|
|
87
|
+
const sugarWarnings: string[] = [];
|
|
88
|
+
const expandedSpec =
|
|
89
|
+
spec && typeof spec === 'object' && !Array.isArray(spec)
|
|
90
|
+
? expandSpecSugar(spec as Record<string, unknown>, sugarWarnings)
|
|
91
|
+
: spec;
|
|
92
|
+
const { spec: normalized, warnings } = compileSpec(expandedSpec);
|
|
93
|
+
emitSpecWarnings([...sugarWarnings, ...warnings], options.onWarn);
|
|
84
94
|
|
|
85
95
|
if (!('type' in normalized) || normalized.type !== 'tilemap') {
|
|
86
96
|
throw new Error(
|
|
@@ -208,7 +218,11 @@ function compileQuantitative(
|
|
|
208
218
|
const legendY = tileGridOffsetY + tilePositions.gridHeight + legendGap;
|
|
209
219
|
const legendWidth = tilePositions.gridWidth;
|
|
210
220
|
|
|
211
|
-
|
|
221
|
+
// Encoding-level format (v8 canonical) wins over deprecated top-level valueFormat
|
|
222
|
+
const formatter = resolveFieldFormatter({
|
|
223
|
+
surfaceFormat: tilemapSpec.encoding.value.format ?? tilemapSpec.valueFormat,
|
|
224
|
+
values: Array.from(stateValueMap.values()),
|
|
225
|
+
});
|
|
212
226
|
const neutralFill = isDarkMode ? '#1e2a30' : '#e0e0e0';
|
|
213
227
|
const neutralStroke = isDarkMode ? 'rgba(255,255,255,0.08)' : '#d0d0d0';
|
|
214
228
|
|
|
@@ -432,6 +446,7 @@ function compileCategorical(
|
|
|
432
446
|
theme,
|
|
433
447
|
isDarkMode: !!isDarkMode,
|
|
434
448
|
category: hasData ? category : undefined,
|
|
449
|
+
showValueLabels: false,
|
|
435
450
|
}),
|
|
436
451
|
);
|
|
437
452
|
}
|
|
@@ -526,6 +541,7 @@ interface TileMarkOptions {
|
|
|
526
541
|
theme: ResolvedTheme;
|
|
527
542
|
isDarkMode: boolean;
|
|
528
543
|
category?: string | null;
|
|
544
|
+
showValueLabels?: boolean;
|
|
529
545
|
}
|
|
530
546
|
|
|
531
547
|
function buildTileMark(opts: TileMarkOptions): TileMapTileMark {
|
|
@@ -544,6 +560,7 @@ function buildTileMark(opts: TileMarkOptions): TileMapTileMark {
|
|
|
544
560
|
theme,
|
|
545
561
|
isDarkMode,
|
|
546
562
|
category,
|
|
563
|
+
showValueLabels = true,
|
|
547
564
|
} = opts;
|
|
548
565
|
const tileCenterX = gridOffsetX + pos.x + tileSize / 2;
|
|
549
566
|
const tileTopY = gridOffsetY + pos.y;
|
|
@@ -553,7 +570,7 @@ function buildTileMark(opts: TileMarkOptions): TileMapTileMark {
|
|
|
553
570
|
|
|
554
571
|
// A two-line layout (code over value) only fits once tiles are large enough;
|
|
555
572
|
// below that we drop the value and center the code so nothing overflows.
|
|
556
|
-
const showValue = tileSize >= 24;
|
|
573
|
+
const showValue = showValueLabels && tileSize >= 24;
|
|
557
574
|
|
|
558
575
|
// Scale the code font with the tile so a 2-char label always fits its box,
|
|
559
576
|
// rather than snapping between two fixed sizes. A 2-char string is ~1.2x the
|
|
@@ -141,10 +141,10 @@ describe('computeTooltipDescriptors', () => {
|
|
|
141
141
|
// Should have fields for y (value) and x (date)
|
|
142
142
|
expect(content.fields.length).toBeGreaterThanOrEqual(1);
|
|
143
143
|
|
|
144
|
-
// The value field should
|
|
144
|
+
// The value field should use compact notation (smart default formatting)
|
|
145
145
|
const valueField = content.fields.find((f) => f.label === 'value');
|
|
146
146
|
expect(valueField).toBeDefined();
|
|
147
|
-
expect(valueField!.value).toBe('1
|
|
147
|
+
expect(valueField!.value).toBe('1.5k');
|
|
148
148
|
});
|
|
149
149
|
|
|
150
150
|
it('tooltip title uses temporal x-axis value', () => {
|