@opendata-ai/openchart-engine 6.26.0 → 6.27.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 +37 -1
- package/dist/index.js +206 -21
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/src/__test-fixtures__/specs.ts +33 -0
- package/src/__tests__/__snapshots__/compile-snapshot.test.ts.snap +6 -0
- package/src/__tests__/axes.test.ts +101 -3
- package/src/__tests__/compile-chart.test.ts +301 -0
- package/src/annotations/__tests__/compute.test.ts +175 -0
- package/src/annotations/position.ts +37 -1
- package/src/annotations/resolve-range.ts +5 -5
- package/src/charts/bar/__tests__/compute.test.ts +102 -0
- package/src/charts/bar/compute.ts +1 -0
- package/src/charts/line/area.ts +1 -1
- package/src/charts/line/compute.ts +7 -1
- package/src/compile.ts +175 -4
- package/src/compiler/normalize.ts +26 -0
- package/src/compiler/types.ts +38 -0
- package/src/layout/axes/ticks.ts +31 -4
- package/src/layout/axes.ts +18 -4
- package/src/layout/dimensions.ts +77 -2
- package/src/legend/compute.ts +6 -1
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as _opendata_ai_openchart_core from '@opendata-ai/openchart-core';
|
|
2
|
-
import { LegendLayout, ResolvedChrome, TooltipContent, A11yMetadata, ResolvedTheme, CompileOptions, ChartLayout, LayerSpec, CompileTableOptions, TableLayout, AnimationSpec, ResolvedAnimation, TileMapEncoding, TileMapPalette, LegendConfig, ThemeConfig, DarkMode, MarkType, MarkDef, DataRow, Encoding, ChromeText, Annotation, LabelConfig, ColumnConfig, GraphSpec, GraphEncoding, GraphLayoutConfig, NodeOverride, SankeyEncoding, SankeyNodeAlign, SankeyLinkColor, VizSpec, ScaleType, EncodingChannel, Rect, LayoutStrategy, Mark, BinTransform, CalculateTransform, ConditionalValueDef, FilterPredicate, TimeUnitTransform, Transform } from '@opendata-ai/openchart-core';
|
|
2
|
+
import { LegendLayout, ResolvedChrome, TooltipContent, A11yMetadata, ResolvedTheme, CompileOptions, ChartLayout, LayerSpec, CompileTableOptions, TableLayout, AnimationSpec, ResolvedAnimation, TileMapEncoding, TileMapPalette, LegendConfig, ThemeConfig, DarkMode, MarkType, MarkDef, DataRow, Encoding, ChromeText, Annotation, LabelConfig, Display, ColumnConfig, GraphSpec, GraphEncoding, GraphLayoutConfig, NodeOverride, SankeyEncoding, SankeyNodeAlign, SankeyLinkColor, VizSpec, ScaleType, EncodingChannel, Rect, LayoutStrategy, Mark, BinTransform, CalculateTransform, ConditionalValueDef, FilterPredicate, TimeUnitTransform, Transform } from '@opendata-ai/openchart-core';
|
|
3
3
|
export { ChartLayout, ChartSpec, CompileOptions, CompileTableOptions, GraphLayout, GraphSpec, LayerSpec, SankeyLayout, SankeySpec, TableLayout, TableSpec, TileMapLayout, TileMapSpec, VizSpec } from '@opendata-ai/openchart-core';
|
|
4
4
|
import { ScaleLinear, ScaleTime, ScaleLogarithmic, ScalePower, ScaleSymLog, ScaleBand, ScalePoint, ScaleOrdinal, ScaleQuantile, ScaleQuantize, ScaleThreshold } from 'd3-scale';
|
|
5
5
|
|
|
@@ -232,6 +232,34 @@ interface NormalizedChrome {
|
|
|
232
232
|
byline?: ChromeText;
|
|
233
233
|
footer?: ChromeText;
|
|
234
234
|
}
|
|
235
|
+
/**
|
|
236
|
+
* Tracks which top-level fields the user explicitly set in their input spec.
|
|
237
|
+
*
|
|
238
|
+
* Built from the raw expandedSpec (post-breakpoint-merge, pre-normalize) so
|
|
239
|
+
* that "user wrote chrome.title" vs "user wrote nothing" is distinguishable
|
|
240
|
+
* after normalization fills in defaults.
|
|
241
|
+
*
|
|
242
|
+
* Used by sparkline display mode to decide whether to suppress chrome/axes/
|
|
243
|
+
* legend/etc. by default vs. respecting an explicit user opt-in.
|
|
244
|
+
*/
|
|
245
|
+
interface UserExplicit {
|
|
246
|
+
/** True if user wrote `chrome` (any non-empty chrome). */
|
|
247
|
+
chrome: boolean;
|
|
248
|
+
/** True if user wrote `legend`. */
|
|
249
|
+
legend: boolean;
|
|
250
|
+
/** True if user wrote `encoding.x.axis`. */
|
|
251
|
+
xAxis: boolean;
|
|
252
|
+
/** True if user wrote `encoding.y.axis`. */
|
|
253
|
+
yAxis: boolean;
|
|
254
|
+
/** True if user wrote `labels`. */
|
|
255
|
+
labels: boolean;
|
|
256
|
+
/** True if user wrote `animation`. */
|
|
257
|
+
animation: boolean;
|
|
258
|
+
/** True if user wrote `watermark`. */
|
|
259
|
+
watermark: boolean;
|
|
260
|
+
/** True if user wrote `crosshair`. */
|
|
261
|
+
crosshair: boolean;
|
|
262
|
+
}
|
|
235
263
|
/** A ChartSpec with all optional fields filled with sensible defaults. */
|
|
236
264
|
interface NormalizedChartSpec {
|
|
237
265
|
/** Resolved mark type string (extracted from spec.mark). */
|
|
@@ -255,6 +283,14 @@ interface NormalizedChartSpec {
|
|
|
255
283
|
hiddenSeries: string[];
|
|
256
284
|
/** Per-series visual style overrides. */
|
|
257
285
|
seriesStyles: Record<string, _opendata_ai_openchart_core.SeriesStyle>;
|
|
286
|
+
/** Display mode controlling chrome/axes/legend stripping. Defaults to `'full'`. */
|
|
287
|
+
display: Display;
|
|
288
|
+
/**
|
|
289
|
+
* Which top-level fields the user explicitly set. Populated by compileChart
|
|
290
|
+
* from the raw expanded spec before normalization. NormalizeChartSpec runs
|
|
291
|
+
* with a default-empty descriptor; compileChart overwrites it post-normalize.
|
|
292
|
+
*/
|
|
293
|
+
userExplicit: UserExplicit;
|
|
258
294
|
}
|
|
259
295
|
/** A TableSpec with all optional fields filled with sensible defaults. */
|
|
260
296
|
interface NormalizedTableSpec {
|
package/dist/index.js
CHANGED
|
@@ -3692,6 +3692,22 @@ function resolvePosition(value2, scale) {
|
|
|
3692
3692
|
}
|
|
3693
3693
|
return null;
|
|
3694
3694
|
}
|
|
3695
|
+
function resolvePositionEdge(value2, scale, edge) {
|
|
3696
|
+
const center2 = resolvePosition(value2, scale);
|
|
3697
|
+
if (center2 === null || !scale) return null;
|
|
3698
|
+
const type = scale.type;
|
|
3699
|
+
if (type === "point") {
|
|
3700
|
+
const s = scale.scale;
|
|
3701
|
+
const halfStep = (s.step?.() ?? 0) / 2;
|
|
3702
|
+
return edge === "start" ? center2 - halfStep : center2 + halfStep;
|
|
3703
|
+
}
|
|
3704
|
+
if (type === "band") {
|
|
3705
|
+
const s = scale.scale;
|
|
3706
|
+
const halfBw = (s.bandwidth?.() ?? 0) / 2;
|
|
3707
|
+
return edge === "start" ? center2 - halfBw : center2 + halfBw;
|
|
3708
|
+
}
|
|
3709
|
+
return center2;
|
|
3710
|
+
}
|
|
3695
3711
|
|
|
3696
3712
|
// src/annotations/collisions.ts
|
|
3697
3713
|
function generateNudgeCandidates(selfBounds, obstacles, padding) {
|
|
@@ -3924,15 +3940,15 @@ function resolveRangeAnnotation(annotation, scales, chartArea, isDark) {
|
|
|
3924
3940
|
let width = chartArea.width;
|
|
3925
3941
|
let height = chartArea.height;
|
|
3926
3942
|
if (annotation.x1 !== void 0 && annotation.x2 !== void 0) {
|
|
3927
|
-
const x1px =
|
|
3928
|
-
const x2px =
|
|
3943
|
+
const x1px = resolvePositionEdge(annotation.x1, scales.x, "start");
|
|
3944
|
+
const x2px = resolvePositionEdge(annotation.x2, scales.x, "end");
|
|
3929
3945
|
if (x1px === null || x2px === null) return null;
|
|
3930
3946
|
x2 = Math.min(x1px, x2px);
|
|
3931
3947
|
width = Math.abs(x2px - x1px);
|
|
3932
3948
|
}
|
|
3933
3949
|
if (annotation.y1 !== void 0 && annotation.y2 !== void 0) {
|
|
3934
|
-
const y1px =
|
|
3935
|
-
const y2px =
|
|
3950
|
+
const y1px = resolvePositionEdge(annotation.y1, scales.y, "end");
|
|
3951
|
+
const y2px = resolvePositionEdge(annotation.y2, scales.y, "start");
|
|
3936
3952
|
if (y1px === null || y2px === null) return null;
|
|
3937
3953
|
y2 = Math.min(y1px, y2px);
|
|
3938
3954
|
height = Math.abs(y2px - y1px);
|
|
@@ -5351,7 +5367,7 @@ function computeSingleArea(spec, scales, _chartArea) {
|
|
|
5351
5367
|
fill: fillValue,
|
|
5352
5368
|
fillOpacity,
|
|
5353
5369
|
stroke: getRepresentativeColor4(isGradientDef3(fillValue) ? color2 : fillValue),
|
|
5354
|
-
strokeWidth: 2,
|
|
5370
|
+
strokeWidth: spec.display === "sparkline" ? 1.25 : 2,
|
|
5355
5371
|
seriesKey: seriesKey === "__default__" ? void 0 : seriesKey,
|
|
5356
5372
|
data: validPoints.map((p) => p.row),
|
|
5357
5373
|
dataPoints: validPoints.map((p) => ({ x: p.x, y: p.yTop, datum: p.row })),
|
|
@@ -5468,6 +5484,7 @@ function computeAreaMarks(spec, scales, chartArea) {
|
|
|
5468
5484
|
// src/charts/line/compute.ts
|
|
5469
5485
|
import { getRepresentativeColor as getRepresentativeColor5 } from "@opendata-ai/openchart-core";
|
|
5470
5486
|
var DEFAULT_STROKE_WIDTH = 2.5;
|
|
5487
|
+
var SPARKLINE_STROKE_WIDTH = 1.25;
|
|
5471
5488
|
var DEFAULT_POINT_RADIUS = 3;
|
|
5472
5489
|
function computeLineMarks(spec, scales, _chartArea, _strategy) {
|
|
5473
5490
|
const encoding = spec.encoding;
|
|
@@ -5534,7 +5551,7 @@ function computeLineMarks(spec, scales, _chartArea, _strategy) {
|
|
|
5534
5551
|
points: allPoints,
|
|
5535
5552
|
path: combinedPath,
|
|
5536
5553
|
stroke: strokeColor,
|
|
5537
|
-
strokeWidth: styleOverride?.strokeWidth ?? DEFAULT_STROKE_WIDTH,
|
|
5554
|
+
strokeWidth: styleOverride?.strokeWidth ?? (spec.display === "sparkline" ? SPARKLINE_STROKE_WIDTH : DEFAULT_STROKE_WIDTH),
|
|
5538
5555
|
strokeDasharray,
|
|
5539
5556
|
opacity: styleOverride?.opacity,
|
|
5540
5557
|
seriesKey: seriesStyleKey,
|
|
@@ -6812,6 +6829,12 @@ function normalizeChartSpec(spec, warnings) {
|
|
|
6812
6829
|
const encoding = inferEncodingTypes(spec.encoding, spec.data, warnings);
|
|
6813
6830
|
const markType = resolveMarkType(spec.mark);
|
|
6814
6831
|
const markDef = resolveMarkDef(spec.mark);
|
|
6832
|
+
const display = spec.display ?? "full";
|
|
6833
|
+
if (display === "sparkline" && markType !== "line" && markType !== "area" && markType !== "bar" && markType !== "point") {
|
|
6834
|
+
warnings.push(
|
|
6835
|
+
`[openchart] display: 'sparkline' works best with mark: 'line' | 'area' | 'bar' | 'point'. Got mark: '${markType}' \u2014 rendering may degrade.`
|
|
6836
|
+
);
|
|
6837
|
+
}
|
|
6815
6838
|
return {
|
|
6816
6839
|
markType,
|
|
6817
6840
|
markDef,
|
|
@@ -6826,7 +6849,20 @@ function normalizeChartSpec(spec, warnings) {
|
|
|
6826
6849
|
darkMode: spec.darkMode ?? "off",
|
|
6827
6850
|
hiddenSeries: spec.hiddenSeries ?? [],
|
|
6828
6851
|
seriesStyles: spec.seriesStyles ?? {},
|
|
6829
|
-
watermark: spec.watermark ?? true
|
|
6852
|
+
watermark: spec.watermark ?? true,
|
|
6853
|
+
display,
|
|
6854
|
+
// Default empty userExplicit; compileChart overwrites this with the real
|
|
6855
|
+
// descriptor built from the raw expanded spec before normalize runs.
|
|
6856
|
+
userExplicit: {
|
|
6857
|
+
chrome: false,
|
|
6858
|
+
legend: false,
|
|
6859
|
+
xAxis: false,
|
|
6860
|
+
yAxis: false,
|
|
6861
|
+
labels: false,
|
|
6862
|
+
animation: false,
|
|
6863
|
+
watermark: false,
|
|
6864
|
+
crosshair: false
|
|
6865
|
+
}
|
|
6830
6866
|
};
|
|
6831
6867
|
}
|
|
6832
6868
|
function normalizeTableSpec(spec, _warnings) {
|
|
@@ -8213,9 +8249,9 @@ import {
|
|
|
8213
8249
|
formatNumber as formatNumber2
|
|
8214
8250
|
} from "@opendata-ai/openchart-core";
|
|
8215
8251
|
var Y_PX_PER_TICK = {
|
|
8216
|
-
full:
|
|
8217
|
-
reduced:
|
|
8218
|
-
minimal:
|
|
8252
|
+
full: 40,
|
|
8253
|
+
reduced: 70,
|
|
8254
|
+
minimal: 120
|
|
8219
8255
|
};
|
|
8220
8256
|
var X_PX_PER_TICK = {
|
|
8221
8257
|
full: 110,
|
|
@@ -8293,7 +8329,21 @@ function buildContinuousTicks(resolvedScale, count) {
|
|
|
8293
8329
|
return continuousTicks(resolvedScale, "full");
|
|
8294
8330
|
}
|
|
8295
8331
|
const raw = scale.ticks(count);
|
|
8296
|
-
|
|
8332
|
+
let ticks2 = raw;
|
|
8333
|
+
if (resolvedScale.type === "log" && raw.length > count) {
|
|
8334
|
+
const base = resolvedScale.channel.scale?.base ?? 10;
|
|
8335
|
+
const logBase = Math.log(base);
|
|
8336
|
+
const powered = raw.filter((v) => {
|
|
8337
|
+
const n = v;
|
|
8338
|
+
if (n <= 0) return false;
|
|
8339
|
+
const exp = Math.log(n) / logBase;
|
|
8340
|
+
return Math.abs(exp - Math.round(exp)) < 1e-9;
|
|
8341
|
+
});
|
|
8342
|
+
if (powered.length >= 2) {
|
|
8343
|
+
ticks2 = powered;
|
|
8344
|
+
}
|
|
8345
|
+
}
|
|
8346
|
+
return ticks2.map((value2) => ({
|
|
8297
8347
|
value: value2,
|
|
8298
8348
|
position: scale(value2),
|
|
8299
8349
|
label: formatTickLabel(value2, resolvedScale)
|
|
@@ -8396,8 +8446,8 @@ function resolveExplicitTicks(values, resolvedScale) {
|
|
|
8396
8446
|
}
|
|
8397
8447
|
|
|
8398
8448
|
// src/layout/axes.ts
|
|
8399
|
-
var HEIGHT_MINIMAL_THRESHOLD =
|
|
8400
|
-
var HEIGHT_REDUCED_THRESHOLD =
|
|
8449
|
+
var HEIGHT_MINIMAL_THRESHOLD = 80;
|
|
8450
|
+
var HEIGHT_REDUCED_THRESHOLD = 100;
|
|
8401
8451
|
var WIDTH_MINIMAL_THRESHOLD = 150;
|
|
8402
8452
|
var WIDTH_REDUCED_THRESHOLD = 300;
|
|
8403
8453
|
var DENSITY_ORDER = ["full", "reduced", "minimal"];
|
|
@@ -8473,7 +8523,7 @@ function computeAxes(scales, chartArea, strategy, theme, measureText, dataContex
|
|
|
8473
8523
|
};
|
|
8474
8524
|
const { fontSize } = tickLabelStyle;
|
|
8475
8525
|
const { fontWeight } = tickLabelStyle;
|
|
8476
|
-
if (scales.x) {
|
|
8526
|
+
if (scales.x && !dataContext?.skipX) {
|
|
8477
8527
|
const axisConfig = scales.x.channel.axis;
|
|
8478
8528
|
const isContinuousX = scales.x.type !== "band" && scales.x.type !== "point" && scales.x.type !== "ordinal";
|
|
8479
8529
|
const xTargetCount = isContinuousX ? targetTickCount(chartArea.width, xDensity, "x") : void 0;
|
|
@@ -8551,7 +8601,7 @@ function computeAxes(scales, chartArea, strategy, theme, measureText, dataContex
|
|
|
8551
8601
|
labelFlush: axisConfig?.labelFlush
|
|
8552
8602
|
};
|
|
8553
8603
|
}
|
|
8554
|
-
if (scales.y) {
|
|
8604
|
+
if (scales.y && !dataContext?.skipY) {
|
|
8555
8605
|
const axisConfig = scales.y.channel.axis;
|
|
8556
8606
|
const isContinuousY = scales.y.type !== "band" && scales.y.type !== "point" && scales.y.type !== "ordinal";
|
|
8557
8607
|
const yTargetCount = isContinuousY ? targetTickCount(chartArea.height, yDensity, "y") : void 0;
|
|
@@ -8703,12 +8753,24 @@ function scalePadding(basePadding, width, height) {
|
|
|
8703
8753
|
}
|
|
8704
8754
|
var MIN_CHART_WIDTH = 60;
|
|
8705
8755
|
var MIN_CHART_HEIGHT = 40;
|
|
8756
|
+
function getMinChartDims(display) {
|
|
8757
|
+
return display === "sparkline" ? { width: 30, height: 20 } : { width: MIN_CHART_WIDTH, height: MIN_CHART_HEIGHT };
|
|
8758
|
+
}
|
|
8759
|
+
function getSparklinePad(spec) {
|
|
8760
|
+
const strokeWidth = spec.markDef.strokeWidth ?? 2;
|
|
8761
|
+
return Math.max(strokeWidth / 2 + 1, 2);
|
|
8762
|
+
}
|
|
8706
8763
|
function computeDimensions(spec, options, legendLayout, theme, strategy, watermark = true) {
|
|
8707
8764
|
const { width, height } = options;
|
|
8708
8765
|
const padding = scalePadding(theme.spacing.padding, width, height);
|
|
8709
8766
|
const hPad = width < BREAKPOINT_COMPACT_MAX ? Math.max(Math.round(padding * HPAD_COMPACT_FRACTION), HPAD_COMPACT_MIN) : padding;
|
|
8710
8767
|
const axisMargin = theme.spacing.axisMargin;
|
|
8711
|
-
const
|
|
8768
|
+
const userExplicit = spec.userExplicit;
|
|
8769
|
+
const isSparkline = spec.display === "sparkline";
|
|
8770
|
+
let chromeMode = strategy?.chromeMode ?? "full";
|
|
8771
|
+
if (isSparkline && !userExplicit.chrome) {
|
|
8772
|
+
chromeMode = "hidden";
|
|
8773
|
+
}
|
|
8712
8774
|
const chrome = computeChrome2(
|
|
8713
8775
|
chromeToInput(spec.chrome),
|
|
8714
8776
|
theme,
|
|
@@ -8718,6 +8780,35 @@ function computeDimensions(spec, options, legendLayout, theme, strategy, waterma
|
|
|
8718
8780
|
padding,
|
|
8719
8781
|
watermark
|
|
8720
8782
|
);
|
|
8783
|
+
if (isSparkline) {
|
|
8784
|
+
const total2 = { x: 0, y: 0, width, height };
|
|
8785
|
+
const sparkPad = getSparklinePad(spec);
|
|
8786
|
+
const xAxisSpace = userExplicit.xAxis ? 26 : 0;
|
|
8787
|
+
const yAxisSpace = userExplicit.yAxis ? 30 : 0;
|
|
8788
|
+
const margins2 = {
|
|
8789
|
+
top: chrome.topHeight + sparkPad,
|
|
8790
|
+
right: sparkPad,
|
|
8791
|
+
bottom: chrome.bottomHeight + sparkPad + xAxisSpace,
|
|
8792
|
+
left: sparkPad + yAxisSpace
|
|
8793
|
+
};
|
|
8794
|
+
if (userExplicit.legend && "entries" in legendLayout && legendLayout.entries.length > 0) {
|
|
8795
|
+
const gap = legendGap(width);
|
|
8796
|
+
if (legendLayout.position === "right" || legendLayout.position === "bottom-right") {
|
|
8797
|
+
margins2.right += legendLayout.bounds.width + 8;
|
|
8798
|
+
} else if (legendLayout.position === "top") {
|
|
8799
|
+
margins2.top += legendLayout.bounds.height + gap;
|
|
8800
|
+
} else if (legendLayout.position === "bottom") {
|
|
8801
|
+
margins2.bottom += legendLayout.bounds.height + gap;
|
|
8802
|
+
}
|
|
8803
|
+
}
|
|
8804
|
+
const chartArea2 = {
|
|
8805
|
+
x: margins2.left,
|
|
8806
|
+
y: margins2.top,
|
|
8807
|
+
width: Math.max(0, width - margins2.left - margins2.right),
|
|
8808
|
+
height: Math.max(0, height - margins2.top - margins2.bottom)
|
|
8809
|
+
};
|
|
8810
|
+
return { total: total2, chrome, chartArea: chartArea2, margins: margins2, theme };
|
|
8811
|
+
}
|
|
8721
8812
|
const total = { x: 0, y: 0, width, height };
|
|
8722
8813
|
const isRadial = spec.markType === "arc";
|
|
8723
8814
|
const encoding = spec.encoding;
|
|
@@ -8891,7 +8982,8 @@ function computeDimensions(spec, options, legendLayout, theme, strategy, waterma
|
|
|
8891
8982
|
width: Math.max(0, width - margins.left - margins.right),
|
|
8892
8983
|
height: Math.max(0, height - margins.top - margins.bottom)
|
|
8893
8984
|
};
|
|
8894
|
-
|
|
8985
|
+
const minDims = getMinChartDims(spec.display);
|
|
8986
|
+
if ((chartArea.width < minDims.width || chartArea.height < minDims.height) && chromeMode !== "hidden") {
|
|
8895
8987
|
const fallbackMode = chromeMode === "full" ? "compact" : "hidden";
|
|
8896
8988
|
const fallbackChrome = computeChrome2(
|
|
8897
8989
|
chromeToInput(spec.chrome),
|
|
@@ -9438,7 +9530,8 @@ function truncateEntries(entries, maxCount) {
|
|
|
9438
9530
|
return truncated;
|
|
9439
9531
|
}
|
|
9440
9532
|
function computeLegend(spec, strategy, theme, chartArea, watermark = true) {
|
|
9441
|
-
|
|
9533
|
+
const sparklineHidden = spec.display === "sparkline" && !spec.userExplicit.legend;
|
|
9534
|
+
if (sparklineHidden || spec.legend?.show === false || strategy.legendMaxHeight === 0) {
|
|
9442
9535
|
return {
|
|
9443
9536
|
position: "top",
|
|
9444
9537
|
entries: [],
|
|
@@ -12176,7 +12269,7 @@ function compileChart(spec, options) {
|
|
|
12176
12269
|
}
|
|
12177
12270
|
let chartSpec = normalized;
|
|
12178
12271
|
const rawWatermark = expandedSpec.watermark;
|
|
12179
|
-
|
|
12272
|
+
let watermark = rawWatermark !== void 0 ? chartSpec.watermark : options.watermark ?? true;
|
|
12180
12273
|
const rawTransforms = expandedSpec.transform;
|
|
12181
12274
|
if (rawTransforms && rawTransforms.length > 0) {
|
|
12182
12275
|
chartSpec = { ...chartSpec, data: runTransforms(chartSpec.data, rawTransforms) };
|
|
@@ -12186,6 +12279,21 @@ function compileChart(spec, options) {
|
|
|
12186
12279
|
let strategy = getLayoutStrategy(breakpoint, heightClass);
|
|
12187
12280
|
const rawSpec = expandedSpec;
|
|
12188
12281
|
const overrides = rawSpec.overrides;
|
|
12282
|
+
const rawEncoding = rawSpec.encoding;
|
|
12283
|
+
const bpForExplicit = overrides?.[breakpoint];
|
|
12284
|
+
const bpEncoding = bpForExplicit?.encoding;
|
|
12285
|
+
const hasChromeKeys = (v) => !!v && typeof v === "object" && Object.keys(v).length > 0;
|
|
12286
|
+
const userExplicit = {
|
|
12287
|
+
chrome: hasChromeKeys(rawSpec.chrome) || hasChromeKeys(bpForExplicit?.chrome),
|
|
12288
|
+
legend: rawSpec.legend !== void 0 || bpForExplicit?.legend !== void 0,
|
|
12289
|
+
xAxis: rawEncoding?.x?.axis !== void 0 || bpEncoding?.x?.axis !== void 0,
|
|
12290
|
+
yAxis: rawEncoding?.y?.axis !== void 0 || bpEncoding?.y?.axis !== void 0,
|
|
12291
|
+
labels: rawSpec.labels !== void 0 || bpForExplicit?.labels !== void 0,
|
|
12292
|
+
animation: rawSpec.animation !== void 0 || bpForExplicit?.animation !== void 0,
|
|
12293
|
+
watermark: rawSpec.watermark !== void 0 || bpForExplicit?.watermark !== void 0,
|
|
12294
|
+
crosshair: rawSpec.crosshair !== void 0 || bpForExplicit?.crosshair !== void 0
|
|
12295
|
+
};
|
|
12296
|
+
chartSpec = { ...chartSpec, userExplicit };
|
|
12189
12297
|
if (overrides?.[breakpoint]) {
|
|
12190
12298
|
const bp = overrides[breakpoint];
|
|
12191
12299
|
if (bp.chrome) {
|
|
@@ -12229,9 +12337,80 @@ function compileChart(spec, options) {
|
|
|
12229
12337
|
};
|
|
12230
12338
|
strategy = { ...strategy, annotationPosition: "inline" };
|
|
12231
12339
|
}
|
|
12340
|
+
if (bp.display !== void 0) {
|
|
12341
|
+
chartSpec = {
|
|
12342
|
+
...chartSpec,
|
|
12343
|
+
display: bp.display
|
|
12344
|
+
};
|
|
12345
|
+
}
|
|
12346
|
+
if (bp.encoding !== void 0) {
|
|
12347
|
+
const bpEnc = bp.encoding;
|
|
12348
|
+
const mergedEncoding = { ...chartSpec.encoding };
|
|
12349
|
+
const NESTED_CHANNEL_KEYS = ["axis", "scale"];
|
|
12350
|
+
for (const channel of Object.keys(bpEnc)) {
|
|
12351
|
+
const baseCh = mergedEncoding[channel];
|
|
12352
|
+
const bpCh = bpEnc[channel];
|
|
12353
|
+
if (bpCh && baseCh) {
|
|
12354
|
+
const merged = { ...baseCh, ...bpCh };
|
|
12355
|
+
for (const key of NESTED_CHANNEL_KEYS) {
|
|
12356
|
+
const baseNested = baseCh[key];
|
|
12357
|
+
const bpNested = bpCh[key];
|
|
12358
|
+
if (baseNested && bpNested && typeof baseNested === "object" && typeof bpNested === "object" && !Array.isArray(baseNested) && !Array.isArray(bpNested)) {
|
|
12359
|
+
merged[key] = { ...baseNested, ...bpNested };
|
|
12360
|
+
}
|
|
12361
|
+
}
|
|
12362
|
+
mergedEncoding[channel] = merged;
|
|
12363
|
+
} else if (bpCh) {
|
|
12364
|
+
mergedEncoding[channel] = bpCh;
|
|
12365
|
+
}
|
|
12366
|
+
}
|
|
12367
|
+
chartSpec = {
|
|
12368
|
+
...chartSpec,
|
|
12369
|
+
encoding: mergedEncoding
|
|
12370
|
+
};
|
|
12371
|
+
}
|
|
12372
|
+
if (typeof bp.watermark === "boolean") {
|
|
12373
|
+
watermark = bp.watermark;
|
|
12374
|
+
chartSpec = { ...chartSpec, watermark };
|
|
12375
|
+
}
|
|
12376
|
+
}
|
|
12377
|
+
if (chartSpec.display === "sparkline" && !chartSpec.userExplicit.labels) {
|
|
12378
|
+
chartSpec = {
|
|
12379
|
+
...chartSpec,
|
|
12380
|
+
labels: { ...chartSpec.labels, density: "none" }
|
|
12381
|
+
};
|
|
12382
|
+
}
|
|
12383
|
+
let rawAnimationSpec = overrides?.[breakpoint]?.animation ?? rawSpec.animation;
|
|
12384
|
+
if (rawAnimationSpec === void 0 && chartSpec.display === "sparkline") {
|
|
12385
|
+
rawAnimationSpec = false;
|
|
12386
|
+
}
|
|
12387
|
+
if (chartSpec.display === "sparkline" && rawAnimationSpec !== false && rawAnimationSpec !== void 0) {
|
|
12388
|
+
const SPARK_DURATION = 1100;
|
|
12389
|
+
if (rawAnimationSpec === true) {
|
|
12390
|
+
rawAnimationSpec = { enter: { duration: SPARK_DURATION } };
|
|
12391
|
+
} else if (typeof rawAnimationSpec === "object") {
|
|
12392
|
+
const cfg = rawAnimationSpec;
|
|
12393
|
+
const enter = cfg.enter;
|
|
12394
|
+
if (enter === void 0 || enter === true) {
|
|
12395
|
+
rawAnimationSpec = {
|
|
12396
|
+
...cfg,
|
|
12397
|
+
enter: { duration: SPARK_DURATION }
|
|
12398
|
+
};
|
|
12399
|
+
} else if (typeof enter === "object" && enter !== null && enter.duration === void 0) {
|
|
12400
|
+
rawAnimationSpec = {
|
|
12401
|
+
...cfg,
|
|
12402
|
+
enter: { ...enter, duration: SPARK_DURATION }
|
|
12403
|
+
};
|
|
12404
|
+
}
|
|
12405
|
+
}
|
|
12232
12406
|
}
|
|
12233
|
-
const rawAnimationSpec = overrides?.[breakpoint]?.animation ?? rawSpec.animation;
|
|
12234
12407
|
const resolvedAnimation = resolveAnimation(rawAnimationSpec);
|
|
12408
|
+
const rawCrosshair = bpForExplicit?.crosshair ?? rawSpec.crosshair;
|
|
12409
|
+
const crosshair = chartSpec.display === "sparkline" && !chartSpec.userExplicit.crosshair ? false : rawCrosshair === true;
|
|
12410
|
+
if (chartSpec.display === "sparkline" && !chartSpec.userExplicit.watermark) {
|
|
12411
|
+
watermark = false;
|
|
12412
|
+
chartSpec = { ...chartSpec, watermark: false };
|
|
12413
|
+
}
|
|
12235
12414
|
const mergedThemeConfig = options.theme ? { ...chartSpec.theme, ...options.theme } : chartSpec.theme;
|
|
12236
12415
|
let theme = resolveTheme4(mergedThemeConfig);
|
|
12237
12416
|
if (options.darkMode) {
|
|
@@ -12276,9 +12455,13 @@ function compileChart(spec, options) {
|
|
|
12276
12455
|
applyColorScaleRange(scales, renderSpec.encoding, theme);
|
|
12277
12456
|
scales.defaultColor = chartSpec.markDef.fill ?? chartSpec.markDef.stroke ?? theme.colors.categorical[0];
|
|
12278
12457
|
const isRadial = chartSpec.markType === "arc";
|
|
12458
|
+
const skipX = chartSpec.display === "sparkline" && !chartSpec.userExplicit.xAxis;
|
|
12459
|
+
const skipY = chartSpec.display === "sparkline" && !chartSpec.userExplicit.yAxis;
|
|
12279
12460
|
const axes = isRadial ? { x: void 0, y: void 0 } : computeAxes(scales, chartArea, strategy, theme, options.measureText, {
|
|
12280
12461
|
data: renderSpec.data,
|
|
12281
|
-
encoding: renderSpec.encoding
|
|
12462
|
+
encoding: renderSpec.encoding,
|
|
12463
|
+
skipX,
|
|
12464
|
+
skipY
|
|
12282
12465
|
});
|
|
12283
12466
|
if (!isRadial) {
|
|
12284
12467
|
computeGridlines(axes, chartArea);
|
|
@@ -12354,6 +12537,8 @@ function compileChart(spec, options) {
|
|
|
12354
12537
|
},
|
|
12355
12538
|
animation: resolvedAnimation,
|
|
12356
12539
|
watermark,
|
|
12540
|
+
display: chartSpec.display,
|
|
12541
|
+
crosshair,
|
|
12357
12542
|
measureText: options.measureText
|
|
12358
12543
|
};
|
|
12359
12544
|
}
|