@opendata-ai/openchart-engine 8.0.0-rc.9 → 8.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +175 -12
- package/dist/index.js +917 -168
- package/dist/index.js.map +1 -1
- package/package.json +3 -4
- package/src/__test-fixtures__/specs.ts +0 -182
- package/src/__tests__/__snapshots__/compile-snapshot.test.ts.snap +0 -2401
- package/src/__tests__/annotation-behavior.test.ts +0 -852
- package/src/__tests__/axes.test.ts +0 -1579
- package/src/__tests__/compile-animation.test.ts +0 -161
- package/src/__tests__/compile-chart.test.ts +0 -1303
- package/src/__tests__/compile-footnotes.test.ts +0 -277
- package/src/__tests__/compile-layer.test.ts +0 -969
- package/src/__tests__/compile-snapshot.test.ts +0 -156
- package/src/__tests__/compound-labels.test.ts +0 -147
- package/src/__tests__/dimensions.test.ts +0 -918
- package/src/__tests__/encoding-sugar.test.ts +0 -390
- package/src/__tests__/facet.test.ts +0 -215
- package/src/__tests__/helpers/invariants.ts +0 -299
- package/src/__tests__/known-bugs.test.ts +0 -566
- package/src/__tests__/layout-fuzz.test.ts +0 -358
- package/src/__tests__/layout-invariants.test.ts +0 -535
- package/src/__tests__/legend.test.ts +0 -721
- package/src/__tests__/mark-keys.test.ts +0 -294
- package/src/__tests__/ranking-recipes.test.ts +0 -260
- package/src/__tests__/rotation.test.ts +0 -83
- package/src/__tests__/scales.test.ts +0 -323
- package/src/__tests__/series-search.test.ts +0 -92
- package/src/__tests__/spec-sugar.test.ts +0 -801
- package/src/__tests__/you-draw-it.test.ts +0 -160
- package/src/annotations/__tests__/compute.test.ts +0 -1672
- package/src/annotations/__tests__/geometry.test.ts +0 -66
- package/src/annotations/__tests__/placement-fuzz.test.ts +0 -256
- package/src/annotations/__tests__/placement-invariants.test.ts +0 -345
- package/src/annotations/__tests__/placement.test.ts +0 -316
- package/src/annotations/__tests__/resolve-text.test.ts +0 -788
- package/src/annotations/__tests__/rich-text.test.ts +0 -91
- package/src/annotations/__tests__/thinning.test.ts +0 -285
- package/src/annotations/collisions.ts +0 -326
- package/src/annotations/compute.ts +0 -333
- package/src/annotations/constants.ts +0 -162
- package/src/annotations/geometry.ts +0 -376
- package/src/annotations/move.ts +0 -135
- package/src/annotations/placement.ts +0 -636
- package/src/annotations/position.ts +0 -131
- package/src/annotations/resolve-range.ts +0 -117
- package/src/annotations/resolve-refline.ts +0 -157
- package/src/annotations/resolve-text.ts +0 -545
- package/src/annotations/rich-text.ts +0 -65
- package/src/annotations/thinning.ts +0 -190
- package/src/barlist/__tests__/compile-barlist.test.ts +0 -200
- package/src/barlist/compile-barlist.ts +0 -391
- package/src/barlist/types.ts +0 -28
- package/src/charts/__tests__/post-process.test.ts +0 -237
- package/src/charts/__tests__/registry.test.ts +0 -116
- package/src/charts/__tests__/utils.test.ts +0 -195
- package/src/charts/_shared/__tests__/density-filter.test.ts +0 -32
- package/src/charts/_shared/density-filter.ts +0 -26
- package/src/charts/_shared/format-label-value.ts +0 -16
- package/src/charts/bar/__tests__/compute.test.ts +0 -934
- package/src/charts/bar/__tests__/gradient-orient.test.ts +0 -127
- package/src/charts/bar/__tests__/labels.test.ts +0 -292
- package/src/charts/bar/compute.ts +0 -539
- package/src/charts/bar/index.ts +0 -60
- package/src/charts/bar/labels.ts +0 -311
- package/src/charts/beeswarm/__tests__/compute.test.ts +0 -280
- package/src/charts/beeswarm/__tests__/dodge.test.ts +0 -148
- package/src/charts/beeswarm/compute.ts +0 -203
- package/src/charts/beeswarm/dodge.ts +0 -155
- package/src/charts/beeswarm/index.ts +0 -32
- package/src/charts/builtin.ts +0 -75
- package/src/charts/calendar/__tests__/compute.test.ts +0 -417
- package/src/charts/calendar/compute.ts +0 -319
- package/src/charts/calendar/index.ts +0 -32
- package/src/charts/column/__tests__/compute.test.ts +0 -540
- package/src/charts/column/__tests__/labels.test.ts +0 -179
- package/src/charts/column/compute.ts +0 -493
- package/src/charts/column/index.ts +0 -53
- package/src/charts/column/labels.ts +0 -229
- package/src/charts/dot/__tests__/compute.test.ts +0 -380
- package/src/charts/dot/__tests__/labels.test.ts +0 -98
- package/src/charts/dot/compute.ts +0 -285
- package/src/charts/dot/index.ts +0 -62
- package/src/charts/dot/labels.ts +0 -121
- package/src/charts/line/__tests__/compute.test.ts +0 -1194
- package/src/charts/line/__tests__/curves.test.ts +0 -51
- package/src/charts/line/__tests__/labels.test.ts +0 -94
- package/src/charts/line/__tests__/mark-options.test.ts +0 -175
- package/src/charts/line/area.ts +0 -484
- package/src/charts/line/compute.ts +0 -356
- package/src/charts/line/curves.ts +0 -85
- package/src/charts/line/index.ts +0 -176
- package/src/charts/line/labels.ts +0 -177
- package/src/charts/parliament/__tests__/compute.test.ts +0 -411
- package/src/charts/parliament/compute.ts +0 -313
- package/src/charts/parliament/index.ts +0 -32
- package/src/charts/pie/__tests__/compute.test.ts +0 -384
- package/src/charts/pie/__tests__/labels.test.ts +0 -132
- package/src/charts/pie/compute.ts +0 -324
- package/src/charts/pie/index.ts +0 -49
- package/src/charts/pie/labels.ts +0 -143
- package/src/charts/post-process.ts +0 -229
- package/src/charts/range/__tests__/compute.test.ts +0 -486
- package/src/charts/range/compute.ts +0 -273
- package/src/charts/range/index.ts +0 -82
- package/src/charts/range/labels.ts +0 -169
- package/src/charts/rect/__tests__/compute.test.ts +0 -120
- package/src/charts/rect/index.ts +0 -127
- package/src/charts/registry.ts +0 -72
- package/src/charts/rule/index.ts +0 -139
- package/src/charts/scatter/__tests__/compute.test.ts +0 -488
- package/src/charts/scatter/__tests__/trendline.test.ts +0 -191
- package/src/charts/scatter/compute.ts +0 -192
- package/src/charts/scatter/index.ts +0 -46
- package/src/charts/scatter/trendline.ts +0 -100
- package/src/charts/text/__tests__/compute.test.ts +0 -307
- package/src/charts/text/index.ts +0 -141
- package/src/charts/tick/__tests__/compute.test.ts +0 -75
- package/src/charts/tick/index.ts +0 -99
- package/src/charts/utils.ts +0 -170
- package/src/charts/waffle/__tests__/compute.test.ts +0 -305
- package/src/charts/waffle/compute.ts +0 -197
- package/src/charts/waffle/index.ts +0 -31
- package/src/compile/__tests__/color-scale-range.test.ts +0 -158
- package/src/compile/__tests__/color-scale-reverse.test.ts +0 -89
- package/src/compile/__tests__/data-clip.test.ts +0 -127
- package/src/compile/__tests__/fill-patterns.test.ts +0 -154
- package/src/compile/__tests__/size-scale.test.ts +0 -108
- package/src/compile/__tests__/watermark-obstacle.test.ts +0 -93
- package/src/compile/color-scale-range.ts +0 -101
- package/src/compile/data-clip.ts +0 -48
- package/src/compile/fill-patterns.ts +0 -74
- package/src/compile/layer.ts +0 -630
- package/src/compile/size-scale.ts +0 -141
- package/src/compile/spec-sugar.ts +0 -758
- package/src/compile/watermark-obstacle.ts +0 -54
- package/src/compile/you-draw-it.ts +0 -123
- package/src/compile.ts +0 -1503
- package/src/compiler/__tests__/a11y-warnings.test.ts +0 -148
- package/src/compiler/__tests__/animation.test.ts +0 -177
- package/src/compiler/__tests__/compile.test.ts +0 -87
- package/src/compiler/__tests__/fixtures/vl-parity/axis-null.json +0 -19
- package/src/compiler/__tests__/fixtures/vl-parity/color-value.json +0 -20
- package/src/compiler/__tests__/fixtures/vl-parity/count-aggregate.json +0 -22
- package/src/compiler/__tests__/fixtures/vl-parity/data-values.json +0 -19
- package/src/compiler/__tests__/fixtures/vl-parity/layer-axis-null.json +0 -14
- package/src/compiler/__tests__/fixtures/vl-parity/layer-count.json +0 -34
- package/src/compiler/__tests__/fixtures/vl-parity/layer-data-values.json +0 -22
- package/src/compiler/__tests__/fixtures/vl-parity/layer-legend-null.json +0 -41
- package/src/compiler/__tests__/fixtures/vl-parity/layer-scheme.json +0 -38
- package/src/compiler/__tests__/fixtures/vl-parity/layer-sort.json +0 -28
- package/src/compiler/__tests__/fixtures/vl-parity/layer-theta.json +0 -28
- package/src/compiler/__tests__/fixtures/vl-parity/layer-title.json +0 -30
- package/src/compiler/__tests__/fixtures/vl-parity/layer-value-def.json +0 -29
- package/src/compiler/__tests__/fixtures/vl-parity/legend-null.json +0 -32
- package/src/compiler/__tests__/fixtures/vl-parity/scheme.json +0 -25
- package/src/compiler/__tests__/fixtures/vl-parity/sort-by-value.json +0 -19
- package/src/compiler/__tests__/fixtures/vl-parity/theta-arc.json +0 -19
- package/src/compiler/__tests__/fixtures/vl-parity/title-subtitle.json +0 -21
- package/src/compiler/__tests__/fixtures/vl-parity/width-height.json +0 -23
- package/src/compiler/__tests__/keys.test.ts +0 -83
- package/src/compiler/__tests__/normalize-highlight.test.ts +0 -103
- package/src/compiler/__tests__/normalize.test.ts +0 -399
- package/src/compiler/__tests__/sparkline-defaults.test.ts +0 -153
- package/src/compiler/__tests__/validate-did-you-mean.test.ts +0 -170
- package/src/compiler/__tests__/validate-highlight.test.ts +0 -112
- package/src/compiler/__tests__/validate-near-miss.test.ts +0 -251
- package/src/compiler/__tests__/validate.test.ts +0 -629
- package/src/compiler/__tests__/vl-parity.test.ts +0 -68
- package/src/compiler/a11y-warnings.ts +0 -110
- package/src/compiler/animation.ts +0 -142
- package/src/compiler/index.ts +0 -47
- package/src/compiler/keys.ts +0 -55
- package/src/compiler/normalize.ts +0 -734
- package/src/compiler/sparkline-defaults.ts +0 -138
- package/src/compiler/types.ts +0 -241
- package/src/compiler/validate.ts +0 -2041
- package/src/endpoint-labels/__tests__/compute.test.ts +0 -587
- package/src/endpoint-labels/compute.ts +0 -621
- package/src/endpoint-labels/constants.ts +0 -54
- package/src/endpoint-labels/format.ts +0 -60
- package/src/endpoint-labels/predict.ts +0 -139
- package/src/format/__tests__/field-format.test.ts +0 -164
- package/src/format/field-format.ts +0 -27
- package/src/geo/__tests__/compile-map.test.ts +0 -1128
- package/src/geo/compile-map.ts +0 -1376
- package/src/geo/join.ts +0 -115
- package/src/geo/projections.ts +0 -65
- package/src/geo/types.ts +0 -26
- package/src/graphs/__tests__/community.test.ts +0 -228
- package/src/graphs/__tests__/compile-graph.test.ts +0 -396
- package/src/graphs/__tests__/encoding.test.ts +0 -415
- package/src/graphs/community.ts +0 -92
- package/src/graphs/compile-graph.ts +0 -329
- package/src/graphs/encoding.ts +0 -356
- package/src/graphs/types.ts +0 -106
- package/src/index.ts +0 -177
- package/src/layout/__tests__/metrics.test.ts +0 -97
- package/src/layout/__tests__/scales-highlight.test.ts +0 -192
- package/src/layout/axes/rotation.ts +0 -152
- package/src/layout/axes/thinning.ts +0 -98
- package/src/layout/axes/ticks.ts +0 -409
- package/src/layout/axes.ts +0 -757
- package/src/layout/dimensions.ts +0 -912
- package/src/layout/facet.ts +0 -91
- package/src/layout/gridlines.ts +0 -84
- package/src/layout/metrics.ts +0 -132
- package/src/layout/plan.ts +0 -631
- package/src/layout/scales.ts +0 -1053
- package/src/layout/shared.ts +0 -44
- package/src/legend/__tests__/continuous.test.ts +0 -318
- package/src/legend/__tests__/redundancy.test.ts +0 -108
- package/src/legend/__tests__/size.test.ts +0 -348
- package/src/legend/__tests__/suppression.test.ts +0 -382
- package/src/legend/compute.ts +0 -748
- package/src/legend/continuous.ts +0 -327
- package/src/legend/size.ts +0 -407
- package/src/legend/suppression.ts +0 -226
- package/src/legend/wrap.ts +0 -117
- package/src/sankey/__tests__/compile-sankey.test.ts +0 -458
- package/src/sankey/__tests__/layout.test.ts +0 -165
- package/src/sankey/__tests__/node-label-wrap.test.ts +0 -114
- package/src/sankey/__tests__/node-sort.test.ts +0 -45
- package/src/sankey/compile-sankey.ts +0 -706
- package/src/sankey/layout.ts +0 -184
- package/src/sankey/types.ts +0 -41
- package/src/tables/__tests__/bar-column.test.ts +0 -147
- package/src/tables/__tests__/category-colors.test.ts +0 -230
- package/src/tables/__tests__/compile-table.test.ts +0 -236
- package/src/tables/__tests__/format-cells.test.ts +0 -143
- package/src/tables/__tests__/heatmap.test.ts +0 -148
- package/src/tables/__tests__/pagination.test.ts +0 -78
- package/src/tables/__tests__/search.test.ts +0 -94
- package/src/tables/__tests__/sort.test.ts +0 -107
- package/src/tables/__tests__/sparkline.test.ts +0 -122
- package/src/tables/bar-column.ts +0 -94
- package/src/tables/category-colors.ts +0 -78
- package/src/tables/compile-table.ts +0 -427
- package/src/tables/format-cells.ts +0 -115
- package/src/tables/heatmap.ts +0 -141
- package/src/tables/pagination.ts +0 -46
- package/src/tables/search.ts +0 -66
- package/src/tables/sort.ts +0 -69
- package/src/tables/sparkline.ts +0 -113
- package/src/tables/utils.ts +0 -16
- package/src/tilemap/__tests__/compile-tilemap.test.ts +0 -576
- package/src/tilemap/compile-tilemap.ts +0 -755
- package/src/tilemap/layout.ts +0 -172
- package/src/tilemap/types.ts +0 -33
- package/src/tooltips/__tests__/compute.test.ts +0 -582
- package/src/tooltips/compute.ts +0 -700
- package/src/transforms/__tests__/aggregate.test.ts +0 -159
- package/src/transforms/__tests__/bin.test.ts +0 -88
- package/src/transforms/__tests__/calculate.test.ts +0 -146
- package/src/transforms/__tests__/conditional.test.ts +0 -127
- package/src/transforms/__tests__/filter-relative.test.ts +0 -202
- package/src/transforms/__tests__/filter.test.ts +0 -59
- package/src/transforms/__tests__/fold.test.ts +0 -79
- package/src/transforms/__tests__/index.test.ts +0 -93
- package/src/transforms/__tests__/predicates.test.ts +0 -193
- package/src/transforms/__tests__/timeunit.test.ts +0 -129
- package/src/transforms/__tests__/window.test.ts +0 -286
- package/src/transforms/aggregate.ts +0 -131
- package/src/transforms/bin.ts +0 -87
- package/src/transforms/calculate.ts +0 -60
- package/src/transforms/conditional.ts +0 -46
- package/src/transforms/filter.ts +0 -122
- package/src/transforms/fold.ts +0 -49
- package/src/transforms/index.ts +0 -60
- package/src/transforms/predicates.ts +0 -123
- package/src/transforms/timeunit.ts +0 -88
- package/src/transforms/window.ts +0 -185
package/dist/index.js
CHANGED
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
getHeightClass,
|
|
10
10
|
getLayoutStrategy,
|
|
11
11
|
isAxislessMark as isAxislessMark3,
|
|
12
|
+
MAX_SR_TABLE_ROWS,
|
|
12
13
|
resolveTheme as resolveTheme7
|
|
13
14
|
} from "@opendata-ai/openchart-core";
|
|
14
15
|
|
|
@@ -8559,6 +8560,11 @@ function computePieLabels(marks, _chartArea, density = "auto", _textFill = "#333
|
|
|
8559
8560
|
width: textWidth,
|
|
8560
8561
|
height: textHeight,
|
|
8561
8562
|
priority: "data",
|
|
8563
|
+
// Index into the ORIGINAL marks array, not `targetMarks`. Density
|
|
8564
|
+
// filtering drops slices and resolveCollisions re-sorts by priority, so
|
|
8565
|
+
// the returned labels line up with neither. Callers assign by this index
|
|
8566
|
+
// instead of zipping positionally.
|
|
8567
|
+
index: marks.indexOf(mark),
|
|
8562
8568
|
style: {
|
|
8563
8569
|
fontFamily: "system-ui, -apple-system, sans-serif",
|
|
8564
8570
|
fontSize: LABEL_FONT_SIZE5,
|
|
@@ -8580,14 +8586,16 @@ function computePieLabels(marks, _chartArea, density = "auto", _textFill = "#333
|
|
|
8580
8586
|
x: c.anchorX,
|
|
8581
8587
|
y: c.anchorY,
|
|
8582
8588
|
style: c.style,
|
|
8583
|
-
visible: true
|
|
8589
|
+
visible: true,
|
|
8590
|
+
...c.index !== void 0 ? { index: c.index } : {}
|
|
8584
8591
|
}));
|
|
8585
8592
|
} else {
|
|
8586
8593
|
resolved = resolveCollisions5(candidates);
|
|
8587
8594
|
}
|
|
8588
|
-
for (let i = 0; i < resolved.length
|
|
8595
|
+
for (let i = 0; i < resolved.length; i++) {
|
|
8589
8596
|
const label = resolved[i];
|
|
8590
|
-
const mark =
|
|
8597
|
+
const mark = label.index !== void 0 ? marks[label.index] : void 0;
|
|
8598
|
+
if (!mark) continue;
|
|
8591
8599
|
if (label.visible) {
|
|
8592
8600
|
label.connector = {
|
|
8593
8601
|
from: { x: label.x, y: label.y },
|
|
@@ -8605,16 +8613,16 @@ function computePieLabels(marks, _chartArea, density = "auto", _textFill = "#333
|
|
|
8605
8613
|
var pieRenderer = (spec, scales, chartArea, strategy, theme) => {
|
|
8606
8614
|
const marks = computePieMarks(spec, scales, chartArea, strategy, false);
|
|
8607
8615
|
const labels = computePieLabels(marks, chartArea, spec.labels.density, theme.colors.text);
|
|
8608
|
-
for (
|
|
8609
|
-
marks[
|
|
8616
|
+
for (const label of labels) {
|
|
8617
|
+
if (label.index !== void 0 && marks[label.index]) marks[label.index].label = label;
|
|
8610
8618
|
}
|
|
8611
8619
|
return marks;
|
|
8612
8620
|
};
|
|
8613
8621
|
var donutRenderer = (spec, scales, chartArea, strategy, theme) => {
|
|
8614
8622
|
const marks = computePieMarks(spec, scales, chartArea, strategy, true);
|
|
8615
8623
|
const labels = computePieLabels(marks, chartArea, spec.labels.density, theme.colors.text);
|
|
8616
|
-
for (
|
|
8617
|
-
marks[
|
|
8624
|
+
for (const label of labels) {
|
|
8625
|
+
if (label.index !== void 0 && marks[label.index]) marks[label.index].label = label;
|
|
8618
8626
|
}
|
|
8619
8627
|
return marks;
|
|
8620
8628
|
};
|
|
@@ -9062,6 +9070,7 @@ var ruleRenderer = (spec, scales, chartArea, _strategy, _theme) => {
|
|
|
9062
9070
|
};
|
|
9063
9071
|
|
|
9064
9072
|
// src/charts/scatter/compute.ts
|
|
9073
|
+
import { isOpaqueColor } from "@opendata-ai/openchart-core";
|
|
9065
9074
|
var DEFAULT_POINT_RADIUS2 = 5;
|
|
9066
9075
|
function resolvePosition2(value2, channelType, scale) {
|
|
9067
9076
|
switch (channelType) {
|
|
@@ -9087,7 +9096,7 @@ function resolvePosition2(value2, channelType, scale) {
|
|
|
9087
9096
|
}
|
|
9088
9097
|
}
|
|
9089
9098
|
}
|
|
9090
|
-
function computeScatterMarks(spec, scales, _chartArea, _strategy) {
|
|
9099
|
+
function computeScatterMarks(spec, scales, _chartArea, _strategy, theme) {
|
|
9091
9100
|
const encoding = spec.encoding;
|
|
9092
9101
|
const xChannel = encoding.x;
|
|
9093
9102
|
const yChannel = encoding.y;
|
|
@@ -9105,6 +9114,10 @@ function computeScatterMarks(spec, scales, _chartArea, _strategy) {
|
|
|
9105
9114
|
const sizeField = sizeEnc?.field;
|
|
9106
9115
|
const resolvedSize = buildSizeScale(sizeEnc, spec.data, SIZE_SCALE_DEFAULTS.point);
|
|
9107
9116
|
const sizeScale = resolvedSize?.scale;
|
|
9117
|
+
const constFill = spec.markDef.fill;
|
|
9118
|
+
const constSize = spec.markDef.size;
|
|
9119
|
+
const bg = theme?.colors?.background;
|
|
9120
|
+
const defaultStroke = bg && isOpaqueColor(bg) ? bg : "#ffffff";
|
|
9108
9121
|
const keyEnc = encoding.key && "field" in encoding.key ? encoding.key : void 0;
|
|
9109
9122
|
const keyField = keyEnc?.field;
|
|
9110
9123
|
const marks = [];
|
|
@@ -9119,10 +9132,12 @@ function computeScatterMarks(spec, scales, _chartArea, _strategy) {
|
|
|
9119
9132
|
if (isSequentialColor && colorField) {
|
|
9120
9133
|
const val = Number(row[colorField]);
|
|
9121
9134
|
color2 = Number.isFinite(val) ? getSequentialColor(scales, val) : getColor(scales, "__default__");
|
|
9122
|
-
} else {
|
|
9135
|
+
} else if (colorField) {
|
|
9123
9136
|
color2 = getColor(scales, category ?? "__default__");
|
|
9137
|
+
} else {
|
|
9138
|
+
color2 = constFill ?? getColor(scales, "__default__");
|
|
9124
9139
|
}
|
|
9125
|
-
let radius = DEFAULT_POINT_RADIUS2;
|
|
9140
|
+
let radius = constSize != null ? constSize : DEFAULT_POINT_RADIUS2;
|
|
9126
9141
|
if (sizeScale && sizeField) {
|
|
9127
9142
|
const sizeVal = Number(row[sizeField]);
|
|
9128
9143
|
if (Number.isFinite(sizeVal)) {
|
|
@@ -9143,9 +9158,9 @@ function computeScatterMarks(spec, scales, _chartArea, _strategy) {
|
|
|
9143
9158
|
cy,
|
|
9144
9159
|
r: radius,
|
|
9145
9160
|
fill: color2,
|
|
9146
|
-
stroke:
|
|
9147
|
-
strokeWidth: 1,
|
|
9148
|
-
fillOpacity: 0.7,
|
|
9161
|
+
stroke: spec.markDef.stroke ?? defaultStroke,
|
|
9162
|
+
strokeWidth: spec.markDef.strokeWidth ?? 1,
|
|
9163
|
+
fillOpacity: spec.markDef.opacity ?? 0.7,
|
|
9149
9164
|
data: row,
|
|
9150
9165
|
aria
|
|
9151
9166
|
});
|
|
@@ -9186,7 +9201,7 @@ function linearRegression(points) {
|
|
|
9186
9201
|
const intercept = (sumY - slope * sumX) / n;
|
|
9187
9202
|
return { slope, intercept };
|
|
9188
9203
|
}
|
|
9189
|
-
function computeTrendLine(marks) {
|
|
9204
|
+
function computeTrendLine(marks, stroke = TRENDLINE_COLOR, strokeWidth = TRENDLINE_STROKE_WIDTH) {
|
|
9190
9205
|
if (marks.length < 2) return null;
|
|
9191
9206
|
const points = marks.map((m) => ({ x: m.cx, y: m.cy }));
|
|
9192
9207
|
const result = linearRegression(points);
|
|
@@ -9209,8 +9224,8 @@ function computeTrendLine(marks) {
|
|
|
9209
9224
|
{ x: minX, y: y12 },
|
|
9210
9225
|
{ x: maxX, y: y2 }
|
|
9211
9226
|
],
|
|
9212
|
-
stroke
|
|
9213
|
-
strokeWidth
|
|
9227
|
+
stroke,
|
|
9228
|
+
strokeWidth,
|
|
9214
9229
|
strokeDasharray: TRENDLINE_DASH,
|
|
9215
9230
|
data: [],
|
|
9216
9231
|
aria
|
|
@@ -9218,13 +9233,20 @@ function computeTrendLine(marks) {
|
|
|
9218
9233
|
}
|
|
9219
9234
|
|
|
9220
9235
|
// src/charts/scatter/index.ts
|
|
9221
|
-
var scatterRenderer = (spec, scales, chartArea, strategy,
|
|
9222
|
-
const pointMarks = computeScatterMarks(spec, scales, chartArea, strategy);
|
|
9236
|
+
var scatterRenderer = (spec, scales, chartArea, strategy, theme) => {
|
|
9237
|
+
const pointMarks = computeScatterMarks(spec, scales, chartArea, strategy, theme);
|
|
9223
9238
|
const marks = [...pointMarks];
|
|
9224
|
-
|
|
9225
|
-
|
|
9239
|
+
const trendline = spec.markDef?.trendline;
|
|
9240
|
+
if (trendline !== false) {
|
|
9241
|
+
const config = typeof trendline === "object" ? trendline : void 0;
|
|
9242
|
+
const stroke = config?.stroke ?? theme?.colors?.text;
|
|
9243
|
+
const trendLine = computeTrendLine(pointMarks, stroke, config?.strokeWidth);
|
|
9226
9244
|
if (trendLine) {
|
|
9227
|
-
|
|
9245
|
+
if (config?.layer === "above") {
|
|
9246
|
+
marks.push(trendLine);
|
|
9247
|
+
} else {
|
|
9248
|
+
marks.unshift(trendLine);
|
|
9249
|
+
}
|
|
9228
9250
|
}
|
|
9229
9251
|
}
|
|
9230
9252
|
return marks;
|
|
@@ -9704,6 +9726,16 @@ function stripIgnoredKeys(spec, warnings) {
|
|
|
9704
9726
|
const { $schema: _schema, ...rest } = spec;
|
|
9705
9727
|
return rest;
|
|
9706
9728
|
}
|
|
9729
|
+
function stripRemovedMarkRender(spec, warnings) {
|
|
9730
|
+
const mark = spec.mark;
|
|
9731
|
+
if (!mark || typeof mark !== "object" || Array.isArray(mark)) return spec;
|
|
9732
|
+
if (!("render" in mark)) return spec;
|
|
9733
|
+
warnings.push(
|
|
9734
|
+
"[openchart] mark.render was removed in v8. This field is stripped for backward compatibility. Pass { renderer } to createChart() or the compile options instead."
|
|
9735
|
+
);
|
|
9736
|
+
const { render: _render, ...restMark } = mark;
|
|
9737
|
+
return { ...spec, mark: restMark };
|
|
9738
|
+
}
|
|
9707
9739
|
function applyFixedSizeDefault(spec) {
|
|
9708
9740
|
if (typeof spec.width === "number" && typeof spec.height === "number" && spec.responsive === void 0) {
|
|
9709
9741
|
return { ...spec, responsive: false };
|
|
@@ -9846,7 +9878,16 @@ function expandChannelSugar(spec, warnings) {
|
|
|
9846
9878
|
}
|
|
9847
9879
|
return result;
|
|
9848
9880
|
}
|
|
9849
|
-
var COUNT_GROUP_CHANNELS = [
|
|
9881
|
+
var COUNT_GROUP_CHANNELS = [
|
|
9882
|
+
"x",
|
|
9883
|
+
"y",
|
|
9884
|
+
"color",
|
|
9885
|
+
"detail",
|
|
9886
|
+
"strokeDash",
|
|
9887
|
+
"facet",
|
|
9888
|
+
"row",
|
|
9889
|
+
"column"
|
|
9890
|
+
];
|
|
9850
9891
|
function expandCountAggregate(spec) {
|
|
9851
9892
|
const encoding = spec.encoding;
|
|
9852
9893
|
if (!encoding || typeof encoding !== "object") return spec;
|
|
@@ -9965,6 +10006,7 @@ function expandChartSugar(spec, warnings, inheritedData) {
|
|
|
9965
10006
|
out = expandTopLevelTitle(out);
|
|
9966
10007
|
out = expandDescriptionSugar(out);
|
|
9967
10008
|
out = stripIgnoredKeys(out, warnings);
|
|
10009
|
+
out = stripRemovedMarkRender(out, warnings);
|
|
9968
10010
|
out = applyFixedSizeDefault(out);
|
|
9969
10011
|
out = expandAnnotationSugar(out, warnings);
|
|
9970
10012
|
out = expandChannelSugar(out, warnings);
|
|
@@ -10081,6 +10123,12 @@ function resolveAnimation(spec) {
|
|
|
10081
10123
|
const enter = resolvePhase(config.enter, ENTER_DEFAULTS);
|
|
10082
10124
|
const update = resolvePhase(config.update, UPDATE_DEFAULTS);
|
|
10083
10125
|
const exit = resolvePhase(config.exit, EXIT_DEFAULTS);
|
|
10126
|
+
if (update && config.update && typeof config.update === "object" && !Array.isArray(config.update)) {
|
|
10127
|
+
const cap = config.update.maxMarks;
|
|
10128
|
+
if (typeof cap === "number" && Number.isFinite(cap) && cap >= 1) {
|
|
10129
|
+
update.maxMarks = Math.floor(cap);
|
|
10130
|
+
}
|
|
10131
|
+
}
|
|
10084
10132
|
if (!enter && !update && !exit) return void 0;
|
|
10085
10133
|
return {
|
|
10086
10134
|
enter: enter ?? void 0,
|
|
@@ -10122,9 +10170,9 @@ function resolveStagger(stagger, defaults) {
|
|
|
10122
10170
|
import {
|
|
10123
10171
|
isBarListSpec,
|
|
10124
10172
|
isChartSpec,
|
|
10173
|
+
isGeoMapSpec,
|
|
10125
10174
|
isGraphSpec,
|
|
10126
10175
|
isLayerSpec,
|
|
10127
|
-
isMapSpec,
|
|
10128
10176
|
isSankeySpec,
|
|
10129
10177
|
isTableSpec,
|
|
10130
10178
|
isTileMapSpec,
|
|
@@ -10473,6 +10521,7 @@ function normalizeChartSpec(spec, warnings) {
|
|
|
10473
10521
|
data: spec.data,
|
|
10474
10522
|
encoding,
|
|
10475
10523
|
chrome: normalizeChrome(spec.chrome),
|
|
10524
|
+
chromeLayout: spec.chromeLayout,
|
|
10476
10525
|
metrics: spec.metrics,
|
|
10477
10526
|
seriesSearch: normalizeSeriesSearch(spec, encoding, warnings),
|
|
10478
10527
|
youDrawIt: normalizeYouDrawIt(spec),
|
|
@@ -10546,16 +10595,16 @@ function normalizeSankeySpec(spec, _warnings) {
|
|
|
10546
10595
|
watermark: spec.watermark ?? true
|
|
10547
10596
|
};
|
|
10548
10597
|
}
|
|
10549
|
-
function normalizeGraphSpec(spec) {
|
|
10550
|
-
const
|
|
10598
|
+
function normalizeGraphSpec(spec, warnings) {
|
|
10599
|
+
const layout = {
|
|
10551
10600
|
type: "force",
|
|
10552
|
-
chargeStrength: -300,
|
|
10553
|
-
linkDistance: 30
|
|
10554
|
-
};
|
|
10555
|
-
const layout = spec.layout ? {
|
|
10556
|
-
...defaultLayout,
|
|
10557
10601
|
...spec.layout
|
|
10558
|
-
}
|
|
10602
|
+
};
|
|
10603
|
+
let seedNode = typeof spec.seedNode === "string" ? { id: spec.seedNode } : spec.seedNode;
|
|
10604
|
+
if (seedNode && !spec.nodes.some((n) => n.id === seedNode?.id)) {
|
|
10605
|
+
warnings.push(`seedNode "${seedNode.id}" does not match any node id; it will be ignored.`);
|
|
10606
|
+
seedNode = void 0;
|
|
10607
|
+
}
|
|
10559
10608
|
return {
|
|
10560
10609
|
type: "graph",
|
|
10561
10610
|
nodes: spec.nodes,
|
|
@@ -10563,11 +10612,15 @@ function normalizeGraphSpec(spec) {
|
|
|
10563
10612
|
encoding: spec.encoding ?? {},
|
|
10564
10613
|
layout,
|
|
10565
10614
|
nodeOverrides: spec.nodeOverrides,
|
|
10615
|
+
seedNode,
|
|
10566
10616
|
chrome: normalizeChrome(spec.chrome),
|
|
10567
10617
|
annotations: normalizeAnnotations(spec.annotations),
|
|
10568
10618
|
theme: spec.theme ?? {},
|
|
10569
10619
|
darkMode: spec.darkMode ?? "off",
|
|
10570
|
-
watermark: spec.watermark ?? true
|
|
10620
|
+
watermark: spec.watermark ?? true,
|
|
10621
|
+
animation: spec.animation,
|
|
10622
|
+
interaction: spec.interaction,
|
|
10623
|
+
legend: spec.legend
|
|
10571
10624
|
};
|
|
10572
10625
|
}
|
|
10573
10626
|
function normalizeTileMapSpec(spec, warnings) {
|
|
@@ -10623,7 +10676,7 @@ function normalizeTileMapSpec(spec, warnings) {
|
|
|
10623
10676
|
valueFormat: spec.valueFormat
|
|
10624
10677
|
};
|
|
10625
10678
|
}
|
|
10626
|
-
function
|
|
10679
|
+
function normalizeGeoMapSpec(spec, _warnings) {
|
|
10627
10680
|
return {
|
|
10628
10681
|
type: "map",
|
|
10629
10682
|
geo: {
|
|
@@ -10675,7 +10728,7 @@ function normalizeSpec(spec, warnings = []) {
|
|
|
10675
10728
|
return normalizeTableSpec(spec, warnings);
|
|
10676
10729
|
}
|
|
10677
10730
|
if (isGraphSpec(spec)) {
|
|
10678
|
-
return normalizeGraphSpec(spec);
|
|
10731
|
+
return normalizeGraphSpec(spec, warnings);
|
|
10679
10732
|
}
|
|
10680
10733
|
if (isSankeySpec(spec)) {
|
|
10681
10734
|
return normalizeSankeySpec(spec, warnings);
|
|
@@ -10683,8 +10736,8 @@ function normalizeSpec(spec, warnings = []) {
|
|
|
10683
10736
|
if (isTileMapSpec(spec)) {
|
|
10684
10737
|
return normalizeTileMapSpec(spec, warnings);
|
|
10685
10738
|
}
|
|
10686
|
-
if (
|
|
10687
|
-
return
|
|
10739
|
+
if (isGeoMapSpec(spec)) {
|
|
10740
|
+
return normalizeGeoMapSpec(spec, warnings);
|
|
10688
10741
|
}
|
|
10689
10742
|
if (isBarListSpec(spec)) {
|
|
10690
10743
|
return normalizeBarListSpec(spec, warnings);
|
|
@@ -11000,6 +11053,40 @@ function validateCalendarSpec(spec, errors) {
|
|
|
11000
11053
|
seenDays.set(dayKey, i);
|
|
11001
11054
|
}
|
|
11002
11055
|
}
|
|
11056
|
+
var MAX_PLAUSIBLE_POINT_RADIUS = 50;
|
|
11057
|
+
function pointSizeError(path2, value2) {
|
|
11058
|
+
const radius = Math.max(1, Math.round(Math.sqrt(value2 / Math.PI)));
|
|
11059
|
+
return {
|
|
11060
|
+
message: `Spec error: ${path2} is a radius in pixels, and ${value2} would draw a ${Math.round(value2 * 2)}px-wide circle. This usually means the value was written in Vega-Lite's units, where point size is an area in px^2.`,
|
|
11061
|
+
path: path2,
|
|
11062
|
+
code: "INVALID_VALUE",
|
|
11063
|
+
suggestion: `Point sizes are radii in px (default 5, typical 2-12). For the dot a Vega-Lite size of ${value2} draws, use ${radius} (r = sqrt(area / pi)).`
|
|
11064
|
+
};
|
|
11065
|
+
}
|
|
11066
|
+
function validatePointSize(spec, errors) {
|
|
11067
|
+
const markType = typeof spec.mark === "string" ? spec.mark : spec.mark?.type;
|
|
11068
|
+
if (markType !== "point") return;
|
|
11069
|
+
if (spec.mark && typeof spec.mark === "object") {
|
|
11070
|
+
const size = spec.mark.size;
|
|
11071
|
+
if (typeof size === "number" && size > MAX_PLAUSIBLE_POINT_RADIUS) {
|
|
11072
|
+
errors.push(pointSizeError("mark.size", size));
|
|
11073
|
+
}
|
|
11074
|
+
}
|
|
11075
|
+
const sizeEnc = spec.encoding && typeof spec.encoding === "object" ? spec.encoding.size : void 0;
|
|
11076
|
+
if (!sizeEnc || typeof sizeEnc !== "object") return;
|
|
11077
|
+
if (typeof sizeEnc.value === "number" && sizeEnc.value > MAX_PLAUSIBLE_POINT_RADIUS) {
|
|
11078
|
+
errors.push(pointSizeError("encoding.size.value", sizeEnc.value));
|
|
11079
|
+
}
|
|
11080
|
+
const range3 = sizeEnc.scale && typeof sizeEnc.scale === "object" ? sizeEnc.scale.range : void 0;
|
|
11081
|
+
if (Array.isArray(range3)) {
|
|
11082
|
+
const worst = range3.find(
|
|
11083
|
+
(entry) => typeof entry === "number" && entry > MAX_PLAUSIBLE_POINT_RADIUS
|
|
11084
|
+
);
|
|
11085
|
+
if (typeof worst === "number") {
|
|
11086
|
+
errors.push(pointSizeError("encoding.size.scale.range", worst));
|
|
11087
|
+
}
|
|
11088
|
+
}
|
|
11089
|
+
}
|
|
11003
11090
|
function validateChartSpec(spec, errors) {
|
|
11004
11091
|
const markType = typeof spec.mark === "string" ? spec.mark : spec.mark?.type;
|
|
11005
11092
|
if (!Array.isArray(spec.data)) {
|
|
@@ -11105,6 +11192,7 @@ function validateChartSpec(spec, errors) {
|
|
|
11105
11192
|
if (markType === "calendar") {
|
|
11106
11193
|
validateCalendarSpec(spec, errors);
|
|
11107
11194
|
}
|
|
11195
|
+
validatePointSize(spec, errors);
|
|
11108
11196
|
if (Array.isArray(spec.transform)) {
|
|
11109
11197
|
const transforms = spec.transform;
|
|
11110
11198
|
for (let i = 0; i < transforms.length; i++) {
|
|
@@ -11317,6 +11405,52 @@ function validateChartSpec(spec, errors) {
|
|
|
11317
11405
|
}
|
|
11318
11406
|
}
|
|
11319
11407
|
}
|
|
11408
|
+
for (const channel of ["row", "column"]) {
|
|
11409
|
+
const ch = encoding[channel];
|
|
11410
|
+
if (ch && typeof ch === "object") {
|
|
11411
|
+
const facetCh = ch;
|
|
11412
|
+
if (!facetCh.field || typeof facetCh.field !== "string") {
|
|
11413
|
+
errors.push({
|
|
11414
|
+
message: `Spec error: encoding.${channel}.field is required and must be a non-empty string`,
|
|
11415
|
+
path: `encoding.${channel}.field`,
|
|
11416
|
+
code: "MISSING_FIELD",
|
|
11417
|
+
suggestion: `Add a field property to encoding.${channel} (e.g. { field: "category", type: "nominal" })`
|
|
11418
|
+
});
|
|
11419
|
+
} else if (!dataColumns.has(facetCh.field) && !transformFields.has(facetCh.field)) {
|
|
11420
|
+
errors.push({
|
|
11421
|
+
message: `Spec error: encoding.${channel}.field "${facetCh.field}" does not exist in data. Available columns: ${availableColumns}`,
|
|
11422
|
+
path: `encoding.${channel}.field`,
|
|
11423
|
+
code: "DATA_FIELD_MISSING",
|
|
11424
|
+
suggestion: `Use one of the available data columns: ${availableColumns}.${didYouMean(facetCh.field, columnList)}`
|
|
11425
|
+
});
|
|
11426
|
+
}
|
|
11427
|
+
if (!facetCh.type || facetCh.type !== "nominal" && facetCh.type !== "ordinal") {
|
|
11428
|
+
errors.push({
|
|
11429
|
+
message: `Spec error: encoding.${channel}.type must be "nominal" or "ordinal"${facetCh.type ? `, got "${facetCh.type}"` : ""}`,
|
|
11430
|
+
path: `encoding.${channel}.type`,
|
|
11431
|
+
code: facetCh.type ? "INVALID_VALUE" : "MISSING_FIELD",
|
|
11432
|
+
suggestion: `Set encoding.${channel}.type to "nominal" or "ordinal"`
|
|
11433
|
+
});
|
|
11434
|
+
}
|
|
11435
|
+
if (encoding.facet && typeof encoding.facet === "object") {
|
|
11436
|
+
errors.push({
|
|
11437
|
+
message: `Spec error: encoding.${channel} and encoding.facet cannot be used together`,
|
|
11438
|
+
path: `encoding.${channel}`,
|
|
11439
|
+
code: "INVALID_VALUE",
|
|
11440
|
+
suggestion: `Use either encoding.${channel} or encoding.facet, not both`
|
|
11441
|
+
});
|
|
11442
|
+
}
|
|
11443
|
+
const otherChannel = channel === "row" ? "column" : "row";
|
|
11444
|
+
if (encoding[otherChannel]) {
|
|
11445
|
+
errors.push({
|
|
11446
|
+
message: "Spec error: encoding.row and encoding.column cannot be used together (cross-product faceting is not yet supported)",
|
|
11447
|
+
path: `encoding.${channel}`,
|
|
11448
|
+
code: "INVALID_VALUE",
|
|
11449
|
+
suggestion: "Use encoding.facet with columns for grid layout, or use only row or column"
|
|
11450
|
+
});
|
|
11451
|
+
}
|
|
11452
|
+
}
|
|
11453
|
+
}
|
|
11320
11454
|
if (spec.darkMode !== void 0 && !VALID_DARK_MODES.has(spec.darkMode)) {
|
|
11321
11455
|
errors.push({
|
|
11322
11456
|
message: `Spec error: darkMode must be "auto", "force", or "off"`,
|
|
@@ -11496,6 +11630,35 @@ function validateGraphSpec(spec, errors) {
|
|
|
11496
11630
|
nodeIds.add(node.id);
|
|
11497
11631
|
}
|
|
11498
11632
|
}
|
|
11633
|
+
if (spec.seedNode !== void 0) {
|
|
11634
|
+
if (typeof spec.seedNode === "string") {
|
|
11635
|
+
if (spec.seedNode === "") {
|
|
11636
|
+
errors.push({
|
|
11637
|
+
message: 'Spec error: "seedNode" must be a non-empty node id',
|
|
11638
|
+
path: "seedNode",
|
|
11639
|
+
code: "MISSING_FIELD",
|
|
11640
|
+
suggestion: `Use one of the existing node ids, e.g. seedNode: "${[...nodeIds][0] ?? "a"}"`
|
|
11641
|
+
});
|
|
11642
|
+
}
|
|
11643
|
+
} else if (typeof spec.seedNode !== "object" || spec.seedNode === null || Array.isArray(spec.seedNode)) {
|
|
11644
|
+
errors.push({
|
|
11645
|
+
message: `Spec error: "seedNode" must be a node id string or an object like { id, style }, got ${Array.isArray(spec.seedNode) ? "array" : typeof spec.seedNode}`,
|
|
11646
|
+
path: "seedNode",
|
|
11647
|
+
code: "INVALID_TYPE",
|
|
11648
|
+
suggestion: `Use the id shorthand (seedNode: "${[...nodeIds][0] ?? "a"}") or the object form (seedNode: { id: "${[...nodeIds][0] ?? "a"}", style: { radius: 14 } })`
|
|
11649
|
+
});
|
|
11650
|
+
} else {
|
|
11651
|
+
const seedId = spec.seedNode.id;
|
|
11652
|
+
if (typeof seedId !== "string" || seedId === "") {
|
|
11653
|
+
errors.push({
|
|
11654
|
+
message: 'Spec error: "seedNode" must have a non-empty string "id" field',
|
|
11655
|
+
path: "seedNode.id",
|
|
11656
|
+
code: "MISSING_FIELD",
|
|
11657
|
+
suggestion: `Add the seed node id, e.g. seedNode: { id: "${[...nodeIds][0] ?? "a"}" }`
|
|
11658
|
+
});
|
|
11659
|
+
}
|
|
11660
|
+
}
|
|
11661
|
+
}
|
|
11499
11662
|
if (!Array.isArray(spec.edges)) {
|
|
11500
11663
|
errors.push({
|
|
11501
11664
|
message: 'Spec error: graph spec requires an "edges" array',
|
|
@@ -11550,14 +11713,28 @@ function validateGraphSpec(spec, errors) {
|
|
|
11550
11713
|
}
|
|
11551
11714
|
if (spec.encoding && typeof spec.encoding === "object") {
|
|
11552
11715
|
const encoding = spec.encoding;
|
|
11553
|
-
const
|
|
11554
|
-
const
|
|
11555
|
-
|
|
11556
|
-
|
|
11557
|
-
|
|
11716
|
+
const nodeFields = /* @__PURE__ */ new Set();
|
|
11717
|
+
for (const node of nodes) {
|
|
11718
|
+
if (node && typeof node === "object") {
|
|
11719
|
+
for (const key of Object.keys(node)) nodeFields.add(key);
|
|
11720
|
+
}
|
|
11721
|
+
}
|
|
11722
|
+
const edgeFields = /* @__PURE__ */ new Set();
|
|
11723
|
+
for (const edge of edges) {
|
|
11724
|
+
if (edge && typeof edge === "object") {
|
|
11725
|
+
for (const key of Object.keys(edge)) edgeFields.add(key);
|
|
11726
|
+
}
|
|
11727
|
+
}
|
|
11728
|
+
const nodeChannels = [
|
|
11729
|
+
"nodeColor",
|
|
11730
|
+
"nodeSize",
|
|
11731
|
+
"nodeOpacity",
|
|
11732
|
+
"nodeLabel",
|
|
11733
|
+
"nodeLabelPriority"
|
|
11734
|
+
];
|
|
11558
11735
|
for (const channel of nodeChannels) {
|
|
11559
11736
|
const ch = encoding[channel];
|
|
11560
|
-
if (ch?.field && typeof ch.field === "string" && !nodeFields.has(ch.field)) {
|
|
11737
|
+
if (ch?.field && typeof ch.field === "string" && nodes.length > 0 && !nodeFields.has(ch.field)) {
|
|
11561
11738
|
errors.push({
|
|
11562
11739
|
message: `Spec error: encoding.${channel}.field "${ch.field}" does not exist on nodes. Available fields: ${[...nodeFields].join(", ")}`,
|
|
11563
11740
|
path: `encoding.${channel}.field`,
|
|
@@ -11566,10 +11743,10 @@ function validateGraphSpec(spec, errors) {
|
|
|
11566
11743
|
});
|
|
11567
11744
|
}
|
|
11568
11745
|
}
|
|
11569
|
-
const edgeChannels = ["edgeColor", "edgeWidth"];
|
|
11746
|
+
const edgeChannels = ["edgeColor", "edgeWidth", "edgeStyle"];
|
|
11570
11747
|
for (const channel of edgeChannels) {
|
|
11571
11748
|
const ch = encoding[channel];
|
|
11572
|
-
if (ch?.field && typeof ch.field === "string" &&
|
|
11749
|
+
if (ch?.field && typeof ch.field === "string" && edges.length > 0 && !edgeFields.has(ch.field)) {
|
|
11573
11750
|
errors.push({
|
|
11574
11751
|
message: `Spec error: encoding.${channel}.field "${ch.field}" does not exist on edges. Available fields: ${[...edgeFields].join(", ")}`,
|
|
11575
11752
|
path: `encoding.${channel}.field`,
|
|
@@ -11782,7 +11959,7 @@ function validateTileMapSpec(spec, errors) {
|
|
|
11782
11959
|
});
|
|
11783
11960
|
}
|
|
11784
11961
|
}
|
|
11785
|
-
function
|
|
11962
|
+
function validateGeoMapSpec(spec, errors) {
|
|
11786
11963
|
if (!spec.geo || typeof spec.geo !== "object") {
|
|
11787
11964
|
errors.push({
|
|
11788
11965
|
message: 'Spec error: map spec requires a "geo" object with a TopoJSON "features" field',
|
|
@@ -12162,6 +12339,22 @@ function validateLayerSpec(spec, errors) {
|
|
|
12162
12339
|
}
|
|
12163
12340
|
}
|
|
12164
12341
|
}
|
|
12342
|
+
function validateAnimation(spec, errors) {
|
|
12343
|
+
const animation = spec.animation;
|
|
12344
|
+
if (!animation || typeof animation !== "object" || Array.isArray(animation)) return;
|
|
12345
|
+
const update = animation.update;
|
|
12346
|
+
if (!update || typeof update !== "object" || Array.isArray(update)) return;
|
|
12347
|
+
const maxMarks = update.maxMarks;
|
|
12348
|
+
if (maxMarks === void 0) return;
|
|
12349
|
+
if (typeof maxMarks !== "number" || !Number.isFinite(maxMarks) || maxMarks < 1) {
|
|
12350
|
+
errors.push({
|
|
12351
|
+
message: `Spec error: animation.update.maxMarks must be a number >= 1, got ${JSON.stringify(maxMarks)}`,
|
|
12352
|
+
path: "animation.update.maxMarks",
|
|
12353
|
+
code: "INVALID_VALUE",
|
|
12354
|
+
suggestion: "Set animation.update.maxMarks to the largest mark count that should still tween, e.g. animation: { update: { maxMarks: 5000 } }. Omit it to use the default of 500."
|
|
12355
|
+
});
|
|
12356
|
+
}
|
|
12357
|
+
}
|
|
12165
12358
|
function validateSpec(spec) {
|
|
12166
12359
|
const errors = [];
|
|
12167
12360
|
if (!spec || typeof spec !== "object" || Array.isArray(spec)) {
|
|
@@ -12266,10 +12459,13 @@ function validateSpec(spec) {
|
|
|
12266
12459
|
} else if (isTileMap) {
|
|
12267
12460
|
validateTileMapSpec(obj, errors);
|
|
12268
12461
|
} else if (isMap) {
|
|
12269
|
-
|
|
12462
|
+
validateGeoMapSpec(obj, errors);
|
|
12270
12463
|
} else if (isBarList) {
|
|
12271
12464
|
validateBarListSpec(obj, errors);
|
|
12272
12465
|
}
|
|
12466
|
+
if (!isGraph) {
|
|
12467
|
+
validateAnimation(obj, errors);
|
|
12468
|
+
}
|
|
12273
12469
|
if (errors.length > 0) {
|
|
12274
12470
|
return { valid: false, errors, normalized: null };
|
|
12275
12471
|
}
|
|
@@ -12293,6 +12489,36 @@ ${errorMessages}`);
|
|
|
12293
12489
|
return { spec: normalized, warnings };
|
|
12294
12490
|
}
|
|
12295
12491
|
|
|
12492
|
+
// src/layout/shared.ts
|
|
12493
|
+
function chromeToInput(chrome) {
|
|
12494
|
+
return {
|
|
12495
|
+
eyebrow: chrome.eyebrow,
|
|
12496
|
+
title: chrome.title,
|
|
12497
|
+
subtitle: chrome.subtitle,
|
|
12498
|
+
source: chrome.source,
|
|
12499
|
+
byline: chrome.byline,
|
|
12500
|
+
footer: chrome.footer,
|
|
12501
|
+
brand: chrome.brand
|
|
12502
|
+
};
|
|
12503
|
+
}
|
|
12504
|
+
function scalePadding(basePadding, width, height) {
|
|
12505
|
+
const minDim = Math.min(width, height);
|
|
12506
|
+
if (minDim >= 500) return basePadding;
|
|
12507
|
+
if (minDim <= 200) return Math.max(Math.round(basePadding * 0.5), 4);
|
|
12508
|
+
const t = (minDim - 200) / 300;
|
|
12509
|
+
return Math.max(Math.round(basePadding * (0.5 + t * 0.5)), 4);
|
|
12510
|
+
}
|
|
12511
|
+
function bottomMargin(bottomHeight, padding, xAxisHeight) {
|
|
12512
|
+
return padding + bottomHeight + xAxisHeight;
|
|
12513
|
+
}
|
|
12514
|
+
var INLINE_TICK_OVERHANG_PAD = 6;
|
|
12515
|
+
function resolveChromeLayout(spec, options) {
|
|
12516
|
+
const encoding = spec?.encoding;
|
|
12517
|
+
const isFaceted = !!(encoding?.facet || encoding?.row || encoding?.column);
|
|
12518
|
+
if (isFaceted) return "subtract";
|
|
12519
|
+
return spec?.chromeLayout ?? options?.chromeLayout ?? "subtract";
|
|
12520
|
+
}
|
|
12521
|
+
|
|
12296
12522
|
// src/barlist/compile-barlist.ts
|
|
12297
12523
|
var DEFAULT_ROW_GAP = 8;
|
|
12298
12524
|
var LABEL_BAR_GAP = 12;
|
|
@@ -12340,14 +12566,19 @@ function compileBarList(spec, options) {
|
|
|
12340
12566
|
watermark
|
|
12341
12567
|
);
|
|
12342
12568
|
const padding = theme.spacing.padding;
|
|
12569
|
+
const chromeLayout = resolveChromeLayout(
|
|
12570
|
+
spec,
|
|
12571
|
+
options
|
|
12572
|
+
);
|
|
12573
|
+
const grownHeight = chromeLayout === "grow" ? options.height + chrome.topHeight + chrome.bottomHeight : options.height;
|
|
12343
12574
|
const fullArea = {
|
|
12344
12575
|
x: padding,
|
|
12345
12576
|
y: padding + chrome.topHeight,
|
|
12346
12577
|
width: options.width - padding * 2,
|
|
12347
|
-
height: options.height - chrome.topHeight - chrome.bottomHeight - padding * 2
|
|
12578
|
+
height: chromeLayout === "grow" ? options.height - padding * 2 : options.height - chrome.topHeight - chrome.bottomHeight - padding * 2
|
|
12348
12579
|
};
|
|
12349
12580
|
if (fullArea.width <= 0 || fullArea.height <= 0) {
|
|
12350
|
-
return emptyLayout2(chrome, theme, options, watermark);
|
|
12581
|
+
return emptyLayout2(chrome, theme, { ...options, height: grownHeight }, watermark);
|
|
12351
12582
|
}
|
|
12352
12583
|
const labelField = barlistSpec.encoding.label.field;
|
|
12353
12584
|
const valueField = barlistSpec.encoding.value.field;
|
|
@@ -12532,7 +12763,7 @@ function compileBarList(spec, options) {
|
|
|
12532
12763
|
a11y,
|
|
12533
12764
|
theme,
|
|
12534
12765
|
width: options.width,
|
|
12535
|
-
height:
|
|
12766
|
+
height: grownHeight,
|
|
12536
12767
|
animation: resolvedAnimation,
|
|
12537
12768
|
watermark,
|
|
12538
12769
|
measureText
|
|
@@ -13317,9 +13548,9 @@ function buildBandScale(channel, data, rangeStart, rangeEnd, defaultPadding = DE
|
|
|
13317
13548
|
}
|
|
13318
13549
|
return { scale, type: "band", channel };
|
|
13319
13550
|
}
|
|
13320
|
-
function buildPointScale(channel, data, rangeStart, rangeEnd) {
|
|
13551
|
+
function buildPointScale(channel, data, rangeStart, rangeEnd, defaultPadding = 0.5) {
|
|
13321
13552
|
const values = channel.scale?.domain ? channel.scale.domain : applyCategoricalSort(uniqueStrings(fieldValues(data, channel.field)), channel.sort);
|
|
13322
|
-
const padding = channel.scale?.padding ?? channel.scale?.paddingOuter ??
|
|
13553
|
+
const padding = channel.scale?.padding ?? channel.scale?.paddingOuter ?? defaultPadding;
|
|
13323
13554
|
const scale = point().domain(values).range([rangeStart, rangeEnd]).padding(padding);
|
|
13324
13555
|
if (channel.scale?.reverse) {
|
|
13325
13556
|
const [r0, r1] = scale.range();
|
|
@@ -13396,7 +13627,7 @@ function buildPositionalScale(channel, data, rangeStart, rangeEnd, chartType, ax
|
|
|
13396
13627
|
case "point":
|
|
13397
13628
|
return buildPointScale(channel, data, rangeStart, rangeEnd);
|
|
13398
13629
|
case "ordinal":
|
|
13399
|
-
return
|
|
13630
|
+
return buildCategoricalScale(channel, data, rangeStart, rangeEnd, chartType, axis);
|
|
13400
13631
|
}
|
|
13401
13632
|
}
|
|
13402
13633
|
switch (channel.type) {
|
|
@@ -13406,17 +13637,21 @@ function buildPositionalScale(channel, data, rangeStart, rangeEnd, chartType, ax
|
|
|
13406
13637
|
return buildLinearScale(channel, data, rangeStart, rangeEnd);
|
|
13407
13638
|
case "nominal":
|
|
13408
13639
|
case "ordinal":
|
|
13409
|
-
|
|
13410
|
-
return buildBandScale(channel, data, rangeStart, rangeEnd, HEATMAP_BAND_PADDING);
|
|
13411
|
-
}
|
|
13412
|
-
if (chartType === "bar" || chartType === "beeswarm" || chartType === "range" || (chartType === "circle" || chartType === "lollipop") && axis === "y") {
|
|
13413
|
-
return buildBandScale(channel, data, rangeStart, rangeEnd);
|
|
13414
|
-
}
|
|
13415
|
-
return buildPointScale(channel, data, rangeStart, rangeEnd);
|
|
13640
|
+
return buildCategoricalScale(channel, data, rangeStart, rangeEnd, chartType, axis);
|
|
13416
13641
|
default:
|
|
13417
13642
|
return buildLinearScale(channel, data, rangeStart, rangeEnd);
|
|
13418
13643
|
}
|
|
13419
13644
|
}
|
|
13645
|
+
function buildCategoricalScale(channel, data, rangeStart, rangeEnd, chartType, axis) {
|
|
13646
|
+
if (chartType === "rect") {
|
|
13647
|
+
return buildBandScale(channel, data, rangeStart, rangeEnd, HEATMAP_BAND_PADDING);
|
|
13648
|
+
}
|
|
13649
|
+
if (chartType === "bar" || chartType === "beeswarm" || chartType === "range" || (chartType === "circle" || chartType === "lollipop") && axis === "y") {
|
|
13650
|
+
return buildBandScale(channel, data, rangeStart, rangeEnd);
|
|
13651
|
+
}
|
|
13652
|
+
const isTrendMark = chartType === "line" || chartType === "area";
|
|
13653
|
+
return buildPointScale(channel, data, rangeStart, rangeEnd, isTrendMark ? 0 : 0.5);
|
|
13654
|
+
}
|
|
13420
13655
|
function computeScales(spec, chartArea, data) {
|
|
13421
13656
|
const result = {};
|
|
13422
13657
|
const encoding = spec.encoding;
|
|
@@ -13660,6 +13895,7 @@ var LEGEND_PADDING = 8;
|
|
|
13660
13895
|
var LEGEND_RIGHT_WIDTH = 120;
|
|
13661
13896
|
var RIGHT_LEGEND_MAX_HEIGHT_RATIO = 0.4;
|
|
13662
13897
|
var TOP_LEGEND_MAX_ROWS = 2;
|
|
13898
|
+
var ARC_LABEL_CROWDING_LIMIT = 21;
|
|
13663
13899
|
function hasLegendContent(content) {
|
|
13664
13900
|
return content.entries.length > 0 || content.continuous != null;
|
|
13665
13901
|
}
|
|
@@ -13817,6 +14053,12 @@ function computeLegendContent(spec, strategy, theme, availableWidth, availableHe
|
|
|
13817
14053
|
}
|
|
13818
14054
|
}
|
|
13819
14055
|
}
|
|
14056
|
+
const density = spec.labels.density;
|
|
14057
|
+
const everySliceLabeled = density === "all" || density === "auto";
|
|
14058
|
+
const uncrowded = seriesCount > 0 && seriesCount <= ARC_LABEL_CROWDING_LIMIT;
|
|
14059
|
+
if (spec.markType === "arc" && everySliceLabeled && uncrowded && !spec.userExplicit?.legend) {
|
|
14060
|
+
entries = [];
|
|
14061
|
+
}
|
|
13820
14062
|
const labelStyle = {
|
|
13821
14063
|
fontFamily: theme.fonts.family,
|
|
13822
14064
|
fontSize: theme.fonts.sizes.small,
|
|
@@ -14561,6 +14803,32 @@ function applyBandLabelStride(ticks2, stride) {
|
|
|
14561
14803
|
const lastIdx = ticks2.length - 1;
|
|
14562
14804
|
return ticks2.filter((_, i) => (lastIdx - i) % stride === 0);
|
|
14563
14805
|
}
|
|
14806
|
+
var LABEL_EDGE_GUARD = 2;
|
|
14807
|
+
function clampXTickLabels(ticks2, totalWidth, tickAngle, fontSize, fontWeight, measureText) {
|
|
14808
|
+
const rotated = tickAngle !== void 0 && Math.abs(tickAngle) > 10;
|
|
14809
|
+
const rad = rotated ? Math.abs(tickAngle) * Math.PI / 180 : 0;
|
|
14810
|
+
const across = rotated ? fontSize * 1.2 * Math.sin(rad) / 2 : 0;
|
|
14811
|
+
return ticks2.map((tick) => {
|
|
14812
|
+
const width = measureLabel(tick.label, fontSize, fontWeight, measureText);
|
|
14813
|
+
let left2;
|
|
14814
|
+
let right2;
|
|
14815
|
+
if (rotated) {
|
|
14816
|
+
const along = width * Math.cos(rad);
|
|
14817
|
+
const trailsLeft = tickAngle < 0;
|
|
14818
|
+
left2 = trailsLeft ? -(along + across) : -across;
|
|
14819
|
+
right2 = trailsLeft ? across : along + across;
|
|
14820
|
+
} else {
|
|
14821
|
+
left2 = -width / 2;
|
|
14822
|
+
right2 = width / 2;
|
|
14823
|
+
}
|
|
14824
|
+
let x2 = tick.position;
|
|
14825
|
+
const overRight = x2 + right2 - (totalWidth - LABEL_EDGE_GUARD);
|
|
14826
|
+
if (overRight > 0) x2 -= overRight;
|
|
14827
|
+
const overLeft = LABEL_EDGE_GUARD - (x2 + left2);
|
|
14828
|
+
if (overLeft > 0) x2 += overLeft;
|
|
14829
|
+
return x2 === tick.position ? tick : { ...tick, labelPosition: x2 };
|
|
14830
|
+
});
|
|
14831
|
+
}
|
|
14564
14832
|
function computeAxes(scales, chartArea, strategy, theme, measureText, dataContext) {
|
|
14565
14833
|
const result = {};
|
|
14566
14834
|
const baseDensity = strategy.axisLabelDensity;
|
|
@@ -14773,6 +15041,14 @@ function computeAxes(scales, chartArea, strategy, theme, measureText, dataContex
|
|
|
14773
15041
|
const totalWidth = dataContext?.totalWidth ?? chartArea.x + chartArea.width;
|
|
14774
15042
|
if (result.x) {
|
|
14775
15043
|
const isRotated = !!result.x.tickAngle && Math.abs(result.x.tickAngle) > 10;
|
|
15044
|
+
result.x.ticks = clampXTickLabels(
|
|
15045
|
+
result.x.ticks,
|
|
15046
|
+
totalWidth,
|
|
15047
|
+
result.x.tickAngle,
|
|
15048
|
+
result.x.tickLabelStyle.fontSize,
|
|
15049
|
+
result.x.tickLabelStyle.fontWeight,
|
|
15050
|
+
measureText
|
|
15051
|
+
);
|
|
14776
15052
|
result.x.extent = computeXAxisExtentFromLabels({
|
|
14777
15053
|
labels: result.x.ticks.map((t) => t.label),
|
|
14778
15054
|
tickAngle: result.x.tickAngle,
|
|
@@ -14826,30 +15102,6 @@ function computeAxes(scales, chartArea, strategy, theme, measureText, dataContex
|
|
|
14826
15102
|
return result;
|
|
14827
15103
|
}
|
|
14828
15104
|
|
|
14829
|
-
// src/layout/shared.ts
|
|
14830
|
-
function chromeToInput(chrome) {
|
|
14831
|
-
return {
|
|
14832
|
-
eyebrow: chrome.eyebrow,
|
|
14833
|
-
title: chrome.title,
|
|
14834
|
-
subtitle: chrome.subtitle,
|
|
14835
|
-
source: chrome.source,
|
|
14836
|
-
byline: chrome.byline,
|
|
14837
|
-
footer: chrome.footer,
|
|
14838
|
-
brand: chrome.brand
|
|
14839
|
-
};
|
|
14840
|
-
}
|
|
14841
|
-
function scalePadding(basePadding, width, height) {
|
|
14842
|
-
const minDim = Math.min(width, height);
|
|
14843
|
-
if (minDim >= 500) return basePadding;
|
|
14844
|
-
if (minDim <= 200) return Math.max(Math.round(basePadding * 0.5), 4);
|
|
14845
|
-
const t = (minDim - 200) / 300;
|
|
14846
|
-
return Math.max(Math.round(basePadding * (0.5 + t * 0.5)), 4);
|
|
14847
|
-
}
|
|
14848
|
-
function bottomMargin(bottomHeight, padding, xAxisHeight) {
|
|
14849
|
-
return padding + bottomHeight + xAxisHeight;
|
|
14850
|
-
}
|
|
14851
|
-
var INLINE_TICK_OVERHANG_PAD = 6;
|
|
14852
|
-
|
|
14853
15105
|
// src/layout/plan.ts
|
|
14854
15106
|
function createMeasureFn(measureText) {
|
|
14855
15107
|
if (measureText) {
|
|
@@ -15071,7 +15323,9 @@ function resolveLayoutPlan(chartSpec, renderSpec, options, theme, strategy, wate
|
|
|
15071
15323
|
if (hasTopLegend) topMargin += TOP_LEGEND_GAP_ABOVE + legendContent.height + gap;
|
|
15072
15324
|
topMargin += effectiveTopAxisGap;
|
|
15073
15325
|
const bMargin = bottomMargin(chrome.bottomHeight, padding, xAxisExtent);
|
|
15074
|
-
const
|
|
15326
|
+
const chromeLayout = resolveChromeLayout(renderSpec, options);
|
|
15327
|
+
const effectiveHeight = chromeLayout === "grow" ? height + chrome.topHeight + chrome.bottomHeight : height;
|
|
15328
|
+
const chartHeight = Math.max(0, effectiveHeight - topMargin - bMargin);
|
|
15075
15329
|
const rightMargin = hPad + (isRadial ? hPad : axisMargin);
|
|
15076
15330
|
const rightAxisReserve = options.rightAxisReserve ?? 0;
|
|
15077
15331
|
const provisionalArea = {
|
|
@@ -15223,11 +15477,12 @@ function compileLayer(spec, options, compileChart2) {
|
|
|
15223
15477
|
const singleSpec = buildPrimarySpec(leaves, spec);
|
|
15224
15478
|
return compileChart2(singleSpec, options);
|
|
15225
15479
|
}
|
|
15480
|
+
const layerOptions = { ...options, layered: true };
|
|
15226
15481
|
if (spec.resolve?.scale?.y === "independent") {
|
|
15227
|
-
return compileLayerIndependent(leaves, spec,
|
|
15482
|
+
return compileLayerIndependent(leaves, spec, layerOptions, compileChart2);
|
|
15228
15483
|
}
|
|
15229
15484
|
const primarySpec = buildPrimarySpec(leaves, spec);
|
|
15230
|
-
const primaryLayout = compileChart2(primarySpec,
|
|
15485
|
+
const primaryLayout = compileChart2(primarySpec, layerOptions);
|
|
15231
15486
|
const allMarks = [];
|
|
15232
15487
|
const seenLabels = /* @__PURE__ */ new Set();
|
|
15233
15488
|
const pLegend = primaryLayout.legend;
|
|
@@ -15240,7 +15495,7 @@ function compileLayer(spec, options, compileChart2) {
|
|
|
15240
15495
|
zIndex: leaf.zIndex ?? i
|
|
15241
15496
|
}));
|
|
15242
15497
|
indexedLeaves.sort((a, b) => a.zIndex - b.zIndex);
|
|
15243
|
-
const leafOptions = { ...
|
|
15498
|
+
const leafOptions = { ...layerOptions, frozenChartArea: primaryLayout.area };
|
|
15244
15499
|
const sharedDomains = computeSharedDomains(leaves);
|
|
15245
15500
|
for (const { leaf } of indexedLeaves) {
|
|
15246
15501
|
const themedLeaf = {
|
|
@@ -15349,11 +15604,9 @@ function compileLayerIndependent(leaves, layerSpec, options, compileChart2) {
|
|
|
15349
15604
|
};
|
|
15350
15605
|
const xField0 = leaf0.encoding?.x?.field;
|
|
15351
15606
|
const xField1 = leaf1.encoding?.x?.field;
|
|
15352
|
-
const
|
|
15353
|
-
|
|
15354
|
-
|
|
15355
|
-
let leaf0WithUnionX = ensureXDomainCoverage(leaf0, xField0, unionXValues);
|
|
15356
|
-
let leaf1WithUnionX = ensureXDomainCoverage(leaf1, xField1, unionXValues);
|
|
15607
|
+
const union = withUnionXDomain(leaf0, leaf1);
|
|
15608
|
+
let leaf0WithUnionX = union.leaf0;
|
|
15609
|
+
let leaf1WithUnionX = union.leaf1;
|
|
15357
15610
|
const aligned = alignYDomains(leaf0WithUnionX, leaf1WithUnionX);
|
|
15358
15611
|
if (aligned) {
|
|
15359
15612
|
leaf0WithUnionX = withYDomain(leaf0WithUnionX, aligned.domain0);
|
|
@@ -15500,20 +15753,75 @@ function compileLayerIndependent(leaves, layerSpec, options, compileChart2) {
|
|
|
15500
15753
|
tooltipDescriptors: mergedTooltips
|
|
15501
15754
|
};
|
|
15502
15755
|
}
|
|
15503
|
-
function
|
|
15504
|
-
if (!
|
|
15505
|
-
|
|
15506
|
-
|
|
15507
|
-
|
|
15508
|
-
|
|
15509
|
-
|
|
15510
|
-
|
|
15756
|
+
function withXDomain(leaf, domain) {
|
|
15757
|
+
if (!leaf.encoding?.x) return leaf;
|
|
15758
|
+
return {
|
|
15759
|
+
...leaf,
|
|
15760
|
+
encoding: {
|
|
15761
|
+
...leaf.encoding,
|
|
15762
|
+
x: {
|
|
15763
|
+
...leaf.encoding.x,
|
|
15764
|
+
scale: {
|
|
15765
|
+
...leaf.encoding.x.scale,
|
|
15766
|
+
domain
|
|
15767
|
+
}
|
|
15768
|
+
}
|
|
15511
15769
|
}
|
|
15770
|
+
};
|
|
15771
|
+
}
|
|
15772
|
+
function withUnionXDomain(leaf0, leaf1) {
|
|
15773
|
+
const xEnc0 = leaf0.encoding?.x;
|
|
15774
|
+
const xEnc1 = leaf1.encoding?.x;
|
|
15775
|
+
const xField0 = xEnc0?.field;
|
|
15776
|
+
const xField1 = xEnc1?.field;
|
|
15777
|
+
if (!xField0 || !xField1) return { leaf0, leaf1 };
|
|
15778
|
+
const xType = xEnc0?.type ?? xEnc1?.type;
|
|
15779
|
+
const pinned0 = xEnc0?.scale?.domain !== void 0;
|
|
15780
|
+
const pinned1 = xEnc1?.scale?.domain !== void 0;
|
|
15781
|
+
if (pinned0 && pinned1) return { leaf0, leaf1 };
|
|
15782
|
+
const values0 = leaf0.data.map((row) => row[xField0]);
|
|
15783
|
+
const values1 = leaf1.data.map((row) => row[xField1]);
|
|
15784
|
+
const allValues = [...values0, ...values1].filter((v) => v != null);
|
|
15785
|
+
if (allValues.length === 0) return { leaf0, leaf1 };
|
|
15786
|
+
let domain;
|
|
15787
|
+
if (xType === "temporal") {
|
|
15788
|
+
let minMs = Number.POSITIVE_INFINITY;
|
|
15789
|
+
let maxMs = Number.NEGATIVE_INFINITY;
|
|
15790
|
+
for (const v of allValues) {
|
|
15791
|
+
const ms = (v instanceof Date ? v : new Date(String(v))).getTime();
|
|
15792
|
+
if (Number.isNaN(ms)) continue;
|
|
15793
|
+
if (ms < minMs) minMs = ms;
|
|
15794
|
+
if (ms > maxMs) maxMs = ms;
|
|
15795
|
+
}
|
|
15796
|
+
if (minMs <= maxMs) {
|
|
15797
|
+
domain = [new Date(minMs).toISOString(), new Date(maxMs).toISOString()];
|
|
15798
|
+
}
|
|
15799
|
+
} else if (xType === "quantitative") {
|
|
15800
|
+
let min4 = Number.POSITIVE_INFINITY;
|
|
15801
|
+
let max4 = Number.NEGATIVE_INFINITY;
|
|
15802
|
+
for (const v of allValues) {
|
|
15803
|
+
const n = typeof v === "number" ? v : Number(v);
|
|
15804
|
+
if (!Number.isFinite(n)) continue;
|
|
15805
|
+
if (n < min4) min4 = n;
|
|
15806
|
+
if (n > max4) max4 = n;
|
|
15807
|
+
}
|
|
15808
|
+
if (min4 <= max4) domain = [min4, max4];
|
|
15809
|
+
} else {
|
|
15810
|
+
const seen = /* @__PURE__ */ new Set();
|
|
15811
|
+
const categories = [];
|
|
15812
|
+
for (const v of allValues) {
|
|
15813
|
+
const s = String(v);
|
|
15814
|
+
if (!seen.has(s)) {
|
|
15815
|
+
seen.add(s);
|
|
15816
|
+
categories.push(s);
|
|
15817
|
+
}
|
|
15818
|
+
}
|
|
15819
|
+
if (categories.length > 0) domain = categories;
|
|
15512
15820
|
}
|
|
15513
|
-
if (
|
|
15821
|
+
if (domain === void 0) return { leaf0, leaf1 };
|
|
15514
15822
|
return {
|
|
15515
|
-
|
|
15516
|
-
|
|
15823
|
+
leaf0: pinned0 ? leaf0 : withXDomain(leaf0, domain),
|
|
15824
|
+
leaf1: pinned1 ? leaf1 : withXDomain(leaf1, domain)
|
|
15517
15825
|
};
|
|
15518
15826
|
}
|
|
15519
15827
|
function alignYDomains(leaf0, leaf1) {
|
|
@@ -15736,7 +16044,7 @@ function resolveYouDrawIt(config, marks, scales, chartArea, xField) {
|
|
|
15736
16044
|
}
|
|
15737
16045
|
|
|
15738
16046
|
// src/compiler/a11y-warnings.ts
|
|
15739
|
-
import { contrastRatio, findAccessibleColor, isOpaqueColor } from "@opendata-ai/openchart-core";
|
|
16047
|
+
import { contrastRatio, findAccessibleColor, isOpaqueColor as isOpaqueColor2 } from "@opendata-ai/openchart-core";
|
|
15740
16048
|
var GRAPHIC_MIN = 3;
|
|
15741
16049
|
var TEXT_MIN = 4.5;
|
|
15742
16050
|
var ADJACENT_FILL_MARKS = /* @__PURE__ */ new Set(["bar", "area", "arc", "waffle"]);
|
|
@@ -15744,7 +16052,7 @@ var fmt = (ratio) => `${ratio.toFixed(2)}:1`;
|
|
|
15744
16052
|
function collectContrastWarnings(scales, markType, theme) {
|
|
15745
16053
|
const warnings = [];
|
|
15746
16054
|
const bg = theme.colors.background;
|
|
15747
|
-
const bgIsCheckable =
|
|
16055
|
+
const bgIsCheckable = isOpaqueColor2(bg);
|
|
15748
16056
|
const series = [];
|
|
15749
16057
|
if (scales.color && scales.color.type !== "sequential") {
|
|
15750
16058
|
const ordinal2 = scales.color.scale;
|
|
@@ -15792,6 +16100,37 @@ function collectContrastWarnings(scales, markType, theme) {
|
|
|
15792
16100
|
return warnings;
|
|
15793
16101
|
}
|
|
15794
16102
|
|
|
16103
|
+
// src/compiler/mark-render-mode.ts
|
|
16104
|
+
var AUTO_CANVAS_THRESHOLD = 1e3;
|
|
16105
|
+
var AUTO_CANVAS_REFUSAL_WARN_THRESHOLD = 5e3;
|
|
16106
|
+
function resolveMarkRenderMode(args, warnings = []) {
|
|
16107
|
+
const { markType, pointCount, display, faceted, layered } = args;
|
|
16108
|
+
const requested = args.requested ?? "auto";
|
|
16109
|
+
if (requested === "svg") return "svg";
|
|
16110
|
+
const refusal = describeRefusal(markType, display, faceted, layered);
|
|
16111
|
+
if (refusal) {
|
|
16112
|
+
if (requested === "canvas") {
|
|
16113
|
+
warnings.push(
|
|
16114
|
+
`Chart warning: renderer "canvas" is not supported ${refusal}; rendering marks as SVG instead.`
|
|
16115
|
+
);
|
|
16116
|
+
} else if (pointCount > AUTO_CANVAS_REFUSAL_WARN_THRESHOLD) {
|
|
16117
|
+
warnings.push(
|
|
16118
|
+
`[openchart] Rendering ${pointCount} point marks as SVG: the canvas mark layer is not supported ${refusal}. Expect slow paint and interaction. Reduce the point count, or restructure so the dense marks compile as a single unlayered, unfaceted point chart.`
|
|
16119
|
+
);
|
|
16120
|
+
}
|
|
16121
|
+
return "svg";
|
|
16122
|
+
}
|
|
16123
|
+
if (requested === "canvas") return "canvas";
|
|
16124
|
+
return pointCount > AUTO_CANVAS_THRESHOLD ? "canvas" : "svg";
|
|
16125
|
+
}
|
|
16126
|
+
function describeRefusal(markType, display, faceted, layered) {
|
|
16127
|
+
if (markType !== "point") return `for ${markType} marks (point marks only)`;
|
|
16128
|
+
if (faceted) return "on faceted charts";
|
|
16129
|
+
if (layered) return "on layered charts";
|
|
16130
|
+
if (display === "sparkline") return "on sparklines";
|
|
16131
|
+
return void 0;
|
|
16132
|
+
}
|
|
16133
|
+
|
|
15795
16134
|
// src/compiler/sparkline-defaults.ts
|
|
15796
16135
|
var TREND_DEADBAND = 5e-4;
|
|
15797
16136
|
function computeTrend(values) {
|
|
@@ -15858,7 +16197,7 @@ function buildSparklineAreaGradient(baseColor) {
|
|
|
15858
16197
|
};
|
|
15859
16198
|
}
|
|
15860
16199
|
|
|
15861
|
-
// src/geo/compile-map.ts
|
|
16200
|
+
// src/geo/compile-geo-map.ts
|
|
15862
16201
|
import {
|
|
15863
16202
|
adaptTheme as adaptTheme2,
|
|
15864
16203
|
buildD3Formatter as buildD3Formatter2,
|
|
@@ -17759,7 +18098,7 @@ function identity_default4() {
|
|
|
17759
18098
|
return projection2;
|
|
17760
18099
|
}
|
|
17761
18100
|
|
|
17762
|
-
// src/geo/compile-map.ts
|
|
18101
|
+
// src/geo/compile-geo-map.ts
|
|
17763
18102
|
import { feature as topoFeature, mesh as topoMesh } from "topojson-client";
|
|
17764
18103
|
|
|
17765
18104
|
// src/geo/join.ts
|
|
@@ -17892,7 +18231,7 @@ function excludePolarFeatures(geojson) {
|
|
|
17892
18231
|
return { type: "FeatureCollection", features: filtered };
|
|
17893
18232
|
}
|
|
17894
18233
|
|
|
17895
|
-
// src/geo/compile-map.ts
|
|
18234
|
+
// src/geo/compile-geo-map.ts
|
|
17896
18235
|
var OVERLAY_LEGEND_INSET = 18;
|
|
17897
18236
|
function validateGeoFeatures(geo) {
|
|
17898
18237
|
if (!geo.features) {
|
|
@@ -17914,14 +18253,14 @@ function validateGeoFeatures(geo) {
|
|
|
17914
18253
|
}
|
|
17915
18254
|
return topo;
|
|
17916
18255
|
}
|
|
17917
|
-
function
|
|
18256
|
+
function compileGeoMap(spec, options) {
|
|
17918
18257
|
const sugarWarnings = [];
|
|
17919
18258
|
const expandedSpec = spec && typeof spec === "object" && !Array.isArray(spec) ? expandSpecSugar(spec, sugarWarnings) : spec;
|
|
17920
18259
|
const { spec: normalized, warnings } = compile(expandedSpec);
|
|
17921
18260
|
emitSpecWarnings([...sugarWarnings, ...warnings], options.onWarn);
|
|
17922
18261
|
if (!("type" in normalized) || normalized.type !== "map") {
|
|
17923
18262
|
throw new Error(
|
|
17924
|
-
"
|
|
18263
|
+
"compileGeoMap received a non-map spec. Use compileChart, compileTileMap, compileSankey, or compileBarList instead."
|
|
17925
18264
|
);
|
|
17926
18265
|
}
|
|
17927
18266
|
const mapSpec = normalized;
|
|
@@ -17951,11 +18290,15 @@ function compileMap(spec, options) {
|
|
|
17951
18290
|
watermark
|
|
17952
18291
|
);
|
|
17953
18292
|
const padding = getBreakpoint(options.width) === "compact" ? Math.max(HPAD_COMPACT_MIN2, Math.round(theme.spacing.padding * HPAD_COMPACT_FRACTION2)) : theme.spacing.padding;
|
|
18293
|
+
const chromeLayout = resolveChromeLayout(
|
|
18294
|
+
spec,
|
|
18295
|
+
options
|
|
18296
|
+
);
|
|
17954
18297
|
const fullArea = {
|
|
17955
18298
|
x: padding,
|
|
17956
18299
|
y: padding + chrome.topHeight,
|
|
17957
18300
|
width: options.width - padding * 2,
|
|
17958
|
-
height: options.height - chrome.topHeight - chrome.bottomHeight - padding * 2
|
|
18301
|
+
height: chromeLayout === "grow" ? options.height - padding * 2 : options.height - chrome.topHeight - chrome.bottomHeight - padding * 2
|
|
17959
18302
|
};
|
|
17960
18303
|
if (fullArea.width <= 0 || fullArea.height <= 0) {
|
|
17961
18304
|
return emptyLayout3(chrome, theme, options, watermark);
|
|
@@ -18057,7 +18400,7 @@ function compileMap(spec, options) {
|
|
|
18057
18400
|
compileWarnings.push(...filteredJoinWarnings);
|
|
18058
18401
|
}
|
|
18059
18402
|
const droppedFeatures = [];
|
|
18060
|
-
const formatter = buildD3Formatter2(mapSpec.valueFormat) ?? formatNumber3;
|
|
18403
|
+
const formatter = buildD3Formatter2(mapSpec.encoding?.color?.format ?? mapSpec.valueFormat) ?? formatNumber3;
|
|
18061
18404
|
const neutralFill = isDarkMode ? "#2a2a2a" : "#e8e8e8";
|
|
18062
18405
|
const neutralStroke = isDarkMode ? "rgba(255,255,255,0.08)" : "rgba(0,0,0,0.06)";
|
|
18063
18406
|
let featureMarks;
|
|
@@ -18852,6 +19195,65 @@ import {
|
|
|
18852
19195
|
resolveTheme as resolveTheme4
|
|
18853
19196
|
} from "@opendata-ai/openchart-core";
|
|
18854
19197
|
|
|
19198
|
+
// src/graphs/animation.ts
|
|
19199
|
+
var ENTER_DEFAULT = {
|
|
19200
|
+
duration: 500,
|
|
19201
|
+
ease: "smooth",
|
|
19202
|
+
stagger: true,
|
|
19203
|
+
cameraFit: true
|
|
19204
|
+
};
|
|
19205
|
+
var UPDATE_DEFAULT = { duration: 300, ease: "smooth" };
|
|
19206
|
+
var EXIT_DEFAULT = { duration: 300, ease: "smooth" };
|
|
19207
|
+
var CAMERA_DEFAULT = { duration: "auto", ease: "smooth" };
|
|
19208
|
+
var HOVER_DEFAULT = { duration: 150, ease: "smooth" };
|
|
19209
|
+
function fullDefaults() {
|
|
19210
|
+
return {
|
|
19211
|
+
enter: { ...ENTER_DEFAULT },
|
|
19212
|
+
update: { ...UPDATE_DEFAULT },
|
|
19213
|
+
exit: { ...EXIT_DEFAULT },
|
|
19214
|
+
camera: { ...CAMERA_DEFAULT },
|
|
19215
|
+
hover: { ...HOVER_DEFAULT }
|
|
19216
|
+
};
|
|
19217
|
+
}
|
|
19218
|
+
function resolveGraphAnimation(spec) {
|
|
19219
|
+
if (spec === void 0 || spec === true) return fullDefaults();
|
|
19220
|
+
if (spec === false) return void 0;
|
|
19221
|
+
return {
|
|
19222
|
+
enter: resolveEnter(spec.enter),
|
|
19223
|
+
update: resolveDurationPhase(spec.update, UPDATE_DEFAULT),
|
|
19224
|
+
exit: resolveDurationPhase(spec.exit, EXIT_DEFAULT),
|
|
19225
|
+
camera: resolveCamera(spec.camera),
|
|
19226
|
+
hover: resolveDurationPhase(spec.hover, HOVER_DEFAULT)
|
|
19227
|
+
};
|
|
19228
|
+
}
|
|
19229
|
+
function resolveEnter(phase) {
|
|
19230
|
+
if (phase === false) return null;
|
|
19231
|
+
if (phase === void 0 || phase === true) return { ...ENTER_DEFAULT };
|
|
19232
|
+
return {
|
|
19233
|
+
duration: phase.duration ?? ENTER_DEFAULT.duration,
|
|
19234
|
+
ease: phase.ease ?? ENTER_DEFAULT.ease,
|
|
19235
|
+
stagger: phase.stagger !== false,
|
|
19236
|
+
cameraFit: ENTER_DEFAULT.cameraFit
|
|
19237
|
+
};
|
|
19238
|
+
}
|
|
19239
|
+
function resolveDurationPhase(phase, defaults) {
|
|
19240
|
+
if (phase === false) return null;
|
|
19241
|
+
if (phase === void 0 || phase === true)
|
|
19242
|
+
return { duration: defaults.duration, ease: defaults.ease };
|
|
19243
|
+
return {
|
|
19244
|
+
duration: phase.duration ?? defaults.duration,
|
|
19245
|
+
ease: phase.ease ?? defaults.ease
|
|
19246
|
+
};
|
|
19247
|
+
}
|
|
19248
|
+
function resolveCamera(phase) {
|
|
19249
|
+
if (phase === false) return null;
|
|
19250
|
+
if (phase === void 0 || phase === true) return { ...CAMERA_DEFAULT };
|
|
19251
|
+
return {
|
|
19252
|
+
duration: phase.duration ?? CAMERA_DEFAULT.duration,
|
|
19253
|
+
ease: phase.ease ?? CAMERA_DEFAULT.ease
|
|
19254
|
+
};
|
|
19255
|
+
}
|
|
19256
|
+
|
|
18855
19257
|
// src/graphs/encoding.ts
|
|
18856
19258
|
var DEFAULT_NODE_RADIUS = 5;
|
|
18857
19259
|
var MIN_NODE_RADIUS = 3;
|
|
@@ -18891,16 +19293,42 @@ function computeDegrees(nodes, edges) {
|
|
|
18891
19293
|
}
|
|
18892
19294
|
return degrees2;
|
|
18893
19295
|
}
|
|
19296
|
+
function resolveCategoricalDomain(values, sort, scaleDomain) {
|
|
19297
|
+
if (Array.isArray(scaleDomain) && scaleDomain.length > 0) {
|
|
19298
|
+
return scaleDomain.map((v) => String(v));
|
|
19299
|
+
}
|
|
19300
|
+
const seen = [];
|
|
19301
|
+
const set = /* @__PURE__ */ new Set();
|
|
19302
|
+
for (const v of values) {
|
|
19303
|
+
if (!set.has(v)) {
|
|
19304
|
+
set.add(v);
|
|
19305
|
+
seen.push(v);
|
|
19306
|
+
}
|
|
19307
|
+
}
|
|
19308
|
+
if (sort === null) return seen;
|
|
19309
|
+
if (Array.isArray(sort)) {
|
|
19310
|
+
const pinned = sort.filter((v) => set.has(v));
|
|
19311
|
+
const pinnedSet = new Set(pinned);
|
|
19312
|
+
const rest = seen.filter((v) => !pinnedSet.has(v));
|
|
19313
|
+
return [...pinned, ...rest];
|
|
19314
|
+
}
|
|
19315
|
+
const sorted = [...seen].sort((a, b) => a.localeCompare(b));
|
|
19316
|
+
return sort === "descending" ? sorted.reverse() : sorted;
|
|
19317
|
+
}
|
|
18894
19318
|
function resolveNodeVisuals(nodes, encoding, edges, theme, nodeOverrides) {
|
|
18895
19319
|
const degrees2 = computeDegrees(nodes, edges);
|
|
18896
19320
|
const maxDegree = Math.max(1, ...degrees2.values());
|
|
18897
19321
|
let sizeScale;
|
|
18898
19322
|
if (encoding.nodeSize?.field) {
|
|
18899
19323
|
const field = encoding.nodeSize.field;
|
|
19324
|
+
const scaleConfig = encoding.nodeSize.scale;
|
|
18900
19325
|
const values = nodes.map((n) => Number(n[field])).filter((v) => Number.isFinite(v));
|
|
18901
19326
|
const sizeMin = min(values) ?? 0;
|
|
18902
19327
|
const sizeMax = max(values) ?? 1;
|
|
18903
|
-
|
|
19328
|
+
const domain = scaleConfig?.domain && scaleConfig.domain.length === 2 ? scaleConfig.domain : [sizeMin, sizeMax];
|
|
19329
|
+
const range3 = scaleConfig?.range && scaleConfig.range.length >= 2 ? [Number(scaleConfig.range[0]), Number(scaleConfig.range[1])] : [MIN_NODE_RADIUS, MAX_NODE_RADIUS];
|
|
19330
|
+
const ctor = scaleConfig?.type === "linear" ? linear2 : sqrt;
|
|
19331
|
+
sizeScale = ctor().domain(domain).range(range3);
|
|
18904
19332
|
}
|
|
18905
19333
|
let colorFn;
|
|
18906
19334
|
if (encoding.nodeColor?.field) {
|
|
@@ -18921,13 +19349,39 @@ function resolveNodeVisuals(nodes, encoding, edges, theme, nodeOverrides) {
|
|
|
18921
19349
|
return Number.isFinite(val) ? colorScale(val) : theme.colors.categorical[0];
|
|
18922
19350
|
};
|
|
18923
19351
|
} else {
|
|
18924
|
-
const domain =
|
|
19352
|
+
const domain = resolveCategoricalDomain(
|
|
19353
|
+
nodes.map((n) => String(n[field] ?? "")),
|
|
19354
|
+
encoding.nodeColor.sort,
|
|
19355
|
+
scaleConfig?.domain
|
|
19356
|
+
);
|
|
18925
19357
|
const range3 = scaleConfig?.range && scaleConfig.range.length > 0 ? scaleConfig.range : theme.colors.categorical;
|
|
18926
19358
|
const ordinalScale = ordinal().domain(domain).range(range3);
|
|
18927
19359
|
colorFn = (node) => ordinalScale(String(node[field] ?? ""));
|
|
18928
19360
|
}
|
|
18929
19361
|
}
|
|
18930
19362
|
const defaultColor = theme.colors.categorical[0];
|
|
19363
|
+
let opacityScale;
|
|
19364
|
+
if (encoding.nodeOpacity?.field) {
|
|
19365
|
+
const field = encoding.nodeOpacity.field;
|
|
19366
|
+
const scaleConfig = encoding.nodeOpacity.scale;
|
|
19367
|
+
const values = nodes.map((n) => Number(n[field])).filter((v) => Number.isFinite(v));
|
|
19368
|
+
const opMin = min(values) ?? 0;
|
|
19369
|
+
const opMax = max(values) ?? 1;
|
|
19370
|
+
const domain = scaleConfig?.domain && scaleConfig.domain.length === 2 ? scaleConfig.domain : [opMin, opMax];
|
|
19371
|
+
const range3 = scaleConfig?.range && scaleConfig.range.length >= 2 ? [Number(scaleConfig.range[0]), Number(scaleConfig.range[1])] : [0.25, 1];
|
|
19372
|
+
opacityScale = linear2().domain(domain).range(range3);
|
|
19373
|
+
}
|
|
19374
|
+
let labelPriorityScale;
|
|
19375
|
+
if (encoding.nodeLabelPriority?.field) {
|
|
19376
|
+
const field = encoding.nodeLabelPriority.field;
|
|
19377
|
+
const scaleConfig = encoding.nodeLabelPriority.scale;
|
|
19378
|
+
const values = nodes.map((n) => Number(n[field])).filter((v) => Number.isFinite(v));
|
|
19379
|
+
const lpMin = min(values) ?? 0;
|
|
19380
|
+
const lpMax = max(values) ?? 1;
|
|
19381
|
+
const domain = scaleConfig?.domain && scaleConfig.domain.length === 2 ? scaleConfig.domain : [lpMin, lpMax];
|
|
19382
|
+
const range3 = scaleConfig?.range && scaleConfig.range.length >= 2 ? [Number(scaleConfig.range[0]), Number(scaleConfig.range[1])] : [0, 1];
|
|
19383
|
+
labelPriorityScale = linear2().domain(domain).range(range3);
|
|
19384
|
+
}
|
|
18931
19385
|
return nodes.map((node) => {
|
|
18932
19386
|
let radius = DEFAULT_NODE_RADIUS;
|
|
18933
19387
|
if (sizeScale && encoding.nodeSize?.field) {
|
|
@@ -18936,6 +19390,13 @@ function resolveNodeVisuals(nodes, encoding, edges, theme, nodeOverrides) {
|
|
|
18936
19390
|
radius = sizeScale(val);
|
|
18937
19391
|
}
|
|
18938
19392
|
}
|
|
19393
|
+
let opacity = 1;
|
|
19394
|
+
if (opacityScale && encoding.nodeOpacity?.field) {
|
|
19395
|
+
const val = Number(node[encoding.nodeOpacity.field]);
|
|
19396
|
+
if (Number.isFinite(val)) {
|
|
19397
|
+
opacity = opacityScale(val);
|
|
19398
|
+
}
|
|
19399
|
+
}
|
|
18939
19400
|
const fill = colorFn ? colorFn(node) : defaultColor;
|
|
18940
19401
|
const stroke = darkenColor(fill);
|
|
18941
19402
|
let label;
|
|
@@ -18945,8 +19406,14 @@ function resolveNodeVisuals(nodes, encoding, edges, theme, nodeOverrides) {
|
|
|
18945
19406
|
} else {
|
|
18946
19407
|
label = node.id;
|
|
18947
19408
|
}
|
|
18948
|
-
|
|
18949
|
-
|
|
19409
|
+
let labelPriority;
|
|
19410
|
+
if (labelPriorityScale && encoding.nodeLabelPriority?.field) {
|
|
19411
|
+
const val = Number(node[encoding.nodeLabelPriority.field]);
|
|
19412
|
+
labelPriority = Number.isFinite(val) ? labelPriorityScale(val) : 0;
|
|
19413
|
+
} else {
|
|
19414
|
+
const degree = degrees2.get(node.id) ?? 0;
|
|
19415
|
+
labelPriority = maxDegree > 0 ? degree / maxDegree : 0;
|
|
19416
|
+
}
|
|
18950
19417
|
const { id: _id, ...rest } = node;
|
|
18951
19418
|
const data = { id: node.id, ...rest };
|
|
18952
19419
|
const override = nodeOverrides?.[node.id];
|
|
@@ -18964,6 +19431,7 @@ function resolveNodeVisuals(nodes, encoding, edges, theme, nodeOverrides) {
|
|
|
18964
19431
|
label,
|
|
18965
19432
|
labelPriority: finalLabelPriority,
|
|
18966
19433
|
community: void 0,
|
|
19434
|
+
opacity,
|
|
18967
19435
|
data
|
|
18968
19436
|
};
|
|
18969
19437
|
});
|
|
@@ -18996,7 +19464,11 @@ function resolveEdgeVisuals(edges, encoding, theme) {
|
|
|
18996
19464
|
return Number.isFinite(val) ? colorScale(val) : hexWithOpacity(theme.colors.axis, 0.4);
|
|
18997
19465
|
};
|
|
18998
19466
|
} else {
|
|
18999
|
-
const domain =
|
|
19467
|
+
const domain = resolveCategoricalDomain(
|
|
19468
|
+
edges.map((e) => String(e[field] ?? "")),
|
|
19469
|
+
encoding.edgeColor.sort,
|
|
19470
|
+
scaleConfig?.domain
|
|
19471
|
+
);
|
|
19000
19472
|
const range3 = scaleConfig?.range && scaleConfig.range.length > 0 ? scaleConfig.range : theme.colors.categorical;
|
|
19001
19473
|
const ordinalScale = ordinal().domain(domain).range(range3);
|
|
19002
19474
|
edgeColorFn = (edge) => ordinalScale(String(edge[field] ?? ""));
|
|
@@ -19007,10 +19479,14 @@ function resolveEdgeVisuals(edges, encoding, theme) {
|
|
|
19007
19479
|
let styleFn;
|
|
19008
19480
|
if (encoding.edgeStyle?.field) {
|
|
19009
19481
|
const field = encoding.edgeStyle.field;
|
|
19010
|
-
const
|
|
19482
|
+
const domain = resolveCategoricalDomain(
|
|
19483
|
+
edges.map((e) => String(e[field] ?? "")),
|
|
19484
|
+
encoding.edgeStyle.sort,
|
|
19485
|
+
encoding.edgeStyle.scale?.domain
|
|
19486
|
+
);
|
|
19011
19487
|
const styleMap = /* @__PURE__ */ new Map();
|
|
19012
|
-
for (let i = 0; i <
|
|
19013
|
-
styleMap.set(
|
|
19488
|
+
for (let i = 0; i < domain.length; i++) {
|
|
19489
|
+
styleMap.set(domain[i], EDGE_STYLES[i % EDGE_STYLES.length]);
|
|
19014
19490
|
}
|
|
19015
19491
|
styleFn = (edge) => styleMap.get(String(edge[field] ?? "")) ?? "solid";
|
|
19016
19492
|
}
|
|
@@ -19068,12 +19544,59 @@ function applyCommunityColors(nodes, colorMap) {
|
|
|
19068
19544
|
}
|
|
19069
19545
|
}
|
|
19070
19546
|
|
|
19547
|
+
// src/graphs/interaction.ts
|
|
19548
|
+
var DEFAULT_DIM_OPACITY = 0.15;
|
|
19549
|
+
var DEFAULT_CURSOR_RADIUS = 80;
|
|
19550
|
+
var DEFAULT_CURSOR_STRENGTH = 30;
|
|
19551
|
+
function resolveGraphInteraction(cfg) {
|
|
19552
|
+
const hover = cfg?.hover;
|
|
19553
|
+
const cursor = cfg?.cursorRepulsion;
|
|
19554
|
+
let cursorRepulsion = null;
|
|
19555
|
+
if (cursor === true) {
|
|
19556
|
+
cursorRepulsion = { radius: DEFAULT_CURSOR_RADIUS, strength: DEFAULT_CURSOR_STRENGTH };
|
|
19557
|
+
} else if (cursor && typeof cursor === "object") {
|
|
19558
|
+
cursorRepulsion = {
|
|
19559
|
+
radius: cursor.radius ?? DEFAULT_CURSOR_RADIUS,
|
|
19560
|
+
strength: cursor.strength ?? DEFAULT_CURSOR_STRENGTH
|
|
19561
|
+
};
|
|
19562
|
+
}
|
|
19563
|
+
return {
|
|
19564
|
+
hoverMode: hover?.mode ?? "neighbors",
|
|
19565
|
+
dimOpacity: hover?.dimOpacity ?? DEFAULT_DIM_OPACITY,
|
|
19566
|
+
selectFlyTo: cfg?.select?.flyTo ?? false,
|
|
19567
|
+
cursorRepulsion,
|
|
19568
|
+
springyDrag: cfg?.springyDrag ?? false
|
|
19569
|
+
};
|
|
19570
|
+
}
|
|
19571
|
+
|
|
19071
19572
|
// src/graphs/compile-graph.ts
|
|
19072
19573
|
var graphNumberFormatter = defaultNumberFormatter8({ allIntegers: false, surface: "chart" });
|
|
19574
|
+
function mergeOverrides(...layers) {
|
|
19575
|
+
const merged = {};
|
|
19576
|
+
for (const layer of layers) {
|
|
19577
|
+
if (!layer) continue;
|
|
19578
|
+
for (const [key, value2] of Object.entries(layer)) {
|
|
19579
|
+
if (value2 !== void 0) merged[key] = value2;
|
|
19580
|
+
}
|
|
19581
|
+
}
|
|
19582
|
+
return merged;
|
|
19583
|
+
}
|
|
19073
19584
|
var SWATCH_SIZE2 = 12;
|
|
19074
19585
|
var SWATCH_GAP2 = 6;
|
|
19075
19586
|
var ENTRY_GAP2 = 16;
|
|
19076
|
-
|
|
19587
|
+
var ENERGY_PRESETS = {
|
|
19588
|
+
gentle: { chargeStrength: -150, velocityDecay: 0.5 },
|
|
19589
|
+
balanced: { chargeStrength: -300, velocityDecay: 0.4 },
|
|
19590
|
+
energetic: { chargeStrength: -600, velocityDecay: 0.3 }
|
|
19591
|
+
};
|
|
19592
|
+
var SETTLE_PRESETS = {
|
|
19593
|
+
quick: 0.05,
|
|
19594
|
+
balanced: 0.0228,
|
|
19595
|
+
thorough: 0.01
|
|
19596
|
+
};
|
|
19597
|
+
var DEFAULT_WARMUP_TICKS = 100;
|
|
19598
|
+
var DEFAULT_WARMUP_BUDGET_MS = 250;
|
|
19599
|
+
function buildGraphLegend(nodes, communityColorMap, hasCommunities, theme, nodeColorField, legendOrder) {
|
|
19077
19600
|
const labelStyle = {
|
|
19078
19601
|
fontFamily: theme.fonts.family,
|
|
19079
19602
|
fontSize: theme.fonts.sizes.small,
|
|
@@ -19083,25 +19606,35 @@ function buildGraphLegend(nodes, communityColorMap, hasCommunities, theme, nodeC
|
|
|
19083
19606
|
};
|
|
19084
19607
|
let entries;
|
|
19085
19608
|
if (hasCommunities && communityColorMap.size > 0) {
|
|
19609
|
+
const counts = /* @__PURE__ */ new Map();
|
|
19610
|
+
for (const node of nodes) {
|
|
19611
|
+
if (node.community != null) {
|
|
19612
|
+
counts.set(node.community, (counts.get(node.community) ?? 0) + 1);
|
|
19613
|
+
}
|
|
19614
|
+
}
|
|
19086
19615
|
entries = [...communityColorMap.entries()].map(([label, color2]) => ({
|
|
19087
19616
|
label,
|
|
19088
19617
|
color: color2,
|
|
19089
19618
|
shape: "circle",
|
|
19090
|
-
active: true
|
|
19619
|
+
active: true,
|
|
19620
|
+
count: counts.get(label) ?? 0
|
|
19091
19621
|
}));
|
|
19092
19622
|
} else if (nodeColorField) {
|
|
19093
19623
|
const categoryColors = /* @__PURE__ */ new Map();
|
|
19624
|
+
const categoryCounts = /* @__PURE__ */ new Map();
|
|
19094
19625
|
for (const node of nodes) {
|
|
19095
19626
|
const category = String(node.data[nodeColorField] ?? node.label ?? node.id);
|
|
19096
19627
|
if (!categoryColors.has(category)) {
|
|
19097
19628
|
categoryColors.set(category, node.fill);
|
|
19098
19629
|
}
|
|
19630
|
+
categoryCounts.set(category, (categoryCounts.get(category) ?? 0) + 1);
|
|
19099
19631
|
}
|
|
19100
|
-
entries = categoryColors.size <= 1 ? [] : [...categoryColors.
|
|
19632
|
+
entries = categoryColors.size <= 1 ? [] : (legendOrder ?? [...categoryColors.keys()]).filter((label) => categoryColors.has(label)).map((label) => ({
|
|
19101
19633
|
label,
|
|
19102
|
-
color:
|
|
19634
|
+
color: categoryColors.get(label),
|
|
19103
19635
|
shape: "circle",
|
|
19104
|
-
active: true
|
|
19636
|
+
active: true,
|
|
19637
|
+
count: categoryCounts.get(label) ?? 0
|
|
19105
19638
|
}));
|
|
19106
19639
|
} else {
|
|
19107
19640
|
entries = [];
|
|
@@ -19117,6 +19650,30 @@ function buildGraphLegend(nodes, communityColorMap, hasCommunities, theme, nodeC
|
|
|
19117
19650
|
swatchChipFill: theme.colors.annotationFill
|
|
19118
19651
|
};
|
|
19119
19652
|
}
|
|
19653
|
+
function buildEdgeLegend(edges, encoding) {
|
|
19654
|
+
const field = encoding.edgeColor?.field;
|
|
19655
|
+
if (!field || (encoding.edgeColor?.type ?? "nominal") === "quantitative") return void 0;
|
|
19656
|
+
const categoryColors = /* @__PURE__ */ new Map();
|
|
19657
|
+
const categoryCounts = /* @__PURE__ */ new Map();
|
|
19658
|
+
for (const edge of edges) {
|
|
19659
|
+
const category = String(edge.data[field] ?? "");
|
|
19660
|
+
if (!categoryColors.has(category)) categoryColors.set(category, edge.stroke);
|
|
19661
|
+
categoryCounts.set(category, (categoryCounts.get(category) ?? 0) + 1);
|
|
19662
|
+
}
|
|
19663
|
+
if (categoryColors.size <= 1) return void 0;
|
|
19664
|
+
const order = resolveCategoricalDomain(
|
|
19665
|
+
edges.map((e) => String(e.data[field] ?? "")),
|
|
19666
|
+
encoding.edgeColor?.sort,
|
|
19667
|
+
encoding.edgeColor?.scale?.domain
|
|
19668
|
+
);
|
|
19669
|
+
return order.filter((label) => categoryColors.has(label)).map((label) => ({
|
|
19670
|
+
label,
|
|
19671
|
+
color: categoryColors.get(label),
|
|
19672
|
+
shape: "line",
|
|
19673
|
+
active: true,
|
|
19674
|
+
count: categoryCounts.get(label) ?? 0
|
|
19675
|
+
}));
|
|
19676
|
+
}
|
|
19120
19677
|
function buildGraphTooltips(nodes) {
|
|
19121
19678
|
const descriptors = /* @__PURE__ */ new Map();
|
|
19122
19679
|
for (const node of nodes) {
|
|
@@ -19143,6 +19700,21 @@ function buildGraphTooltips(nodes) {
|
|
|
19143
19700
|
}
|
|
19144
19701
|
return descriptors;
|
|
19145
19702
|
}
|
|
19703
|
+
function buildEdgeTooltip(edge) {
|
|
19704
|
+
const fields = [];
|
|
19705
|
+
for (const [key, value2] of Object.entries(edge.data)) {
|
|
19706
|
+
if (key === "source" || key === "target") continue;
|
|
19707
|
+
if (value2 == null) continue;
|
|
19708
|
+
fields.push({
|
|
19709
|
+
label: key,
|
|
19710
|
+
value: typeof value2 === "number" ? graphNumberFormatter(value2) : String(value2)
|
|
19711
|
+
});
|
|
19712
|
+
}
|
|
19713
|
+
return {
|
|
19714
|
+
title: `${edge.source} \u2192 ${edge.target}`,
|
|
19715
|
+
fields
|
|
19716
|
+
};
|
|
19717
|
+
}
|
|
19146
19718
|
function compileGraph(spec, options) {
|
|
19147
19719
|
const { spec: normalized, warnings } = compile(spec);
|
|
19148
19720
|
emitSpecWarnings(warnings, options.onWarn);
|
|
@@ -19152,6 +19724,16 @@ function compileGraph(spec, options) {
|
|
|
19152
19724
|
);
|
|
19153
19725
|
}
|
|
19154
19726
|
const graphSpec = normalized;
|
|
19727
|
+
for (const [name, ch] of [
|
|
19728
|
+
["nodeColor", graphSpec.encoding.nodeColor],
|
|
19729
|
+
["edgeColor", graphSpec.encoding.edgeColor]
|
|
19730
|
+
]) {
|
|
19731
|
+
if (ch?.sort != null && ch.type === "quantitative") {
|
|
19732
|
+
options.onWarn?.(
|
|
19733
|
+
`encoding.${name}.sort is ignored for a quantitative field (sort only orders categorical domains).`
|
|
19734
|
+
);
|
|
19735
|
+
}
|
|
19736
|
+
}
|
|
19155
19737
|
const rawWatermark = spec.watermark;
|
|
19156
19738
|
const watermark = rawWatermark !== void 0 ? graphSpec.watermark : options.watermark ?? true;
|
|
19157
19739
|
const mergedThemeConfig = options.theme ? { ...graphSpec.theme, ...options.theme } : graphSpec.theme;
|
|
@@ -19159,12 +19741,23 @@ function compileGraph(spec, options) {
|
|
|
19159
19741
|
if (options.darkMode) {
|
|
19160
19742
|
theme = adaptTheme3(theme);
|
|
19161
19743
|
}
|
|
19744
|
+
const seedNodeIds = graphSpec.seedNode ? [graphSpec.seedNode.id] : [];
|
|
19745
|
+
const nodeOverrides = graphSpec.seedNode ? {
|
|
19746
|
+
...graphSpec.nodeOverrides,
|
|
19747
|
+
[graphSpec.seedNode.id]: mergeOverrides(
|
|
19748
|
+
// Radius is deliberately absent so the seed doesn't fight a nodeSize
|
|
19749
|
+
// encoding; a host wanting a bigger seed sets seedNode.style.radius.
|
|
19750
|
+
{ stroke: theme.colors.text, strokeWidth: 2, alwaysShowLabel: true },
|
|
19751
|
+
graphSpec.seedNode.style,
|
|
19752
|
+
graphSpec.nodeOverrides?.[graphSpec.seedNode.id]
|
|
19753
|
+
)
|
|
19754
|
+
} : graphSpec.nodeOverrides;
|
|
19162
19755
|
const compiledNodes = resolveNodeVisuals(
|
|
19163
19756
|
graphSpec.nodes,
|
|
19164
19757
|
graphSpec.encoding,
|
|
19165
19758
|
graphSpec.edges,
|
|
19166
19759
|
theme,
|
|
19167
|
-
|
|
19760
|
+
nodeOverrides
|
|
19168
19761
|
);
|
|
19169
19762
|
const clusteringField = graphSpec.layout.clustering?.field;
|
|
19170
19763
|
const hasCommunities = !!clusteringField;
|
|
@@ -19177,13 +19770,30 @@ function compileGraph(spec, options) {
|
|
|
19177
19770
|
}
|
|
19178
19771
|
const compiledEdges = resolveEdgeVisuals(graphSpec.edges, graphSpec.encoding, theme);
|
|
19179
19772
|
const useCommunitiesForLegend = hasCommunities && !hasNodeColorEncoding;
|
|
19773
|
+
const nodeColorField = graphSpec.encoding.nodeColor?.field;
|
|
19774
|
+
const legendOrder = nodeColorField ? resolveCategoricalDomain(
|
|
19775
|
+
compiledNodes.map((n) => String(n.data[nodeColorField] ?? n.label ?? n.id)),
|
|
19776
|
+
graphSpec.encoding.nodeColor?.sort,
|
|
19777
|
+
graphSpec.encoding.nodeColor?.scale?.domain
|
|
19778
|
+
) : void 0;
|
|
19180
19779
|
const legend = buildGraphLegend(
|
|
19181
19780
|
compiledNodes,
|
|
19182
19781
|
communityColorMap,
|
|
19183
19782
|
useCommunitiesForLegend,
|
|
19184
19783
|
theme,
|
|
19185
|
-
|
|
19784
|
+
nodeColorField,
|
|
19785
|
+
legendOrder
|
|
19186
19786
|
);
|
|
19787
|
+
const edgeLegend = buildEdgeLegend(compiledEdges, graphSpec.encoding);
|
|
19788
|
+
const legendField = nodeColorField ?? (useCommunitiesForLegend ? clusteringField ?? null : null);
|
|
19789
|
+
let initialHighlight;
|
|
19790
|
+
if (nodeColorField && graphSpec.encoding.nodeColor?.highlight != null) {
|
|
19791
|
+
const raw = graphSpec.encoding.nodeColor.highlight;
|
|
19792
|
+
const requested = Array.isArray(raw) ? raw : [raw];
|
|
19793
|
+
const available = new Set(legendOrder ?? []);
|
|
19794
|
+
const values = requested.filter((v) => available.has(v));
|
|
19795
|
+
if (values.length > 0) initialHighlight = { field: nodeColorField, values };
|
|
19796
|
+
}
|
|
19187
19797
|
const tooltipDescriptors = buildGraphTooltips(compiledNodes);
|
|
19188
19798
|
const communityCount = communityColorMap.size;
|
|
19189
19799
|
const altParts = [
|
|
@@ -19200,17 +19810,26 @@ function compileGraph(spec, options) {
|
|
|
19200
19810
|
};
|
|
19201
19811
|
const collisionPadding = graphSpec.layout.collisionPadding ?? 2;
|
|
19202
19812
|
const maxRadius = compiledNodes.length > 0 ? Math.max(...compiledNodes.map((n) => n.radius)) : DEFAULT_COLLISION_PADDING;
|
|
19813
|
+
const energyPreset = graphSpec.layout.energy ? ENERGY_PRESETS[graphSpec.layout.energy] : ENERGY_PRESETS.balanced;
|
|
19814
|
+
const settlePreset = graphSpec.layout.settle ? SETTLE_PRESETS[graphSpec.layout.settle] : SETTLE_PRESETS.balanced;
|
|
19815
|
+
const warmupRaw = graphSpec.layout.warmup;
|
|
19816
|
+
const warmupTicks = warmupRaw === false ? 0 : typeof warmupRaw === "number" ? Math.max(0, Math.floor(warmupRaw)) : DEFAULT_WARMUP_TICKS;
|
|
19203
19817
|
const simulationConfig = {
|
|
19204
|
-
chargeStrength: graphSpec.layout.chargeStrength ??
|
|
19818
|
+
chargeStrength: graphSpec.layout.chargeStrength ?? energyPreset.chargeStrength,
|
|
19205
19819
|
linkDistance: graphSpec.layout.linkDistance ?? 30,
|
|
19206
19820
|
clustering: clusteringField ? { field: clusteringField, strength: 0.5 } : null,
|
|
19207
|
-
alphaDecay:
|
|
19208
|
-
velocityDecay:
|
|
19821
|
+
alphaDecay: settlePreset,
|
|
19822
|
+
velocityDecay: energyPreset.velocityDecay,
|
|
19209
19823
|
collisionRadius: maxRadius + collisionPadding,
|
|
19210
19824
|
collisionPadding,
|
|
19211
19825
|
linkStrength: graphSpec.layout.linkStrength,
|
|
19212
|
-
centerForce: graphSpec.layout.centerForce
|
|
19826
|
+
centerForce: graphSpec.layout.centerForce,
|
|
19827
|
+
seed: graphSpec.layout.seed,
|
|
19828
|
+
warmupTicks,
|
|
19829
|
+
warmupBudgetMs: DEFAULT_WARMUP_BUDGET_MS
|
|
19213
19830
|
};
|
|
19831
|
+
const animation = resolveGraphAnimation(graphSpec.animation);
|
|
19832
|
+
const interaction = resolveGraphInteraction(graphSpec.interaction);
|
|
19214
19833
|
const chrome = computeChrome4(
|
|
19215
19834
|
{
|
|
19216
19835
|
title: graphSpec.chrome.title,
|
|
@@ -19239,7 +19858,13 @@ function compileGraph(spec, options) {
|
|
|
19239
19858
|
height: options.height
|
|
19240
19859
|
},
|
|
19241
19860
|
simulationConfig,
|
|
19242
|
-
watermark
|
|
19861
|
+
watermark,
|
|
19862
|
+
animation,
|
|
19863
|
+
interaction,
|
|
19864
|
+
legendField,
|
|
19865
|
+
initialHighlight,
|
|
19866
|
+
seedNodeIds,
|
|
19867
|
+
edgeLegend
|
|
19243
19868
|
};
|
|
19244
19869
|
}
|
|
19245
19870
|
var DEFAULT_COLLISION_PADDING = 5;
|
|
@@ -19332,6 +19957,7 @@ function legendLayoutHasContent(legendLayout) {
|
|
|
19332
19957
|
}
|
|
19333
19958
|
var MIN_CHART_WIDTH = 60;
|
|
19334
19959
|
var MIN_CHART_HEIGHT2 = 40;
|
|
19960
|
+
var PLOT_SHARE_MAX = 0.4;
|
|
19335
19961
|
var SERIES_SEARCH_INPUT_HEIGHT = 32;
|
|
19336
19962
|
var SERIES_SEARCH_GAP = 12;
|
|
19337
19963
|
function getMinChartDims(display) {
|
|
@@ -19374,8 +20000,10 @@ function computeDimensions(spec, options, legendLayout, theme, strategy, waterma
|
|
|
19374
20000
|
watermark,
|
|
19375
20001
|
bottomLegendReservation
|
|
19376
20002
|
);
|
|
20003
|
+
const chromeLayout = resolveChromeLayout(spec, options);
|
|
20004
|
+
const effectiveHeight = chromeLayout === "grow" ? height + chrome.topHeight + chrome.bottomHeight : height;
|
|
19377
20005
|
if (isSparkline) {
|
|
19378
|
-
const total2 = { x: 0, y: 0, width, height };
|
|
20006
|
+
const total2 = { x: 0, y: 0, width, height: effectiveHeight };
|
|
19379
20007
|
const sparkPad = getSparklinePad(spec);
|
|
19380
20008
|
const xAxisSpace = userExplicit.xAxis ? 26 : 0;
|
|
19381
20009
|
const yAxisSpace = userExplicit.yAxis ? 30 : 0;
|
|
@@ -19399,7 +20027,7 @@ function computeDimensions(spec, options, legendLayout, theme, strategy, waterma
|
|
|
19399
20027
|
x: margins2.left,
|
|
19400
20028
|
y: margins2.top,
|
|
19401
20029
|
width: Math.max(0, width - margins2.left - margins2.right),
|
|
19402
|
-
height: Math.max(0,
|
|
20030
|
+
height: Math.max(0, effectiveHeight - margins2.top - margins2.bottom)
|
|
19403
20031
|
};
|
|
19404
20032
|
return {
|
|
19405
20033
|
total: total2,
|
|
@@ -19411,7 +20039,7 @@ function computeDimensions(spec, options, legendLayout, theme, strategy, waterma
|
|
|
19411
20039
|
effectiveAxisGap: 0
|
|
19412
20040
|
};
|
|
19413
20041
|
}
|
|
19414
|
-
const total = { x: 0, y: 0, width, height };
|
|
20042
|
+
const total = { x: 0, y: 0, width, height: effectiveHeight };
|
|
19415
20043
|
const isRadial = isAxislessMark2(spec.markType);
|
|
19416
20044
|
const encoding = spec.encoding;
|
|
19417
20045
|
const xAxisSuppressed = encoding.x?.axis === false;
|
|
@@ -19641,10 +20269,11 @@ function computeDimensions(spec, options, legendLayout, theme, strategy, waterma
|
|
|
19641
20269
|
x: margins.left,
|
|
19642
20270
|
y: margins.top,
|
|
19643
20271
|
width: Math.max(0, width - margins.left - margins.right),
|
|
19644
|
-
height: Math.max(0,
|
|
20272
|
+
height: Math.max(0, effectiveHeight - margins.top - margins.bottom)
|
|
19645
20273
|
};
|
|
19646
20274
|
const minDims = getMinChartDims(spec.display);
|
|
19647
|
-
|
|
20275
|
+
const chromeEatsPlot = chromeLayout !== "grow" && chrome.topHeight > height * PLOT_SHARE_MAX;
|
|
20276
|
+
if ((chartArea.width < minDims.width || chartArea.height < minDims.height || chromeEatsPlot) && chromeMode !== "hidden") {
|
|
19648
20277
|
const fallbackMode = chromeMode === "full" ? "compact" : "hidden";
|
|
19649
20278
|
const fallbackChrome = computeChrome5(
|
|
19650
20279
|
chromeToInput(spec.chrome),
|
|
@@ -19670,7 +20299,7 @@ function computeDimensions(spec, options, legendLayout, theme, strategy, waterma
|
|
|
19670
20299
|
x: margins.left,
|
|
19671
20300
|
y: margins.top,
|
|
19672
20301
|
width: Math.max(0, width - margins.left - margins.right),
|
|
19673
|
-
height: Math.max(0,
|
|
20302
|
+
height: Math.max(0, effectiveHeight - margins.top - margins.bottom)
|
|
19674
20303
|
};
|
|
19675
20304
|
const fallbackMetricsTopY = topPad + fallbackChrome.topHeight;
|
|
19676
20305
|
const fallbackMetricsArea = { x: hPad, width: Math.max(0, width - hPad * 2) };
|
|
@@ -19687,7 +20316,7 @@ function computeDimensions(spec, options, legendLayout, theme, strategy, waterma
|
|
|
19687
20316
|
chartArea = {
|
|
19688
20317
|
...chartArea,
|
|
19689
20318
|
y: margins.top,
|
|
19690
|
-
height: Math.max(0,
|
|
20319
|
+
height: Math.max(0, effectiveHeight - margins.top - margins.bottom)
|
|
19691
20320
|
};
|
|
19692
20321
|
}
|
|
19693
20322
|
return {
|
|
@@ -19703,7 +20332,8 @@ function computeDimensions(spec, options, legendLayout, theme, strategy, waterma
|
|
|
19703
20332
|
fallbackMetricsArea
|
|
19704
20333
|
) : void 0,
|
|
19705
20334
|
xAxisHeight,
|
|
19706
|
-
effectiveAxisGap: fallbackEffectiveAxisGap
|
|
20335
|
+
effectiveAxisGap: fallbackEffectiveAxisGap,
|
|
20336
|
+
chromeStripped: true
|
|
19707
20337
|
};
|
|
19708
20338
|
}
|
|
19709
20339
|
}
|
|
@@ -19715,7 +20345,7 @@ function computeDimensions(spec, options, legendLayout, theme, strategy, waterma
|
|
|
19715
20345
|
chartArea = {
|
|
19716
20346
|
...chartArea,
|
|
19717
20347
|
y: margins.top,
|
|
19718
|
-
height: Math.max(0,
|
|
20348
|
+
height: Math.max(0, effectiveHeight - margins.top - margins.bottom)
|
|
19719
20349
|
};
|
|
19720
20350
|
}
|
|
19721
20351
|
return {
|
|
@@ -20467,14 +21097,19 @@ function compileSankey(spec, options) {
|
|
|
20467
21097
|
watermark
|
|
20468
21098
|
);
|
|
20469
21099
|
const padding = theme.spacing.padding;
|
|
21100
|
+
const chromeLayout = resolveChromeLayout(
|
|
21101
|
+
spec,
|
|
21102
|
+
options
|
|
21103
|
+
);
|
|
21104
|
+
const grownHeight = chromeLayout === "grow" ? options.height + chrome.topHeight + chrome.bottomHeight : options.height;
|
|
20470
21105
|
const fullArea = {
|
|
20471
21106
|
x: padding,
|
|
20472
21107
|
y: padding + chrome.topHeight,
|
|
20473
21108
|
width: options.width - padding * 2,
|
|
20474
|
-
height: options.height - chrome.topHeight - chrome.bottomHeight - padding * 2
|
|
21109
|
+
height: chromeLayout === "grow" ? options.height - padding * 2 : options.height - chrome.topHeight - chrome.bottomHeight - padding * 2
|
|
20475
21110
|
};
|
|
20476
21111
|
if (fullArea.width <= 0 || fullArea.height <= 0) {
|
|
20477
|
-
return emptyLayout4(fullArea, chrome, theme, options, watermark);
|
|
21112
|
+
return emptyLayout4(fullArea, chrome, theme, { ...options, height: grownHeight }, watermark);
|
|
20478
21113
|
}
|
|
20479
21114
|
const sourceField = sankeySpec.encoding.source.field;
|
|
20480
21115
|
const targetField = sankeySpec.encoding.target.field;
|
|
@@ -20514,7 +21149,7 @@ function compileSankey(spec, options) {
|
|
|
20514
21149
|
height: fullArea.height - legend.bounds.height - legendGap2
|
|
20515
21150
|
};
|
|
20516
21151
|
if (area.height <= 0) {
|
|
20517
|
-
return emptyLayout4(area, chrome, theme, options, watermark);
|
|
21152
|
+
return emptyLayout4(area, chrome, theme, { ...options, height: grownHeight }, watermark);
|
|
20518
21153
|
}
|
|
20519
21154
|
const labelFontSize = theme.fonts.sizes.small;
|
|
20520
21155
|
const labelFontWeight = theme.fonts.weights.normal;
|
|
@@ -20666,7 +21301,7 @@ function compileSankey(spec, options) {
|
|
|
20666
21301
|
theme,
|
|
20667
21302
|
dimensions: {
|
|
20668
21303
|
width: options.width,
|
|
20669
|
-
height:
|
|
21304
|
+
height: grownHeight
|
|
20670
21305
|
},
|
|
20671
21306
|
animation: resolvedAnimation,
|
|
20672
21307
|
watermark,
|
|
@@ -21485,6 +22120,10 @@ var LEGEND_ENTRY_GAP = 16;
|
|
|
21485
22120
|
function clamp(value2, min4, max4) {
|
|
21486
22121
|
return Math.min(max4, Math.max(min4, value2));
|
|
21487
22122
|
}
|
|
22123
|
+
function growContentHeight(contentHeight, chromeLayout, budgetHeight, chrome) {
|
|
22124
|
+
if (chromeLayout !== "grow") return contentHeight;
|
|
22125
|
+
return Math.max(contentHeight, budgetHeight + chrome.topHeight + chrome.bottomHeight);
|
|
22126
|
+
}
|
|
21488
22127
|
function compileTileMap(spec, options) {
|
|
21489
22128
|
const sugarWarnings = [];
|
|
21490
22129
|
const expandedSpec = spec && typeof spec === "object" && !Array.isArray(spec) ? expandSpecSugar(spec, sugarWarnings) : spec;
|
|
@@ -21521,22 +22160,44 @@ function compileTileMap(spec, options) {
|
|
|
21521
22160
|
watermark
|
|
21522
22161
|
);
|
|
21523
22162
|
const padding = getBreakpoint2(options.width) === "compact" ? Math.max(HPAD_COMPACT_MIN4, Math.round(theme.spacing.padding * HPAD_COMPACT_FRACTION4)) : theme.spacing.padding;
|
|
22163
|
+
const chromeLayout = resolveChromeLayout(
|
|
22164
|
+
spec,
|
|
22165
|
+
options
|
|
22166
|
+
);
|
|
21524
22167
|
const fullArea = {
|
|
21525
22168
|
x: padding,
|
|
21526
22169
|
y: padding + chrome.topHeight,
|
|
21527
22170
|
width: options.width - padding * 2,
|
|
21528
|
-
height: options.height - chrome.topHeight - chrome.bottomHeight - padding * 2
|
|
22171
|
+
height: chromeLayout === "grow" ? options.height - padding * 2 : options.height - chrome.topHeight - chrome.bottomHeight - padding * 2
|
|
21529
22172
|
};
|
|
21530
22173
|
if (fullArea.width <= 0 || fullArea.height <= 0) {
|
|
21531
22174
|
return emptyLayout5(chrome, theme, options, watermark);
|
|
21532
22175
|
}
|
|
21533
22176
|
const isCategorical = tilemapSpec.encoding.color !== void 0 || tilemapSpec.colors !== void 0;
|
|
21534
22177
|
if (isCategorical) {
|
|
21535
|
-
return compileCategorical(
|
|
22178
|
+
return compileCategorical(
|
|
22179
|
+
tilemapSpec,
|
|
22180
|
+
options,
|
|
22181
|
+
theme,
|
|
22182
|
+
chrome,
|
|
22183
|
+
fullArea,
|
|
22184
|
+
isDarkMode,
|
|
22185
|
+
watermark,
|
|
22186
|
+
chromeLayout
|
|
22187
|
+
);
|
|
21536
22188
|
}
|
|
21537
|
-
return compileQuantitative(
|
|
22189
|
+
return compileQuantitative(
|
|
22190
|
+
tilemapSpec,
|
|
22191
|
+
options,
|
|
22192
|
+
theme,
|
|
22193
|
+
chrome,
|
|
22194
|
+
fullArea,
|
|
22195
|
+
isDarkMode,
|
|
22196
|
+
watermark,
|
|
22197
|
+
chromeLayout
|
|
22198
|
+
);
|
|
21538
22199
|
}
|
|
21539
|
-
function compileQuantitative(tilemapSpec, options, theme, chrome, fullArea, isDarkMode, watermark) {
|
|
22200
|
+
function compileQuantitative(tilemapSpec, options, theme, chrome, fullArea, isDarkMode, watermark, chromeLayout) {
|
|
21540
22201
|
const stateField = tilemapSpec.encoding.state.field;
|
|
21541
22202
|
const valueField = tilemapSpec.encoding.value.field;
|
|
21542
22203
|
const stateValueMap = /* @__PURE__ */ new Map();
|
|
@@ -21637,7 +22298,12 @@ function compileQuantitative(tilemapSpec, options, theme, chrome, fullArea, isDa
|
|
|
21637
22298
|
};
|
|
21638
22299
|
const resolvedAnimation = resolveAnimation(tilemapSpec.animation);
|
|
21639
22300
|
const padding = fullArea.x;
|
|
21640
|
-
const contentHeight =
|
|
22301
|
+
const contentHeight = growContentHeight(
|
|
22302
|
+
tileGridOffsetY + tilePositions.gridHeight + legendGap2 + legendTotalHeight + chrome.bottomHeight + padding,
|
|
22303
|
+
chromeLayout,
|
|
22304
|
+
options.height,
|
|
22305
|
+
chrome
|
|
22306
|
+
);
|
|
21641
22307
|
return {
|
|
21642
22308
|
area: fullArea,
|
|
21643
22309
|
chrome,
|
|
@@ -21654,7 +22320,7 @@ function compileQuantitative(tilemapSpec, options, theme, chrome, fullArea, isDa
|
|
|
21654
22320
|
measureText: options.measureText ?? ((text, fontSize) => ({ width: estimateTextWidth23(text, fontSize), height: fontSize }))
|
|
21655
22321
|
};
|
|
21656
22322
|
}
|
|
21657
|
-
function compileCategorical(tilemapSpec, options, theme, chrome, fullArea, isDarkMode, watermark) {
|
|
22323
|
+
function compileCategorical(tilemapSpec, options, theme, chrome, fullArea, isDarkMode, watermark, chromeLayout) {
|
|
21658
22324
|
const stateField = tilemapSpec.encoding.state.field;
|
|
21659
22325
|
const colorField = tilemapSpec.encoding.color?.field ?? tilemapSpec.encoding.value.field;
|
|
21660
22326
|
const stateCategoryMap = /* @__PURE__ */ new Map();
|
|
@@ -21773,7 +22439,12 @@ function compileCategorical(tilemapSpec, options, theme, chrome, fullArea, isDar
|
|
|
21773
22439
|
};
|
|
21774
22440
|
const resolvedAnimation = resolveAnimation(tilemapSpec.animation);
|
|
21775
22441
|
const padding = fullArea.x;
|
|
21776
|
-
const contentHeight =
|
|
22442
|
+
const contentHeight = growContentHeight(
|
|
22443
|
+
tileGridOffsetY + tilePositions.gridHeight + legendGap2 + legendTotalHeight + chrome.bottomHeight + padding,
|
|
22444
|
+
chromeLayout,
|
|
22445
|
+
options.height,
|
|
22446
|
+
chrome
|
|
22447
|
+
);
|
|
21777
22448
|
return {
|
|
21778
22449
|
area: fullArea,
|
|
21779
22450
|
chrome,
|
|
@@ -22881,7 +23552,7 @@ function compileChart(spec, optionsInput) {
|
|
|
22881
23552
|
throw new Error("compileChart received a sankey spec. Use compileSankey instead.");
|
|
22882
23553
|
}
|
|
22883
23554
|
if ("type" in normalized && normalized.type === "map") {
|
|
22884
|
-
throw new Error("compileChart received a map spec. Use
|
|
23555
|
+
throw new Error("compileChart received a map spec. Use compileGeoMap instead.");
|
|
22885
23556
|
}
|
|
22886
23557
|
let chartSpec = normalized;
|
|
22887
23558
|
const rawWatermark = expandedSpec.watermark;
|
|
@@ -23034,6 +23705,10 @@ function compileChart(spec, optionsInput) {
|
|
|
23034
23705
|
watermark = false;
|
|
23035
23706
|
chartSpec = { ...chartSpec, watermark: false };
|
|
23036
23707
|
}
|
|
23708
|
+
if (heightClass === "cramped" && !chartSpec.userExplicit.watermark) {
|
|
23709
|
+
watermark = false;
|
|
23710
|
+
chartSpec = { ...chartSpec, watermark: false };
|
|
23711
|
+
}
|
|
23037
23712
|
const mergedThemeConfig = options.theme ? { ...chartSpec.theme, ...options.theme } : chartSpec.theme;
|
|
23038
23713
|
let theme = resolveTheme7(mergedThemeConfig);
|
|
23039
23714
|
if (options.darkMode) {
|
|
@@ -23065,12 +23740,35 @@ function compileChart(spec, optionsInput) {
|
|
|
23065
23740
|
}
|
|
23066
23741
|
};
|
|
23067
23742
|
}
|
|
23743
|
+
let facetDirection = "wrap";
|
|
23744
|
+
const rowChannel = renderSpec.encoding.row;
|
|
23745
|
+
const colChannel = renderSpec.encoding.column;
|
|
23746
|
+
if (rowChannel?.field || colChannel?.field) {
|
|
23747
|
+
const channel = rowChannel?.field ? rowChannel : colChannel;
|
|
23748
|
+
facetDirection = rowChannel?.field ? "row" : "column";
|
|
23749
|
+
const desugared = { ...renderSpec.encoding };
|
|
23750
|
+
delete desugared.row;
|
|
23751
|
+
delete desugared.column;
|
|
23752
|
+
desugared.facet = {
|
|
23753
|
+
field: channel.field,
|
|
23754
|
+
type: channel.type,
|
|
23755
|
+
sort: channel.sort,
|
|
23756
|
+
...facetDirection === "row" ? { columns: 1 } : {}
|
|
23757
|
+
};
|
|
23758
|
+
renderSpec = { ...renderSpec, encoding: desugared };
|
|
23759
|
+
const chartDesugared = { ...chartSpec.encoding };
|
|
23760
|
+
delete chartDesugared.row;
|
|
23761
|
+
delete chartDesugared.column;
|
|
23762
|
+
chartDesugared.facet = desugared.facet;
|
|
23763
|
+
chartSpec = { ...chartSpec, encoding: chartDesugared };
|
|
23764
|
+
}
|
|
23068
23765
|
const facetChannel = renderSpec.encoding.facet;
|
|
23069
23766
|
if (facetChannel?.field) {
|
|
23070
23767
|
return compileFaceted(
|
|
23071
23768
|
chartSpec,
|
|
23072
23769
|
renderSpec,
|
|
23073
23770
|
facetChannel,
|
|
23771
|
+
facetDirection,
|
|
23074
23772
|
options,
|
|
23075
23773
|
theme,
|
|
23076
23774
|
strategy,
|
|
@@ -23135,7 +23833,10 @@ function compileChart(spec, optionsInput) {
|
|
|
23135
23833
|
skipY,
|
|
23136
23834
|
markType: chartSpec.markType,
|
|
23137
23835
|
totalWidth: options.width,
|
|
23138
|
-
|
|
23836
|
+
// If the guardrail stripped chrome, the plan's y-ticks were sized
|
|
23837
|
+
// against the pre-strip (shorter) plot. Drop them so computeAxes
|
|
23838
|
+
// regenerates against the final (taller) chartArea.
|
|
23839
|
+
precomputedYTicks: !dims.chromeStripped && plan.yTickValues.length > 0 ? plan.yTickValues : void 0
|
|
23139
23840
|
});
|
|
23140
23841
|
const xAxisExtent = axes.x?.extent ?? 0;
|
|
23141
23842
|
dims.chrome.bottomAnchorY = chartArea.y + chartArea.height + xAxisExtent;
|
|
@@ -23150,6 +23851,19 @@ function compileChart(spec, optionsInput) {
|
|
|
23150
23851
|
const renderer = getChartRenderer(rendererKey);
|
|
23151
23852
|
const marks = renderer ? renderer(renderSpec, scales, chartArea, strategy, theme, options.width) : [];
|
|
23152
23853
|
applyFillPatterns(marks, chartSpec.markDef, theme);
|
|
23854
|
+
const markRenderModeWarnings = [];
|
|
23855
|
+
const markRenderMode = resolveMarkRenderMode(
|
|
23856
|
+
{
|
|
23857
|
+
requested: options.renderer,
|
|
23858
|
+
markType: chartSpec.markType,
|
|
23859
|
+
pointCount: marks.reduce((n, m) => m.type === "point" ? n + 1 : n, 0),
|
|
23860
|
+
display: chartSpec.display,
|
|
23861
|
+
faceted: false,
|
|
23862
|
+
layered: options.layered ?? false
|
|
23863
|
+
},
|
|
23864
|
+
markRenderModeWarnings
|
|
23865
|
+
);
|
|
23866
|
+
emitSpecWarnings(markRenderModeWarnings, options.onWarn);
|
|
23153
23867
|
const xFieldForYdi = chartSpec.encoding.x && "field" in chartSpec.encoding.x ? chartSpec.encoding.x.field : void 0;
|
|
23154
23868
|
const youDrawIt = resolveYouDrawIt(chartSpec.youDrawIt, marks, scales, chartArea, xFieldForYdi);
|
|
23155
23869
|
const endpointLabels = computeEndpointLabels(
|
|
@@ -23251,6 +23965,7 @@ function compileChart(spec, optionsInput) {
|
|
|
23251
23965
|
a11y: {
|
|
23252
23966
|
altText,
|
|
23253
23967
|
dataTableFallback,
|
|
23968
|
+
...chartSpec.data.length > MAX_SR_TABLE_ROWS ? { totalRows: chartSpec.data.length } : {},
|
|
23254
23969
|
role: "img",
|
|
23255
23970
|
keyboardNavigable: marks.length > 0,
|
|
23256
23971
|
...chartSpec.a11y?.hidden ? { hidden: true } : {}
|
|
@@ -23258,7 +23973,10 @@ function compileChart(spec, optionsInput) {
|
|
|
23258
23973
|
theme,
|
|
23259
23974
|
dimensions: {
|
|
23260
23975
|
width: options.width,
|
|
23261
|
-
|
|
23976
|
+
// In chromeLayout 'grow' mode, computeDimensions grows total.height by the
|
|
23977
|
+
// chrome height so the plot keeps its full budget. In the default
|
|
23978
|
+
// 'subtract' mode total.height === options.height, so this is a no-op.
|
|
23979
|
+
height: dims.total.height
|
|
23262
23980
|
},
|
|
23263
23981
|
animation: resolvedAnimation,
|
|
23264
23982
|
watermark,
|
|
@@ -23266,10 +23984,11 @@ function compileChart(spec, optionsInput) {
|
|
|
23266
23984
|
crosshair,
|
|
23267
23985
|
measureText: options.measureText,
|
|
23268
23986
|
...xInvert ? { xInvert } : {},
|
|
23269
|
-
...yInvert ? { yInvert } : {}
|
|
23987
|
+
...yInvert ? { yInvert } : {},
|
|
23988
|
+
...markRenderMode === "canvas" ? { markRenderMode } : {}
|
|
23270
23989
|
};
|
|
23271
23990
|
}
|
|
23272
|
-
function compileFaceted(chartSpec, renderSpec, facetChannel, options, theme, strategy, watermark, resolvedAnimation, crosshair, rawSpec, optionsInput) {
|
|
23991
|
+
function compileFaceted(chartSpec, renderSpec, facetChannel, facetDirection, options, theme, strategy, watermark, resolvedAnimation, crosshair, rawSpec, optionsInput) {
|
|
23273
23992
|
const measure = createMeasureFn(options.measureText);
|
|
23274
23993
|
const panelEncoding = { ...renderSpec.encoding };
|
|
23275
23994
|
delete panelEncoding.facet;
|
|
@@ -23315,10 +24034,10 @@ function compileFaceted(chartSpec, renderSpec, facetChannel, options, theme, str
|
|
|
23315
24034
|
plan.xAxisExtent,
|
|
23316
24035
|
dims.effectiveAxisGap
|
|
23317
24036
|
);
|
|
23318
|
-
const leftReservation = plan.leftGutter;
|
|
23319
24037
|
const bottomReservation = plan.xAxisExtent;
|
|
23320
|
-
const
|
|
23321
|
-
|
|
24038
|
+
const effectiveColumns = facetDirection === "column" ? facetValues.length : facetChannel.columns;
|
|
24039
|
+
const grid = computeFacetGrid(facetValues, effectiveColumns, chartArea, {
|
|
24040
|
+
left: 0,
|
|
23322
24041
|
bottom: bottomReservation
|
|
23323
24042
|
});
|
|
23324
24043
|
if (!optionsInput.facetHeightGrown && grid.panels.length > 0 && grid.panels[0].area.height < MIN_PANEL_HEIGHT) {
|
|
@@ -23333,8 +24052,10 @@ function compileFaceted(chartSpec, renderSpec, facetChannel, options, theme, str
|
|
|
23333
24052
|
}
|
|
23334
24053
|
}
|
|
23335
24054
|
const resolveConfig = chartSpec.resolve;
|
|
23336
|
-
const
|
|
23337
|
-
const
|
|
24055
|
+
const xDefault = facetDirection === "column" ? "independent" : "shared";
|
|
24056
|
+
const yDefault = facetDirection === "row" ? "independent" : "shared";
|
|
24057
|
+
const yResolve = resolveConfig?.scale?.y ?? yDefault;
|
|
24058
|
+
const xResolve = resolveConfig?.scale?.x ?? xDefault;
|
|
23338
24059
|
const fullScales = computeScales(panelSpec, chartArea, renderSpec.data);
|
|
23339
24060
|
const sharedXDomain = xResolve === "shared" && fullScales.x ? fullScales.x.scale.domain() : void 0;
|
|
23340
24061
|
const sharedYDomain = yResolve === "shared" && fullScales.y ? fullScales.y.scale.domain() : void 0;
|
|
@@ -23399,6 +24120,16 @@ function compileFaceted(chartSpec, renderSpec, facetChannel, options, theme, str
|
|
|
23399
24120
|
tickMarks: false
|
|
23400
24121
|
};
|
|
23401
24122
|
}
|
|
24123
|
+
const isBottomRow = gridPanel.row === grid.rows - 1;
|
|
24124
|
+
if (xResolve === "shared" && facetDirection === "row" && !isBottomRow && panelAxes.x) {
|
|
24125
|
+
panelAxes.x = {
|
|
24126
|
+
...panelAxes.x,
|
|
24127
|
+
ticks: [],
|
|
24128
|
+
label: void 0,
|
|
24129
|
+
domainLine: false,
|
|
24130
|
+
tickMarks: false
|
|
24131
|
+
};
|
|
24132
|
+
}
|
|
23402
24133
|
const panelMarks = renderer ? renderer(
|
|
23403
24134
|
panelSpecWithDomains,
|
|
23404
24135
|
panelScales,
|
|
@@ -23452,10 +24183,11 @@ function compileFaceted(chartSpec, renderSpec, facetChannel, options, theme, str
|
|
|
23452
24183
|
annotations: panelAnnotations,
|
|
23453
24184
|
header: {
|
|
23454
24185
|
text: gridPanel.key,
|
|
23455
|
-
x: gridPanel.headerPos.x,
|
|
24186
|
+
x: facetDirection === "row" ? gridPanel.area.x : gridPanel.headerPos.x,
|
|
23456
24187
|
y: gridPanel.headerPos.y,
|
|
23457
24188
|
fontSize: theme.fonts.sizes.body,
|
|
23458
|
-
fontWeight: theme.fonts.weights.medium
|
|
24189
|
+
fontWeight: theme.fonts.weights.medium,
|
|
24190
|
+
...facetDirection === "row" ? { textAnchor: "start" } : {}
|
|
23459
24191
|
}
|
|
23460
24192
|
});
|
|
23461
24193
|
}
|
|
@@ -23492,6 +24224,19 @@ function compileFaceted(chartSpec, renderSpec, facetChannel, options, theme, str
|
|
|
23492
24224
|
chartSpec.data
|
|
23493
24225
|
);
|
|
23494
24226
|
assignAnimationIndices(allMarks, resolvedAnimation);
|
|
24227
|
+
const facetRenderModeWarnings = [];
|
|
24228
|
+
resolveMarkRenderMode(
|
|
24229
|
+
{
|
|
24230
|
+
requested: options.renderer,
|
|
24231
|
+
markType: chartSpec.markType,
|
|
24232
|
+
pointCount: allMarks.reduce((n, m) => m.type === "point" ? n + 1 : n, 0),
|
|
24233
|
+
display: chartSpec.display,
|
|
24234
|
+
faceted: true,
|
|
24235
|
+
layered: options.layered ?? false
|
|
24236
|
+
},
|
|
24237
|
+
facetRenderModeWarnings
|
|
24238
|
+
);
|
|
24239
|
+
emitSpecWarnings(facetRenderModeWarnings, options.onWarn);
|
|
23495
24240
|
return {
|
|
23496
24241
|
area: chartArea,
|
|
23497
24242
|
chrome: allFootnotes.length > 0 ? { ...dims.chrome, footnotes: allFootnotes } : dims.chrome,
|
|
@@ -23508,6 +24253,7 @@ function compileFaceted(chartSpec, renderSpec, facetChannel, options, theme, str
|
|
|
23508
24253
|
a11y: {
|
|
23509
24254
|
altText,
|
|
23510
24255
|
dataTableFallback,
|
|
24256
|
+
...chartSpec.data.length > MAX_SR_TABLE_ROWS ? { totalRows: chartSpec.data.length } : {},
|
|
23511
24257
|
role: "img",
|
|
23512
24258
|
keyboardNavigable: allMarks.length > 0,
|
|
23513
24259
|
...chartSpec.a11y?.hidden ? { hidden: true } : {}
|
|
@@ -23523,7 +24269,8 @@ function compileFaceted(chartSpec, renderSpec, facetChannel, options, theme, str
|
|
|
23523
24269
|
panels: panelLayouts,
|
|
23524
24270
|
facetField: facetChannel.field,
|
|
23525
24271
|
columns: grid.columns,
|
|
23526
|
-
sharedScales: yResolve === "shared" && xResolve === "shared"
|
|
24272
|
+
sharedScales: yResolve === "shared" && xResolve === "shared",
|
|
24273
|
+
direction: facetDirection
|
|
23527
24274
|
}
|
|
23528
24275
|
};
|
|
23529
24276
|
}
|
|
@@ -23562,14 +24309,15 @@ function compileSankey2(spec, options) {
|
|
|
23562
24309
|
function compileTileMap2(spec, options) {
|
|
23563
24310
|
return compileTileMap(spec, options);
|
|
23564
24311
|
}
|
|
23565
|
-
function
|
|
23566
|
-
return
|
|
24312
|
+
function compileGeoMap2(spec, options) {
|
|
24313
|
+
return compileGeoMap(spec, options);
|
|
23567
24314
|
}
|
|
23568
24315
|
function compileBarList2(spec, options) {
|
|
23569
24316
|
return compileBarList(spec, options);
|
|
23570
24317
|
}
|
|
23571
24318
|
export {
|
|
23572
24319
|
ARROWHEAD_LENGTH,
|
|
24320
|
+
AUTO_CANVAS_THRESHOLD,
|
|
23573
24321
|
BOLD_SPAN_FONT_WEIGHT,
|
|
23574
24322
|
DEFAULT_ANNOTATION_FONT_SIZE,
|
|
23575
24323
|
DEFAULT_LINE_HEIGHT,
|
|
@@ -23577,15 +24325,16 @@ export {
|
|
|
23577
24325
|
EXIT_DEFAULTS,
|
|
23578
24326
|
UPDATE_DEFAULTS,
|
|
23579
24327
|
buildAreaPath,
|
|
24328
|
+
buildEdgeTooltip,
|
|
23580
24329
|
buildLinePath,
|
|
23581
24330
|
clampStaggerDelay,
|
|
23582
24331
|
clearRenderers,
|
|
23583
24332
|
compile,
|
|
23584
24333
|
compileBarList2 as compileBarList,
|
|
23585
24334
|
compileChart,
|
|
24335
|
+
compileGeoMap2 as compileGeoMap,
|
|
23586
24336
|
compileGraph2 as compileGraph,
|
|
23587
24337
|
compileLayer2 as compileLayer,
|
|
23588
|
-
compileMap2 as compileMap,
|
|
23589
24338
|
compileSankey2 as compileSankey,
|
|
23590
24339
|
compileTable,
|
|
23591
24340
|
compileTileMap2 as compileTileMap,
|