@opendata-ai/openchart-engine 6.27.0 → 6.28.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 +38 -6
- package/dist/index.js +1040 -521
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/src/__tests__/__snapshots__/compile-snapshot.test.ts.snap +31 -4
- package/src/__tests__/axes.test.ts +101 -3
- package/src/__tests__/legend.test.ts +2 -2
- 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/barlist/__tests__/compile-barlist.test.ts +200 -0
- package/src/barlist/compile-barlist.ts +380 -0
- package/src/barlist/types.ts +28 -0
- package/src/charts/bar/__tests__/compute.test.ts +222 -0
- package/src/charts/bar/compute.ts +77 -44
- package/src/charts/bar/index.ts +1 -0
- package/src/charts/bar/labels.ts +3 -2
- package/src/charts/column/compute.ts +60 -27
- package/src/charts/column/index.ts +1 -0
- package/src/charts/column/labels.ts +2 -1
- package/src/charts/line/__tests__/compute.test.ts +2 -2
- package/src/charts/line/area.ts +25 -4
- package/src/charts/line/compute.ts +15 -5
- package/src/compile.ts +26 -1
- package/src/compiler/normalize.ts +25 -1
- package/src/compiler/types.ts +5 -3
- package/src/compiler/validate.ts +120 -5
- package/src/index.ts +5 -0
- package/src/layout/axes/ticks.ts +37 -8
- package/src/layout/axes.ts +11 -4
- package/src/layout/dimensions.ts +10 -4
- package/src/layout/scales.ts +10 -0
- package/src/legend/wrap.ts +1 -1
- package/src/tilemap/__tests__/compile-tilemap.test.ts +5 -2
- package/src/tilemap/compile-tilemap.ts +41 -29
- package/src/tooltips/compute.ts +4 -2
package/dist/index.js
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
// src/compile.ts
|
|
2
2
|
import {
|
|
3
3
|
AXIS_TITLE_TRAILING_PAD as AXIS_TITLE_TRAILING_PAD2,
|
|
4
|
-
adaptTheme as
|
|
4
|
+
adaptTheme as adaptTheme5,
|
|
5
5
|
BREAKPOINT_COMPACT_MAX as BREAKPOINT_COMPACT_MAX2,
|
|
6
6
|
computeLabelBounds,
|
|
7
|
-
estimateTextWidth as
|
|
7
|
+
estimateTextWidth as estimateTextWidth16,
|
|
8
8
|
generateAltText,
|
|
9
9
|
generateDataTable,
|
|
10
10
|
getAxisTitleOffset as getAxisTitleOffset2,
|
|
11
11
|
getBreakpoint,
|
|
12
12
|
getHeightClass,
|
|
13
13
|
getLayoutStrategy,
|
|
14
|
-
resolveTheme as
|
|
14
|
+
resolveTheme as resolveTheme5,
|
|
15
15
|
TICK_LABEL_OFFSET
|
|
16
16
|
} from "@opendata-ai/openchart-core";
|
|
17
17
|
|
|
@@ -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);
|
|
@@ -4296,8 +4312,9 @@ function computeBarMarks(spec, scales, _chartArea, _strategy) {
|
|
|
4296
4312
|
const conditionalColor = encoding.color && isConditionalValueDef(encoding.color) ? encoding.color : void 0;
|
|
4297
4313
|
const colorField = colorEnc?.field;
|
|
4298
4314
|
const isSequentialColor = colorEnc?.type === "quantitative";
|
|
4315
|
+
let marks;
|
|
4299
4316
|
if (!colorField || isSequentialColor) {
|
|
4300
|
-
|
|
4317
|
+
marks = computeSimpleBars(
|
|
4301
4318
|
spec.data,
|
|
4302
4319
|
xChannel.field,
|
|
4303
4320
|
yChannel.field,
|
|
@@ -4309,13 +4326,40 @@ function computeBarMarks(spec, scales, _chartArea, _strategy) {
|
|
|
4309
4326
|
isSequentialColor,
|
|
4310
4327
|
conditionalColor
|
|
4311
4328
|
);
|
|
4312
|
-
}
|
|
4313
|
-
|
|
4314
|
-
|
|
4315
|
-
|
|
4316
|
-
|
|
4317
|
-
|
|
4318
|
-
|
|
4329
|
+
} else {
|
|
4330
|
+
const categoryGroups = groupByField(spec.data, yChannel.field);
|
|
4331
|
+
const needsStacking = Array.from(categoryGroups.values()).some((rows) => rows.length > 1);
|
|
4332
|
+
if (needsStacking) {
|
|
4333
|
+
const stackDisabled = xChannel.stack === null || xChannel.stack === false;
|
|
4334
|
+
if (stackDisabled) {
|
|
4335
|
+
marks = computeGroupedBars(
|
|
4336
|
+
spec.data,
|
|
4337
|
+
xChannel.field,
|
|
4338
|
+
yChannel.field,
|
|
4339
|
+
colorField,
|
|
4340
|
+
xScale,
|
|
4341
|
+
yScale,
|
|
4342
|
+
bandwidth,
|
|
4343
|
+
baseline,
|
|
4344
|
+
scales
|
|
4345
|
+
);
|
|
4346
|
+
} else {
|
|
4347
|
+
const stackMode = xChannel.stack === "normalize" ? "normalize" : xChannel.stack === "center" ? "center" : "zero";
|
|
4348
|
+
marks = computeStackedBars(
|
|
4349
|
+
spec.data,
|
|
4350
|
+
xChannel.field,
|
|
4351
|
+
yChannel.field,
|
|
4352
|
+
colorField,
|
|
4353
|
+
xScale,
|
|
4354
|
+
yScale,
|
|
4355
|
+
bandwidth,
|
|
4356
|
+
baseline,
|
|
4357
|
+
scales,
|
|
4358
|
+
stackMode
|
|
4359
|
+
);
|
|
4360
|
+
}
|
|
4361
|
+
} else {
|
|
4362
|
+
marks = computeColoredBars(
|
|
4319
4363
|
spec.data,
|
|
4320
4364
|
xChannel.field,
|
|
4321
4365
|
yChannel.field,
|
|
@@ -4327,31 +4371,8 @@ function computeBarMarks(spec, scales, _chartArea, _strategy) {
|
|
|
4327
4371
|
scales
|
|
4328
4372
|
);
|
|
4329
4373
|
}
|
|
4330
|
-
const stackMode = xChannel.stack === "normalize" ? "normalize" : xChannel.stack === "center" ? "center" : "zero";
|
|
4331
|
-
return computeStackedBars(
|
|
4332
|
-
spec.data,
|
|
4333
|
-
xChannel.field,
|
|
4334
|
-
yChannel.field,
|
|
4335
|
-
colorField,
|
|
4336
|
-
xScale,
|
|
4337
|
-
yScale,
|
|
4338
|
-
bandwidth,
|
|
4339
|
-
baseline,
|
|
4340
|
-
scales,
|
|
4341
|
-
stackMode
|
|
4342
|
-
);
|
|
4343
4374
|
}
|
|
4344
|
-
return
|
|
4345
|
-
spec.data,
|
|
4346
|
-
xChannel.field,
|
|
4347
|
-
yChannel.field,
|
|
4348
|
-
colorField,
|
|
4349
|
-
xScale,
|
|
4350
|
-
yScale,
|
|
4351
|
-
bandwidth,
|
|
4352
|
-
baseline,
|
|
4353
|
-
scales
|
|
4354
|
-
);
|
|
4375
|
+
return applyMarkDefOverrides(marks, spec, bandwidth);
|
|
4355
4376
|
}
|
|
4356
4377
|
function computeStackedBars(data, valueField, categoryField, colorField, xScale, yScale, bandwidth, _baseline, scales, stackMode = "zero") {
|
|
4357
4378
|
const marks = [];
|
|
@@ -4470,6 +4491,27 @@ function computeColoredBars(data, valueField, categoryField, colorField, xScale,
|
|
|
4470
4491
|
}
|
|
4471
4492
|
return marks;
|
|
4472
4493
|
}
|
|
4494
|
+
function applyMarkDefOverrides(marks, spec, bandwidth) {
|
|
4495
|
+
const { markDef } = spec;
|
|
4496
|
+
const fixedSize = markDef.size;
|
|
4497
|
+
const crSpec = markDef.cornerRadius;
|
|
4498
|
+
if (fixedSize == null && crSpec == null) return marks;
|
|
4499
|
+
for (const mark of marks) {
|
|
4500
|
+
if (fixedSize != null && mark.stackGroup === void 0) {
|
|
4501
|
+
const barHeight = Math.min(fixedSize, bandwidth);
|
|
4502
|
+
const offset = (bandwidth - barHeight) / 2;
|
|
4503
|
+
mark.y = mark.y + offset;
|
|
4504
|
+
mark.height = barHeight;
|
|
4505
|
+
}
|
|
4506
|
+
const effectiveHeight = mark.height;
|
|
4507
|
+
if (crSpec === "pill") {
|
|
4508
|
+
mark.cornerRadius = effectiveHeight / 2;
|
|
4509
|
+
} else if (typeof crSpec === "number") {
|
|
4510
|
+
mark.cornerRadius = crSpec;
|
|
4511
|
+
}
|
|
4512
|
+
}
|
|
4513
|
+
return marks;
|
|
4514
|
+
}
|
|
4473
4515
|
function computeSimpleBars(data, valueField, categoryField, xScale, yScale, bandwidth, baseline, scales, sequentialColor = false, conditionalColor) {
|
|
4474
4516
|
const marks = [];
|
|
4475
4517
|
for (const row of data) {
|
|
@@ -4556,7 +4598,7 @@ var LABEL_FONT_SIZE = 11;
|
|
|
4556
4598
|
var LABEL_FONT_WEIGHT = 600;
|
|
4557
4599
|
var LABEL_PADDING = 6;
|
|
4558
4600
|
var MIN_WIDTH_FOR_INSIDE_LABEL = 40;
|
|
4559
|
-
function computeBarLabels(marks, _chartArea, density = "auto", labelFormat, labelPrefix, valueField) {
|
|
4601
|
+
function computeBarLabels(marks, _chartArea, density = "auto", labelFormat, labelPrefix, valueField, labelColor) {
|
|
4560
4602
|
const targetMarks = filterByDensity(marks, density);
|
|
4561
4603
|
const candidates = [];
|
|
4562
4604
|
const fitsInSegment = [];
|
|
@@ -4607,11 +4649,11 @@ function computeBarLabels(marks, _chartArea, density = "auto", labelFormat, labe
|
|
|
4607
4649
|
} else {
|
|
4608
4650
|
if (isNegative) {
|
|
4609
4651
|
anchorX = mark.x - LABEL_PADDING;
|
|
4610
|
-
fill = getRepresentativeColor(mark.fill);
|
|
4652
|
+
fill = labelColor ?? getRepresentativeColor(mark.fill);
|
|
4611
4653
|
textAnchor = "end";
|
|
4612
4654
|
} else {
|
|
4613
4655
|
anchorX = mark.x + mark.width + LABEL_PADDING;
|
|
4614
|
-
fill = getRepresentativeColor(mark.fill);
|
|
4656
|
+
fill = labelColor ?? getRepresentativeColor(mark.fill);
|
|
4615
4657
|
textAnchor = "start";
|
|
4616
4658
|
}
|
|
4617
4659
|
}
|
|
@@ -4684,7 +4726,8 @@ var barRenderer = (spec, scales, chartArea, strategy, _theme) => {
|
|
|
4684
4726
|
spec.labels.density,
|
|
4685
4727
|
spec.labels.format,
|
|
4686
4728
|
spec.labels.prefix,
|
|
4687
|
-
valueField
|
|
4729
|
+
valueField,
|
|
4730
|
+
spec.labels.color
|
|
4688
4731
|
);
|
|
4689
4732
|
for (let i = 0; i < marks.length && i < labels.length; i++) {
|
|
4690
4733
|
marks[i].label = labels[i];
|
|
@@ -4713,13 +4756,14 @@ function computeColumnMarks(spec, scales, _chartArea, _strategy) {
|
|
|
4713
4756
|
const conditionalColor = encoding.color && isConditionalValueDef(encoding.color) ? encoding.color : void 0;
|
|
4714
4757
|
const colorField = colorEnc?.field;
|
|
4715
4758
|
const isSequentialColor = colorEnc?.type === "quantitative";
|
|
4759
|
+
let marks;
|
|
4716
4760
|
if (colorField && !isSequentialColor) {
|
|
4717
4761
|
const categoryGroups = groupByField(spec.data, xChannel.field);
|
|
4718
4762
|
const needsStacking = Array.from(categoryGroups.values()).some((rows) => rows.length > 1);
|
|
4719
4763
|
if (needsStacking) {
|
|
4720
4764
|
const stackDisabled = yChannel.stack === null || yChannel.stack === false;
|
|
4721
4765
|
if (stackDisabled) {
|
|
4722
|
-
|
|
4766
|
+
marks = computeGroupedColumns(
|
|
4723
4767
|
spec.data,
|
|
4724
4768
|
xChannel.field,
|
|
4725
4769
|
yChannel.field,
|
|
@@ -4730,9 +4774,23 @@ function computeColumnMarks(spec, scales, _chartArea, _strategy) {
|
|
|
4730
4774
|
baseline,
|
|
4731
4775
|
scales
|
|
4732
4776
|
);
|
|
4777
|
+
} else {
|
|
4778
|
+
const stackMode = yChannel.stack === "normalize" ? "normalize" : yChannel.stack === "center" ? "center" : "zero";
|
|
4779
|
+
marks = computeStackedColumns(
|
|
4780
|
+
spec.data,
|
|
4781
|
+
xChannel.field,
|
|
4782
|
+
yChannel.field,
|
|
4783
|
+
colorField,
|
|
4784
|
+
xScale,
|
|
4785
|
+
yScale,
|
|
4786
|
+
bandwidth,
|
|
4787
|
+
baseline,
|
|
4788
|
+
scales,
|
|
4789
|
+
stackMode
|
|
4790
|
+
);
|
|
4733
4791
|
}
|
|
4734
|
-
|
|
4735
|
-
|
|
4792
|
+
} else {
|
|
4793
|
+
marks = computeColoredColumns(
|
|
4736
4794
|
spec.data,
|
|
4737
4795
|
xChannel.field,
|
|
4738
4796
|
yChannel.field,
|
|
@@ -4741,34 +4799,24 @@ function computeColumnMarks(spec, scales, _chartArea, _strategy) {
|
|
|
4741
4799
|
yScale,
|
|
4742
4800
|
bandwidth,
|
|
4743
4801
|
baseline,
|
|
4744
|
-
scales
|
|
4745
|
-
stackMode
|
|
4802
|
+
scales
|
|
4746
4803
|
);
|
|
4747
4804
|
}
|
|
4748
|
-
|
|
4805
|
+
} else {
|
|
4806
|
+
marks = computeSimpleColumns(
|
|
4749
4807
|
spec.data,
|
|
4750
4808
|
xChannel.field,
|
|
4751
4809
|
yChannel.field,
|
|
4752
|
-
colorField,
|
|
4753
4810
|
xScale,
|
|
4754
4811
|
yScale,
|
|
4755
4812
|
bandwidth,
|
|
4756
4813
|
baseline,
|
|
4757
|
-
scales
|
|
4814
|
+
scales,
|
|
4815
|
+
isSequentialColor,
|
|
4816
|
+
conditionalColor
|
|
4758
4817
|
);
|
|
4759
4818
|
}
|
|
4760
|
-
return
|
|
4761
|
-
spec.data,
|
|
4762
|
-
xChannel.field,
|
|
4763
|
-
yChannel.field,
|
|
4764
|
-
xScale,
|
|
4765
|
-
yScale,
|
|
4766
|
-
bandwidth,
|
|
4767
|
-
baseline,
|
|
4768
|
-
scales,
|
|
4769
|
-
isSequentialColor,
|
|
4770
|
-
conditionalColor
|
|
4771
|
-
);
|
|
4819
|
+
return applyMarkDefOverrides2(marks, spec, bandwidth);
|
|
4772
4820
|
}
|
|
4773
4821
|
function computeSimpleColumns(data, categoryField, valueField, xScale, yScale, bandwidth, baseline, scales, sequentialColor = false, conditionalColor) {
|
|
4774
4822
|
const marks = [];
|
|
@@ -4934,6 +4982,27 @@ function computeStackedColumns(data, categoryField, valueField, colorField, xSca
|
|
|
4934
4982
|
}
|
|
4935
4983
|
return marks;
|
|
4936
4984
|
}
|
|
4985
|
+
function applyMarkDefOverrides2(marks, spec, bandwidth) {
|
|
4986
|
+
const { markDef } = spec;
|
|
4987
|
+
const fixedSize = markDef.size;
|
|
4988
|
+
const crSpec = markDef.cornerRadius;
|
|
4989
|
+
if (fixedSize == null && crSpec == null) return marks;
|
|
4990
|
+
for (const mark of marks) {
|
|
4991
|
+
if (fixedSize != null && mark.stackGroup === void 0) {
|
|
4992
|
+
const barWidth = Math.min(fixedSize, bandwidth);
|
|
4993
|
+
const offset = (bandwidth - barWidth) / 2;
|
|
4994
|
+
mark.x = mark.x + offset;
|
|
4995
|
+
mark.width = barWidth;
|
|
4996
|
+
}
|
|
4997
|
+
const effectiveWidth = mark.width;
|
|
4998
|
+
if (crSpec === "pill") {
|
|
4999
|
+
mark.cornerRadius = effectiveWidth / 2;
|
|
5000
|
+
} else if (typeof crSpec === "number") {
|
|
5001
|
+
mark.cornerRadius = crSpec;
|
|
5002
|
+
}
|
|
5003
|
+
}
|
|
5004
|
+
return marks;
|
|
5005
|
+
}
|
|
4937
5006
|
|
|
4938
5007
|
// src/charts/column/labels.ts
|
|
4939
5008
|
import {
|
|
@@ -4945,7 +5014,7 @@ import {
|
|
|
4945
5014
|
var LABEL_FONT_SIZE2 = 10;
|
|
4946
5015
|
var LABEL_FONT_WEIGHT2 = 600;
|
|
4947
5016
|
var LABEL_OFFSET_Y = 6;
|
|
4948
|
-
function computeColumnLabels(marks, _chartArea, density = "auto", labelFormat, labelPrefix, valueField) {
|
|
5017
|
+
function computeColumnLabels(marks, _chartArea, density = "auto", labelFormat, labelPrefix, valueField, labelColor) {
|
|
4949
5018
|
const targetMarks = filterByDensity(marks, density);
|
|
4950
5019
|
const formatter = buildD3Formatter2(labelFormat);
|
|
4951
5020
|
const candidates = [];
|
|
@@ -4986,7 +5055,7 @@ function computeColumnLabels(marks, _chartArea, density = "auto", labelFormat, l
|
|
|
4986
5055
|
fontFamily: "system-ui, -apple-system, sans-serif",
|
|
4987
5056
|
fontSize: LABEL_FONT_SIZE2,
|
|
4988
5057
|
fontWeight: LABEL_FONT_WEIGHT2,
|
|
4989
|
-
fill: getRepresentativeColor2(mark.fill),
|
|
5058
|
+
fill: labelColor ?? getRepresentativeColor2(mark.fill),
|
|
4990
5059
|
lineHeight: 1.2,
|
|
4991
5060
|
textAnchor: "middle",
|
|
4992
5061
|
dominantBaseline: isNegative ? "hanging" : "auto"
|
|
@@ -5016,7 +5085,8 @@ var columnRenderer = (spec, scales, chartArea, strategy, _theme) => {
|
|
|
5016
5085
|
spec.labels.density,
|
|
5017
5086
|
spec.labels.format,
|
|
5018
5087
|
spec.labels.prefix,
|
|
5019
|
-
valueField
|
|
5088
|
+
valueField,
|
|
5089
|
+
spec.labels.color
|
|
5020
5090
|
);
|
|
5021
5091
|
for (let i = 0; i < marks.length && i < labels.length; i++) {
|
|
5022
5092
|
marks[i].label = labels[i];
|
|
@@ -5339,9 +5409,26 @@ function computeSingleArea(spec, scales, _chartArea) {
|
|
|
5339
5409
|
const ariaLabel = seriesKey === "__default__" ? `Area with ${validPoints.length} data points` : `${seriesKey}: area with ${validPoints.length} data points`;
|
|
5340
5410
|
const aria = { label: ariaLabel };
|
|
5341
5411
|
const markFill = spec.markDef.fill;
|
|
5342
|
-
|
|
5343
|
-
|
|
5344
|
-
|
|
5412
|
+
let fillValue;
|
|
5413
|
+
let fillOpacity;
|
|
5414
|
+
if (markFill != null) {
|
|
5415
|
+
fillValue = markFill;
|
|
5416
|
+
fillOpacity = isGradientDef3(markFill) ? 1 : spec.markDef.opacity ?? (y2Channel ? 0.25 : DEFAULT_FILL_OPACITY);
|
|
5417
|
+
} else {
|
|
5418
|
+
const colorStr = getRepresentativeColor4(color2);
|
|
5419
|
+
fillValue = {
|
|
5420
|
+
gradient: "linear",
|
|
5421
|
+
x1: 0,
|
|
5422
|
+
y1: 0,
|
|
5423
|
+
x2: 0,
|
|
5424
|
+
y2: 1,
|
|
5425
|
+
stops: [
|
|
5426
|
+
{ offset: 0, color: colorStr, opacity: 0.12 },
|
|
5427
|
+
{ offset: 1, color: colorStr, opacity: 0 }
|
|
5428
|
+
]
|
|
5429
|
+
};
|
|
5430
|
+
fillOpacity = 1;
|
|
5431
|
+
}
|
|
5345
5432
|
marks.push({
|
|
5346
5433
|
type: "area",
|
|
5347
5434
|
topPoints,
|
|
@@ -5351,7 +5438,7 @@ function computeSingleArea(spec, scales, _chartArea) {
|
|
|
5351
5438
|
fill: fillValue,
|
|
5352
5439
|
fillOpacity,
|
|
5353
5440
|
stroke: getRepresentativeColor4(isGradientDef3(fillValue) ? color2 : fillValue),
|
|
5354
|
-
strokeWidth: spec.display === "sparkline" ? 1.25 :
|
|
5441
|
+
strokeWidth: spec.markDef.strokeWidth ?? (spec.display === "sparkline" ? 1.25 : 1.5),
|
|
5355
5442
|
seriesKey: seriesKey === "__default__" ? void 0 : seriesKey,
|
|
5356
5443
|
data: validPoints.map((p) => p.row),
|
|
5357
5444
|
dataPoints: validPoints.map((p) => ({ x: p.x, y: p.yTop, datum: p.row })),
|
|
@@ -5467,7 +5554,7 @@ function computeAreaMarks(spec, scales, chartArea) {
|
|
|
5467
5554
|
|
|
5468
5555
|
// src/charts/line/compute.ts
|
|
5469
5556
|
import { getRepresentativeColor as getRepresentativeColor5 } from "@opendata-ai/openchart-core";
|
|
5470
|
-
var DEFAULT_STROKE_WIDTH =
|
|
5557
|
+
var DEFAULT_STROKE_WIDTH = 1.5;
|
|
5471
5558
|
var SPARKLINE_STROKE_WIDTH = 1.25;
|
|
5472
5559
|
var DEFAULT_POINT_RADIUS = 3;
|
|
5473
5560
|
function computeLineMarks(spec, scales, _chartArea, _strategy) {
|
|
@@ -5535,7 +5622,7 @@ function computeLineMarks(spec, scales, _chartArea, _strategy) {
|
|
|
5535
5622
|
points: allPoints,
|
|
5536
5623
|
path: combinedPath,
|
|
5537
5624
|
stroke: strokeColor,
|
|
5538
|
-
strokeWidth: styleOverride?.strokeWidth ?? (spec.display === "sparkline" ? SPARKLINE_STROKE_WIDTH : DEFAULT_STROKE_WIDTH),
|
|
5625
|
+
strokeWidth: styleOverride?.strokeWidth ?? spec.markDef.strokeWidth ?? (spec.display === "sparkline" ? SPARKLINE_STROKE_WIDTH : DEFAULT_STROKE_WIDTH),
|
|
5539
5626
|
strokeDasharray,
|
|
5540
5627
|
opacity: styleOverride?.opacity,
|
|
5541
5628
|
seriesKey: seriesStyleKey,
|
|
@@ -5545,25 +5632,30 @@ function computeLineMarks(spec, scales, _chartArea, _strategy) {
|
|
|
5545
5632
|
};
|
|
5546
5633
|
marks.push(lineMark);
|
|
5547
5634
|
const markPoint = spec.markDef.point;
|
|
5548
|
-
const showPoints = markPoint === true || markPoint === "transparent" || isSequentialColor;
|
|
5635
|
+
const showPoints = markPoint === true || markPoint === "transparent" || markPoint === "endpoints" || isSequentialColor;
|
|
5549
5636
|
if (showPoints) {
|
|
5550
5637
|
const isTransparent = markPoint === "transparent";
|
|
5638
|
+
const isEndpoints = markPoint === "endpoints";
|
|
5551
5639
|
const seriesShowPoints = styleOverride?.showPoints !== false;
|
|
5640
|
+
const lastIdx = pointsWithData.length - 1;
|
|
5552
5641
|
for (let i = 0; i < pointsWithData.length; i++) {
|
|
5553
5642
|
const p = pointsWithData[i];
|
|
5554
|
-
const
|
|
5643
|
+
const isEndpoint = i === 0 || i === lastIdx;
|
|
5644
|
+
const visible = seriesShowPoints && !isTransparent && (!isEndpoints || isEndpoint);
|
|
5555
5645
|
let pointColor = color2;
|
|
5556
5646
|
if (isSequentialColor) {
|
|
5557
5647
|
const val = Number(p.row[sequentialColorField]);
|
|
5558
5648
|
pointColor = Number.isFinite(val) ? getSequentialColor(scales, val) : color2;
|
|
5559
5649
|
}
|
|
5650
|
+
const hollow = isEndpoints && visible;
|
|
5651
|
+
const pointColorStr = getRepresentativeColor5(pointColor);
|
|
5560
5652
|
const pointMark = {
|
|
5561
5653
|
type: "point",
|
|
5562
5654
|
cx: p.x,
|
|
5563
5655
|
cy: p.y,
|
|
5564
5656
|
r: visible ? DEFAULT_POINT_RADIUS : 0,
|
|
5565
|
-
fill:
|
|
5566
|
-
stroke: visible ? "#ffffff" : "transparent",
|
|
5657
|
+
fill: hollow ? "transparent" : pointColorStr,
|
|
5658
|
+
stroke: hollow ? pointColorStr : visible ? "#ffffff" : "transparent",
|
|
5567
5659
|
strokeWidth: visible ? 1.5 : 0,
|
|
5568
5660
|
fillOpacity: isTransparent ? 0 : 1,
|
|
5569
5661
|
data: p.row,
|
|
@@ -6293,248 +6385,75 @@ function registerBuiltinRenderers() {
|
|
|
6293
6385
|
}
|
|
6294
6386
|
registerBuiltinRenderers();
|
|
6295
6387
|
|
|
6296
|
-
// src/
|
|
6297
|
-
|
|
6298
|
-
|
|
6299
|
-
|
|
6388
|
+
// src/barlist/compile-barlist.ts
|
|
6389
|
+
import {
|
|
6390
|
+
adaptTheme,
|
|
6391
|
+
buildD3Formatter as buildD3Formatter4,
|
|
6392
|
+
computeChrome,
|
|
6393
|
+
estimateTextWidth as estimateTextWidth7,
|
|
6394
|
+
formatNumber as formatNumber2,
|
|
6395
|
+
resolveTheme
|
|
6396
|
+
} from "@opendata-ai/openchart-core";
|
|
6397
|
+
|
|
6398
|
+
// src/compiler/animation.ts
|
|
6399
|
+
var ENTER_DEFAULTS = {
|
|
6400
|
+
duration: 500,
|
|
6401
|
+
ease: "smooth",
|
|
6402
|
+
staggerDelay: 80,
|
|
6403
|
+
staggerOrder: "index",
|
|
6404
|
+
annotationDelay: 200
|
|
6405
|
+
};
|
|
6406
|
+
var MAX_TOTAL_STAGGER_MS = 2e3;
|
|
6407
|
+
function resolveAnimation(spec) {
|
|
6408
|
+
if (spec === void 0 || spec === false) return void 0;
|
|
6409
|
+
if (spec === true) {
|
|
6410
|
+
return {
|
|
6411
|
+
enabled: true,
|
|
6412
|
+
duration: ENTER_DEFAULTS.duration,
|
|
6413
|
+
ease: ENTER_DEFAULTS.ease,
|
|
6414
|
+
staggerDelay: ENTER_DEFAULTS.staggerDelay,
|
|
6415
|
+
staggerOrder: ENTER_DEFAULTS.staggerOrder,
|
|
6416
|
+
annotationDelay: ENTER_DEFAULTS.annotationDelay
|
|
6417
|
+
};
|
|
6300
6418
|
}
|
|
6301
|
-
const
|
|
6302
|
-
|
|
6303
|
-
|
|
6304
|
-
const rm = mark;
|
|
6305
|
-
obstacles.push({ x: rm.x, y: rm.y, width: rm.width, height: rm.height });
|
|
6306
|
-
} else if (mark.type === "point") {
|
|
6307
|
-
const pm = mark;
|
|
6308
|
-
obstacles.push({
|
|
6309
|
-
x: pm.cx - pm.r,
|
|
6310
|
-
y: pm.cy - pm.r,
|
|
6311
|
-
width: pm.r * 2,
|
|
6312
|
-
height: pm.r * 2
|
|
6313
|
-
});
|
|
6314
|
-
}
|
|
6419
|
+
const config = spec;
|
|
6420
|
+
if (config.enter === false || config.enter === void 0 && !hasAnyPhase(config)) {
|
|
6421
|
+
return void 0;
|
|
6315
6422
|
}
|
|
6316
|
-
|
|
6423
|
+
const enterConfig = resolvePhaseConfig(config.enter);
|
|
6424
|
+
return {
|
|
6425
|
+
enabled: true,
|
|
6426
|
+
duration: enterConfig.duration,
|
|
6427
|
+
ease: enterConfig.ease,
|
|
6428
|
+
staggerDelay: enterConfig.staggerDelay,
|
|
6429
|
+
staggerOrder: enterConfig.staggerOrder,
|
|
6430
|
+
annotationDelay: config.annotationDelay ?? ENTER_DEFAULTS.annotationDelay
|
|
6431
|
+
};
|
|
6317
6432
|
}
|
|
6318
|
-
function
|
|
6319
|
-
|
|
6320
|
-
|
|
6321
|
-
let cy;
|
|
6322
|
-
let left2;
|
|
6323
|
-
let right2;
|
|
6324
|
-
if (mark.type === "point") {
|
|
6325
|
-
const pm = mark;
|
|
6326
|
-
cy = pm.cy;
|
|
6327
|
-
left2 = pm.cx - pm.r;
|
|
6328
|
-
right2 = pm.cx + pm.r;
|
|
6329
|
-
} else if (mark.type === "rect") {
|
|
6330
|
-
const rm = mark;
|
|
6331
|
-
cy = rm.y + rm.height / 2;
|
|
6332
|
-
left2 = rm.x;
|
|
6333
|
-
right2 = rm.x + rm.width;
|
|
6334
|
-
} else {
|
|
6335
|
-
continue;
|
|
6336
|
-
}
|
|
6337
|
-
const key = Math.round(cy);
|
|
6338
|
-
const existing = rows.get(key);
|
|
6339
|
-
if (existing) {
|
|
6340
|
-
existing.minX = Math.min(existing.minX, left2);
|
|
6341
|
-
existing.maxX = Math.max(existing.maxX, right2);
|
|
6342
|
-
} else {
|
|
6343
|
-
rows.set(key, { minX: left2, maxX: right2, bandY: cy });
|
|
6344
|
-
}
|
|
6345
|
-
}
|
|
6346
|
-
const bandScale = scales.y.scale;
|
|
6347
|
-
const bandwidth = bandScale.bandwidth?.() ?? 0;
|
|
6348
|
-
if (bandwidth === 0) return [];
|
|
6349
|
-
const obstacles = [];
|
|
6350
|
-
for (const { minX, maxX, bandY } of rows.values()) {
|
|
6351
|
-
obstacles.push({
|
|
6352
|
-
x: minX,
|
|
6353
|
-
y: bandY - bandwidth / 2,
|
|
6354
|
-
width: maxX - minX,
|
|
6355
|
-
height: bandwidth
|
|
6356
|
-
});
|
|
6357
|
-
}
|
|
6358
|
-
return obstacles;
|
|
6433
|
+
function clampStaggerDelay(delay, elementCount) {
|
|
6434
|
+
if (elementCount <= 1) return 0;
|
|
6435
|
+
return Math.min(delay, MAX_TOTAL_STAGGER_MS / elementCount);
|
|
6359
6436
|
}
|
|
6360
|
-
function
|
|
6361
|
-
|
|
6362
|
-
const xType = encoding.x?.type;
|
|
6363
|
-
const yType = encoding.y?.type;
|
|
6364
|
-
const isVertical = (xType === "nominal" || xType === "ordinal" || xType === "temporal") && yType === "quantitative";
|
|
6365
|
-
if (isVertical) {
|
|
6366
|
-
return "bar:vertical";
|
|
6367
|
-
}
|
|
6368
|
-
} else if (markType === "arc") {
|
|
6369
|
-
const innerRadius = markDef.innerRadius;
|
|
6370
|
-
if (innerRadius && innerRadius > 0) {
|
|
6371
|
-
return "arc:donut";
|
|
6372
|
-
}
|
|
6373
|
-
}
|
|
6374
|
-
return markType;
|
|
6437
|
+
function hasAnyPhase(config) {
|
|
6438
|
+
return config.enter !== void 0 || config.update !== void 0 || config.exit !== void 0;
|
|
6375
6439
|
}
|
|
6376
|
-
function
|
|
6377
|
-
|
|
6378
|
-
|
|
6379
|
-
|
|
6380
|
-
|
|
6381
|
-
|
|
6382
|
-
|
|
6383
|
-
|
|
6384
|
-
case "arc":
|
|
6385
|
-
return mark.endAngle - mark.startAngle;
|
|
6386
|
-
// arc angle extent
|
|
6387
|
-
case "line":
|
|
6388
|
-
case "area":
|
|
6389
|
-
return 0;
|
|
6390
|
-
// series marks don't have individual values
|
|
6391
|
-
default:
|
|
6392
|
-
return 0;
|
|
6440
|
+
function resolvePhaseConfig(phase) {
|
|
6441
|
+
if (phase === void 0 || phase === true) {
|
|
6442
|
+
return {
|
|
6443
|
+
duration: ENTER_DEFAULTS.duration,
|
|
6444
|
+
ease: ENTER_DEFAULTS.ease,
|
|
6445
|
+
staggerDelay: ENTER_DEFAULTS.staggerDelay,
|
|
6446
|
+
staggerOrder: ENTER_DEFAULTS.staggerOrder
|
|
6447
|
+
};
|
|
6393
6448
|
}
|
|
6394
|
-
|
|
6395
|
-
|
|
6396
|
-
|
|
6397
|
-
|
|
6398
|
-
|
|
6399
|
-
|
|
6400
|
-
|
|
6401
|
-
|
|
6402
|
-
return av - bv;
|
|
6403
|
-
});
|
|
6404
|
-
for (let i = 0; i < indexed.length; i++) {
|
|
6405
|
-
const m = indexed[i].mark;
|
|
6406
|
-
if (m.type === "rect" && m.stackGroup) continue;
|
|
6407
|
-
m.animationIndex = i;
|
|
6408
|
-
}
|
|
6409
|
-
}
|
|
6410
|
-
const groupIndexMap = /* @__PURE__ */ new Map();
|
|
6411
|
-
const groupStackPos = /* @__PURE__ */ new Map();
|
|
6412
|
-
let nextGroupIndex = 0;
|
|
6413
|
-
for (const mark of marks) {
|
|
6414
|
-
if (mark.type === "rect" && mark.stackGroup) {
|
|
6415
|
-
const rect = mark;
|
|
6416
|
-
const group = rect.stackGroup;
|
|
6417
|
-
if (!groupIndexMap.has(group)) {
|
|
6418
|
-
groupIndexMap.set(group, nextGroupIndex++);
|
|
6419
|
-
}
|
|
6420
|
-
rect.animationIndex = groupIndexMap.get(group);
|
|
6421
|
-
const pos = groupStackPos.get(group) ?? 0;
|
|
6422
|
-
rect.stackPos = pos;
|
|
6423
|
-
groupStackPos.set(group, pos + 1);
|
|
6424
|
-
}
|
|
6425
|
-
}
|
|
6426
|
-
}
|
|
6427
|
-
|
|
6428
|
-
// src/compile/color-scale-range.ts
|
|
6429
|
-
function applyColorScaleRange(scales, encoding, theme) {
|
|
6430
|
-
if (!scales.color) return;
|
|
6431
|
-
const hasExplicitRange = !!(encoding.color && "field" in encoding.color && encoding.color.scale?.range?.length);
|
|
6432
|
-
if (hasExplicitRange) return;
|
|
6433
|
-
if (scales.color.type === "sequential") {
|
|
6434
|
-
const seqStops = Object.values(theme.colors.sequential)[0] ?? theme.colors.categorical;
|
|
6435
|
-
scales.color.scale.range([
|
|
6436
|
-
seqStops[0],
|
|
6437
|
-
seqStops[seqStops.length - 1]
|
|
6438
|
-
]);
|
|
6439
|
-
} else {
|
|
6440
|
-
scales.color.scale.range(theme.colors.categorical);
|
|
6441
|
-
}
|
|
6442
|
-
}
|
|
6443
|
-
|
|
6444
|
-
// src/compile/data-clip.ts
|
|
6445
|
-
function filterClippedDomains(data, encoding) {
|
|
6446
|
-
let result = data;
|
|
6447
|
-
for (const channel of ["x", "y"]) {
|
|
6448
|
-
const enc = encoding[channel];
|
|
6449
|
-
if (!enc?.scale?.clip || !enc.scale.domain) continue;
|
|
6450
|
-
const domain = enc.scale.domain;
|
|
6451
|
-
const field = enc.field;
|
|
6452
|
-
if (Array.isArray(domain) && domain.length === 2 && typeof domain[0] === "number") {
|
|
6453
|
-
const [lo, hi] = domain;
|
|
6454
|
-
result = result.filter((row) => {
|
|
6455
|
-
const v = Number(row[field]);
|
|
6456
|
-
return Number.isFinite(v) && v >= lo && v <= hi;
|
|
6457
|
-
});
|
|
6458
|
-
}
|
|
6459
|
-
}
|
|
6460
|
-
return result;
|
|
6461
|
-
}
|
|
6462
|
-
|
|
6463
|
-
// src/compile/watermark-obstacle.ts
|
|
6464
|
-
import { BRAND_RESERVE_WIDTH } from "@opendata-ai/openchart-core";
|
|
6465
|
-
var WATERMARK_HEIGHT = 30;
|
|
6466
|
-
var X_AXIS_EXTENT_WITH_LABEL = 48;
|
|
6467
|
-
var X_AXIS_EXTENT_TICKS_ONLY = 26;
|
|
6468
|
-
function computeWatermarkObstacle(dims, watermark, axes, theme) {
|
|
6469
|
-
if (!watermark) return null;
|
|
6470
|
-
const chartArea = dims.chartArea;
|
|
6471
|
-
const brandPadding = theme.spacing.padding;
|
|
6472
|
-
const brandX = dims.total.width - brandPadding - BRAND_RESERVE_WIDTH;
|
|
6473
|
-
const xAxisExtent = axes.x?.label ? X_AXIS_EXTENT_WITH_LABEL : axes.x ? X_AXIS_EXTENT_TICKS_ONLY : 0;
|
|
6474
|
-
const firstBottomChrome = dims.chrome.source ?? dims.chrome.byline ?? dims.chrome.footer;
|
|
6475
|
-
const brandY = firstBottomChrome ? chartArea.y + chartArea.height + xAxisExtent + firstBottomChrome.y : chartArea.y + chartArea.height + xAxisExtent + theme.spacing.chartToFooter;
|
|
6476
|
-
return { x: brandX, y: brandY, width: BRAND_RESERVE_WIDTH, height: WATERMARK_HEIGHT };
|
|
6477
|
-
}
|
|
6478
|
-
|
|
6479
|
-
// src/compiler/animation.ts
|
|
6480
|
-
var ENTER_DEFAULTS = {
|
|
6481
|
-
duration: 500,
|
|
6482
|
-
ease: "smooth",
|
|
6483
|
-
staggerDelay: 80,
|
|
6484
|
-
staggerOrder: "index",
|
|
6485
|
-
annotationDelay: 200
|
|
6486
|
-
};
|
|
6487
|
-
var MAX_TOTAL_STAGGER_MS = 2e3;
|
|
6488
|
-
function resolveAnimation(spec) {
|
|
6489
|
-
if (spec === void 0 || spec === false) return void 0;
|
|
6490
|
-
if (spec === true) {
|
|
6491
|
-
return {
|
|
6492
|
-
enabled: true,
|
|
6493
|
-
duration: ENTER_DEFAULTS.duration,
|
|
6494
|
-
ease: ENTER_DEFAULTS.ease,
|
|
6495
|
-
staggerDelay: ENTER_DEFAULTS.staggerDelay,
|
|
6496
|
-
staggerOrder: ENTER_DEFAULTS.staggerOrder,
|
|
6497
|
-
annotationDelay: ENTER_DEFAULTS.annotationDelay
|
|
6498
|
-
};
|
|
6499
|
-
}
|
|
6500
|
-
const config = spec;
|
|
6501
|
-
if (config.enter === false || config.enter === void 0 && !hasAnyPhase(config)) {
|
|
6502
|
-
return void 0;
|
|
6503
|
-
}
|
|
6504
|
-
const enterConfig = resolvePhaseConfig(config.enter);
|
|
6505
|
-
return {
|
|
6506
|
-
enabled: true,
|
|
6507
|
-
duration: enterConfig.duration,
|
|
6508
|
-
ease: enterConfig.ease,
|
|
6509
|
-
staggerDelay: enterConfig.staggerDelay,
|
|
6510
|
-
staggerOrder: enterConfig.staggerOrder,
|
|
6511
|
-
annotationDelay: config.annotationDelay ?? ENTER_DEFAULTS.annotationDelay
|
|
6512
|
-
};
|
|
6513
|
-
}
|
|
6514
|
-
function clampStaggerDelay(delay, elementCount) {
|
|
6515
|
-
if (elementCount <= 1) return 0;
|
|
6516
|
-
return Math.min(delay, MAX_TOTAL_STAGGER_MS / elementCount);
|
|
6517
|
-
}
|
|
6518
|
-
function hasAnyPhase(config) {
|
|
6519
|
-
return config.enter !== void 0 || config.update !== void 0 || config.exit !== void 0;
|
|
6520
|
-
}
|
|
6521
|
-
function resolvePhaseConfig(phase) {
|
|
6522
|
-
if (phase === void 0 || phase === true) {
|
|
6523
|
-
return {
|
|
6524
|
-
duration: ENTER_DEFAULTS.duration,
|
|
6525
|
-
ease: ENTER_DEFAULTS.ease,
|
|
6526
|
-
staggerDelay: ENTER_DEFAULTS.staggerDelay,
|
|
6527
|
-
staggerOrder: ENTER_DEFAULTS.staggerOrder
|
|
6528
|
-
};
|
|
6529
|
-
}
|
|
6530
|
-
const cfg = phase;
|
|
6531
|
-
const stagger = resolveStagger(cfg.stagger);
|
|
6532
|
-
return {
|
|
6533
|
-
duration: cfg.duration ?? ENTER_DEFAULTS.duration,
|
|
6534
|
-
ease: cfg.ease ?? ENTER_DEFAULTS.ease,
|
|
6535
|
-
staggerDelay: stagger.delay,
|
|
6536
|
-
staggerOrder: stagger.order
|
|
6537
|
-
};
|
|
6449
|
+
const cfg = phase;
|
|
6450
|
+
const stagger = resolveStagger(cfg.stagger);
|
|
6451
|
+
return {
|
|
6452
|
+
duration: cfg.duration ?? ENTER_DEFAULTS.duration,
|
|
6453
|
+
ease: cfg.ease ?? ENTER_DEFAULTS.ease,
|
|
6454
|
+
staggerDelay: stagger.delay,
|
|
6455
|
+
staggerOrder: stagger.order
|
|
6456
|
+
};
|
|
6538
6457
|
}
|
|
6539
6458
|
function resolveStagger(stagger) {
|
|
6540
6459
|
if (stagger === false) return { delay: 0, order: "index" };
|
|
@@ -6549,6 +6468,7 @@ function resolveStagger(stagger) {
|
|
|
6549
6468
|
|
|
6550
6469
|
// src/compiler/normalize.ts
|
|
6551
6470
|
import {
|
|
6471
|
+
isBarListSpec,
|
|
6552
6472
|
isChartSpec,
|
|
6553
6473
|
isGraphSpec,
|
|
6554
6474
|
isLayerSpec,
|
|
@@ -6806,7 +6726,8 @@ function normalizeLabels(labels) {
|
|
|
6806
6726
|
density: labels.density ?? "auto",
|
|
6807
6727
|
format: labels.format ?? "",
|
|
6808
6728
|
prefix: labels.prefix ?? "",
|
|
6809
|
-
offsets: labels.offsets
|
|
6729
|
+
offsets: labels.offsets,
|
|
6730
|
+
color: labels.color
|
|
6810
6731
|
};
|
|
6811
6732
|
}
|
|
6812
6733
|
function normalizeChartSpec(spec, warnings) {
|
|
@@ -6952,6 +6873,22 @@ function normalizeTileMapSpec(spec, warnings) {
|
|
|
6952
6873
|
valueFormat: spec.valueFormat
|
|
6953
6874
|
};
|
|
6954
6875
|
}
|
|
6876
|
+
function normalizeBarListSpec(spec, _warnings) {
|
|
6877
|
+
return {
|
|
6878
|
+
type: "barlist",
|
|
6879
|
+
data: spec.data,
|
|
6880
|
+
encoding: spec.encoding,
|
|
6881
|
+
barHeight: spec.barHeight ?? 6,
|
|
6882
|
+
cornerRadius: spec.cornerRadius ?? "pill",
|
|
6883
|
+
maxItems: spec.maxItems ?? 20,
|
|
6884
|
+
chrome: normalizeChrome(spec.chrome),
|
|
6885
|
+
theme: spec.theme ?? {},
|
|
6886
|
+
darkMode: spec.darkMode ?? "off",
|
|
6887
|
+
watermark: spec.watermark ?? true,
|
|
6888
|
+
animation: spec.animation ?? true,
|
|
6889
|
+
valueFormat: spec.valueFormat
|
|
6890
|
+
};
|
|
6891
|
+
}
|
|
6955
6892
|
function normalizeSpec(spec, warnings = []) {
|
|
6956
6893
|
if (isLayerSpec(spec)) {
|
|
6957
6894
|
const leaves = flattenLayers(spec);
|
|
@@ -6975,8 +6912,11 @@ function normalizeSpec(spec, warnings = []) {
|
|
|
6975
6912
|
if (isTileMapSpec(spec)) {
|
|
6976
6913
|
return normalizeTileMapSpec(spec, warnings);
|
|
6977
6914
|
}
|
|
6915
|
+
if (isBarListSpec(spec)) {
|
|
6916
|
+
return normalizeBarListSpec(spec, warnings);
|
|
6917
|
+
}
|
|
6978
6918
|
throw new Error(
|
|
6979
|
-
`Unknown spec shape. Expected mark (chart), layer, type: 'table', type: 'graph', type: 'sankey', or type: '
|
|
6919
|
+
`Unknown spec shape. Expected mark (chart), layer, type: 'table', type: 'graph', type: 'sankey', type: 'tilemap', or type: 'barlist'.`
|
|
6980
6920
|
);
|
|
6981
6921
|
}
|
|
6982
6922
|
function flattenLayers(spec, parentData, parentEncoding, parentTransforms, parentWatermark) {
|
|
@@ -7616,6 +7556,98 @@ function validateTileMapSpec(spec, errors) {
|
|
|
7616
7556
|
});
|
|
7617
7557
|
}
|
|
7618
7558
|
}
|
|
7559
|
+
function validateBarListSpec(spec, errors) {
|
|
7560
|
+
if (!Array.isArray(spec.data)) {
|
|
7561
|
+
errors.push({
|
|
7562
|
+
message: 'Spec error: barlist spec requires a "data" array',
|
|
7563
|
+
path: "data",
|
|
7564
|
+
code: "INVALID_TYPE",
|
|
7565
|
+
suggestion: 'Provide data as an array of objects, e.g. data: [{ label: "Category A", value: 42 }]'
|
|
7566
|
+
});
|
|
7567
|
+
return;
|
|
7568
|
+
}
|
|
7569
|
+
if (spec.data.length === 0) {
|
|
7570
|
+
errors.push({
|
|
7571
|
+
message: 'Spec error: "data" array must be non-empty',
|
|
7572
|
+
path: "data",
|
|
7573
|
+
code: "EMPTY_DATA",
|
|
7574
|
+
suggestion: "Add at least one data row"
|
|
7575
|
+
});
|
|
7576
|
+
return;
|
|
7577
|
+
}
|
|
7578
|
+
const firstRow = spec.data[0];
|
|
7579
|
+
if (typeof firstRow !== "object" || firstRow === null || Array.isArray(firstRow)) {
|
|
7580
|
+
errors.push({
|
|
7581
|
+
message: 'Spec error: each item in "data" must be a plain object',
|
|
7582
|
+
path: "data[0]",
|
|
7583
|
+
code: "INVALID_TYPE",
|
|
7584
|
+
suggestion: 'Each data item should be an object, e.g. { label: "Category A", value: 42 }'
|
|
7585
|
+
});
|
|
7586
|
+
return;
|
|
7587
|
+
}
|
|
7588
|
+
if (!spec.encoding || typeof spec.encoding !== "object") {
|
|
7589
|
+
errors.push({
|
|
7590
|
+
message: 'Spec error: barlist spec requires an "encoding" object with label and value channels',
|
|
7591
|
+
path: "encoding",
|
|
7592
|
+
code: "MISSING_FIELD",
|
|
7593
|
+
suggestion: 'Add an encoding object, e.g. encoding: { label: { field: "name", type: "nominal" }, value: { field: "count", type: "quantitative" } }'
|
|
7594
|
+
});
|
|
7595
|
+
return;
|
|
7596
|
+
}
|
|
7597
|
+
const encoding = spec.encoding;
|
|
7598
|
+
const dataColumns = new Set(Object.keys(firstRow));
|
|
7599
|
+
const availableColumns = [...dataColumns].join(", ");
|
|
7600
|
+
for (const channel of ["label", "value"]) {
|
|
7601
|
+
const ch = encoding[channel];
|
|
7602
|
+
if (!ch || typeof ch !== "object") {
|
|
7603
|
+
errors.push({
|
|
7604
|
+
message: `Spec error: barlist encoding requires "${channel}" channel`,
|
|
7605
|
+
path: `encoding.${channel}`,
|
|
7606
|
+
code: "MISSING_FIELD",
|
|
7607
|
+
suggestion: `Add encoding.${channel} with a field from your data (${availableColumns}). Example: ${channel}: { field: "${[...dataColumns][0] ?? "myField"}", type: "${channel === "value" ? "quantitative" : "nominal"}" }`
|
|
7608
|
+
});
|
|
7609
|
+
continue;
|
|
7610
|
+
}
|
|
7611
|
+
if (!ch.field || typeof ch.field !== "string") {
|
|
7612
|
+
errors.push({
|
|
7613
|
+
message: `Spec error: encoding.${channel} must have a "field" string`,
|
|
7614
|
+
path: `encoding.${channel}.field`,
|
|
7615
|
+
code: "MISSING_FIELD",
|
|
7616
|
+
suggestion: `Add a field name from your data columns: ${availableColumns}`
|
|
7617
|
+
});
|
|
7618
|
+
continue;
|
|
7619
|
+
}
|
|
7620
|
+
if (!dataColumns.has(ch.field)) {
|
|
7621
|
+
errors.push({
|
|
7622
|
+
message: `Spec error: encoding.${channel}.field "${ch.field}" does not exist in data. Available columns: ${availableColumns}`,
|
|
7623
|
+
path: `encoding.${channel}.field`,
|
|
7624
|
+
code: "DATA_FIELD_MISSING",
|
|
7625
|
+
suggestion: `Use one of the available data columns: ${availableColumns}`
|
|
7626
|
+
});
|
|
7627
|
+
}
|
|
7628
|
+
}
|
|
7629
|
+
for (const channel of ["subtitle", "color", "tooltip"]) {
|
|
7630
|
+
const ch = encoding[channel];
|
|
7631
|
+
if (!ch) continue;
|
|
7632
|
+
const field = ch.field;
|
|
7633
|
+
if (field && typeof field === "string" && !dataColumns.has(field)) {
|
|
7634
|
+
errors.push({
|
|
7635
|
+
message: `Spec error: encoding.${channel}.field "${field}" does not exist in data. Available columns: ${availableColumns}`,
|
|
7636
|
+
path: `encoding.${channel}.field`,
|
|
7637
|
+
code: "DATA_FIELD_MISSING",
|
|
7638
|
+
suggestion: `Use one of the available data columns: ${availableColumns}`
|
|
7639
|
+
});
|
|
7640
|
+
}
|
|
7641
|
+
}
|
|
7642
|
+
if (spec.darkMode !== void 0 && !VALID_DARK_MODES.has(spec.darkMode)) {
|
|
7643
|
+
errors.push({
|
|
7644
|
+
message: 'Spec error: darkMode must be "auto", "force", or "off"',
|
|
7645
|
+
path: "darkMode",
|
|
7646
|
+
code: "INVALID_VALUE",
|
|
7647
|
+
suggestion: 'Use one of: "auto" (system preference), "force" (always dark), or "off" (always light)'
|
|
7648
|
+
});
|
|
7649
|
+
}
|
|
7650
|
+
}
|
|
7619
7651
|
function validateLayerSpec(spec, errors) {
|
|
7620
7652
|
const layer = spec.layer;
|
|
7621
7653
|
if (layer.length === 0) {
|
|
@@ -7688,105 +7720,550 @@ function validateLayerSpec(spec, errors) {
|
|
|
7688
7720
|
}
|
|
7689
7721
|
}
|
|
7690
7722
|
}
|
|
7691
|
-
}
|
|
7692
|
-
function validateSpec(spec) {
|
|
7693
|
-
const errors = [];
|
|
7694
|
-
if (!spec || typeof spec !== "object" || Array.isArray(spec)) {
|
|
7695
|
-
return {
|
|
7696
|
-
valid: false,
|
|
7697
|
-
errors: [
|
|
7698
|
-
{
|
|
7699
|
-
message: "Spec error: spec must be a non-null object",
|
|
7700
|
-
code: "INVALID_TYPE",
|
|
7701
|
-
suggestion: 'Pass a spec object with at least a "mark" field for charts, e.g. { mark: "line", data: [...], encoding: {...} }'
|
|
7702
|
-
}
|
|
7703
|
-
],
|
|
7704
|
-
normalized: null
|
|
7705
|
-
};
|
|
7723
|
+
}
|
|
7724
|
+
function validateSpec(spec) {
|
|
7725
|
+
const errors = [];
|
|
7726
|
+
if (!spec || typeof spec !== "object" || Array.isArray(spec)) {
|
|
7727
|
+
return {
|
|
7728
|
+
valid: false,
|
|
7729
|
+
errors: [
|
|
7730
|
+
{
|
|
7731
|
+
message: "Spec error: spec must be a non-null object",
|
|
7732
|
+
code: "INVALID_TYPE",
|
|
7733
|
+
suggestion: 'Pass a spec object with at least a "mark" field for charts, e.g. { mark: "line", data: [...], encoding: {...} }'
|
|
7734
|
+
}
|
|
7735
|
+
],
|
|
7736
|
+
normalized: null
|
|
7737
|
+
};
|
|
7738
|
+
}
|
|
7739
|
+
const obj = spec;
|
|
7740
|
+
const hasLayer = "layer" in obj && Array.isArray(obj.layer);
|
|
7741
|
+
const hasMark = "mark" in obj;
|
|
7742
|
+
const isTable = obj.type === "table";
|
|
7743
|
+
const isGraph = obj.type === "graph";
|
|
7744
|
+
const isSankey = obj.type === "sankey";
|
|
7745
|
+
const isTileMap = obj.type === "tilemap";
|
|
7746
|
+
const isBarList = obj.type === "barlist";
|
|
7747
|
+
const isLayer = hasLayer && !isTable && !isGraph && !isSankey && !isTileMap && !isBarList;
|
|
7748
|
+
const isChart = hasMark && !hasLayer && !isTable && !isGraph && !isSankey && !isTileMap && !isBarList;
|
|
7749
|
+
if (!isChart && !isTable && !isGraph && !isSankey && !isTileMap && !isBarList && !isLayer) {
|
|
7750
|
+
return {
|
|
7751
|
+
valid: false,
|
|
7752
|
+
errors: [
|
|
7753
|
+
{
|
|
7754
|
+
message: 'Spec error: spec must have a "mark" field for charts, a "layer" array for layered charts, or a "type" field for tables/graphs/sankey/tilemap/barlist',
|
|
7755
|
+
path: "mark",
|
|
7756
|
+
code: "MISSING_FIELD",
|
|
7757
|
+
suggestion: `Add a "mark" field for charts (e.g. mark: "bar"), a "layer" array for layered charts, or a "type" field (type: "table", type: "graph", type: "sankey", type: "tilemap", or type: "barlist"). Valid mark types: ${[...MARK_TYPES].join(", ")}`
|
|
7758
|
+
}
|
|
7759
|
+
],
|
|
7760
|
+
normalized: null
|
|
7761
|
+
};
|
|
7762
|
+
}
|
|
7763
|
+
if (isLayer) {
|
|
7764
|
+
validateLayerSpec(obj, errors);
|
|
7765
|
+
}
|
|
7766
|
+
if (isChart) {
|
|
7767
|
+
const mark = obj.mark;
|
|
7768
|
+
let markValue;
|
|
7769
|
+
if (typeof mark === "string") {
|
|
7770
|
+
markValue = mark;
|
|
7771
|
+
} else if (mark && typeof mark === "object" && !Array.isArray(mark)) {
|
|
7772
|
+
markValue = mark.type;
|
|
7773
|
+
}
|
|
7774
|
+
if (!markValue || !MARK_TYPES.has(markValue)) {
|
|
7775
|
+
return {
|
|
7776
|
+
valid: false,
|
|
7777
|
+
errors: [
|
|
7778
|
+
{
|
|
7779
|
+
message: `Spec error: "${markValue ?? String(mark)}" is not a valid mark type. Valid mark types: ${[...MARK_TYPES].join(", ")}`,
|
|
7780
|
+
path: "mark",
|
|
7781
|
+
code: "INVALID_VALUE",
|
|
7782
|
+
suggestion: `Change mark to one of: ${[...MARK_TYPES].join(", ")}`
|
|
7783
|
+
}
|
|
7784
|
+
],
|
|
7785
|
+
normalized: null
|
|
7786
|
+
};
|
|
7787
|
+
}
|
|
7788
|
+
validateChartSpec(obj, errors);
|
|
7789
|
+
} else if (isTable) {
|
|
7790
|
+
validateTableSpec(obj, errors);
|
|
7791
|
+
} else if (isGraph) {
|
|
7792
|
+
validateGraphSpec(obj, errors);
|
|
7793
|
+
} else if (isSankey) {
|
|
7794
|
+
validateSankeySpec(obj, errors);
|
|
7795
|
+
} else if (isTileMap) {
|
|
7796
|
+
validateTileMapSpec(obj, errors);
|
|
7797
|
+
} else if (isBarList) {
|
|
7798
|
+
validateBarListSpec(obj, errors);
|
|
7799
|
+
}
|
|
7800
|
+
if (errors.length > 0) {
|
|
7801
|
+
return { valid: false, errors, normalized: null };
|
|
7802
|
+
}
|
|
7803
|
+
return {
|
|
7804
|
+
valid: true,
|
|
7805
|
+
errors: [],
|
|
7806
|
+
normalized: spec
|
|
7807
|
+
};
|
|
7808
|
+
}
|
|
7809
|
+
|
|
7810
|
+
// src/compiler/index.ts
|
|
7811
|
+
function compile(spec) {
|
|
7812
|
+
const validation = validateSpec(spec);
|
|
7813
|
+
if (!validation.valid || !validation.normalized) {
|
|
7814
|
+
const errorMessages = validation.errors.map((e) => e.message).join("\n");
|
|
7815
|
+
throw new Error(`Invalid spec:
|
|
7816
|
+
${errorMessages}`);
|
|
7817
|
+
}
|
|
7818
|
+
const warnings = [];
|
|
7819
|
+
const normalized = normalizeSpec(validation.normalized, warnings);
|
|
7820
|
+
return { spec: normalized, warnings };
|
|
7821
|
+
}
|
|
7822
|
+
|
|
7823
|
+
// src/barlist/compile-barlist.ts
|
|
7824
|
+
var DEFAULT_ROW_GAP = 8;
|
|
7825
|
+
var LABEL_BAR_GAP = 12;
|
|
7826
|
+
var BAR_VALUE_GAP = 12;
|
|
7827
|
+
var VALUE_WIDTH = 56;
|
|
7828
|
+
var LABEL_FONT_SIZE6 = 13;
|
|
7829
|
+
var LABEL_FONT_WEIGHT6 = 500;
|
|
7830
|
+
var SUBTITLE_FONT_SIZE = 12;
|
|
7831
|
+
var SUBTITLE_FONT_WEIGHT = 400;
|
|
7832
|
+
var VALUE_FONT_SIZE = 12;
|
|
7833
|
+
var VALUE_FONT_WEIGHT = 400;
|
|
7834
|
+
var BARLIST_COLORS = ["#06b6d4", "#34d399", "#fbbf24", "#f472b6", "#a78bfa"];
|
|
7835
|
+
function compileBarList(spec, options) {
|
|
7836
|
+
const { spec: normalized } = compile(spec);
|
|
7837
|
+
if (!("type" in normalized) || normalized.type !== "barlist") {
|
|
7838
|
+
throw new Error(
|
|
7839
|
+
"compileBarList received a non-barlist spec. Use compileChart, compileTable, compileGraph, compileSankey, or compileTileMap instead."
|
|
7840
|
+
);
|
|
7841
|
+
}
|
|
7842
|
+
const barlistSpec = normalized;
|
|
7843
|
+
const rawWatermark = spec.watermark;
|
|
7844
|
+
const watermark = rawWatermark !== void 0 ? barlistSpec.watermark : options.watermark ?? true;
|
|
7845
|
+
const mergedThemeConfig = options.theme ? { ...barlistSpec.theme, ...options.theme } : barlistSpec.theme;
|
|
7846
|
+
const lightTheme = resolveTheme(mergedThemeConfig);
|
|
7847
|
+
let theme = lightTheme;
|
|
7848
|
+
if (options.darkMode) {
|
|
7849
|
+
theme = adaptTheme(theme);
|
|
7850
|
+
}
|
|
7851
|
+
const chrome = computeChrome(
|
|
7852
|
+
{
|
|
7853
|
+
title: barlistSpec.chrome.title,
|
|
7854
|
+
subtitle: barlistSpec.chrome.subtitle,
|
|
7855
|
+
source: barlistSpec.chrome.source,
|
|
7856
|
+
byline: barlistSpec.chrome.byline,
|
|
7857
|
+
footer: barlistSpec.chrome.footer
|
|
7858
|
+
},
|
|
7859
|
+
theme,
|
|
7860
|
+
options.width,
|
|
7861
|
+
options.measureText,
|
|
7862
|
+
"full",
|
|
7863
|
+
void 0,
|
|
7864
|
+
watermark
|
|
7865
|
+
);
|
|
7866
|
+
const padding = theme.spacing.padding;
|
|
7867
|
+
const fullArea = {
|
|
7868
|
+
x: padding,
|
|
7869
|
+
y: padding + chrome.topHeight,
|
|
7870
|
+
width: options.width - padding * 2,
|
|
7871
|
+
height: options.height - chrome.topHeight - chrome.bottomHeight - padding * 2
|
|
7872
|
+
};
|
|
7873
|
+
if (fullArea.width <= 0 || fullArea.height <= 0) {
|
|
7874
|
+
return emptyLayout(chrome, theme, options, watermark);
|
|
7875
|
+
}
|
|
7876
|
+
const labelField = barlistSpec.encoding.label.field;
|
|
7877
|
+
const valueField = barlistSpec.encoding.value.field;
|
|
7878
|
+
const subtitleField = barlistSpec.encoding.subtitle?.field;
|
|
7879
|
+
const colorField = barlistSpec.encoding.color?.field;
|
|
7880
|
+
const barHeight = barlistSpec.barHeight;
|
|
7881
|
+
const cornerRadius = barlistSpec.cornerRadius === "pill" ? barHeight / 2 : barlistSpec.cornerRadius;
|
|
7882
|
+
const rowContentHeight = Math.max(barHeight, LABEL_FONT_SIZE6 * 1.4);
|
|
7883
|
+
const rowHeight = rowContentHeight + DEFAULT_ROW_GAP;
|
|
7884
|
+
const maxFittingRows = Math.max(1, Math.floor(fullArea.height / rowHeight));
|
|
7885
|
+
const validRows = barlistSpec.data.filter((row) => {
|
|
7886
|
+
const val = row[valueField];
|
|
7887
|
+
return val !== null && val !== void 0 && !Number.isNaN(Number(val));
|
|
7888
|
+
}).sort((a, b) => Number(b[valueField]) - Number(a[valueField])).slice(0, Math.min(barlistSpec.maxItems, maxFittingRows));
|
|
7889
|
+
if (validRows.length === 0) {
|
|
7890
|
+
return emptyLayout(chrome, theme, options, watermark);
|
|
7891
|
+
}
|
|
7892
|
+
const maxValue = Math.max(...validRows.map((r) => Math.abs(Number(r[valueField]))));
|
|
7893
|
+
const colorMap = /* @__PURE__ */ new Map();
|
|
7894
|
+
let colorIndex = 0;
|
|
7895
|
+
const palette = BARLIST_COLORS;
|
|
7896
|
+
function getColor2(row, idx) {
|
|
7897
|
+
if (colorField) {
|
|
7898
|
+
const key = String(row[colorField] ?? "");
|
|
7899
|
+
if (!colorMap.has(key)) {
|
|
7900
|
+
colorMap.set(key, palette[colorIndex % palette.length]);
|
|
7901
|
+
colorIndex++;
|
|
7902
|
+
}
|
|
7903
|
+
return colorMap.get(key);
|
|
7904
|
+
}
|
|
7905
|
+
return palette[idx % palette.length];
|
|
7906
|
+
}
|
|
7907
|
+
const formatter = buildD3Formatter4(barlistSpec.valueFormat) ?? formatNumber2;
|
|
7908
|
+
const measureText = options.measureText ?? ((text, fontSize) => ({
|
|
7909
|
+
width: estimateTextWidth7(text, fontSize),
|
|
7910
|
+
height: fontSize
|
|
7911
|
+
}));
|
|
7912
|
+
const perRowLabelWidths = /* @__PURE__ */ new Map();
|
|
7913
|
+
let maxCombinedWidth = 0;
|
|
7914
|
+
for (let i = 0; i < validRows.length; i++) {
|
|
7915
|
+
const row = validRows[i];
|
|
7916
|
+
const label = String(row[labelField] ?? "");
|
|
7917
|
+
const labelW = measureText(label, LABEL_FONT_SIZE6, LABEL_FONT_WEIGHT6).width;
|
|
7918
|
+
perRowLabelWidths.set(i, labelW);
|
|
7919
|
+
let combined = labelW + 4;
|
|
7920
|
+
if (subtitleField && row[subtitleField] != null) {
|
|
7921
|
+
const subtitle = String(row[subtitleField]);
|
|
7922
|
+
combined = labelW + 6 + measureText(subtitle, SUBTITLE_FONT_SIZE, SUBTITLE_FONT_WEIGHT).width + 4;
|
|
7923
|
+
}
|
|
7924
|
+
maxCombinedWidth = Math.max(maxCombinedWidth, combined);
|
|
7925
|
+
}
|
|
7926
|
+
const isNarrow = fullArea.width < 400;
|
|
7927
|
+
const labelBarGap = isNarrow ? 8 : LABEL_BAR_GAP;
|
|
7928
|
+
const barValueGap = isNarrow ? 6 : BAR_VALUE_GAP;
|
|
7929
|
+
const valueWidth = isNarrow ? 44 : VALUE_WIDTH;
|
|
7930
|
+
const maxLabelPct = isNarrow ? 0.35 : 0.4;
|
|
7931
|
+
const labelWidth = Math.max(50, Math.min(maxCombinedWidth, fullArea.width * maxLabelPct));
|
|
7932
|
+
const barAreaWidth = fullArea.width - labelWidth - labelBarGap - barValueGap - valueWidth;
|
|
7933
|
+
const labelColor = theme.colors.text;
|
|
7934
|
+
const subtitleColor = options.darkMode ? "rgba(255,255,255,0.5)" : "rgba(0,0,0,0.45)";
|
|
7935
|
+
const valueColor = options.darkMode ? "rgba(255,255,255,0.6)" : "rgba(0,0,0,0.55)";
|
|
7936
|
+
const rows = [];
|
|
7937
|
+
for (let i = 0; i < validRows.length; i++) {
|
|
7938
|
+
const row = validRows[i];
|
|
7939
|
+
const value2 = Number(row[valueField]);
|
|
7940
|
+
const labelText = String(row[labelField] ?? "");
|
|
7941
|
+
const formattedValue = formatter(value2);
|
|
7942
|
+
const barColor = getColor2(row, i);
|
|
7943
|
+
const pct = maxValue > 0 ? Math.abs(value2) / maxValue : 0;
|
|
7944
|
+
const rowY = fullArea.y + i * rowHeight;
|
|
7945
|
+
const centerY = rowY + rowContentHeight / 2;
|
|
7946
|
+
const labelX = fullArea.x;
|
|
7947
|
+
const labelStyle = {
|
|
7948
|
+
fontFamily: theme.fonts.family,
|
|
7949
|
+
fontSize: LABEL_FONT_SIZE6,
|
|
7950
|
+
fontWeight: LABEL_FONT_WEIGHT6,
|
|
7951
|
+
fill: labelColor,
|
|
7952
|
+
lineHeight: 1.4
|
|
7953
|
+
};
|
|
7954
|
+
let subtitle;
|
|
7955
|
+
if (subtitleField && row[subtitleField] != null) {
|
|
7956
|
+
const subtitleText = String(row[subtitleField]);
|
|
7957
|
+
const subtitleX = labelX + (perRowLabelWidths.get(i) ?? 0) + 6;
|
|
7958
|
+
subtitle = {
|
|
7959
|
+
text: subtitleText,
|
|
7960
|
+
x: subtitleX,
|
|
7961
|
+
y: centerY,
|
|
7962
|
+
style: {
|
|
7963
|
+
fontFamily: theme.fonts.family,
|
|
7964
|
+
fontSize: SUBTITLE_FONT_SIZE,
|
|
7965
|
+
fontWeight: SUBTITLE_FONT_WEIGHT,
|
|
7966
|
+
fill: subtitleColor,
|
|
7967
|
+
lineHeight: 1.4
|
|
7968
|
+
},
|
|
7969
|
+
visible: true
|
|
7970
|
+
};
|
|
7971
|
+
}
|
|
7972
|
+
const trackX = fullArea.x + labelWidth + labelBarGap;
|
|
7973
|
+
const trackY = centerY - barHeight / 2;
|
|
7974
|
+
const trackWidth = Math.max(barAreaWidth, 0);
|
|
7975
|
+
const barWidth = Math.max(pct * trackWidth, 0);
|
|
7976
|
+
const valueLabelX = trackX + trackWidth + barValueGap + valueWidth;
|
|
7977
|
+
const valueLabelStyle = {
|
|
7978
|
+
fontFamily: `${theme.fonts.family}, ui-monospace, monospace`,
|
|
7979
|
+
fontSize: VALUE_FONT_SIZE,
|
|
7980
|
+
fontWeight: VALUE_FONT_WEIGHT,
|
|
7981
|
+
fill: valueColor,
|
|
7982
|
+
lineHeight: 1.4
|
|
7983
|
+
};
|
|
7984
|
+
const rowMark = {
|
|
7985
|
+
type: "barlist-row",
|
|
7986
|
+
index: i,
|
|
7987
|
+
y: rowY,
|
|
7988
|
+
height: rowHeight,
|
|
7989
|
+
label: {
|
|
7990
|
+
text: labelText,
|
|
7991
|
+
x: labelX,
|
|
7992
|
+
y: centerY,
|
|
7993
|
+
style: labelStyle,
|
|
7994
|
+
visible: true
|
|
7995
|
+
},
|
|
7996
|
+
subtitle,
|
|
7997
|
+
track: {
|
|
7998
|
+
x: trackX,
|
|
7999
|
+
y: trackY,
|
|
8000
|
+
width: trackWidth,
|
|
8001
|
+
height: barHeight,
|
|
8002
|
+
cornerRadius
|
|
8003
|
+
},
|
|
8004
|
+
bar: {
|
|
8005
|
+
x: trackX,
|
|
8006
|
+
y: trackY,
|
|
8007
|
+
width: barWidth,
|
|
8008
|
+
height: barHeight,
|
|
8009
|
+
cornerRadius,
|
|
8010
|
+
fill: barColor
|
|
8011
|
+
},
|
|
8012
|
+
valueLabel: {
|
|
8013
|
+
text: formattedValue,
|
|
8014
|
+
x: valueLabelX,
|
|
8015
|
+
y: centerY,
|
|
8016
|
+
style: valueLabelStyle,
|
|
8017
|
+
visible: true
|
|
8018
|
+
},
|
|
8019
|
+
value: value2,
|
|
8020
|
+
formattedValue,
|
|
8021
|
+
aria: {
|
|
8022
|
+
role: "listitem",
|
|
8023
|
+
label: `${labelText}: ${formattedValue}`
|
|
8024
|
+
},
|
|
8025
|
+
animationIndex: i,
|
|
8026
|
+
data: row
|
|
8027
|
+
};
|
|
8028
|
+
rows.push(rowMark);
|
|
8029
|
+
}
|
|
8030
|
+
const tooltipDescriptors = /* @__PURE__ */ new Map();
|
|
8031
|
+
for (const row of rows) {
|
|
8032
|
+
const fields = [
|
|
8033
|
+
{ label: barlistSpec.encoding.value.title ?? valueField, value: row.formattedValue }
|
|
8034
|
+
];
|
|
8035
|
+
tooltipDescriptors.set(String(row.index), {
|
|
8036
|
+
title: row.label.text,
|
|
8037
|
+
fields
|
|
8038
|
+
});
|
|
8039
|
+
}
|
|
8040
|
+
const a11y = {
|
|
8041
|
+
altText: `Bar list showing ${rows.length} items ranked by ${valueField}`,
|
|
8042
|
+
dataTableFallback: rows.map((r) => [r.label.text, r.formattedValue]),
|
|
8043
|
+
role: "list",
|
|
8044
|
+
keyboardNavigable: rows.length > 0
|
|
8045
|
+
};
|
|
8046
|
+
const resolvedAnimation = resolveAnimation(barlistSpec.animation);
|
|
8047
|
+
return {
|
|
8048
|
+
area: fullArea,
|
|
8049
|
+
chrome,
|
|
8050
|
+
rows,
|
|
8051
|
+
tooltipDescriptors,
|
|
8052
|
+
a11y,
|
|
8053
|
+
theme,
|
|
8054
|
+
width: options.width,
|
|
8055
|
+
height: options.height,
|
|
8056
|
+
animation: resolvedAnimation,
|
|
8057
|
+
watermark,
|
|
8058
|
+
measureText
|
|
8059
|
+
};
|
|
8060
|
+
}
|
|
8061
|
+
function emptyLayout(chrome, theme, options, watermark) {
|
|
8062
|
+
return {
|
|
8063
|
+
area: { x: 0, y: 0, width: 0, height: 0 },
|
|
8064
|
+
chrome,
|
|
8065
|
+
rows: [],
|
|
8066
|
+
tooltipDescriptors: /* @__PURE__ */ new Map(),
|
|
8067
|
+
a11y: {
|
|
8068
|
+
altText: "Empty bar list",
|
|
8069
|
+
dataTableFallback: [],
|
|
8070
|
+
role: "list",
|
|
8071
|
+
keyboardNavigable: false
|
|
8072
|
+
},
|
|
8073
|
+
theme,
|
|
8074
|
+
width: options.width,
|
|
8075
|
+
height: options.height,
|
|
8076
|
+
watermark,
|
|
8077
|
+
animation: void 0,
|
|
8078
|
+
measureText: options.measureText ?? ((text, fontSize) => ({ width: estimateTextWidth7(text, fontSize), height: fontSize }))
|
|
8079
|
+
};
|
|
8080
|
+
}
|
|
8081
|
+
|
|
8082
|
+
// src/charts/post-process.ts
|
|
8083
|
+
function computeMarkObstacles(marks, scales) {
|
|
8084
|
+
if (scales.y?.type === "band") {
|
|
8085
|
+
return computeBandRowObstacles(marks, scales);
|
|
8086
|
+
}
|
|
8087
|
+
const obstacles = [];
|
|
8088
|
+
for (const mark of marks) {
|
|
8089
|
+
if (mark.type === "rect") {
|
|
8090
|
+
const rm = mark;
|
|
8091
|
+
obstacles.push({ x: rm.x, y: rm.y, width: rm.width, height: rm.height });
|
|
8092
|
+
} else if (mark.type === "point") {
|
|
8093
|
+
const pm = mark;
|
|
8094
|
+
obstacles.push({
|
|
8095
|
+
x: pm.cx - pm.r,
|
|
8096
|
+
y: pm.cy - pm.r,
|
|
8097
|
+
width: pm.r * 2,
|
|
8098
|
+
height: pm.r * 2
|
|
8099
|
+
});
|
|
8100
|
+
}
|
|
8101
|
+
}
|
|
8102
|
+
return obstacles;
|
|
8103
|
+
}
|
|
8104
|
+
function computeBandRowObstacles(marks, scales) {
|
|
8105
|
+
const rows = /* @__PURE__ */ new Map();
|
|
8106
|
+
for (const mark of marks) {
|
|
8107
|
+
let cy;
|
|
8108
|
+
let left2;
|
|
8109
|
+
let right2;
|
|
8110
|
+
if (mark.type === "point") {
|
|
8111
|
+
const pm = mark;
|
|
8112
|
+
cy = pm.cy;
|
|
8113
|
+
left2 = pm.cx - pm.r;
|
|
8114
|
+
right2 = pm.cx + pm.r;
|
|
8115
|
+
} else if (mark.type === "rect") {
|
|
8116
|
+
const rm = mark;
|
|
8117
|
+
cy = rm.y + rm.height / 2;
|
|
8118
|
+
left2 = rm.x;
|
|
8119
|
+
right2 = rm.x + rm.width;
|
|
8120
|
+
} else {
|
|
8121
|
+
continue;
|
|
8122
|
+
}
|
|
8123
|
+
const key = Math.round(cy);
|
|
8124
|
+
const existing = rows.get(key);
|
|
8125
|
+
if (existing) {
|
|
8126
|
+
existing.minX = Math.min(existing.minX, left2);
|
|
8127
|
+
existing.maxX = Math.max(existing.maxX, right2);
|
|
8128
|
+
} else {
|
|
8129
|
+
rows.set(key, { minX: left2, maxX: right2, bandY: cy });
|
|
8130
|
+
}
|
|
8131
|
+
}
|
|
8132
|
+
const bandScale = scales.y.scale;
|
|
8133
|
+
const bandwidth = bandScale.bandwidth?.() ?? 0;
|
|
8134
|
+
if (bandwidth === 0) return [];
|
|
8135
|
+
const obstacles = [];
|
|
8136
|
+
for (const { minX, maxX, bandY } of rows.values()) {
|
|
8137
|
+
obstacles.push({
|
|
8138
|
+
x: minX,
|
|
8139
|
+
y: bandY - bandwidth / 2,
|
|
8140
|
+
width: maxX - minX,
|
|
8141
|
+
height: bandwidth
|
|
8142
|
+
});
|
|
7706
8143
|
}
|
|
7707
|
-
|
|
7708
|
-
|
|
7709
|
-
|
|
7710
|
-
|
|
7711
|
-
|
|
7712
|
-
|
|
7713
|
-
|
|
7714
|
-
|
|
7715
|
-
|
|
7716
|
-
|
|
7717
|
-
|
|
7718
|
-
|
|
7719
|
-
|
|
7720
|
-
|
|
7721
|
-
|
|
7722
|
-
path: "mark",
|
|
7723
|
-
code: "MISSING_FIELD",
|
|
7724
|
-
suggestion: `Add a "mark" field for charts (e.g. mark: "bar"), a "layer" array for layered charts, or a "type" field for tables/graphs/sankey/tilemap (type: "table", type: "graph", type: "sankey", or type: "tilemap"). Valid mark types: ${[...MARK_TYPES].join(", ")}`
|
|
7725
|
-
}
|
|
7726
|
-
],
|
|
7727
|
-
normalized: null
|
|
7728
|
-
};
|
|
8144
|
+
return obstacles;
|
|
8145
|
+
}
|
|
8146
|
+
function resolveRendererKey(markType, encoding, markDef) {
|
|
8147
|
+
if (markType === "bar") {
|
|
8148
|
+
const xType = encoding.x?.type;
|
|
8149
|
+
const yType = encoding.y?.type;
|
|
8150
|
+
const isVertical = (xType === "nominal" || xType === "ordinal" || xType === "temporal") && yType === "quantitative";
|
|
8151
|
+
if (isVertical) {
|
|
8152
|
+
return "bar:vertical";
|
|
8153
|
+
}
|
|
8154
|
+
} else if (markType === "arc") {
|
|
8155
|
+
const innerRadius = markDef.innerRadius;
|
|
8156
|
+
if (innerRadius && innerRadius > 0) {
|
|
8157
|
+
return "arc:donut";
|
|
8158
|
+
}
|
|
7729
8159
|
}
|
|
7730
|
-
|
|
7731
|
-
|
|
8160
|
+
return markType;
|
|
8161
|
+
}
|
|
8162
|
+
function getMarkPrimaryValue(mark) {
|
|
8163
|
+
switch (mark.type) {
|
|
8164
|
+
case "rect":
|
|
8165
|
+
return mark.height;
|
|
8166
|
+
// bar height is the primary value encoding
|
|
8167
|
+
case "point":
|
|
8168
|
+
return mark.cy;
|
|
8169
|
+
// y position for scatter
|
|
8170
|
+
case "arc":
|
|
8171
|
+
return mark.endAngle - mark.startAngle;
|
|
8172
|
+
// arc angle extent
|
|
8173
|
+
case "line":
|
|
8174
|
+
case "area":
|
|
8175
|
+
return 0;
|
|
8176
|
+
// series marks don't have individual values
|
|
8177
|
+
default:
|
|
8178
|
+
return 0;
|
|
7732
8179
|
}
|
|
7733
|
-
|
|
7734
|
-
|
|
7735
|
-
|
|
7736
|
-
|
|
7737
|
-
|
|
7738
|
-
|
|
7739
|
-
|
|
8180
|
+
}
|
|
8181
|
+
function assignAnimationIndices(marks, animation) {
|
|
8182
|
+
if (!animation?.enabled) return;
|
|
8183
|
+
if (animation.staggerOrder === "value") {
|
|
8184
|
+
const indexed = marks.map((m, i) => ({ mark: m, idx: i }));
|
|
8185
|
+
indexed.sort((a, b) => {
|
|
8186
|
+
const av = getMarkPrimaryValue(a.mark);
|
|
8187
|
+
const bv = getMarkPrimaryValue(b.mark);
|
|
8188
|
+
return av - bv;
|
|
8189
|
+
});
|
|
8190
|
+
for (let i = 0; i < indexed.length; i++) {
|
|
8191
|
+
const m = indexed[i].mark;
|
|
8192
|
+
if (m.type === "rect" && m.stackGroup) continue;
|
|
8193
|
+
m.animationIndex = i;
|
|
7740
8194
|
}
|
|
7741
|
-
|
|
7742
|
-
|
|
7743
|
-
|
|
7744
|
-
|
|
7745
|
-
|
|
7746
|
-
|
|
7747
|
-
|
|
7748
|
-
|
|
7749
|
-
|
|
7750
|
-
|
|
7751
|
-
|
|
7752
|
-
|
|
7753
|
-
|
|
8195
|
+
}
|
|
8196
|
+
const groupIndexMap = /* @__PURE__ */ new Map();
|
|
8197
|
+
const groupStackPos = /* @__PURE__ */ new Map();
|
|
8198
|
+
let nextGroupIndex = 0;
|
|
8199
|
+
for (const mark of marks) {
|
|
8200
|
+
if (mark.type === "rect" && mark.stackGroup) {
|
|
8201
|
+
const rect = mark;
|
|
8202
|
+
const group = rect.stackGroup;
|
|
8203
|
+
if (!groupIndexMap.has(group)) {
|
|
8204
|
+
groupIndexMap.set(group, nextGroupIndex++);
|
|
8205
|
+
}
|
|
8206
|
+
rect.animationIndex = groupIndexMap.get(group);
|
|
8207
|
+
const pos = groupStackPos.get(group) ?? 0;
|
|
8208
|
+
rect.stackPos = pos;
|
|
8209
|
+
groupStackPos.set(group, pos + 1);
|
|
7754
8210
|
}
|
|
7755
|
-
validateChartSpec(obj, errors);
|
|
7756
|
-
} else if (isTable) {
|
|
7757
|
-
validateTableSpec(obj, errors);
|
|
7758
|
-
} else if (isGraph) {
|
|
7759
|
-
validateGraphSpec(obj, errors);
|
|
7760
|
-
} else if (isSankey) {
|
|
7761
|
-
validateSankeySpec(obj, errors);
|
|
7762
|
-
} else if (isTileMap) {
|
|
7763
|
-
validateTileMapSpec(obj, errors);
|
|
7764
8211
|
}
|
|
7765
|
-
|
|
7766
|
-
|
|
8212
|
+
}
|
|
8213
|
+
|
|
8214
|
+
// src/compile/color-scale-range.ts
|
|
8215
|
+
function applyColorScaleRange(scales, encoding, theme) {
|
|
8216
|
+
if (!scales.color) return;
|
|
8217
|
+
const hasExplicitRange = !!(encoding.color && "field" in encoding.color && encoding.color.scale?.range?.length);
|
|
8218
|
+
if (hasExplicitRange) return;
|
|
8219
|
+
if (scales.color.type === "sequential") {
|
|
8220
|
+
const seqStops = Object.values(theme.colors.sequential)[0] ?? theme.colors.categorical;
|
|
8221
|
+
scales.color.scale.range([
|
|
8222
|
+
seqStops[0],
|
|
8223
|
+
seqStops[seqStops.length - 1]
|
|
8224
|
+
]);
|
|
8225
|
+
} else {
|
|
8226
|
+
scales.color.scale.range(theme.colors.categorical);
|
|
7767
8227
|
}
|
|
7768
|
-
return {
|
|
7769
|
-
valid: true,
|
|
7770
|
-
errors: [],
|
|
7771
|
-
normalized: spec
|
|
7772
|
-
};
|
|
7773
8228
|
}
|
|
7774
8229
|
|
|
7775
|
-
// src/
|
|
7776
|
-
function
|
|
7777
|
-
|
|
7778
|
-
|
|
7779
|
-
const
|
|
7780
|
-
|
|
7781
|
-
|
|
8230
|
+
// src/compile/data-clip.ts
|
|
8231
|
+
function filterClippedDomains(data, encoding) {
|
|
8232
|
+
let result = data;
|
|
8233
|
+
for (const channel of ["x", "y"]) {
|
|
8234
|
+
const enc = encoding[channel];
|
|
8235
|
+
if (!enc?.scale?.clip || !enc.scale.domain) continue;
|
|
8236
|
+
const domain = enc.scale.domain;
|
|
8237
|
+
const field = enc.field;
|
|
8238
|
+
if (Array.isArray(domain) && domain.length === 2 && typeof domain[0] === "number") {
|
|
8239
|
+
const [lo, hi] = domain;
|
|
8240
|
+
result = result.filter((row) => {
|
|
8241
|
+
const v = Number(row[field]);
|
|
8242
|
+
return Number.isFinite(v) && v >= lo && v <= hi;
|
|
8243
|
+
});
|
|
8244
|
+
}
|
|
7782
8245
|
}
|
|
7783
|
-
|
|
7784
|
-
|
|
7785
|
-
|
|
8246
|
+
return result;
|
|
8247
|
+
}
|
|
8248
|
+
|
|
8249
|
+
// src/compile/watermark-obstacle.ts
|
|
8250
|
+
import { BRAND_RESERVE_WIDTH } from "@opendata-ai/openchart-core";
|
|
8251
|
+
var WATERMARK_HEIGHT = 30;
|
|
8252
|
+
var X_AXIS_EXTENT_WITH_LABEL = 48;
|
|
8253
|
+
var X_AXIS_EXTENT_TICKS_ONLY = 26;
|
|
8254
|
+
function computeWatermarkObstacle(dims, watermark, axes, theme) {
|
|
8255
|
+
if (!watermark) return null;
|
|
8256
|
+
const chartArea = dims.chartArea;
|
|
8257
|
+
const brandPadding = theme.spacing.padding;
|
|
8258
|
+
const brandX = dims.total.width - brandPadding - BRAND_RESERVE_WIDTH;
|
|
8259
|
+
const xAxisExtent = axes.x?.label ? X_AXIS_EXTENT_WITH_LABEL : axes.x ? X_AXIS_EXTENT_TICKS_ONLY : 0;
|
|
8260
|
+
const firstBottomChrome = dims.chrome.source ?? dims.chrome.byline ?? dims.chrome.footer;
|
|
8261
|
+
const brandY = firstBottomChrome ? chartArea.y + chartArea.height + xAxisExtent + firstBottomChrome.y : chartArea.y + chartArea.height + xAxisExtent + theme.spacing.chartToFooter;
|
|
8262
|
+
return { x: brandX, y: brandY, width: BRAND_RESERVE_WIDTH, height: WATERMARK_HEIGHT };
|
|
7786
8263
|
}
|
|
7787
8264
|
|
|
7788
8265
|
// src/graphs/compile-graph.ts
|
|
7789
|
-
import { adaptTheme, computeChrome, resolveTheme } from "@opendata-ai/openchart-core";
|
|
8266
|
+
import { adaptTheme as adaptTheme2, computeChrome as computeChrome2, resolveTheme as resolveTheme2 } from "@opendata-ai/openchart-core";
|
|
7790
8267
|
|
|
7791
8268
|
// src/graphs/encoding.ts
|
|
7792
8269
|
var DEFAULT_NODE_RADIUS = 5;
|
|
@@ -8090,9 +8567,9 @@ function compileGraph(spec, options) {
|
|
|
8090
8567
|
const rawWatermark = spec.watermark;
|
|
8091
8568
|
const watermark = rawWatermark !== void 0 ? graphSpec.watermark : options.watermark ?? true;
|
|
8092
8569
|
const mergedThemeConfig = options.theme ? { ...graphSpec.theme, ...options.theme } : graphSpec.theme;
|
|
8093
|
-
let theme =
|
|
8570
|
+
let theme = resolveTheme2(mergedThemeConfig);
|
|
8094
8571
|
if (options.darkMode) {
|
|
8095
|
-
theme =
|
|
8572
|
+
theme = adaptTheme2(theme);
|
|
8096
8573
|
}
|
|
8097
8574
|
const compiledNodes = resolveNodeVisuals(
|
|
8098
8575
|
graphSpec.nodes,
|
|
@@ -8146,7 +8623,7 @@ function compileGraph(spec, options) {
|
|
|
8146
8623
|
linkStrength: graphSpec.layout.linkStrength,
|
|
8147
8624
|
centerForce: graphSpec.layout.centerForce
|
|
8148
8625
|
};
|
|
8149
|
-
const chrome =
|
|
8626
|
+
const chrome = computeChrome2(
|
|
8150
8627
|
{
|
|
8151
8628
|
title: graphSpec.chrome.title,
|
|
8152
8629
|
subtitle: graphSpec.chrome.subtitle,
|
|
@@ -8180,11 +8657,11 @@ function compileGraph(spec, options) {
|
|
|
8180
8657
|
var DEFAULT_COLLISION_PADDING = 5;
|
|
8181
8658
|
|
|
8182
8659
|
// src/layout/axes/thinning.ts
|
|
8183
|
-
import { estimateTextWidth as
|
|
8660
|
+
import { estimateTextWidth as estimateTextWidth8 } from "@opendata-ai/openchart-core";
|
|
8184
8661
|
var MIN_TICK_GAP_FACTOR = 1;
|
|
8185
8662
|
var MIN_TICK_COUNT = 2;
|
|
8186
8663
|
function measureLabel(text, fontSize, fontWeight, measureText) {
|
|
8187
|
-
return measureText ? measureText(text, fontSize, fontWeight).width :
|
|
8664
|
+
return measureText ? measureText(text, fontSize, fontWeight).width : estimateTextWidth8(text, fontSize, fontWeight);
|
|
8188
8665
|
}
|
|
8189
8666
|
function ticksOverlap(ticks2, fontSize, fontWeight, measureText, orientation = "horizontal") {
|
|
8190
8667
|
if (ticks2.length < 2) return false;
|
|
@@ -8226,16 +8703,16 @@ function thinTicksUntilFit(ticks2, fontSize, fontWeight, measureText, orientatio
|
|
|
8226
8703
|
// src/layout/axes/ticks.ts
|
|
8227
8704
|
import {
|
|
8228
8705
|
abbreviateNumber as abbreviateNumber2,
|
|
8229
|
-
buildD3Formatter as
|
|
8706
|
+
buildD3Formatter as buildD3Formatter5,
|
|
8230
8707
|
buildTemporalFormatter,
|
|
8231
|
-
estimateTextWidth as
|
|
8708
|
+
estimateTextWidth as estimateTextWidth9,
|
|
8232
8709
|
formatDate,
|
|
8233
|
-
formatNumber as
|
|
8710
|
+
formatNumber as formatNumber3
|
|
8234
8711
|
} from "@opendata-ai/openchart-core";
|
|
8235
8712
|
var Y_PX_PER_TICK = {
|
|
8236
|
-
full:
|
|
8237
|
-
reduced:
|
|
8238
|
-
minimal:
|
|
8713
|
+
full: 40,
|
|
8714
|
+
reduced: 70,
|
|
8715
|
+
minimal: 120
|
|
8239
8716
|
};
|
|
8240
8717
|
var X_PX_PER_TICK = {
|
|
8241
8718
|
full: 110,
|
|
@@ -8275,7 +8752,8 @@ var NUMERIC_SCALE_TYPES = /* @__PURE__ */ new Set([
|
|
|
8275
8752
|
]);
|
|
8276
8753
|
var TEMPORAL_SCALE_TYPES = /* @__PURE__ */ new Set(["time", "utc"]);
|
|
8277
8754
|
function formatTickLabel(value2, resolvedScale) {
|
|
8278
|
-
const
|
|
8755
|
+
const axisConfig = resolvedScale.channel.axis || void 0;
|
|
8756
|
+
const formatStr = axisConfig?.format;
|
|
8279
8757
|
if (TEMPORAL_SCALE_TYPES.has(resolvedScale.type)) {
|
|
8280
8758
|
const temporalFmt = buildTemporalFormatter(formatStr);
|
|
8281
8759
|
if (temporalFmt) return temporalFmt(value2);
|
|
@@ -8285,11 +8763,11 @@ function formatTickLabel(value2, resolvedScale) {
|
|
|
8285
8763
|
if (NUMERIC_SCALE_TYPES.has(resolvedScale.type)) {
|
|
8286
8764
|
const num = value2;
|
|
8287
8765
|
if (formatStr) {
|
|
8288
|
-
const fmt =
|
|
8766
|
+
const fmt = buildD3Formatter5(formatStr);
|
|
8289
8767
|
if (fmt) return fmt(num);
|
|
8290
8768
|
}
|
|
8291
8769
|
if (Math.abs(num) >= 1e3) return abbreviateNumber2(num);
|
|
8292
|
-
return
|
|
8770
|
+
return formatNumber3(num);
|
|
8293
8771
|
}
|
|
8294
8772
|
return String(value2);
|
|
8295
8773
|
}
|
|
@@ -8303,8 +8781,8 @@ function continuousTicks(resolvedScale, density, targetCount) {
|
|
|
8303
8781
|
label: formatTickLabel(value2, resolvedScale)
|
|
8304
8782
|
}));
|
|
8305
8783
|
}
|
|
8306
|
-
const
|
|
8307
|
-
const count =
|
|
8784
|
+
const axCfg = resolvedScale.channel.axis || void 0;
|
|
8785
|
+
const count = axCfg?.tickCount ?? targetCount ?? TICK_COUNTS[density];
|
|
8308
8786
|
return buildContinuousTicks(resolvedScale, count);
|
|
8309
8787
|
}
|
|
8310
8788
|
function buildContinuousTicks(resolvedScale, count) {
|
|
@@ -8313,7 +8791,21 @@ function buildContinuousTicks(resolvedScale, count) {
|
|
|
8313
8791
|
return continuousTicks(resolvedScale, "full");
|
|
8314
8792
|
}
|
|
8315
8793
|
const raw = scale.ticks(count);
|
|
8316
|
-
|
|
8794
|
+
let ticks2 = raw;
|
|
8795
|
+
if (resolvedScale.type === "log" && raw.length > count) {
|
|
8796
|
+
const base = resolvedScale.channel.scale?.base ?? 10;
|
|
8797
|
+
const logBase = Math.log(base);
|
|
8798
|
+
const powered = raw.filter((v) => {
|
|
8799
|
+
const n = v;
|
|
8800
|
+
if (n <= 0) return false;
|
|
8801
|
+
const exp = Math.log(n) / logBase;
|
|
8802
|
+
return Math.abs(exp - Math.round(exp)) < 1e-9;
|
|
8803
|
+
});
|
|
8804
|
+
if (powered.length >= 2) {
|
|
8805
|
+
ticks2 = powered;
|
|
8806
|
+
}
|
|
8807
|
+
}
|
|
8808
|
+
return ticks2.map((value2) => ({
|
|
8317
8809
|
value: value2,
|
|
8318
8810
|
position: scale(value2),
|
|
8319
8811
|
label: formatTickLabel(value2, resolvedScale)
|
|
@@ -8326,12 +8818,13 @@ function scaleSupportsTickCount(resolvedScale) {
|
|
|
8326
8818
|
function categoricalTicks(resolvedScale, density, orientation = "horizontal", bandwidth, labelAngle, fontSize, fontWeight, measureText, subtitleContext) {
|
|
8327
8819
|
const scale = resolvedScale.scale;
|
|
8328
8820
|
const domain = scale.domain();
|
|
8329
|
-
const
|
|
8821
|
+
const catAxisCfg = resolvedScale.channel.axis || void 0;
|
|
8822
|
+
const explicitTickCount = catAxisCfg?.tickCount;
|
|
8330
8823
|
let selectedValues = domain;
|
|
8331
8824
|
if (resolvedScale.type === "band" && orientation === "horizontal") {
|
|
8332
8825
|
if (bandwidth !== void 0 && bandwidth > 0 && fontSize !== void 0) {
|
|
8333
8826
|
const maxLabelWidth = domain.reduce((max4, v) => {
|
|
8334
|
-
const w = measureText ? measureText(v, fontSize, fontWeight ?? 400).width :
|
|
8827
|
+
const w = measureText ? measureText(v, fontSize, fontWeight ?? 400).width : estimateTextWidth9(v, fontSize, fontWeight ?? 400);
|
|
8335
8828
|
return Math.max(max4, w);
|
|
8336
8829
|
}, 0);
|
|
8337
8830
|
const angleRad = labelAngle !== void 0 ? Math.abs(labelAngle) * Math.PI / 180 : 0;
|
|
@@ -8416,8 +8909,8 @@ function resolveExplicitTicks(values, resolvedScale) {
|
|
|
8416
8909
|
}
|
|
8417
8910
|
|
|
8418
8911
|
// src/layout/axes.ts
|
|
8419
|
-
var HEIGHT_MINIMAL_THRESHOLD =
|
|
8420
|
-
var HEIGHT_REDUCED_THRESHOLD =
|
|
8912
|
+
var HEIGHT_MINIMAL_THRESHOLD = 80;
|
|
8913
|
+
var HEIGHT_REDUCED_THRESHOLD = 100;
|
|
8421
8914
|
var WIDTH_MINIMAL_THRESHOLD = 150;
|
|
8422
8915
|
var WIDTH_REDUCED_THRESHOLD = 300;
|
|
8423
8916
|
var DENSITY_ORDER = ["full", "reduced", "minimal"];
|
|
@@ -8493,7 +8986,7 @@ function computeAxes(scales, chartArea, strategy, theme, measureText, dataContex
|
|
|
8493
8986
|
};
|
|
8494
8987
|
const { fontSize } = tickLabelStyle;
|
|
8495
8988
|
const { fontWeight } = tickLabelStyle;
|
|
8496
|
-
if (scales.x && !dataContext?.skipX) {
|
|
8989
|
+
if (scales.x && !dataContext?.skipX && scales.x.channel.axis !== false) {
|
|
8497
8990
|
const axisConfig = scales.x.channel.axis;
|
|
8498
8991
|
const isContinuousX = scales.x.type !== "band" && scales.x.type !== "point" && scales.x.type !== "ordinal";
|
|
8499
8992
|
const xTargetCount = isContinuousX ? targetTickCount(chartArea.width, xDensity, "x") : void 0;
|
|
@@ -8571,7 +9064,7 @@ function computeAxes(scales, chartArea, strategy, theme, measureText, dataContex
|
|
|
8571
9064
|
labelFlush: axisConfig?.labelFlush
|
|
8572
9065
|
};
|
|
8573
9066
|
}
|
|
8574
|
-
if (scales.y && !dataContext?.skipY) {
|
|
9067
|
+
if (scales.y && !dataContext?.skipY && scales.y.channel.axis !== false) {
|
|
8575
9068
|
const axisConfig = scales.y.channel.axis;
|
|
8576
9069
|
const isContinuousY = scales.y.type !== "band" && scales.y.type !== "point" && scales.y.type !== "ordinal";
|
|
8577
9070
|
const yTargetCount = isContinuousY ? targetTickCount(chartArea.height, yDensity, "y") : void 0;
|
|
@@ -8647,8 +9140,8 @@ function computeAxes(scales, chartArea, strategy, theme, measureText, dataContex
|
|
|
8647
9140
|
import {
|
|
8648
9141
|
AXIS_TITLE_TRAILING_PAD,
|
|
8649
9142
|
BREAKPOINT_COMPACT_MAX,
|
|
8650
|
-
computeChrome as
|
|
8651
|
-
estimateTextWidth as
|
|
9143
|
+
computeChrome as computeChrome3,
|
|
9144
|
+
estimateTextWidth as estimateTextWidth11,
|
|
8652
9145
|
getAxisTitleOffset,
|
|
8653
9146
|
HPAD_COMPACT_FRACTION,
|
|
8654
9147
|
HPAD_COMPACT_MIN,
|
|
@@ -8663,12 +9156,12 @@ import {
|
|
|
8663
9156
|
} from "@opendata-ai/openchart-core";
|
|
8664
9157
|
|
|
8665
9158
|
// src/legend/wrap.ts
|
|
8666
|
-
import { COMPACT_WIDTH, estimateTextWidth as
|
|
9159
|
+
import { COMPACT_WIDTH, estimateTextWidth as estimateTextWidth10 } from "@opendata-ai/openchart-core";
|
|
8667
9160
|
var SWATCH_SIZE2 = 12;
|
|
8668
9161
|
var SWATCH_GAP2 = 6;
|
|
8669
9162
|
var ENTRY_GAP2 = 16;
|
|
8670
9163
|
var ENTRY_GAP_COMPACT = 10;
|
|
8671
|
-
var LEGEND_GAP =
|
|
9164
|
+
var LEGEND_GAP = 8;
|
|
8672
9165
|
function legendGap(width) {
|
|
8673
9166
|
return width < COMPACT_WIDTH ? 0 : LEGEND_GAP;
|
|
8674
9167
|
}
|
|
@@ -8682,7 +9175,7 @@ function measureLegendWrap(entries, maxWidth, labelStyle, maxRows, entryGap = EN
|
|
|
8682
9175
|
let fittingCount = entries.length;
|
|
8683
9176
|
let fittingCountLocked = false;
|
|
8684
9177
|
for (let i = 0; i < entries.length; i++) {
|
|
8685
|
-
const labelWidth =
|
|
9178
|
+
const labelWidth = estimateTextWidth10(
|
|
8686
9179
|
entries[i].label,
|
|
8687
9180
|
labelStyle.fontSize,
|
|
8688
9181
|
labelStyle.fontWeight
|
|
@@ -8728,7 +9221,9 @@ function getMinChartDims(display) {
|
|
|
8728
9221
|
}
|
|
8729
9222
|
function getSparklinePad(spec) {
|
|
8730
9223
|
const strokeWidth = spec.markDef.strokeWidth ?? 2;
|
|
8731
|
-
|
|
9224
|
+
const hasPoints = !!spec.markDef.point;
|
|
9225
|
+
const pointRadius = hasPoints ? 3 : 0;
|
|
9226
|
+
return Math.max(strokeWidth / 2 + 1, pointRadius + 1, 2);
|
|
8732
9227
|
}
|
|
8733
9228
|
function computeDimensions(spec, options, legendLayout, theme, strategy, watermark = true) {
|
|
8734
9229
|
const { width, height } = options;
|
|
@@ -8741,7 +9236,7 @@ function computeDimensions(spec, options, legendLayout, theme, strategy, waterma
|
|
|
8741
9236
|
if (isSparkline && !userExplicit.chrome) {
|
|
8742
9237
|
chromeMode = "hidden";
|
|
8743
9238
|
}
|
|
8744
|
-
const chrome =
|
|
9239
|
+
const chrome = computeChrome3(
|
|
8745
9240
|
chromeToInput(spec.chrome),
|
|
8746
9241
|
theme,
|
|
8747
9242
|
width,
|
|
@@ -8782,11 +9277,12 @@ function computeDimensions(spec, options, legendLayout, theme, strategy, waterma
|
|
|
8782
9277
|
const total = { x: 0, y: 0, width, height };
|
|
8783
9278
|
const isRadial = spec.markType === "arc";
|
|
8784
9279
|
const encoding = spec.encoding;
|
|
8785
|
-
const
|
|
9280
|
+
const xAxisSuppressed = encoding.x?.axis === false;
|
|
9281
|
+
const xAxis = !xAxisSuppressed && encoding.x?.axis;
|
|
8786
9282
|
const hasXAxisLabel = !!xAxis?.title;
|
|
8787
9283
|
const xTickAngle = xAxis?.labelAngle;
|
|
8788
9284
|
let xAxisHeight;
|
|
8789
|
-
if (isRadial) {
|
|
9285
|
+
if (isRadial || xAxisSuppressed) {
|
|
8790
9286
|
xAxisHeight = 0;
|
|
8791
9287
|
} else if (xTickAngle && Math.abs(xTickAngle) > 10) {
|
|
8792
9288
|
const angleRad = Math.abs(xTickAngle) * (Math.PI / 180);
|
|
@@ -8795,7 +9291,7 @@ function computeDimensions(spec, options, legendLayout, theme, strategy, waterma
|
|
|
8795
9291
|
if (xField) {
|
|
8796
9292
|
for (const row of spec.data) {
|
|
8797
9293
|
const label = String(row[xField] ?? "");
|
|
8798
|
-
const w =
|
|
9294
|
+
const w = estimateTextWidth11(label, theme.fonts.sizes.axisTick, theme.fonts.weights.normal);
|
|
8799
9295
|
if (w > maxLabelWidth) maxLabelWidth = w;
|
|
8800
9296
|
}
|
|
8801
9297
|
}
|
|
@@ -8825,7 +9321,7 @@ function computeDimensions(spec, options, legendLayout, theme, strategy, waterma
|
|
|
8825
9321
|
const label = String(row[colorField] ?? "");
|
|
8826
9322
|
if (!seen.has(label)) {
|
|
8827
9323
|
seen.add(label);
|
|
8828
|
-
const w =
|
|
9324
|
+
const w = estimateTextWidth11(label, 11, 600);
|
|
8829
9325
|
if (w > maxLabelWidth) maxLabelWidth = w;
|
|
8830
9326
|
}
|
|
8831
9327
|
}
|
|
@@ -8845,7 +9341,7 @@ function computeDimensions(spec, options, legendLayout, theme, strategy, waterma
|
|
|
8845
9341
|
const maxXStr = String(maxX);
|
|
8846
9342
|
for (const ann of spec.annotations) {
|
|
8847
9343
|
if (ann.type === "text" && String(ann.x) === maxXStr) {
|
|
8848
|
-
const textWidth =
|
|
9344
|
+
const textWidth = estimateTextWidth11(ann.text, ann.fontSize ?? 11, ann.fontWeight ?? 600);
|
|
8849
9345
|
const dx = ann.offset?.dx ?? 0;
|
|
8850
9346
|
const anchor = ann.anchor ?? "auto";
|
|
8851
9347
|
const baseRightExtent = anchor === "left" ? textWidth : (
|
|
@@ -8863,19 +9359,20 @@ function computeDimensions(spec, options, legendLayout, theme, strategy, waterma
|
|
|
8863
9359
|
}
|
|
8864
9360
|
}
|
|
8865
9361
|
}
|
|
8866
|
-
|
|
9362
|
+
const yAxisSuppressed = encoding.y?.axis === false;
|
|
9363
|
+
if (encoding.y && !isRadial && !yAxisSuppressed) {
|
|
8867
9364
|
if (spec.markType === "bar" || spec.markType === "circle" || spec.markType === "lollipop" || encoding.y.type === "nominal" || encoding.y.type === "ordinal") {
|
|
8868
9365
|
const yField = encoding.y.field;
|
|
8869
9366
|
const yLabelField = encoding.y.axis?.labelField;
|
|
8870
9367
|
let maxLabelWidth = 0;
|
|
8871
9368
|
for (const row of spec.data) {
|
|
8872
9369
|
const label = String(row[yField] ?? "");
|
|
8873
|
-
let w =
|
|
9370
|
+
let w = estimateTextWidth11(label, theme.fonts.sizes.axisTick, theme.fonts.weights.normal);
|
|
8874
9371
|
if (yLabelField) {
|
|
8875
9372
|
const subtitle = String(row[yLabelField] ?? "");
|
|
8876
9373
|
if (subtitle) {
|
|
8877
9374
|
const gap = theme.fonts.sizes.axisTick * 0.6;
|
|
8878
|
-
const subtitleWidth =
|
|
9375
|
+
const subtitleWidth = estimateTextWidth11(
|
|
8879
9376
|
subtitle,
|
|
8880
9377
|
theme.fonts.sizes.axisTick,
|
|
8881
9378
|
theme.fonts.weights.normal
|
|
@@ -8918,7 +9415,7 @@ function computeDimensions(spec, options, legendLayout, theme, strategy, waterma
|
|
|
8918
9415
|
}
|
|
8919
9416
|
const negPrefix = spec.data.some((r) => Number(r[yField]) < 0) ? "-" : "";
|
|
8920
9417
|
const labelEst = negPrefix + sampleLabel;
|
|
8921
|
-
const labelWidth =
|
|
9418
|
+
const labelWidth = estimateTextWidth11(
|
|
8922
9419
|
labelEst,
|
|
8923
9420
|
theme.fonts.sizes.axisTick,
|
|
8924
9421
|
theme.fonts.weights.normal
|
|
@@ -8955,7 +9452,7 @@ function computeDimensions(spec, options, legendLayout, theme, strategy, waterma
|
|
|
8955
9452
|
const minDims = getMinChartDims(spec.display);
|
|
8956
9453
|
if ((chartArea.width < minDims.width || chartArea.height < minDims.height) && chromeMode !== "hidden") {
|
|
8957
9454
|
const fallbackMode = chromeMode === "full" ? "compact" : "hidden";
|
|
8958
|
-
const fallbackChrome =
|
|
9455
|
+
const fallbackChrome = computeChrome3(
|
|
8959
9456
|
chromeToInput(spec.chrome),
|
|
8960
9457
|
theme,
|
|
8961
9458
|
width,
|
|
@@ -9090,6 +9587,13 @@ function buildLinearScale(channel, data, rangeStart, rangeEnd) {
|
|
|
9090
9587
|
const scale = linear2().domain([domainMin, domainMax]).range([rangeStart, rangeEnd]);
|
|
9091
9588
|
if (!channel.scale?.domain && channel.scale?.nice !== false) {
|
|
9092
9589
|
scale.nice();
|
|
9590
|
+
if (channel.scale?.zero === false) {
|
|
9591
|
+
const [nicedMin, nicedMax] = scale.domain();
|
|
9592
|
+
if (nicedMin < domainMin || nicedMax > domainMax) {
|
|
9593
|
+
scale.domain([domainMin, domainMax]);
|
|
9594
|
+
scale.nice(20);
|
|
9595
|
+
}
|
|
9596
|
+
}
|
|
9093
9597
|
}
|
|
9094
9598
|
applyContinuousConfig(scale, channel);
|
|
9095
9599
|
return { scale, type: "linear", channel };
|
|
@@ -9440,7 +9944,7 @@ function computeScales(spec, chartArea, data) {
|
|
|
9440
9944
|
}
|
|
9441
9945
|
|
|
9442
9946
|
// src/legend/compute.ts
|
|
9443
|
-
import { BRAND_RESERVE_WIDTH as BRAND_RESERVE_WIDTH2, COMPACT_WIDTH as COMPACT_WIDTH2, estimateTextWidth as
|
|
9947
|
+
import { BRAND_RESERVE_WIDTH as BRAND_RESERVE_WIDTH2, COMPACT_WIDTH as COMPACT_WIDTH2, estimateTextWidth as estimateTextWidth12 } from "@opendata-ai/openchart-core";
|
|
9444
9948
|
var LEGEND_PADDING = 8;
|
|
9445
9949
|
var LEGEND_RIGHT_WIDTH = 120;
|
|
9446
9950
|
var RIGHT_LEGEND_MAX_HEIGHT_RATIO = 0.4;
|
|
@@ -9557,7 +10061,7 @@ function computeLegend(spec, strategy, theme, chartArea, watermark = true) {
|
|
|
9557
10061
|
}
|
|
9558
10062
|
if (resolvedPosition === "right" || resolvedPosition === "bottom-right") {
|
|
9559
10063
|
const maxLabelWidth = Math.max(
|
|
9560
|
-
...entries.map((e) =>
|
|
10064
|
+
...entries.map((e) => estimateTextWidth12(e.label, labelStyle.fontSize, labelStyle.fontWeight))
|
|
9561
10065
|
);
|
|
9562
10066
|
const legendWidth = Math.min(
|
|
9563
10067
|
LEGEND_RIGHT_WIDTH,
|
|
@@ -9617,7 +10121,7 @@ function computeLegend(spec, strategy, theme, chartArea, watermark = true) {
|
|
|
9617
10121
|
entries = truncateEntries(entries, fittingCount);
|
|
9618
10122
|
}
|
|
9619
10123
|
const totalWidth = entries.reduce((sum2, entry) => {
|
|
9620
|
-
const labelWidth =
|
|
10124
|
+
const labelWidth = estimateTextWidth12(entry.label, labelStyle.fontSize, labelStyle.fontWeight);
|
|
9621
10125
|
return sum2 + SWATCH_SIZE2 + SWATCH_GAP2 + labelWidth + effectiveEntryGap;
|
|
9622
10126
|
}, 0);
|
|
9623
10127
|
const { rowCount } = measureLegendWrap(
|
|
@@ -9649,12 +10153,12 @@ function computeLegend(spec, strategy, theme, chartArea, watermark = true) {
|
|
|
9649
10153
|
|
|
9650
10154
|
// src/sankey/compile-sankey.ts
|
|
9651
10155
|
import {
|
|
9652
|
-
adaptTheme as
|
|
9653
|
-
buildD3Formatter as
|
|
9654
|
-
computeChrome as
|
|
9655
|
-
estimateTextWidth as
|
|
9656
|
-
formatNumber as
|
|
9657
|
-
resolveTheme as
|
|
10156
|
+
adaptTheme as adaptTheme3,
|
|
10157
|
+
buildD3Formatter as buildD3Formatter6,
|
|
10158
|
+
computeChrome as computeChrome4,
|
|
10159
|
+
estimateTextWidth as estimateTextWidth13,
|
|
10160
|
+
formatNumber as formatNumber4,
|
|
10161
|
+
resolveTheme as resolveTheme3
|
|
9658
10162
|
} from "@opendata-ai/openchart-core";
|
|
9659
10163
|
|
|
9660
10164
|
// ../../node_modules/.bun/d3-array@2.12.1/node_modules/d3-array/src/max.js
|
|
@@ -10237,16 +10741,16 @@ function compileSankey(spec, options) {
|
|
|
10237
10741
|
const rawWatermark = spec.watermark;
|
|
10238
10742
|
const watermark = rawWatermark !== void 0 ? sankeySpec.watermark : options.watermark ?? true;
|
|
10239
10743
|
const mergedThemeConfig = options.theme ? { ...sankeySpec.theme, ...options.theme } : sankeySpec.theme;
|
|
10240
|
-
const lightTheme =
|
|
10744
|
+
const lightTheme = resolveTheme3(mergedThemeConfig);
|
|
10241
10745
|
let theme = lightTheme;
|
|
10242
10746
|
if (options.darkMode) {
|
|
10243
|
-
theme =
|
|
10747
|
+
theme = adaptTheme3(theme);
|
|
10244
10748
|
theme = {
|
|
10245
10749
|
...theme,
|
|
10246
10750
|
colors: { ...theme.colors, categorical: lightTheme.colors.categorical }
|
|
10247
10751
|
};
|
|
10248
10752
|
}
|
|
10249
|
-
const chrome =
|
|
10753
|
+
const chrome = computeChrome4(
|
|
10250
10754
|
{
|
|
10251
10755
|
title: sankeySpec.chrome.title,
|
|
10252
10756
|
subtitle: sankeySpec.chrome.subtitle,
|
|
@@ -10269,7 +10773,7 @@ function compileSankey(spec, options) {
|
|
|
10269
10773
|
height: options.height - chrome.topHeight - chrome.bottomHeight - padding * 2
|
|
10270
10774
|
};
|
|
10271
10775
|
if (fullArea.width <= 0 || fullArea.height <= 0) {
|
|
10272
|
-
return
|
|
10776
|
+
return emptyLayout2(fullArea, chrome, theme, options, watermark);
|
|
10273
10777
|
}
|
|
10274
10778
|
const sourceField = sankeySpec.encoding.source.field;
|
|
10275
10779
|
const targetField = sankeySpec.encoding.target.field;
|
|
@@ -10305,7 +10809,7 @@ function compileSankey(spec, options) {
|
|
|
10305
10809
|
height: fullArea.height - legend.bounds.height - legendGap2
|
|
10306
10810
|
};
|
|
10307
10811
|
if (area.height <= 0) {
|
|
10308
|
-
return
|
|
10812
|
+
return emptyLayout2(area, chrome, theme, options, watermark);
|
|
10309
10813
|
}
|
|
10310
10814
|
const labelFontSize = theme.fonts.sizes.small;
|
|
10311
10815
|
const labelFontWeight = theme.fonts.weights.normal;
|
|
@@ -10333,7 +10837,7 @@ function compileSankey(spec, options) {
|
|
|
10333
10837
|
if (labelsLeft) continue;
|
|
10334
10838
|
const labelX = (node.x1 ?? nodeWidth) + LABEL_GAP;
|
|
10335
10839
|
const labelText = node.label ?? node.id;
|
|
10336
|
-
const labelWidth =
|
|
10840
|
+
const labelWidth = estimateTextWidth13(labelText, labelFontSize, labelFontWeight);
|
|
10337
10841
|
const overflow = labelX + labelWidth - rightEdge;
|
|
10338
10842
|
if (overflow > maxOverflow) maxOverflow = overflow;
|
|
10339
10843
|
}
|
|
@@ -10523,10 +11027,10 @@ function buildSankeyLegend(nodeColorMap, colorField, data, sourceField, targetFi
|
|
|
10523
11027
|
}
|
|
10524
11028
|
function formatFlowValue(value2, valueFormat) {
|
|
10525
11029
|
if (valueFormat) {
|
|
10526
|
-
const fmt =
|
|
11030
|
+
const fmt = buildD3Formatter6(valueFormat);
|
|
10527
11031
|
if (fmt) return fmt(value2);
|
|
10528
11032
|
}
|
|
10529
|
-
return
|
|
11033
|
+
return formatNumber4(value2);
|
|
10530
11034
|
}
|
|
10531
11035
|
function buildTooltipDescriptors(nodes, links, valueFormat) {
|
|
10532
11036
|
const descriptors = /* @__PURE__ */ new Map();
|
|
@@ -10557,7 +11061,7 @@ function buildTooltipDescriptors(nodes, links, valueFormat) {
|
|
|
10557
11061
|
}
|
|
10558
11062
|
return descriptors;
|
|
10559
11063
|
}
|
|
10560
|
-
function
|
|
11064
|
+
function emptyLayout2(area, chrome, theme, options, watermark) {
|
|
10561
11065
|
return {
|
|
10562
11066
|
area,
|
|
10563
11067
|
chrome,
|
|
@@ -10595,7 +11099,7 @@ function emptyLayout(area, chrome, theme, options, watermark) {
|
|
|
10595
11099
|
}
|
|
10596
11100
|
|
|
10597
11101
|
// src/tables/compile-table.ts
|
|
10598
|
-
import { computeChrome as
|
|
11102
|
+
import { computeChrome as computeChrome5, estimateTextWidth as estimateTextWidth14 } from "@opendata-ai/openchart-core";
|
|
10599
11103
|
|
|
10600
11104
|
// src/tables/bar-column.ts
|
|
10601
11105
|
var NEGATIVE_BAR_COLOR = "#c44e52";
|
|
@@ -10712,7 +11216,7 @@ function computeCategoryColors(data, column, theme, darkMode) {
|
|
|
10712
11216
|
}
|
|
10713
11217
|
|
|
10714
11218
|
// src/tables/format-cells.ts
|
|
10715
|
-
import { buildD3Formatter as
|
|
11219
|
+
import { buildD3Formatter as buildD3Formatter7, formatDate as formatDate2, formatNumber as formatNumber5 } from "@opendata-ai/openchart-core";
|
|
10716
11220
|
function isNumericValue(value2) {
|
|
10717
11221
|
if (typeof value2 === "number") return Number.isFinite(value2);
|
|
10718
11222
|
return false;
|
|
@@ -10731,7 +11235,7 @@ function formatCell(value2, column) {
|
|
|
10731
11235
|
};
|
|
10732
11236
|
}
|
|
10733
11237
|
if (column.format && isNumericValue(value2)) {
|
|
10734
|
-
const formatter =
|
|
11238
|
+
const formatter = buildD3Formatter7(column.format);
|
|
10735
11239
|
if (formatter) {
|
|
10736
11240
|
return {
|
|
10737
11241
|
value: value2,
|
|
@@ -10743,7 +11247,7 @@ function formatCell(value2, column) {
|
|
|
10743
11247
|
if (isNumericValue(value2)) {
|
|
10744
11248
|
return {
|
|
10745
11249
|
value: value2,
|
|
10746
|
-
formattedValue:
|
|
11250
|
+
formattedValue: formatNumber5(value2),
|
|
10747
11251
|
style
|
|
10748
11252
|
};
|
|
10749
11253
|
}
|
|
@@ -10763,13 +11267,13 @@ function formatCell(value2, column) {
|
|
|
10763
11267
|
function formatValueForSearch(value2, column) {
|
|
10764
11268
|
if (value2 == null) return "";
|
|
10765
11269
|
if (column.format && isNumericValue(value2)) {
|
|
10766
|
-
const formatter =
|
|
11270
|
+
const formatter = buildD3Formatter7(column.format);
|
|
10767
11271
|
if (formatter) {
|
|
10768
11272
|
return formatter(value2);
|
|
10769
11273
|
}
|
|
10770
11274
|
}
|
|
10771
11275
|
if (isNumericValue(value2)) {
|
|
10772
|
-
return
|
|
11276
|
+
return formatNumber5(value2);
|
|
10773
11277
|
}
|
|
10774
11278
|
return String(value2);
|
|
10775
11279
|
}
|
|
@@ -11010,13 +11514,13 @@ function estimateColumnWidth(col, data, fontSize) {
|
|
|
11010
11514
|
if (col.image) return (col.image.width ?? 24) + PADDING;
|
|
11011
11515
|
if (col.flag) return 60;
|
|
11012
11516
|
const label = col.label ?? col.key;
|
|
11013
|
-
const headerWidth =
|
|
11517
|
+
const headerWidth = estimateTextWidth14(label, fontSize, 600) + PADDING;
|
|
11014
11518
|
const sampleSize = Math.min(100, data.length);
|
|
11015
11519
|
let maxDataWidth = 0;
|
|
11016
11520
|
for (let i = 0; i < sampleSize; i++) {
|
|
11017
11521
|
const val = data[i][col.key];
|
|
11018
11522
|
const text = val == null ? "" : String(val);
|
|
11019
|
-
const width =
|
|
11523
|
+
const width = estimateTextWidth14(text, fontSize, 400) + PADDING;
|
|
11020
11524
|
if (width > maxDataWidth) maxDataWidth = width;
|
|
11021
11525
|
}
|
|
11022
11526
|
return Math.max(MIN_WIDTH, headerWidth, maxDataWidth);
|
|
@@ -11200,7 +11704,7 @@ function compileTableLayout(spec, options, theme) {
|
|
|
11200
11704
|
return { id: rowId, cells, data: row };
|
|
11201
11705
|
});
|
|
11202
11706
|
const watermark = spec.watermark;
|
|
11203
|
-
const chrome =
|
|
11707
|
+
const chrome = computeChrome5(
|
|
11204
11708
|
{
|
|
11205
11709
|
title: spec.chrome.title,
|
|
11206
11710
|
subtitle: spec.chrome.subtitle,
|
|
@@ -11242,16 +11746,16 @@ function compileTableLayout(spec, options, theme) {
|
|
|
11242
11746
|
|
|
11243
11747
|
// src/tilemap/compile-tilemap.ts
|
|
11244
11748
|
import {
|
|
11245
|
-
adaptTheme as
|
|
11246
|
-
buildD3Formatter as
|
|
11247
|
-
computeChrome as
|
|
11248
|
-
estimateTextWidth as
|
|
11249
|
-
formatNumber as
|
|
11250
|
-
resolveTheme as
|
|
11749
|
+
adaptTheme as adaptTheme4,
|
|
11750
|
+
buildD3Formatter as buildD3Formatter8,
|
|
11751
|
+
computeChrome as computeChrome6,
|
|
11752
|
+
estimateTextWidth as estimateTextWidth15,
|
|
11753
|
+
formatNumber as formatNumber6,
|
|
11754
|
+
resolveTheme as resolveTheme4,
|
|
11251
11755
|
SEQUENTIAL_PALETTES
|
|
11252
11756
|
} from "@opendata-ai/openchart-core";
|
|
11253
|
-
var TILE_CORNER_RADIUS =
|
|
11254
|
-
var TILE_STROKE_WIDTH =
|
|
11757
|
+
var TILE_CORNER_RADIUS = 6;
|
|
11758
|
+
var TILE_STROKE_WIDTH = 1;
|
|
11255
11759
|
function compileTileMap(spec, options) {
|
|
11256
11760
|
const { spec: normalized } = compile(spec);
|
|
11257
11761
|
if (!("type" in normalized) || normalized.type !== "tilemap") {
|
|
@@ -11263,13 +11767,13 @@ function compileTileMap(spec, options) {
|
|
|
11263
11767
|
const rawWatermark = spec.watermark;
|
|
11264
11768
|
const watermark = rawWatermark !== void 0 ? tilemapSpec.watermark : options.watermark ?? true;
|
|
11265
11769
|
const mergedThemeConfig = options.theme ? { ...tilemapSpec.theme, ...options.theme } : tilemapSpec.theme;
|
|
11266
|
-
const lightTheme =
|
|
11770
|
+
const lightTheme = resolveTheme4(mergedThemeConfig);
|
|
11267
11771
|
let theme = lightTheme;
|
|
11268
11772
|
if (options.darkMode) {
|
|
11269
|
-
theme =
|
|
11773
|
+
theme = adaptTheme4(theme);
|
|
11270
11774
|
}
|
|
11271
11775
|
const isDarkMode = options.darkMode;
|
|
11272
|
-
const chrome =
|
|
11776
|
+
const chrome = computeChrome6(
|
|
11273
11777
|
{
|
|
11274
11778
|
title: tilemapSpec.chrome.title,
|
|
11275
11779
|
subtitle: tilemapSpec.chrome.subtitle,
|
|
@@ -11292,7 +11796,7 @@ function compileTileMap(spec, options) {
|
|
|
11292
11796
|
height: options.height - chrome.topHeight - chrome.bottomHeight - padding * 2
|
|
11293
11797
|
};
|
|
11294
11798
|
if (fullArea.width <= 0 || fullArea.height <= 0) {
|
|
11295
|
-
return
|
|
11799
|
+
return emptyLayout3(chrome, theme, options, watermark);
|
|
11296
11800
|
}
|
|
11297
11801
|
const stateField = tilemapSpec.encoding.state.field;
|
|
11298
11802
|
const valueField = tilemapSpec.encoding.value.field;
|
|
@@ -11311,26 +11815,26 @@ function compileTileMap(spec, options) {
|
|
|
11311
11815
|
const min4 = values.length > 0 ? Math.min(...values) : 0;
|
|
11312
11816
|
const max4 = values.length > 0 ? Math.max(...values) : 100;
|
|
11313
11817
|
const paletteStops = [...SEQUENTIAL_PALETTES[tilemapSpec.palette] ?? SEQUENTIAL_PALETTES.blue];
|
|
11314
|
-
|
|
11315
|
-
const
|
|
11316
|
-
const
|
|
11818
|
+
const baseColor = isDarkMode ? paletteStops[0] : paletteStops[paletteStops.length - 1];
|
|
11819
|
+
const opacityRange = isDarkMode ? [0.15, 1] : [0.2, 1];
|
|
11820
|
+
const opacityScale = linear2().domain([min4, max4]).range(opacityRange).clamp(true);
|
|
11317
11821
|
const showLegend = tilemapSpec.legend?.show !== false;
|
|
11318
|
-
const legendBarHeight =
|
|
11319
|
-
const legendLabelGap =
|
|
11822
|
+
const legendBarHeight = 6;
|
|
11823
|
+
const legendLabelGap = 6;
|
|
11320
11824
|
const legendTotalHeight = showLegend ? legendBarHeight + legendLabelGap + 14 : 0;
|
|
11321
11825
|
const legendGap2 = showLegend ? 8 : 0;
|
|
11322
11826
|
const tileAreaHeight = fullArea.height - legendTotalHeight - legendGap2;
|
|
11323
|
-
const tilePositions = computeTilePositions(fullArea.width, tileAreaHeight,
|
|
11827
|
+
const tilePositions = computeTilePositions(fullArea.width, tileAreaHeight, 5);
|
|
11324
11828
|
const tileGridOffsetX = fullArea.x + (fullArea.width - tilePositions.gridWidth) / 2;
|
|
11325
11829
|
const tileGridOffsetY = fullArea.y;
|
|
11326
11830
|
const legendX = tileGridOffsetX;
|
|
11327
11831
|
const legendY = tileGridOffsetY + tilePositions.gridHeight + legendGap2;
|
|
11328
11832
|
const legendWidth = tilePositions.gridWidth;
|
|
11329
|
-
const formatter =
|
|
11833
|
+
const formatter = buildD3Formatter8(tilemapSpec.valueFormat) ?? formatNumber6;
|
|
11330
11834
|
const neutralFillLight = "#e0e0e0";
|
|
11331
|
-
const neutralFillDark = "#
|
|
11835
|
+
const neutralFillDark = "#1e2a30";
|
|
11332
11836
|
const neutralStrokeLight = "#d0d0d0";
|
|
11333
|
-
const neutralStrokeDark = "
|
|
11837
|
+
const neutralStrokeDark = "rgba(255,255,255,0.08)";
|
|
11334
11838
|
const neutralFill = isDarkMode ? neutralFillDark : neutralFillLight;
|
|
11335
11839
|
const neutralStroke = isDarkMode ? neutralStrokeDark : neutralStrokeLight;
|
|
11336
11840
|
const tiles = [];
|
|
@@ -11339,26 +11843,31 @@ function compileTileMap(spec, options) {
|
|
|
11339
11843
|
if (!pos) continue;
|
|
11340
11844
|
const hasData = stateValueMap.has(stateCode);
|
|
11341
11845
|
const value2 = hasData ? stateValueMap.get(stateCode) : null;
|
|
11342
|
-
const
|
|
11846
|
+
const opacity = hasData ? opacityScale(value2) : 0;
|
|
11847
|
+
const fill = hasData ? baseColor : neutralFill;
|
|
11848
|
+
const stroke = hasData ? isDarkMode ? "rgba(255,255,255,0.1)" : "rgba(0,0,0,0.1)" : neutralStroke;
|
|
11343
11849
|
const formattedValue = hasData ? formatter(value2) : "\u2013";
|
|
11344
11850
|
const labelStyle = {
|
|
11345
11851
|
fontFamily: theme.fonts.family,
|
|
11346
|
-
fontSize: tilePositions.tileSize > 24 ?
|
|
11852
|
+
fontSize: tilePositions.tileSize > 24 ? 10 : 7,
|
|
11347
11853
|
fontWeight: 700,
|
|
11348
11854
|
fill: "#ffffff",
|
|
11349
11855
|
lineHeight: 1.2
|
|
11350
11856
|
};
|
|
11351
11857
|
const valueLabelStyle = {
|
|
11352
11858
|
fontFamily: theme.fonts.family,
|
|
11353
|
-
fontSize: tilePositions.tileSize > 24 ?
|
|
11354
|
-
fontWeight:
|
|
11355
|
-
fill: "
|
|
11859
|
+
fontSize: tilePositions.tileSize > 24 ? 10 : 7,
|
|
11860
|
+
fontWeight: 300,
|
|
11861
|
+
fill: "rgba(255,255,255,0.6)",
|
|
11356
11862
|
lineHeight: 1.2
|
|
11357
11863
|
};
|
|
11358
|
-
const
|
|
11864
|
+
const tileCenterX = tileGridOffsetX + pos.x + tilePositions.tileSize / 2;
|
|
11865
|
+
const tileTopY = tileGridOffsetY + pos.y;
|
|
11866
|
+
const sz = tilePositions.tileSize;
|
|
11867
|
+
const valueLabel = sz < 24 ? { text: "", x: 0, y: 0, style: valueLabelStyle, visible: false } : {
|
|
11359
11868
|
text: formattedValue,
|
|
11360
|
-
x:
|
|
11361
|
-
y:
|
|
11869
|
+
x: tileCenterX,
|
|
11870
|
+
y: tileTopY + sz * 0.78,
|
|
11362
11871
|
style: valueLabelStyle,
|
|
11363
11872
|
visible: true
|
|
11364
11873
|
};
|
|
@@ -11366,10 +11875,11 @@ function compileTileMap(spec, options) {
|
|
|
11366
11875
|
type: "tile",
|
|
11367
11876
|
stateCode,
|
|
11368
11877
|
x: tileGridOffsetX + pos.x,
|
|
11369
|
-
y:
|
|
11370
|
-
size:
|
|
11878
|
+
y: tileTopY,
|
|
11879
|
+
size: sz,
|
|
11371
11880
|
fill,
|
|
11372
|
-
|
|
11881
|
+
fillOpacity: hasData ? opacity : 1,
|
|
11882
|
+
stroke,
|
|
11373
11883
|
strokeWidth: TILE_STROKE_WIDTH,
|
|
11374
11884
|
cornerRadius: TILE_CORNER_RADIUS,
|
|
11375
11885
|
value: value2 ?? null,
|
|
@@ -11377,8 +11887,8 @@ function compileTileMap(spec, options) {
|
|
|
11377
11887
|
hasData,
|
|
11378
11888
|
label: {
|
|
11379
11889
|
text: stateCode,
|
|
11380
|
-
x:
|
|
11381
|
-
y:
|
|
11890
|
+
x: tileCenterX,
|
|
11891
|
+
y: tileTopY + sz * 0.28,
|
|
11382
11892
|
style: labelStyle,
|
|
11383
11893
|
visible: true
|
|
11384
11894
|
},
|
|
@@ -11404,10 +11914,12 @@ function compileTileMap(spec, options) {
|
|
|
11404
11914
|
}
|
|
11405
11915
|
let gradientLegend = null;
|
|
11406
11916
|
if (showLegend) {
|
|
11407
|
-
const
|
|
11408
|
-
|
|
11409
|
-
|
|
11410
|
-
|
|
11917
|
+
const numStops = 5;
|
|
11918
|
+
const gradientColorStops = Array.from({ length: numStops }, (_, i) => {
|
|
11919
|
+
const t = i / (numStops - 1);
|
|
11920
|
+
const o = opacityRange[0] + t * (opacityRange[1] - opacityRange[0]);
|
|
11921
|
+
return { offset: t, color: baseColor, opacity: o };
|
|
11922
|
+
});
|
|
11411
11923
|
gradientLegend = {
|
|
11412
11924
|
type: "gradient",
|
|
11413
11925
|
position: "bottom",
|
|
@@ -11456,10 +11968,10 @@ function compileTileMap(spec, options) {
|
|
|
11456
11968
|
height: options.height,
|
|
11457
11969
|
animation: resolvedAnimation,
|
|
11458
11970
|
watermark,
|
|
11459
|
-
measureText: options.measureText ?? ((text, fontSize) => ({ width:
|
|
11971
|
+
measureText: options.measureText ?? ((text, fontSize) => ({ width: estimateTextWidth15(text, fontSize), height: fontSize }))
|
|
11460
11972
|
};
|
|
11461
11973
|
}
|
|
11462
|
-
function
|
|
11974
|
+
function emptyLayout3(chrome, theme, options, watermark) {
|
|
11463
11975
|
return {
|
|
11464
11976
|
area: { x: 0, y: 0, width: 0, height: 0 },
|
|
11465
11977
|
chrome,
|
|
@@ -11491,7 +12003,7 @@ function emptyLayout2(chrome, theme, options, watermark) {
|
|
|
11491
12003
|
height: options.height,
|
|
11492
12004
|
watermark,
|
|
11493
12005
|
animation: void 0,
|
|
11494
|
-
measureText: options.measureText ?? ((text, fontSize) => ({ width:
|
|
12006
|
+
measureText: options.measureText ?? ((text, fontSize) => ({ width: estimateTextWidth15(text, fontSize), height: fontSize }))
|
|
11495
12007
|
};
|
|
11496
12008
|
}
|
|
11497
12009
|
|
|
@@ -11499,7 +12011,7 @@ function emptyLayout2(chrome, theme, options, watermark) {
|
|
|
11499
12011
|
import {
|
|
11500
12012
|
buildTemporalFormatter as buildTemporalFormatter2,
|
|
11501
12013
|
formatDate as formatDate3,
|
|
11502
|
-
formatNumber as
|
|
12014
|
+
formatNumber as formatNumber7,
|
|
11503
12015
|
getRepresentativeColor as getRepresentativeColor10
|
|
11504
12016
|
} from "@opendata-ai/openchart-core";
|
|
11505
12017
|
function formatValue(value2, fieldType, format2) {
|
|
@@ -11514,18 +12026,20 @@ function formatValue(value2, fieldType, format2) {
|
|
|
11514
12026
|
try {
|
|
11515
12027
|
return format(format2)(value2);
|
|
11516
12028
|
} catch {
|
|
11517
|
-
return
|
|
12029
|
+
return formatNumber7(value2);
|
|
11518
12030
|
}
|
|
11519
12031
|
}
|
|
11520
|
-
return
|
|
12032
|
+
return formatNumber7(value2);
|
|
11521
12033
|
}
|
|
11522
12034
|
return String(value2);
|
|
11523
12035
|
}
|
|
11524
12036
|
function resolveLabel(ch) {
|
|
11525
|
-
|
|
12037
|
+
const ax = ch.axis || void 0;
|
|
12038
|
+
return ch.title ?? ax?.title ?? ch.field;
|
|
11526
12039
|
}
|
|
11527
12040
|
function resolveFormat(ch) {
|
|
11528
|
-
|
|
12041
|
+
const ax = ch.axis || void 0;
|
|
12042
|
+
return ch.format ?? ax?.format;
|
|
11529
12043
|
}
|
|
11530
12044
|
function buildExplicitTooltipFields(row, channels) {
|
|
11531
12045
|
return channels.map((ch) => ({
|
|
@@ -12382,9 +12896,9 @@ function compileChart(spec, options) {
|
|
|
12382
12896
|
chartSpec = { ...chartSpec, watermark: false };
|
|
12383
12897
|
}
|
|
12384
12898
|
const mergedThemeConfig = options.theme ? { ...chartSpec.theme, ...options.theme } : chartSpec.theme;
|
|
12385
|
-
let theme =
|
|
12899
|
+
let theme = resolveTheme5(mergedThemeConfig);
|
|
12386
12900
|
if (options.darkMode) {
|
|
12387
|
-
theme =
|
|
12901
|
+
theme = adaptTheme5(theme);
|
|
12388
12902
|
}
|
|
12389
12903
|
const preliminaryArea = {
|
|
12390
12904
|
x: 0,
|
|
@@ -12570,7 +13084,7 @@ function estimateYAxisLabelWidth(data, encoding, baseFontSize) {
|
|
|
12570
13084
|
let maxWidth = 0;
|
|
12571
13085
|
for (const row of data) {
|
|
12572
13086
|
const label = String(row[yField] ?? "");
|
|
12573
|
-
const w =
|
|
13087
|
+
const w = estimateTextWidth16(label, baseFontSize, 400);
|
|
12574
13088
|
if (w > maxWidth) maxWidth = w;
|
|
12575
13089
|
}
|
|
12576
13090
|
return maxWidth > 0 ? maxWidth + 10 : 40;
|
|
@@ -12599,7 +13113,7 @@ function estimateYAxisLabelWidth(data, encoding, baseFontSize) {
|
|
|
12599
13113
|
}
|
|
12600
13114
|
const hasNeg = data.some((r) => Number(r[yField]) < 0);
|
|
12601
13115
|
const labelEst = (hasNeg ? "-" : "") + sampleLabel;
|
|
12602
|
-
return
|
|
13116
|
+
return estimateTextWidth16(labelEst, baseFontSize, 400) + 10;
|
|
12603
13117
|
}
|
|
12604
13118
|
function compileLayerIndependent(leaves, layerSpec, options) {
|
|
12605
13119
|
if (leaves.length > 2) {
|
|
@@ -12616,10 +13130,11 @@ function compileLayerIndependent(leaves, layerSpec, options) {
|
|
|
12616
13130
|
`Dual-axis charts require matching x-field types across layers. Layer 0 has '${xType0}', layer 1 has '${xType1}'.`
|
|
12617
13131
|
);
|
|
12618
13132
|
}
|
|
12619
|
-
const theme =
|
|
13133
|
+
const theme = resolveTheme5(layerSpec.theme ?? leaf1.theme);
|
|
12620
13134
|
const axisFontSize = theme.fonts?.sizes?.axisTick ?? 11;
|
|
12621
13135
|
const rightAxisWidth = estimateYAxisLabelWidth(leaf1.data, leaf1.encoding, axisFontSize);
|
|
12622
|
-
const
|
|
13136
|
+
const yAxisConfig = leaf1.encoding?.y?.axis || void 0;
|
|
13137
|
+
const hasRightAxisTitle = !!yAxisConfig?.title;
|
|
12623
13138
|
const tickExtent = TICK_LABEL_OFFSET + rightAxisWidth;
|
|
12624
13139
|
const bodyFontSize = theme.fonts?.sizes?.body ?? 13;
|
|
12625
13140
|
const axisTitleOffset = getAxisTitleOffset2(options.width);
|
|
@@ -12881,9 +13396,9 @@ function compileTable(spec, options) {
|
|
|
12881
13396
|
}
|
|
12882
13397
|
const tableSpec = normalized;
|
|
12883
13398
|
const mergedThemeConfig = options.theme ? { ...tableSpec.theme, ...options.theme } : tableSpec.theme;
|
|
12884
|
-
let theme =
|
|
13399
|
+
let theme = resolveTheme5(mergedThemeConfig);
|
|
12885
13400
|
if (options.darkMode) {
|
|
12886
|
-
theme =
|
|
13401
|
+
theme = adaptTheme5(theme);
|
|
12887
13402
|
}
|
|
12888
13403
|
const rawWatermark = spec.watermark;
|
|
12889
13404
|
const watermark = rawWatermark !== void 0 ? tableSpec.watermark : options.watermark ?? true;
|
|
@@ -12898,10 +13413,14 @@ function compileSankey2(spec, options) {
|
|
|
12898
13413
|
function compileTileMap2(spec, options) {
|
|
12899
13414
|
return compileTileMap(spec, options);
|
|
12900
13415
|
}
|
|
13416
|
+
function compileBarList2(spec, options) {
|
|
13417
|
+
return compileBarList(spec, options);
|
|
13418
|
+
}
|
|
12901
13419
|
export {
|
|
12902
13420
|
clampStaggerDelay,
|
|
12903
13421
|
clearRenderers,
|
|
12904
13422
|
compile,
|
|
13423
|
+
compileBarList2 as compileBarList,
|
|
12905
13424
|
compileChart,
|
|
12906
13425
|
compileGraph2 as compileGraph,
|
|
12907
13426
|
compileLayer,
|