@opendata-ai/openchart-engine 8.0.0-rc.9 → 8.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +175 -12
- package/dist/index.js +917 -168
- package/dist/index.js.map +1 -1
- package/package.json +3 -4
- package/src/__test-fixtures__/specs.ts +0 -182
- package/src/__tests__/__snapshots__/compile-snapshot.test.ts.snap +0 -2401
- package/src/__tests__/annotation-behavior.test.ts +0 -852
- package/src/__tests__/axes.test.ts +0 -1579
- package/src/__tests__/compile-animation.test.ts +0 -161
- package/src/__tests__/compile-chart.test.ts +0 -1303
- package/src/__tests__/compile-footnotes.test.ts +0 -277
- package/src/__tests__/compile-layer.test.ts +0 -969
- package/src/__tests__/compile-snapshot.test.ts +0 -156
- package/src/__tests__/compound-labels.test.ts +0 -147
- package/src/__tests__/dimensions.test.ts +0 -918
- package/src/__tests__/encoding-sugar.test.ts +0 -390
- package/src/__tests__/facet.test.ts +0 -215
- package/src/__tests__/helpers/invariants.ts +0 -299
- package/src/__tests__/known-bugs.test.ts +0 -566
- package/src/__tests__/layout-fuzz.test.ts +0 -358
- package/src/__tests__/layout-invariants.test.ts +0 -535
- package/src/__tests__/legend.test.ts +0 -721
- package/src/__tests__/mark-keys.test.ts +0 -294
- package/src/__tests__/ranking-recipes.test.ts +0 -260
- package/src/__tests__/rotation.test.ts +0 -83
- package/src/__tests__/scales.test.ts +0 -323
- package/src/__tests__/series-search.test.ts +0 -92
- package/src/__tests__/spec-sugar.test.ts +0 -801
- package/src/__tests__/you-draw-it.test.ts +0 -160
- package/src/annotations/__tests__/compute.test.ts +0 -1672
- package/src/annotations/__tests__/geometry.test.ts +0 -66
- package/src/annotations/__tests__/placement-fuzz.test.ts +0 -256
- package/src/annotations/__tests__/placement-invariants.test.ts +0 -345
- package/src/annotations/__tests__/placement.test.ts +0 -316
- package/src/annotations/__tests__/resolve-text.test.ts +0 -788
- package/src/annotations/__tests__/rich-text.test.ts +0 -91
- package/src/annotations/__tests__/thinning.test.ts +0 -285
- package/src/annotations/collisions.ts +0 -326
- package/src/annotations/compute.ts +0 -333
- package/src/annotations/constants.ts +0 -162
- package/src/annotations/geometry.ts +0 -376
- package/src/annotations/move.ts +0 -135
- package/src/annotations/placement.ts +0 -636
- package/src/annotations/position.ts +0 -131
- package/src/annotations/resolve-range.ts +0 -117
- package/src/annotations/resolve-refline.ts +0 -157
- package/src/annotations/resolve-text.ts +0 -545
- package/src/annotations/rich-text.ts +0 -65
- package/src/annotations/thinning.ts +0 -190
- package/src/barlist/__tests__/compile-barlist.test.ts +0 -200
- package/src/barlist/compile-barlist.ts +0 -391
- package/src/barlist/types.ts +0 -28
- package/src/charts/__tests__/post-process.test.ts +0 -237
- package/src/charts/__tests__/registry.test.ts +0 -116
- package/src/charts/__tests__/utils.test.ts +0 -195
- package/src/charts/_shared/__tests__/density-filter.test.ts +0 -32
- package/src/charts/_shared/density-filter.ts +0 -26
- package/src/charts/_shared/format-label-value.ts +0 -16
- package/src/charts/bar/__tests__/compute.test.ts +0 -934
- package/src/charts/bar/__tests__/gradient-orient.test.ts +0 -127
- package/src/charts/bar/__tests__/labels.test.ts +0 -292
- package/src/charts/bar/compute.ts +0 -539
- package/src/charts/bar/index.ts +0 -60
- package/src/charts/bar/labels.ts +0 -311
- package/src/charts/beeswarm/__tests__/compute.test.ts +0 -280
- package/src/charts/beeswarm/__tests__/dodge.test.ts +0 -148
- package/src/charts/beeswarm/compute.ts +0 -203
- package/src/charts/beeswarm/dodge.ts +0 -155
- package/src/charts/beeswarm/index.ts +0 -32
- package/src/charts/builtin.ts +0 -75
- package/src/charts/calendar/__tests__/compute.test.ts +0 -417
- package/src/charts/calendar/compute.ts +0 -319
- package/src/charts/calendar/index.ts +0 -32
- package/src/charts/column/__tests__/compute.test.ts +0 -540
- package/src/charts/column/__tests__/labels.test.ts +0 -179
- package/src/charts/column/compute.ts +0 -493
- package/src/charts/column/index.ts +0 -53
- package/src/charts/column/labels.ts +0 -229
- package/src/charts/dot/__tests__/compute.test.ts +0 -380
- package/src/charts/dot/__tests__/labels.test.ts +0 -98
- package/src/charts/dot/compute.ts +0 -285
- package/src/charts/dot/index.ts +0 -62
- package/src/charts/dot/labels.ts +0 -121
- package/src/charts/line/__tests__/compute.test.ts +0 -1194
- package/src/charts/line/__tests__/curves.test.ts +0 -51
- package/src/charts/line/__tests__/labels.test.ts +0 -94
- package/src/charts/line/__tests__/mark-options.test.ts +0 -175
- package/src/charts/line/area.ts +0 -484
- package/src/charts/line/compute.ts +0 -356
- package/src/charts/line/curves.ts +0 -85
- package/src/charts/line/index.ts +0 -176
- package/src/charts/line/labels.ts +0 -177
- package/src/charts/parliament/__tests__/compute.test.ts +0 -411
- package/src/charts/parliament/compute.ts +0 -313
- package/src/charts/parliament/index.ts +0 -32
- package/src/charts/pie/__tests__/compute.test.ts +0 -384
- package/src/charts/pie/__tests__/labels.test.ts +0 -132
- package/src/charts/pie/compute.ts +0 -324
- package/src/charts/pie/index.ts +0 -49
- package/src/charts/pie/labels.ts +0 -143
- package/src/charts/post-process.ts +0 -229
- package/src/charts/range/__tests__/compute.test.ts +0 -486
- package/src/charts/range/compute.ts +0 -273
- package/src/charts/range/index.ts +0 -82
- package/src/charts/range/labels.ts +0 -169
- package/src/charts/rect/__tests__/compute.test.ts +0 -120
- package/src/charts/rect/index.ts +0 -127
- package/src/charts/registry.ts +0 -72
- package/src/charts/rule/index.ts +0 -139
- package/src/charts/scatter/__tests__/compute.test.ts +0 -488
- package/src/charts/scatter/__tests__/trendline.test.ts +0 -191
- package/src/charts/scatter/compute.ts +0 -192
- package/src/charts/scatter/index.ts +0 -46
- package/src/charts/scatter/trendline.ts +0 -100
- package/src/charts/text/__tests__/compute.test.ts +0 -307
- package/src/charts/text/index.ts +0 -141
- package/src/charts/tick/__tests__/compute.test.ts +0 -75
- package/src/charts/tick/index.ts +0 -99
- package/src/charts/utils.ts +0 -170
- package/src/charts/waffle/__tests__/compute.test.ts +0 -305
- package/src/charts/waffle/compute.ts +0 -197
- package/src/charts/waffle/index.ts +0 -31
- package/src/compile/__tests__/color-scale-range.test.ts +0 -158
- package/src/compile/__tests__/color-scale-reverse.test.ts +0 -89
- package/src/compile/__tests__/data-clip.test.ts +0 -127
- package/src/compile/__tests__/fill-patterns.test.ts +0 -154
- package/src/compile/__tests__/size-scale.test.ts +0 -108
- package/src/compile/__tests__/watermark-obstacle.test.ts +0 -93
- package/src/compile/color-scale-range.ts +0 -101
- package/src/compile/data-clip.ts +0 -48
- package/src/compile/fill-patterns.ts +0 -74
- package/src/compile/layer.ts +0 -630
- package/src/compile/size-scale.ts +0 -141
- package/src/compile/spec-sugar.ts +0 -758
- package/src/compile/watermark-obstacle.ts +0 -54
- package/src/compile/you-draw-it.ts +0 -123
- package/src/compile.ts +0 -1503
- package/src/compiler/__tests__/a11y-warnings.test.ts +0 -148
- package/src/compiler/__tests__/animation.test.ts +0 -177
- package/src/compiler/__tests__/compile.test.ts +0 -87
- package/src/compiler/__tests__/fixtures/vl-parity/axis-null.json +0 -19
- package/src/compiler/__tests__/fixtures/vl-parity/color-value.json +0 -20
- package/src/compiler/__tests__/fixtures/vl-parity/count-aggregate.json +0 -22
- package/src/compiler/__tests__/fixtures/vl-parity/data-values.json +0 -19
- package/src/compiler/__tests__/fixtures/vl-parity/layer-axis-null.json +0 -14
- package/src/compiler/__tests__/fixtures/vl-parity/layer-count.json +0 -34
- package/src/compiler/__tests__/fixtures/vl-parity/layer-data-values.json +0 -22
- package/src/compiler/__tests__/fixtures/vl-parity/layer-legend-null.json +0 -41
- package/src/compiler/__tests__/fixtures/vl-parity/layer-scheme.json +0 -38
- package/src/compiler/__tests__/fixtures/vl-parity/layer-sort.json +0 -28
- package/src/compiler/__tests__/fixtures/vl-parity/layer-theta.json +0 -28
- package/src/compiler/__tests__/fixtures/vl-parity/layer-title.json +0 -30
- package/src/compiler/__tests__/fixtures/vl-parity/layer-value-def.json +0 -29
- package/src/compiler/__tests__/fixtures/vl-parity/legend-null.json +0 -32
- package/src/compiler/__tests__/fixtures/vl-parity/scheme.json +0 -25
- package/src/compiler/__tests__/fixtures/vl-parity/sort-by-value.json +0 -19
- package/src/compiler/__tests__/fixtures/vl-parity/theta-arc.json +0 -19
- package/src/compiler/__tests__/fixtures/vl-parity/title-subtitle.json +0 -21
- package/src/compiler/__tests__/fixtures/vl-parity/width-height.json +0 -23
- package/src/compiler/__tests__/keys.test.ts +0 -83
- package/src/compiler/__tests__/normalize-highlight.test.ts +0 -103
- package/src/compiler/__tests__/normalize.test.ts +0 -399
- package/src/compiler/__tests__/sparkline-defaults.test.ts +0 -153
- package/src/compiler/__tests__/validate-did-you-mean.test.ts +0 -170
- package/src/compiler/__tests__/validate-highlight.test.ts +0 -112
- package/src/compiler/__tests__/validate-near-miss.test.ts +0 -251
- package/src/compiler/__tests__/validate.test.ts +0 -629
- package/src/compiler/__tests__/vl-parity.test.ts +0 -68
- package/src/compiler/a11y-warnings.ts +0 -110
- package/src/compiler/animation.ts +0 -142
- package/src/compiler/index.ts +0 -47
- package/src/compiler/keys.ts +0 -55
- package/src/compiler/normalize.ts +0 -734
- package/src/compiler/sparkline-defaults.ts +0 -138
- package/src/compiler/types.ts +0 -241
- package/src/compiler/validate.ts +0 -2041
- package/src/endpoint-labels/__tests__/compute.test.ts +0 -587
- package/src/endpoint-labels/compute.ts +0 -621
- package/src/endpoint-labels/constants.ts +0 -54
- package/src/endpoint-labels/format.ts +0 -60
- package/src/endpoint-labels/predict.ts +0 -139
- package/src/format/__tests__/field-format.test.ts +0 -164
- package/src/format/field-format.ts +0 -27
- package/src/geo/__tests__/compile-map.test.ts +0 -1128
- package/src/geo/compile-map.ts +0 -1376
- package/src/geo/join.ts +0 -115
- package/src/geo/projections.ts +0 -65
- package/src/geo/types.ts +0 -26
- package/src/graphs/__tests__/community.test.ts +0 -228
- package/src/graphs/__tests__/compile-graph.test.ts +0 -396
- package/src/graphs/__tests__/encoding.test.ts +0 -415
- package/src/graphs/community.ts +0 -92
- package/src/graphs/compile-graph.ts +0 -329
- package/src/graphs/encoding.ts +0 -356
- package/src/graphs/types.ts +0 -106
- package/src/index.ts +0 -177
- package/src/layout/__tests__/metrics.test.ts +0 -97
- package/src/layout/__tests__/scales-highlight.test.ts +0 -192
- package/src/layout/axes/rotation.ts +0 -152
- package/src/layout/axes/thinning.ts +0 -98
- package/src/layout/axes/ticks.ts +0 -409
- package/src/layout/axes.ts +0 -757
- package/src/layout/dimensions.ts +0 -912
- package/src/layout/facet.ts +0 -91
- package/src/layout/gridlines.ts +0 -84
- package/src/layout/metrics.ts +0 -132
- package/src/layout/plan.ts +0 -631
- package/src/layout/scales.ts +0 -1053
- package/src/layout/shared.ts +0 -44
- package/src/legend/__tests__/continuous.test.ts +0 -318
- package/src/legend/__tests__/redundancy.test.ts +0 -108
- package/src/legend/__tests__/size.test.ts +0 -348
- package/src/legend/__tests__/suppression.test.ts +0 -382
- package/src/legend/compute.ts +0 -748
- package/src/legend/continuous.ts +0 -327
- package/src/legend/size.ts +0 -407
- package/src/legend/suppression.ts +0 -226
- package/src/legend/wrap.ts +0 -117
- package/src/sankey/__tests__/compile-sankey.test.ts +0 -458
- package/src/sankey/__tests__/layout.test.ts +0 -165
- package/src/sankey/__tests__/node-label-wrap.test.ts +0 -114
- package/src/sankey/__tests__/node-sort.test.ts +0 -45
- package/src/sankey/compile-sankey.ts +0 -706
- package/src/sankey/layout.ts +0 -184
- package/src/sankey/types.ts +0 -41
- package/src/tables/__tests__/bar-column.test.ts +0 -147
- package/src/tables/__tests__/category-colors.test.ts +0 -230
- package/src/tables/__tests__/compile-table.test.ts +0 -236
- package/src/tables/__tests__/format-cells.test.ts +0 -143
- package/src/tables/__tests__/heatmap.test.ts +0 -148
- package/src/tables/__tests__/pagination.test.ts +0 -78
- package/src/tables/__tests__/search.test.ts +0 -94
- package/src/tables/__tests__/sort.test.ts +0 -107
- package/src/tables/__tests__/sparkline.test.ts +0 -122
- package/src/tables/bar-column.ts +0 -94
- package/src/tables/category-colors.ts +0 -78
- package/src/tables/compile-table.ts +0 -427
- package/src/tables/format-cells.ts +0 -115
- package/src/tables/heatmap.ts +0 -141
- package/src/tables/pagination.ts +0 -46
- package/src/tables/search.ts +0 -66
- package/src/tables/sort.ts +0 -69
- package/src/tables/sparkline.ts +0 -113
- package/src/tables/utils.ts +0 -16
- package/src/tilemap/__tests__/compile-tilemap.test.ts +0 -576
- package/src/tilemap/compile-tilemap.ts +0 -755
- package/src/tilemap/layout.ts +0 -172
- package/src/tilemap/types.ts +0 -33
- package/src/tooltips/__tests__/compute.test.ts +0 -582
- package/src/tooltips/compute.ts +0 -700
- package/src/transforms/__tests__/aggregate.test.ts +0 -159
- package/src/transforms/__tests__/bin.test.ts +0 -88
- package/src/transforms/__tests__/calculate.test.ts +0 -146
- package/src/transforms/__tests__/conditional.test.ts +0 -127
- package/src/transforms/__tests__/filter-relative.test.ts +0 -202
- package/src/transforms/__tests__/filter.test.ts +0 -59
- package/src/transforms/__tests__/fold.test.ts +0 -79
- package/src/transforms/__tests__/index.test.ts +0 -93
- package/src/transforms/__tests__/predicates.test.ts +0 -193
- package/src/transforms/__tests__/timeunit.test.ts +0 -129
- package/src/transforms/__tests__/window.test.ts +0 -286
- package/src/transforms/aggregate.ts +0 -131
- package/src/transforms/bin.ts +0 -87
- package/src/transforms/calculate.ts +0 -60
- package/src/transforms/conditional.ts +0 -46
- package/src/transforms/filter.ts +0 -122
- package/src/transforms/fold.ts +0 -49
- package/src/transforms/index.ts +0 -60
- package/src/transforms/predicates.ts +0 -123
- package/src/transforms/timeunit.ts +0 -88
- package/src/transforms/window.ts +0 -185
|
@@ -1,323 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from 'vitest';
|
|
2
|
-
import type { NormalizedChartSpec } from '../compiler/types';
|
|
3
|
-
import { computeScales } from '../layout/scales';
|
|
4
|
-
|
|
5
|
-
const lineSpec: NormalizedChartSpec = {
|
|
6
|
-
markType: 'line',
|
|
7
|
-
markDef: { type: 'line' },
|
|
8
|
-
data: [
|
|
9
|
-
{ date: '2020-01-01', value: 10, country: 'US' },
|
|
10
|
-
{ date: '2021-01-01', value: 50, country: 'US' },
|
|
11
|
-
{ date: '2022-01-01', value: 30, country: 'UK' },
|
|
12
|
-
],
|
|
13
|
-
encoding: {
|
|
14
|
-
x: { field: 'date', type: 'temporal' },
|
|
15
|
-
y: { field: 'value', type: 'quantitative' },
|
|
16
|
-
color: { field: 'country', type: 'nominal' },
|
|
17
|
-
},
|
|
18
|
-
chrome: {},
|
|
19
|
-
annotations: [],
|
|
20
|
-
responsive: true,
|
|
21
|
-
theme: {},
|
|
22
|
-
darkMode: 'off',
|
|
23
|
-
labels: { density: 'auto', format: '' },
|
|
24
|
-
};
|
|
25
|
-
|
|
26
|
-
const barSpec: NormalizedChartSpec = {
|
|
27
|
-
markType: 'bar',
|
|
28
|
-
markDef: { type: 'bar' },
|
|
29
|
-
data: [
|
|
30
|
-
{ category: 'A', count: 10 },
|
|
31
|
-
{ category: 'B', count: 30 },
|
|
32
|
-
{ category: 'C', count: 20 },
|
|
33
|
-
],
|
|
34
|
-
encoding: {
|
|
35
|
-
x: { field: 'count', type: 'quantitative' },
|
|
36
|
-
y: { field: 'category', type: 'nominal' },
|
|
37
|
-
},
|
|
38
|
-
chrome: {},
|
|
39
|
-
annotations: [],
|
|
40
|
-
responsive: true,
|
|
41
|
-
theme: {},
|
|
42
|
-
darkMode: 'off',
|
|
43
|
-
labels: { density: 'auto', format: '' },
|
|
44
|
-
};
|
|
45
|
-
|
|
46
|
-
const chartArea = { x: 50, y: 50, width: 500, height: 300 };
|
|
47
|
-
|
|
48
|
-
describe('computeScales', () => {
|
|
49
|
-
it('creates a time scale for temporal x encoding', () => {
|
|
50
|
-
const scales = computeScales(lineSpec, chartArea, lineSpec.data);
|
|
51
|
-
expect(scales.x).toBeDefined();
|
|
52
|
-
expect(scales.x!.type).toBe('time');
|
|
53
|
-
|
|
54
|
-
// The scale should map dates within the range
|
|
55
|
-
const pos = scales.x!.scale(new Date('2020-06-01'));
|
|
56
|
-
expect(pos).toBeGreaterThanOrEqual(chartArea.x);
|
|
57
|
-
expect(pos).toBeLessThanOrEqual(chartArea.x + chartArea.width);
|
|
58
|
-
});
|
|
59
|
-
|
|
60
|
-
it('creates a linear scale for quantitative y encoding', () => {
|
|
61
|
-
const scales = computeScales(lineSpec, chartArea, lineSpec.data);
|
|
62
|
-
expect(scales.y).toBeDefined();
|
|
63
|
-
expect(scales.y!.type).toBe('linear');
|
|
64
|
-
|
|
65
|
-
// Y is inverted (SVG coordinates); line charts default to zero: false
|
|
66
|
-
const domain = scales.y!.scale.domain();
|
|
67
|
-
expect(domain[0]).toBeLessThanOrEqual(10);
|
|
68
|
-
expect(domain[1]).toBeGreaterThanOrEqual(50);
|
|
69
|
-
});
|
|
70
|
-
|
|
71
|
-
it('line charts exclude zero by default (zero: false)', () => {
|
|
72
|
-
const scales = computeScales(lineSpec, chartArea, lineSpec.data);
|
|
73
|
-
const domain = scales.y!.scale.domain();
|
|
74
|
-
expect(domain[0]).toBeGreaterThan(0);
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
it('bar charts include zero by default', () => {
|
|
78
|
-
const scales = computeScales(barSpec, chartArea, barSpec.data);
|
|
79
|
-
const domain = scales.x!.scale.domain();
|
|
80
|
-
expect(domain[0]).toBe(0);
|
|
81
|
-
});
|
|
82
|
-
|
|
83
|
-
it('creates an ordinal scale for color encoding', () => {
|
|
84
|
-
const scales = computeScales(lineSpec, chartArea, lineSpec.data);
|
|
85
|
-
expect(scales.color).toBeDefined();
|
|
86
|
-
expect(scales.color!.type).toBe('ordinal');
|
|
87
|
-
|
|
88
|
-
const usColor = scales.color!.scale('US');
|
|
89
|
-
const ukColor = scales.color!.scale('UK');
|
|
90
|
-
expect(typeof usColor).toBe('string');
|
|
91
|
-
expect(usColor).not.toBe(ukColor);
|
|
92
|
-
});
|
|
93
|
-
|
|
94
|
-
it('creates band scales for bar chart categorical axis', () => {
|
|
95
|
-
const scales = computeScales(barSpec, chartArea, barSpec.data);
|
|
96
|
-
expect(scales.y).toBeDefined();
|
|
97
|
-
expect(scales.y!.type).toBe('band');
|
|
98
|
-
|
|
99
|
-
// Band scale should have bandwidth
|
|
100
|
-
expect(scales.y!.scale.bandwidth()).toBeGreaterThan(0);
|
|
101
|
-
});
|
|
102
|
-
|
|
103
|
-
it('derives correct domain from data', () => {
|
|
104
|
-
const scales = computeScales(barSpec, chartArea, barSpec.data);
|
|
105
|
-
|
|
106
|
-
// Y should have all categories
|
|
107
|
-
const yDomain = scales.y!.scale.domain();
|
|
108
|
-
expect(yDomain).toContain('A');
|
|
109
|
-
expect(yDomain).toContain('B');
|
|
110
|
-
expect(yDomain).toContain('C');
|
|
111
|
-
|
|
112
|
-
// X domain should span 0 to >= max value
|
|
113
|
-
const xDomain = scales.x!.scale.domain();
|
|
114
|
-
expect(xDomain[0]).toBe(0);
|
|
115
|
-
expect(xDomain[1]).toBeGreaterThanOrEqual(30);
|
|
116
|
-
});
|
|
117
|
-
});
|
|
118
|
-
|
|
119
|
-
// ---------------------------------------------------------------------------
|
|
120
|
-
// Expanded scale type tests
|
|
121
|
-
// ---------------------------------------------------------------------------
|
|
122
|
-
|
|
123
|
-
/** Helper to make a spec with an explicit scale type on the y axis. */
|
|
124
|
-
function makeQuantSpec(scaleConfig: Record<string, unknown>): NormalizedChartSpec {
|
|
125
|
-
return {
|
|
126
|
-
markType: 'line',
|
|
127
|
-
markDef: { type: 'line' },
|
|
128
|
-
data: [
|
|
129
|
-
{ x: 1, y: 1 },
|
|
130
|
-
{ x: 2, y: 10 },
|
|
131
|
-
{ x: 3, y: 100 },
|
|
132
|
-
{ x: 4, y: 1000 },
|
|
133
|
-
],
|
|
134
|
-
encoding: {
|
|
135
|
-
x: { field: 'x', type: 'quantitative' },
|
|
136
|
-
y: { field: 'y', type: 'quantitative', scale: scaleConfig },
|
|
137
|
-
},
|
|
138
|
-
chrome: {},
|
|
139
|
-
annotations: [],
|
|
140
|
-
responsive: true,
|
|
141
|
-
theme: {},
|
|
142
|
-
darkMode: 'off',
|
|
143
|
-
labels: { density: 'auto', format: '' },
|
|
144
|
-
} as NormalizedChartSpec;
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
describe('expanded scale types', () => {
|
|
148
|
-
it('creates a log scale with explicit type override', () => {
|
|
149
|
-
const spec = makeQuantSpec({ type: 'log' });
|
|
150
|
-
const scales = computeScales(spec, chartArea, spec.data);
|
|
151
|
-
expect(scales.y!.type).toBe('log');
|
|
152
|
-
// Log scale maps multiplicatively - position for 10 should be between 1 and 100
|
|
153
|
-
const pos1 = scales.y!.scale(1) as number;
|
|
154
|
-
const pos10 = scales.y!.scale(10) as number;
|
|
155
|
-
const pos100 = scales.y!.scale(100) as number;
|
|
156
|
-
expect(pos10).toBeLessThan(pos1); // Y is inverted
|
|
157
|
-
expect(pos10).toBeGreaterThan(pos100);
|
|
158
|
-
});
|
|
159
|
-
|
|
160
|
-
it('applies base config to log scale', () => {
|
|
161
|
-
const spec = makeQuantSpec({ type: 'log', base: 2 });
|
|
162
|
-
const scales = computeScales(spec, chartArea, spec.data);
|
|
163
|
-
expect(scales.y!.type).toBe('log');
|
|
164
|
-
});
|
|
165
|
-
|
|
166
|
-
it('creates a pow scale with exponent', () => {
|
|
167
|
-
const spec = makeQuantSpec({ type: 'pow', exponent: 2 });
|
|
168
|
-
const scales = computeScales(spec, chartArea, spec.data);
|
|
169
|
-
expect(scales.y!.type).toBe('pow');
|
|
170
|
-
// Pow scale should still map data to pixel range
|
|
171
|
-
const pos = scales.y!.scale(50) as number;
|
|
172
|
-
expect(pos).toBeGreaterThanOrEqual(chartArea.y);
|
|
173
|
-
expect(pos).toBeLessThanOrEqual(chartArea.y + chartArea.height);
|
|
174
|
-
});
|
|
175
|
-
|
|
176
|
-
it('creates a sqrt scale', () => {
|
|
177
|
-
const spec = makeQuantSpec({ type: 'sqrt' });
|
|
178
|
-
const scales = computeScales(spec, chartArea, spec.data);
|
|
179
|
-
expect(scales.y!.type).toBe('sqrt');
|
|
180
|
-
});
|
|
181
|
-
|
|
182
|
-
it('creates a symlog scale with constant', () => {
|
|
183
|
-
const spec = makeQuantSpec({ type: 'symlog', constant: 2 });
|
|
184
|
-
const scales = computeScales(spec, chartArea, spec.data);
|
|
185
|
-
expect(scales.y!.type).toBe('symlog');
|
|
186
|
-
});
|
|
187
|
-
|
|
188
|
-
it('creates a utc scale for explicit utc type', () => {
|
|
189
|
-
const spec: NormalizedChartSpec = {
|
|
190
|
-
markType: 'line',
|
|
191
|
-
markDef: { type: 'line' },
|
|
192
|
-
data: [
|
|
193
|
-
{ date: '2020-01-01', value: 10 },
|
|
194
|
-
{ date: '2022-01-01', value: 30 },
|
|
195
|
-
],
|
|
196
|
-
encoding: {
|
|
197
|
-
x: { field: 'date', type: 'temporal', scale: { type: 'utc' } },
|
|
198
|
-
y: { field: 'value', type: 'quantitative' },
|
|
199
|
-
},
|
|
200
|
-
chrome: {},
|
|
201
|
-
annotations: [],
|
|
202
|
-
responsive: true,
|
|
203
|
-
theme: {},
|
|
204
|
-
darkMode: 'off',
|
|
205
|
-
labels: { density: 'auto', format: '' },
|
|
206
|
-
};
|
|
207
|
-
const scales = computeScales(spec, chartArea, spec.data);
|
|
208
|
-
expect(scales.x!.type).toBe('utc');
|
|
209
|
-
});
|
|
210
|
-
|
|
211
|
-
it('creates a quantile scale', () => {
|
|
212
|
-
const spec = makeQuantSpec({ type: 'quantile' });
|
|
213
|
-
const scales = computeScales(spec, chartArea, spec.data);
|
|
214
|
-
expect(scales.y!.type).toBe('quantile');
|
|
215
|
-
});
|
|
216
|
-
|
|
217
|
-
it('creates a quantize scale', () => {
|
|
218
|
-
const spec = makeQuantSpec({ type: 'quantize' });
|
|
219
|
-
const scales = computeScales(spec, chartArea, spec.data);
|
|
220
|
-
expect(scales.y!.type).toBe('quantize');
|
|
221
|
-
});
|
|
222
|
-
|
|
223
|
-
it('creates a threshold scale', () => {
|
|
224
|
-
const spec = makeQuantSpec({ type: 'threshold', domain: [10, 100] });
|
|
225
|
-
const scales = computeScales(spec, chartArea, spec.data);
|
|
226
|
-
expect(scales.y!.type).toBe('threshold');
|
|
227
|
-
});
|
|
228
|
-
});
|
|
229
|
-
|
|
230
|
-
describe('scale config properties', () => {
|
|
231
|
-
it('applies clamp to linear scale', () => {
|
|
232
|
-
const spec = makeQuantSpec({ type: 'linear', domain: [0, 100], clamp: true });
|
|
233
|
-
const scales = computeScales(spec, chartArea, spec.data);
|
|
234
|
-
// Values outside domain should be clamped to range edges
|
|
235
|
-
const posAbove = scales.y!.scale(200) as number;
|
|
236
|
-
const posAtMax = scales.y!.scale(100) as number;
|
|
237
|
-
expect(posAbove).toBe(posAtMax);
|
|
238
|
-
});
|
|
239
|
-
|
|
240
|
-
it('applies reverse to linear scale', () => {
|
|
241
|
-
const specNormal = makeQuantSpec({ type: 'linear' });
|
|
242
|
-
const specReversed = makeQuantSpec({ type: 'linear', reverse: true });
|
|
243
|
-
const normal = computeScales(specNormal, chartArea, specNormal.data);
|
|
244
|
-
const reversed = computeScales(specReversed, chartArea, specReversed.data);
|
|
245
|
-
|
|
246
|
-
// In a reversed scale, higher values should map to the opposite end
|
|
247
|
-
const normalRange = normal.y!.scale.range() as number[];
|
|
248
|
-
const reversedRange = reversed.y!.scale.range() as number[];
|
|
249
|
-
expect(normalRange[0]).toBe(reversedRange[1]);
|
|
250
|
-
expect(normalRange[1]).toBe(reversedRange[0]);
|
|
251
|
-
});
|
|
252
|
-
|
|
253
|
-
it('applies padding to band scale', () => {
|
|
254
|
-
const specDefault: NormalizedChartSpec = {
|
|
255
|
-
...barSpec,
|
|
256
|
-
encoding: {
|
|
257
|
-
x: { field: 'count', type: 'quantitative' },
|
|
258
|
-
y: { field: 'category', type: 'nominal' },
|
|
259
|
-
},
|
|
260
|
-
};
|
|
261
|
-
const specPadded: NormalizedChartSpec = {
|
|
262
|
-
...barSpec,
|
|
263
|
-
encoding: {
|
|
264
|
-
x: { field: 'count', type: 'quantitative' },
|
|
265
|
-
y: { field: 'category', type: 'nominal', scale: { padding: 0.1 } },
|
|
266
|
-
},
|
|
267
|
-
};
|
|
268
|
-
|
|
269
|
-
const defaultScales = computeScales(specDefault, chartArea, specDefault.data);
|
|
270
|
-
const paddedScales = computeScales(specPadded, chartArea, specPadded.data);
|
|
271
|
-
|
|
272
|
-
// Smaller padding = wider bands
|
|
273
|
-
const defaultBandwidth = defaultScales.y!.scale.bandwidth!() as number;
|
|
274
|
-
const paddedBandwidth = paddedScales.y!.scale.bandwidth!() as number;
|
|
275
|
-
expect(paddedBandwidth).toBeGreaterThan(defaultBandwidth);
|
|
276
|
-
});
|
|
277
|
-
|
|
278
|
-
it('point scale honors paddingOuter as a padding alias', () => {
|
|
279
|
-
const ordinalBase = {
|
|
280
|
-
...lineSpec,
|
|
281
|
-
data: [
|
|
282
|
-
{ year: 'A', value: 10 },
|
|
283
|
-
{ year: 'B', value: 20 },
|
|
284
|
-
{ year: 'C', value: 30 },
|
|
285
|
-
],
|
|
286
|
-
};
|
|
287
|
-
const wide: NormalizedChartSpec = {
|
|
288
|
-
...ordinalBase,
|
|
289
|
-
encoding: {
|
|
290
|
-
x: { field: 'year', type: 'ordinal', scale: { paddingOuter: 0.5 } },
|
|
291
|
-
y: { field: 'value', type: 'quantitative' },
|
|
292
|
-
},
|
|
293
|
-
};
|
|
294
|
-
const tight: NormalizedChartSpec = {
|
|
295
|
-
...ordinalBase,
|
|
296
|
-
encoding: {
|
|
297
|
-
x: { field: 'year', type: 'ordinal', scale: { paddingOuter: 0.04 } },
|
|
298
|
-
y: { field: 'value', type: 'quantitative' },
|
|
299
|
-
},
|
|
300
|
-
};
|
|
301
|
-
|
|
302
|
-
const wideScales = computeScales(wide, chartArea, wide.data);
|
|
303
|
-
const tightScales = computeScales(tight, chartArea, tight.data);
|
|
304
|
-
expect(wideScales.x!.type).toBe('point');
|
|
305
|
-
|
|
306
|
-
// Less outer padding pushes the first point closer to the left edge.
|
|
307
|
-
const wideFirst = wideScales.x!.scale('A') as number;
|
|
308
|
-
const tightFirst = tightScales.x!.scale('A') as number;
|
|
309
|
-
expect(tightFirst).toBeLessThan(wideFirst);
|
|
310
|
-
});
|
|
311
|
-
|
|
312
|
-
it('backward compatible: existing specs still work', () => {
|
|
313
|
-
// lineSpec and barSpec from before should still produce valid scales
|
|
314
|
-
const lineScales = computeScales(lineSpec, chartArea, lineSpec.data);
|
|
315
|
-
expect(lineScales.x!.type).toBe('time');
|
|
316
|
-
expect(lineScales.y!.type).toBe('linear');
|
|
317
|
-
expect(lineScales.color!.type).toBe('ordinal');
|
|
318
|
-
|
|
319
|
-
const barScales = computeScales(barSpec, chartArea, barSpec.data);
|
|
320
|
-
expect(barScales.x!.type).toBe('linear');
|
|
321
|
-
expect(barScales.y!.type).toBe('band');
|
|
322
|
-
});
|
|
323
|
-
});
|
|
@@ -1,92 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* seriesSearch compilation: band reservation and resolved content.
|
|
3
|
-
*
|
|
4
|
-
* The engine reserves an empty SVG band below chrome (and the metric bar)
|
|
5
|
-
* and exposes its rect + the searchable values on layout.seriesSearch; the
|
|
6
|
-
* vanilla adapter overlays the DOM combobox on that rect.
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
import { describe, expect, it, vi } from 'vitest';
|
|
10
|
-
import { compileChart } from '../compile';
|
|
11
|
-
|
|
12
|
-
const searchSpec = {
|
|
13
|
-
mark: 'line' as const,
|
|
14
|
-
data: [
|
|
15
|
-
{ date: '2020-01-01', value: 10, country: 'US' },
|
|
16
|
-
{ date: '2021-01-01', value: 40, country: 'US' },
|
|
17
|
-
{ date: '2020-01-01', value: 15, country: 'UK' },
|
|
18
|
-
{ date: '2021-01-01', value: 35, country: 'UK' },
|
|
19
|
-
{ date: '2020-01-01', value: 22, country: 'France' },
|
|
20
|
-
{ date: '2021-01-01', value: 28, country: 'France' },
|
|
21
|
-
],
|
|
22
|
-
encoding: {
|
|
23
|
-
x: { field: 'date', type: 'temporal' as const },
|
|
24
|
-
y: { field: 'value', type: 'quantitative' as const },
|
|
25
|
-
color: { field: 'country', type: 'nominal' as const },
|
|
26
|
-
},
|
|
27
|
-
chrome: { title: 'Find your country' },
|
|
28
|
-
};
|
|
29
|
-
|
|
30
|
-
describe('compileChart seriesSearch', () => {
|
|
31
|
-
it('omits the band when seriesSearch is not set', () => {
|
|
32
|
-
const layout = compileChart(searchSpec, { width: 600, height: 400 });
|
|
33
|
-
expect(layout.seriesSearch).toBeUndefined();
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
it('reserves a band below chrome and shifts the chart area down', () => {
|
|
37
|
-
const base = compileChart(searchSpec, { width: 600, height: 400 });
|
|
38
|
-
const layout = compileChart({ ...searchSpec, seriesSearch: true }, { width: 600, height: 400 });
|
|
39
|
-
|
|
40
|
-
const band = layout.seriesSearch;
|
|
41
|
-
expect(band).toBeDefined();
|
|
42
|
-
expect(band!.height).toBeGreaterThan(0);
|
|
43
|
-
expect(band!.width).toBeGreaterThan(0);
|
|
44
|
-
// Band sits below the top chrome block and above the chart area
|
|
45
|
-
expect(band!.y).toBeGreaterThanOrEqual(layout.chrome.topHeight);
|
|
46
|
-
expect(band!.y + band!.height).toBeLessThanOrEqual(layout.area.y);
|
|
47
|
-
// The reservation pushes the plot down relative to the no-search layout
|
|
48
|
-
expect(layout.area.y).toBeGreaterThan(base.area.y);
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
it('exposes the distinct color values and resolved placeholder', () => {
|
|
52
|
-
const layout = compileChart(
|
|
53
|
-
{ ...searchSpec, seriesSearch: { placeholder: 'Find a country' } },
|
|
54
|
-
{ width: 600, height: 400 },
|
|
55
|
-
);
|
|
56
|
-
expect(layout.seriesSearch?.values).toEqual(['US', 'UK', 'France']);
|
|
57
|
-
expect(layout.seriesSearch?.placeholder).toBe('Find a country');
|
|
58
|
-
|
|
59
|
-
const defaulted = compileChart(
|
|
60
|
-
{ ...searchSpec, seriesSearch: true },
|
|
61
|
-
{ width: 600, height: 400 },
|
|
62
|
-
);
|
|
63
|
-
expect(defaulted.seriesSearch?.placeholder).toBe('Find a series');
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
it('warns and disables when there is no categorical color encoding', () => {
|
|
67
|
-
const warn = vi.spyOn(console, 'warn').mockImplementation(() => {});
|
|
68
|
-
try {
|
|
69
|
-
const layout = compileChart(
|
|
70
|
-
{
|
|
71
|
-
mark: 'line' as const,
|
|
72
|
-
data: [
|
|
73
|
-
{ date: '2020-01-01', value: 10 },
|
|
74
|
-
{ date: '2021-01-01', value: 40 },
|
|
75
|
-
],
|
|
76
|
-
encoding: {
|
|
77
|
-
x: { field: 'date', type: 'temporal' as const },
|
|
78
|
-
y: { field: 'value', type: 'quantitative' as const },
|
|
79
|
-
},
|
|
80
|
-
seriesSearch: true,
|
|
81
|
-
},
|
|
82
|
-
{ width: 600, height: 400 },
|
|
83
|
-
);
|
|
84
|
-
expect(layout.seriesSearch).toBeUndefined();
|
|
85
|
-
expect(warn).toHaveBeenCalledWith(
|
|
86
|
-
expect.stringContaining('seriesSearch requires a categorical color encoding'),
|
|
87
|
-
);
|
|
88
|
-
} finally {
|
|
89
|
-
warn.mockRestore();
|
|
90
|
-
}
|
|
91
|
-
});
|
|
92
|
-
});
|