@opendata-ai/openchart-engine 8.4.0 → 8.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +7 -1
- package/dist/index.js +258 -73
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
generateAltText,
|
|
7
7
|
generateDataTable,
|
|
8
8
|
getBreakpoint as getBreakpoint3,
|
|
9
|
-
getHeightClass,
|
|
9
|
+
getHeightClass as getHeightClass3,
|
|
10
10
|
getLayoutStrategy,
|
|
11
11
|
isAxislessMark as isAxislessMark3,
|
|
12
12
|
MAX_SR_TABLE_ROWS,
|
|
@@ -839,6 +839,7 @@ var OBSTACLE_WEIGHTS = {
|
|
|
839
839
|
"data-label": 8,
|
|
840
840
|
"endpoint-label": 8,
|
|
841
841
|
legend: 6,
|
|
842
|
+
chrome: 6,
|
|
842
843
|
watermark: 6,
|
|
843
844
|
"axis-band": 6,
|
|
844
845
|
"area-fill": 1.5
|
|
@@ -1207,7 +1208,7 @@ function resolveAnnotationCollisions(annotations, originalSpecs, scales, chartAr
|
|
|
1207
1208
|
placedBounds.push(annotation.bounds ?? annotationBlockBounds(annotation, label, measure));
|
|
1208
1209
|
}
|
|
1209
1210
|
}
|
|
1210
|
-
function clampAnnotationsToBounds(annotations, svgWidth, svgHeight, measure = heuristicMeasure) {
|
|
1211
|
+
function clampAnnotationsToBounds(annotations, svgWidth, svgHeight, measure = heuristicMeasure, topBound = CLAMP_MARGIN) {
|
|
1211
1212
|
for (const annotation of annotations) {
|
|
1212
1213
|
if (annotation.type !== "text" || !annotation.label) continue;
|
|
1213
1214
|
const label = annotation.label;
|
|
@@ -1220,8 +1221,8 @@ function clampAnnotationsToBounds(annotations, svgWidth, svgHeight, measure = he
|
|
|
1220
1221
|
if (bounds.x + dx < CLAMP_MARGIN) {
|
|
1221
1222
|
dx = CLAMP_MARGIN - bounds.x;
|
|
1222
1223
|
}
|
|
1223
|
-
if (bounds.y <
|
|
1224
|
-
dy =
|
|
1224
|
+
if (bounds.y < topBound) {
|
|
1225
|
+
dy = topBound - bounds.y;
|
|
1225
1226
|
}
|
|
1226
1227
|
if (bounds.y + bounds.height + dy > svgHeight - CLAMP_MARGIN) {
|
|
1227
1228
|
dy = svgHeight - CLAMP_MARGIN - (bounds.y + bounds.height);
|
|
@@ -1667,7 +1668,7 @@ function computeAnnotations(spec, scalesOrCtx, chartArea, strategy, isDark, obst
|
|
|
1667
1668
|
autoQueue.length > 0 ? (i) => autoIndices.has(i) : void 0
|
|
1668
1669
|
);
|
|
1669
1670
|
if (ctx.svg.width > 0 && ctx.svg.height > 0) {
|
|
1670
|
-
clampAnnotationsToBounds(annotations, ctx.svg.width, ctx.svg.height, ctx.measure);
|
|
1671
|
+
clampAnnotationsToBounds(annotations, ctx.svg.width, ctx.svg.height, ctx.measure, ctx.topBound);
|
|
1671
1672
|
}
|
|
1672
1673
|
annotations.sort((a, b) => (a.zIndex ?? 0) - (b.zIndex ?? 0));
|
|
1673
1674
|
return annotations;
|
|
@@ -2867,6 +2868,7 @@ function computeBarLabels(marks, chartArea, density = "auto", labelFormatter, la
|
|
|
2867
2868
|
const candidates = [];
|
|
2868
2869
|
const fitsInSegment = [];
|
|
2869
2870
|
const displayAnchorX = [];
|
|
2871
|
+
const haloFlags = [];
|
|
2870
2872
|
const formatter = labelFormatter ?? null;
|
|
2871
2873
|
for (const mark of targetMarks) {
|
|
2872
2874
|
let valuePart;
|
|
@@ -2928,6 +2930,7 @@ function computeBarLabels(marks, chartArea, density = "auto", labelFormatter, la
|
|
|
2928
2930
|
const anchorY = centerY - textHeight / 2;
|
|
2929
2931
|
const leftEdgeX = textAnchor === "end" ? anchorX - textWidth : textAnchor === "middle" ? anchorX - textWidth / 2 : anchorX;
|
|
2930
2932
|
const fits = !(isStacked2 && textWidth > mark.width - 2 * LABEL_PADDING);
|
|
2933
|
+
haloFlags.push(!isInside);
|
|
2931
2934
|
displayAnchorX.push(anchorX);
|
|
2932
2935
|
fitsInSegment.push(fits);
|
|
2933
2936
|
candidates.push({
|
|
@@ -2972,7 +2975,8 @@ function computeBarLabels(marks, chartArea, density = "auto", labelFormatter, la
|
|
|
2972
2975
|
x: displayAnchorX[i],
|
|
2973
2976
|
y: candidates[i].anchorY + halfHeight,
|
|
2974
2977
|
style: candidates[i].style,
|
|
2975
|
-
visible: false
|
|
2978
|
+
visible: false,
|
|
2979
|
+
...haloFlags[i] ? {} : { halo: false }
|
|
2976
2980
|
});
|
|
2977
2981
|
} else {
|
|
2978
2982
|
const r = resolvedByOrig.get(i);
|
|
@@ -2981,6 +2985,7 @@ function computeBarLabels(marks, chartArea, density = "auto", labelFormatter, la
|
|
|
2981
2985
|
const { index: _index, ...rest } = r;
|
|
2982
2986
|
results.push({
|
|
2983
2987
|
...rest,
|
|
2988
|
+
...haloFlags[i] ? {} : { halo: false },
|
|
2984
2989
|
x: r.x + dx,
|
|
2985
2990
|
y: r.y + halfHeight,
|
|
2986
2991
|
connector: r.connector ? {
|
|
@@ -3774,6 +3779,7 @@ function computeColumnLabels(marks, _chartArea, density = "auto", labelFormatter
|
|
|
3774
3779
|
const targetMarks = filterByDensity(marks, density);
|
|
3775
3780
|
const formatter = labelFormatter ?? null;
|
|
3776
3781
|
const candidates = [];
|
|
3782
|
+
const haloFlags = [];
|
|
3777
3783
|
const fitsInSegment = [];
|
|
3778
3784
|
for (const mark of targetMarks) {
|
|
3779
3785
|
let valuePart;
|
|
@@ -3813,6 +3819,7 @@ function computeColumnLabels(marks, _chartArea, density = "auto", labelFormatter
|
|
|
3813
3819
|
fill = labelColor ?? getRepresentativeColor3(mark.fill);
|
|
3814
3820
|
}
|
|
3815
3821
|
fitsInSegment.push(!(isStacked2 && textHeight > mark.height - 2 * LABEL_PADDING_Y));
|
|
3822
|
+
haloFlags.push(!isStacked2);
|
|
3816
3823
|
candidates.push({
|
|
3817
3824
|
text: valuePart,
|
|
3818
3825
|
anchorX,
|
|
@@ -3854,7 +3861,8 @@ function computeColumnLabels(marks, _chartArea, density = "auto", labelFormatter
|
|
|
3854
3861
|
x: candidates[i].anchorX,
|
|
3855
3862
|
y: candidates[i].anchorY + ascent,
|
|
3856
3863
|
style: candidates[i].style,
|
|
3857
|
-
visible: false
|
|
3864
|
+
visible: false,
|
|
3865
|
+
...haloFlags[i] ? {} : { halo: false }
|
|
3858
3866
|
});
|
|
3859
3867
|
continue;
|
|
3860
3868
|
}
|
|
@@ -3863,6 +3871,7 @@ function computeColumnLabels(marks, _chartArea, density = "auto", labelFormatter
|
|
|
3863
3871
|
const { index: _index, ...rest } = r;
|
|
3864
3872
|
results.push({
|
|
3865
3873
|
...rest,
|
|
3874
|
+
...haloFlags[i] ? {} : { halo: false },
|
|
3866
3875
|
y: r.y + ascent,
|
|
3867
3876
|
// The connector originates at the label; shift its start to the baseline
|
|
3868
3877
|
// too so the leader stays glued to the shifted text.
|
|
@@ -10271,6 +10280,7 @@ import {
|
|
|
10271
10280
|
computeXAxisExtentFromLabels as computeXAxisExtentFromLabels2,
|
|
10272
10281
|
defaultNumberFormatter as defaultNumberFormatter6,
|
|
10273
10282
|
estimateTextWidth as estimateTextWidth16,
|
|
10283
|
+
getHeightClass,
|
|
10274
10284
|
HPAD_COMPACT_FRACTION,
|
|
10275
10285
|
HPAD_COMPACT_MIN,
|
|
10276
10286
|
isAxislessMark,
|
|
@@ -12268,6 +12278,7 @@ function resolveLayoutPlan(chartSpec, renderSpec, options, theme, strategy, wate
|
|
|
12268
12278
|
if (renderSpec.display === "sparkline" && !renderSpec.userExplicit?.chrome) {
|
|
12269
12279
|
chromeMode = "hidden";
|
|
12270
12280
|
}
|
|
12281
|
+
const crampedTitle = getHeightClass(height) === "cramped";
|
|
12271
12282
|
if (renderSpec.display === "sparkline" || isRadial) {
|
|
12272
12283
|
const legendContent = computeLegendContent(
|
|
12273
12284
|
chartSpec,
|
|
@@ -12287,7 +12298,8 @@ function resolveLayoutPlan(chartSpec, renderSpec, options, theme, strategy, wate
|
|
|
12287
12298
|
chromeMode,
|
|
12288
12299
|
padding,
|
|
12289
12300
|
watermark,
|
|
12290
|
-
bottomLegendReservation
|
|
12301
|
+
bottomLegendReservation,
|
|
12302
|
+
crampedTitle
|
|
12291
12303
|
);
|
|
12292
12304
|
return {
|
|
12293
12305
|
leftGutter: hPad,
|
|
@@ -12411,7 +12423,8 @@ function resolveLayoutPlan(chartSpec, renderSpec, options, theme, strategy, wate
|
|
|
12411
12423
|
chromeMode,
|
|
12412
12424
|
padding,
|
|
12413
12425
|
watermark,
|
|
12414
|
-
bottomLegendReservation
|
|
12426
|
+
bottomLegendReservation,
|
|
12427
|
+
crampedTitle
|
|
12415
12428
|
);
|
|
12416
12429
|
let effectiveXTickAngle = xTickAngle;
|
|
12417
12430
|
if (xTickAngle === void 0 && xLabels.length > 1) {
|
|
@@ -13550,6 +13563,54 @@ function topologyBBox(topology) {
|
|
|
13550
13563
|
var OVERLAY_LEGEND_INSET = 18;
|
|
13551
13564
|
var NO_DATA_SWATCH_GAP = 12;
|
|
13552
13565
|
var NO_DATA_LABEL_GAP = 5;
|
|
13566
|
+
var CATEGORICAL_SWATCH_SIZE = 10;
|
|
13567
|
+
var CATEGORICAL_SWATCH_GAP = 6;
|
|
13568
|
+
var CATEGORICAL_ENTRY_GAP = 16;
|
|
13569
|
+
var CATEGORICAL_ROW_HEIGHT = CATEGORICAL_SWATCH_SIZE + 6;
|
|
13570
|
+
function categoricalLegendLabelStyle(theme) {
|
|
13571
|
+
return {
|
|
13572
|
+
fontFamily: theme.fonts.family,
|
|
13573
|
+
fontSize: 11,
|
|
13574
|
+
fontWeight: 400,
|
|
13575
|
+
fill: theme.colors.text,
|
|
13576
|
+
lineHeight: 1.2
|
|
13577
|
+
};
|
|
13578
|
+
}
|
|
13579
|
+
function categoricalEntryWidth(label, labelStyle) {
|
|
13580
|
+
return CATEGORICAL_SWATCH_SIZE + CATEGORICAL_SWATCH_GAP + estimateTextWidth18(label, labelStyle.fontSize, labelStyle.fontWeight) + CATEGORICAL_ENTRY_GAP;
|
|
13581
|
+
}
|
|
13582
|
+
function noDataBlockWidth(labelStyle) {
|
|
13583
|
+
return CATEGORICAL_SWATCH_SIZE + NO_DATA_LABEL_GAP + estimateTextWidth18("No data", labelStyle.fontSize, labelStyle.fontWeight);
|
|
13584
|
+
}
|
|
13585
|
+
function wrapCategoricalEntries(widths, legendWidth) {
|
|
13586
|
+
const placed = [];
|
|
13587
|
+
let x = 0;
|
|
13588
|
+
let row = 0;
|
|
13589
|
+
for (let i = 0; i < widths.length; i++) {
|
|
13590
|
+
if (i > 0 && x + widths[i] > legendWidth) {
|
|
13591
|
+
x = 0;
|
|
13592
|
+
row += 1;
|
|
13593
|
+
}
|
|
13594
|
+
placed.push({ x, row });
|
|
13595
|
+
x += widths[i];
|
|
13596
|
+
}
|
|
13597
|
+
return placed;
|
|
13598
|
+
}
|
|
13599
|
+
function collectCategories(rows, field, domain) {
|
|
13600
|
+
const categories = Array.isArray(domain) ? domain.map((c) => String(c)) : [];
|
|
13601
|
+
const seen = new Set(categories);
|
|
13602
|
+
for (const row of rows) {
|
|
13603
|
+
const raw = row[field];
|
|
13604
|
+
if (raw != null) {
|
|
13605
|
+
const cat = String(raw);
|
|
13606
|
+
if (!seen.has(cat)) {
|
|
13607
|
+
seen.add(cat);
|
|
13608
|
+
categories.push(cat);
|
|
13609
|
+
}
|
|
13610
|
+
}
|
|
13611
|
+
}
|
|
13612
|
+
return categories;
|
|
13613
|
+
}
|
|
13553
13614
|
function legendTitleFor(colorEncoding) {
|
|
13554
13615
|
const base = colorEncoding.title ?? colorEncoding.field;
|
|
13555
13616
|
if (!base) return void 0;
|
|
@@ -13678,7 +13739,16 @@ function compileGeoMap(spec, options) {
|
|
|
13678
13739
|
}
|
|
13679
13740
|
if (legendBlockHeight === 0 && showChoroplethLegend && colorEncoding && !isQuantitative) {
|
|
13680
13741
|
const labelHeight = Math.ceil(theme.fonts.sizes.small * 1.3);
|
|
13681
|
-
|
|
13742
|
+
const labelStyle = categoricalLegendLabelStyle(theme);
|
|
13743
|
+
const widths = collectCategories(
|
|
13744
|
+
mapSpec.data,
|
|
13745
|
+
colorEncoding.field,
|
|
13746
|
+
colorEncoding.scale?.domain
|
|
13747
|
+
).map((cat) => categoricalEntryWidth(cat, labelStyle));
|
|
13748
|
+
widths.push(noDataBlockWidth(labelStyle));
|
|
13749
|
+
const placed = wrapCategoricalEntries(widths, fullArea.width);
|
|
13750
|
+
const rows = placed.length > 0 ? placed[placed.length - 1].row + 1 : 1;
|
|
13751
|
+
legendBlockHeight = rows * (Math.max(10, labelHeight) + 6);
|
|
13682
13752
|
}
|
|
13683
13753
|
if (showLegend && !pointLegendOverlay && mapSpec.points?.color) {
|
|
13684
13754
|
if (mapSpec.points.color.type === "quantitative") {
|
|
@@ -13747,6 +13817,11 @@ function compileGeoMap(spec, options) {
|
|
|
13747
13817
|
const droppedFeatures = [];
|
|
13748
13818
|
const formatter = buildD3Formatter2(mapSpec.encoding?.color?.format ?? mapSpec.valueFormat) ?? formatNumber3;
|
|
13749
13819
|
const neutralFill = isDarkMode ? theme.colors.neutral[800] : theme.colors.neutral[100];
|
|
13820
|
+
const noDataPattern = {
|
|
13821
|
+
type: "diagonal",
|
|
13822
|
+
base: neutralFill,
|
|
13823
|
+
line: isDarkMode ? theme.colors.neutral[600] : theme.colors.neutral[300]
|
|
13824
|
+
};
|
|
13750
13825
|
let featureMarks;
|
|
13751
13826
|
let continuousLegend = null;
|
|
13752
13827
|
let categoricalLegend = null;
|
|
@@ -13765,6 +13840,7 @@ function compileGeoMap(spec, options) {
|
|
|
13765
13840
|
colorField: colorEncoding.field,
|
|
13766
13841
|
classScale,
|
|
13767
13842
|
neutralFill,
|
|
13843
|
+
noDataPattern,
|
|
13768
13844
|
formatter,
|
|
13769
13845
|
droppedFeatures
|
|
13770
13846
|
});
|
|
@@ -13799,16 +13875,21 @@ function compileGeoMap(spec, options) {
|
|
|
13799
13875
|
height: continuousContent.barHeight
|
|
13800
13876
|
};
|
|
13801
13877
|
const labelY = bar.y + bar.height + CONTINUOUS_LABEL_GAP + labelStyle.fontSize;
|
|
13802
|
-
const hasUnmatched = featureMarks.some((m) =>
|
|
13803
|
-
const raw = m.data?.[colorEncoding.field];
|
|
13804
|
-
return raw == null || Number.isNaN(Number(raw));
|
|
13805
|
-
});
|
|
13878
|
+
const hasUnmatched = featureMarks.some((m) => m.noData);
|
|
13806
13879
|
const noDataX = bar.x + bar.width + NO_DATA_SWATCH_GAP;
|
|
13807
|
-
const
|
|
13880
|
+
const noDataLabelWidth = estimateTextWidth18(
|
|
13881
|
+
"No data",
|
|
13882
|
+
labelStyle.fontSize,
|
|
13883
|
+
labelStyle.fontWeight
|
|
13884
|
+
);
|
|
13885
|
+
const noData = hasUnmatched && noDataX + bar.height + NO_DATA_LABEL_GAP + noDataLabelWidth < fullArea.x + fullArea.width ? {
|
|
13808
13886
|
x: noDataX,
|
|
13809
13887
|
y: bar.y,
|
|
13810
13888
|
size: bar.height,
|
|
13811
13889
|
fill: neutralFill,
|
|
13890
|
+
// Same hatch the no-data features carry, so the key matches what
|
|
13891
|
+
// is on the map rather than a neutral the ramp's center mimics.
|
|
13892
|
+
pattern: noDataPattern,
|
|
13812
13893
|
label: "No data",
|
|
13813
13894
|
labelX: noDataX + bar.height + NO_DATA_LABEL_GAP,
|
|
13814
13895
|
labelY: bar.y + bar.height
|
|
@@ -13839,6 +13920,7 @@ function compileGeoMap(spec, options) {
|
|
|
13839
13920
|
colorScale: colorEncoding.scale,
|
|
13840
13921
|
isDarkMode: !!isDarkMode,
|
|
13841
13922
|
neutralFill,
|
|
13923
|
+
noDataPattern,
|
|
13842
13924
|
theme,
|
|
13843
13925
|
fullArea,
|
|
13844
13926
|
mapAreaHeight,
|
|
@@ -14290,6 +14372,7 @@ function buildQuantitativeMarks(opts) {
|
|
|
14290
14372
|
colorField,
|
|
14291
14373
|
classScale,
|
|
14292
14374
|
neutralFill,
|
|
14375
|
+
noDataPattern,
|
|
14293
14376
|
formatter,
|
|
14294
14377
|
droppedFeatures
|
|
14295
14378
|
} = opts;
|
|
@@ -14307,13 +14390,17 @@ function buildQuantitativeMarks(opts) {
|
|
|
14307
14390
|
const hasData = dataRow !== null;
|
|
14308
14391
|
let fill = neutralFill;
|
|
14309
14392
|
let binIndex;
|
|
14310
|
-
|
|
14393
|
+
let hasValue = false;
|
|
14394
|
+
if (hasData) {
|
|
14311
14395
|
const raw = dataRow[colorField];
|
|
14312
14396
|
if (raw != null) {
|
|
14313
14397
|
const v = Number(raw);
|
|
14314
14398
|
if (!Number.isNaN(v)) {
|
|
14315
|
-
|
|
14316
|
-
|
|
14399
|
+
hasValue = true;
|
|
14400
|
+
if (classScale) {
|
|
14401
|
+
fill = classScale.color(v);
|
|
14402
|
+
binIndex = classScale.binIndex(v);
|
|
14403
|
+
}
|
|
14317
14404
|
}
|
|
14318
14405
|
}
|
|
14319
14406
|
}
|
|
@@ -14344,7 +14431,8 @@ function buildQuantitativeMarks(opts) {
|
|
|
14344
14431
|
animationIndex: animIndex++,
|
|
14345
14432
|
bounds,
|
|
14346
14433
|
centroid: [cx, cy],
|
|
14347
|
-
binIndex
|
|
14434
|
+
binIndex,
|
|
14435
|
+
...hasValue ? {} : { noData: true, pattern: noDataPattern }
|
|
14348
14436
|
});
|
|
14349
14437
|
}
|
|
14350
14438
|
return { marks };
|
|
@@ -14358,6 +14446,7 @@ function buildCategoricalMarks(opts) {
|
|
|
14358
14446
|
colorScale: scaleConfig,
|
|
14359
14447
|
isDarkMode,
|
|
14360
14448
|
neutralFill,
|
|
14449
|
+
noDataPattern,
|
|
14361
14450
|
theme,
|
|
14362
14451
|
fullArea,
|
|
14363
14452
|
mapAreaHeight,
|
|
@@ -14366,24 +14455,7 @@ function buildCategoricalMarks(opts) {
|
|
|
14366
14455
|
showLegend,
|
|
14367
14456
|
droppedFeatures
|
|
14368
14457
|
} = opts;
|
|
14369
|
-
const categories =
|
|
14370
|
-
const explicitDomain = scaleConfig?.domain;
|
|
14371
|
-
if (explicitDomain && Array.isArray(explicitDomain)) {
|
|
14372
|
-
for (const cat of explicitDomain) {
|
|
14373
|
-
categories.push(String(cat));
|
|
14374
|
-
}
|
|
14375
|
-
}
|
|
14376
|
-
const seen = new Set(categories);
|
|
14377
|
-
for (const row of joined.values()) {
|
|
14378
|
-
const raw = row[colorField];
|
|
14379
|
-
if (raw != null) {
|
|
14380
|
-
const cat = String(raw);
|
|
14381
|
-
if (!seen.has(cat)) {
|
|
14382
|
-
seen.add(cat);
|
|
14383
|
-
categories.push(cat);
|
|
14384
|
-
}
|
|
14385
|
-
}
|
|
14386
|
-
}
|
|
14458
|
+
const categories = collectCategories(joined.values(), colorField, scaleConfig?.domain);
|
|
14387
14459
|
const explicitRange = scaleConfig?.range;
|
|
14388
14460
|
const colorSource = explicitRange && Array.isArray(explicitRange) ? explicitRange : CATEGORICAL_PALETTE2;
|
|
14389
14461
|
const categoryColors = /* @__PURE__ */ new Map();
|
|
@@ -14403,10 +14475,12 @@ function buildCategoricalMarks(opts) {
|
|
|
14403
14475
|
const dataRow = joined.get(featureId) ?? null;
|
|
14404
14476
|
const hasData = dataRow !== null;
|
|
14405
14477
|
let fill = neutralFill;
|
|
14478
|
+
let hasValue = false;
|
|
14406
14479
|
if (hasData) {
|
|
14407
14480
|
const raw = dataRow[colorField];
|
|
14408
14481
|
if (raw != null) {
|
|
14409
14482
|
const cat = String(raw);
|
|
14483
|
+
hasValue = true;
|
|
14410
14484
|
fill = categoryColors.get(cat) ?? neutralFill;
|
|
14411
14485
|
}
|
|
14412
14486
|
}
|
|
@@ -14436,18 +14510,13 @@ function buildCategoricalMarks(opts) {
|
|
|
14436
14510
|
},
|
|
14437
14511
|
animationIndex: animIndex++,
|
|
14438
14512
|
bounds,
|
|
14439
|
-
centroid: [cx, cy]
|
|
14513
|
+
centroid: [cx, cy],
|
|
14514
|
+
...hasValue ? {} : { noData: true, pattern: noDataPattern }
|
|
14440
14515
|
});
|
|
14441
14516
|
}
|
|
14442
14517
|
let legend = null;
|
|
14443
14518
|
if (showLegend && categories.length > 0) {
|
|
14444
|
-
const labelStyle =
|
|
14445
|
-
fontFamily: theme.fonts.family,
|
|
14446
|
-
fontSize: 11,
|
|
14447
|
-
fontWeight: 400,
|
|
14448
|
-
fill: theme.colors.text,
|
|
14449
|
-
lineHeight: 1.2
|
|
14450
|
-
};
|
|
14519
|
+
const labelStyle = categoricalLegendLabelStyle(theme);
|
|
14451
14520
|
const entries = categories.map((cat) => ({
|
|
14452
14521
|
label: cat,
|
|
14453
14522
|
color: categoryColors.get(cat),
|
|
@@ -14456,19 +14525,67 @@ function buildCategoricalMarks(opts) {
|
|
|
14456
14525
|
const legendX = fullArea.x;
|
|
14457
14526
|
const legendY = legendPosition === "bottom" ? fullArea.y + mapAreaHeight + legendReserveGap : fullArea.y + legendReserveGap;
|
|
14458
14527
|
const legendWidth = fullArea.width;
|
|
14459
|
-
const swatchSize =
|
|
14460
|
-
const swatchGap =
|
|
14461
|
-
const entryGap =
|
|
14528
|
+
const swatchSize = CATEGORICAL_SWATCH_SIZE;
|
|
14529
|
+
const swatchGap = CATEGORICAL_SWATCH_GAP;
|
|
14530
|
+
const entryGap = CATEGORICAL_ENTRY_GAP;
|
|
14531
|
+
const entryWidths = entries.map((e) => categoricalEntryWidth(e.label, labelStyle));
|
|
14532
|
+
const placed = wrapCategoricalEntries(entryWidths, legendWidth);
|
|
14533
|
+
const entryPositions = placed.map((p, i) => {
|
|
14534
|
+
const x = legendX + p.x;
|
|
14535
|
+
const y = legendY + p.row * CATEGORICAL_ROW_HEIGHT;
|
|
14536
|
+
return {
|
|
14537
|
+
x,
|
|
14538
|
+
y,
|
|
14539
|
+
labelX: x + swatchSize + swatchGap,
|
|
14540
|
+
labelY: y + swatchSize / 2,
|
|
14541
|
+
width: entryWidths[i],
|
|
14542
|
+
row: p.row
|
|
14543
|
+
};
|
|
14544
|
+
});
|
|
14545
|
+
let rows = placed.length > 0 ? placed[placed.length - 1].row + 1 : 1;
|
|
14546
|
+
const hasUnmatched = marks.some((m) => m.noData);
|
|
14547
|
+
const last = placed[placed.length - 1];
|
|
14548
|
+
const blockWidth = noDataBlockWidth(labelStyle);
|
|
14549
|
+
let noDataOffsetX = last ? last.x + entryWidths[entryWidths.length - 1] : 0;
|
|
14550
|
+
let noDataRow = last ? last.row : 0;
|
|
14551
|
+
if (noDataOffsetX + blockWidth > legendWidth) {
|
|
14552
|
+
noDataOffsetX = 0;
|
|
14553
|
+
noDataRow += 1;
|
|
14554
|
+
}
|
|
14555
|
+
const noDataX = legendX + noDataOffsetX;
|
|
14556
|
+
const noDataY = legendY + noDataRow * CATEGORICAL_ROW_HEIGHT;
|
|
14557
|
+
const chipSize = Math.round(swatchSize * 0.6);
|
|
14558
|
+
const noData = hasUnmatched && blockWidth <= legendWidth ? {
|
|
14559
|
+
x: noDataX + (swatchSize - chipSize) / 2,
|
|
14560
|
+
y: noDataY + swatchSize / 2 - chipSize / 2,
|
|
14561
|
+
size: chipSize,
|
|
14562
|
+
fill: neutralFill,
|
|
14563
|
+
// The same hatch the no-data features carry, so the key matches
|
|
14564
|
+
// what is on the map.
|
|
14565
|
+
pattern: noDataPattern,
|
|
14566
|
+
label: "No data",
|
|
14567
|
+
labelX: noDataX + swatchSize + NO_DATA_LABEL_GAP,
|
|
14568
|
+
labelY: noDataY + swatchSize / 2
|
|
14569
|
+
} : void 0;
|
|
14570
|
+
if (noData) rows = Math.max(rows, noDataRow + 1);
|
|
14462
14571
|
legend = {
|
|
14463
14572
|
type: "categorical",
|
|
14464
14573
|
position: legendPosition,
|
|
14465
|
-
bounds: {
|
|
14574
|
+
bounds: {
|
|
14575
|
+
x: legendX,
|
|
14576
|
+
y: legendY,
|
|
14577
|
+
width: legendWidth,
|
|
14578
|
+
height: rows * CATEGORICAL_ROW_HEIGHT
|
|
14579
|
+
},
|
|
14466
14580
|
labelStyle,
|
|
14467
14581
|
entries,
|
|
14582
|
+
entryPositions,
|
|
14583
|
+
rowHeight: CATEGORICAL_ROW_HEIGHT,
|
|
14468
14584
|
swatchSize,
|
|
14469
14585
|
swatchGap,
|
|
14470
14586
|
entryGap,
|
|
14471
|
-
swatchChipFill: isDarkMode ? "rgba(255,255,255,0.06)" : "rgba(0,0,0,0.04)"
|
|
14587
|
+
swatchChipFill: isDarkMode ? "rgba(255,255,255,0.06)" : "rgba(0,0,0,0.04)",
|
|
14588
|
+
noData
|
|
14472
14589
|
};
|
|
14473
14590
|
}
|
|
14474
14591
|
return { marks, legend };
|
|
@@ -15302,6 +15419,7 @@ import {
|
|
|
15302
15419
|
computeFieldFormatContext as computeFieldFormatContext6,
|
|
15303
15420
|
defaultNumberFormatter as defaultNumberFormatter9,
|
|
15304
15421
|
estimateTextWidth as estimateTextWidth20,
|
|
15422
|
+
getHeightClass as getHeightClass2,
|
|
15305
15423
|
HPAD_COMPACT_FRACTION as HPAD_COMPACT_FRACTION3,
|
|
15306
15424
|
HPAD_COMPACT_MIN as HPAD_COMPACT_MIN3,
|
|
15307
15425
|
isAxislessMark as isAxislessMark2,
|
|
@@ -15414,6 +15532,7 @@ function computeDimensions(spec, options, legendLayout, theme, strategy, waterma
|
|
|
15414
15532
|
chromeMode = "hidden";
|
|
15415
15533
|
}
|
|
15416
15534
|
const bottomLegendReservation = plan ? hasLegendContent(plan.legendContent) && plan.legendContent.position === "bottom" ? plan.legendContent.height + legendGap(width) : 0 : legendLayoutHasContent(legendLayout) && legendLayout.position === "bottom" ? legendLayout.bounds.height + legendGap(width) : 0;
|
|
15535
|
+
const isCrampedHeight = getHeightClass2(height) === "cramped";
|
|
15417
15536
|
const chrome = plan?.chrome ?? computeChrome5(
|
|
15418
15537
|
chromeToInput(spec.chrome),
|
|
15419
15538
|
theme,
|
|
@@ -15422,7 +15541,8 @@ function computeDimensions(spec, options, legendLayout, theme, strategy, waterma
|
|
|
15422
15541
|
chromeMode,
|
|
15423
15542
|
padding,
|
|
15424
15543
|
watermark,
|
|
15425
|
-
bottomLegendReservation
|
|
15544
|
+
bottomLegendReservation,
|
|
15545
|
+
isCrampedHeight
|
|
15426
15546
|
);
|
|
15427
15547
|
const chromeLayout = resolveChromeLayout(spec, options);
|
|
15428
15548
|
const effectiveHeight = chromeLayout === "grow" ? height + chrome.topHeight + chrome.bottomHeight : height;
|
|
@@ -15460,7 +15580,8 @@ function computeDimensions(spec, options, legendLayout, theme, strategy, waterma
|
|
|
15460
15580
|
margins: margins2,
|
|
15461
15581
|
theme,
|
|
15462
15582
|
xAxisHeight: xAxisSpace,
|
|
15463
|
-
effectiveAxisGap: 0
|
|
15583
|
+
effectiveAxisGap: 0,
|
|
15584
|
+
topPad: padding
|
|
15464
15585
|
};
|
|
15465
15586
|
}
|
|
15466
15587
|
const total = { x: 0, y: 0, width, height: effectiveHeight };
|
|
@@ -15497,9 +15618,9 @@ function computeDimensions(spec, options, legendLayout, theme, strategy, waterma
|
|
|
15497
15618
|
const inlineTickOverhang = yIsInlinePre ? theme.fonts.sizes.axisTick + INLINE_TICK_OVERHANG_PAD : 0;
|
|
15498
15619
|
const topAxisGap = isRadial && chrome.topHeight === 0 ? 0 : axisMargin + inlineTickOverhang;
|
|
15499
15620
|
const topPad = width < NARROW_VIEWPORT_MAX3 ? padding + TOP_PAD_EXTRA_NARROW2 : padding;
|
|
15500
|
-
const wantsMetrics = !!spec.metrics && spec.metrics.length > 0 && chromeMode !== "hidden";
|
|
15621
|
+
const wantsMetrics = !!spec.metrics && spec.metrics.length > 0 && chromeMode !== "hidden" && !isCrampedHeight;
|
|
15501
15622
|
const tentativeMetricsHeight = wantsMetrics ? metricBarHeight(metricFonts(theme)) : 0;
|
|
15502
|
-
const wantsSearch = !!spec.seriesSearch && chromeMode !== "hidden";
|
|
15623
|
+
const wantsSearch = !!spec.seriesSearch && chromeMode !== "hidden" && !isCrampedHeight;
|
|
15503
15624
|
const searchReservation = wantsSearch ? SERIES_SEARCH_INPUT_HEIGHT + SERIES_SEARCH_GAP : 0;
|
|
15504
15625
|
const margins = {
|
|
15505
15626
|
top: topPad + chrome.topHeight + tentativeMetricsHeight + searchReservation,
|
|
@@ -15757,6 +15878,7 @@ function computeDimensions(spec, options, legendLayout, theme, strategy, waterma
|
|
|
15757
15878
|
) : void 0,
|
|
15758
15879
|
xAxisHeight,
|
|
15759
15880
|
effectiveAxisGap: fallbackEffectiveAxisGap,
|
|
15881
|
+
topPad,
|
|
15760
15882
|
chromeStripped: true
|
|
15761
15883
|
};
|
|
15762
15884
|
}
|
|
@@ -15781,7 +15903,8 @@ function computeDimensions(spec, options, legendLayout, theme, strategy, waterma
|
|
|
15781
15903
|
metrics: resolvedMetrics,
|
|
15782
15904
|
seriesSearch: wantsSearch ? resolveSeriesSearch(spec, metricsTopY + (resolvedMetrics?.height ?? 0), metricsArea) : void 0,
|
|
15783
15905
|
xAxisHeight,
|
|
15784
|
-
effectiveAxisGap
|
|
15906
|
+
effectiveAxisGap,
|
|
15907
|
+
topPad
|
|
15785
15908
|
};
|
|
15786
15909
|
}
|
|
15787
15910
|
function resolveSeriesSearch(spec, y, area3) {
|
|
@@ -17063,40 +17186,73 @@ function inferAlignment(col, type) {
|
|
|
17063
17186
|
if (col.align) return col.align;
|
|
17064
17187
|
return type === "quantitative" ? "right" : "left";
|
|
17065
17188
|
}
|
|
17066
|
-
function
|
|
17189
|
+
function cellPaddingX(density) {
|
|
17190
|
+
if (density === "condensed") return 24;
|
|
17191
|
+
if (density === "relaxed") return 40;
|
|
17192
|
+
return 32;
|
|
17193
|
+
}
|
|
17194
|
+
function estimateColumnWidth(col, data, fontSize, paddingX) {
|
|
17067
17195
|
const MIN_WIDTH = 60;
|
|
17068
|
-
const PADDING = 24;
|
|
17069
17196
|
if (col.sparkline) return 140;
|
|
17070
|
-
if (col.image) return (col.image.width ?? 24) +
|
|
17197
|
+
if (col.image) return (col.image.width ?? 24) + paddingX;
|
|
17071
17198
|
if (col.flag) return 60;
|
|
17072
17199
|
const label = col.label ?? col.key;
|
|
17073
|
-
const headerWidth = estimateTextWidth22(label, fontSize, 600) +
|
|
17200
|
+
const headerWidth = estimateTextWidth22(label, fontSize, 600) + paddingX;
|
|
17074
17201
|
const sampleSize = Math.min(100, data.length);
|
|
17075
17202
|
let maxDataWidth = 0;
|
|
17076
17203
|
for (let i = 0; i < sampleSize; i++) {
|
|
17077
17204
|
const val = data[i][col.key];
|
|
17078
17205
|
const text = val == null ? "" : String(val);
|
|
17079
|
-
const width = estimateTextWidth22(text, fontSize, 400) +
|
|
17206
|
+
const width = estimateTextWidth22(text, fontSize, 400) + paddingX;
|
|
17080
17207
|
if (width > maxDataWidth) maxDataWidth = width;
|
|
17081
17208
|
}
|
|
17082
17209
|
return Math.max(MIN_WIDTH, headerWidth, maxDataWidth);
|
|
17083
17210
|
}
|
|
17084
|
-
|
|
17211
|
+
var MIN_COLUMN_WIDTH = 60;
|
|
17212
|
+
function resolveColumns(columns, data, totalWidth, theme, density, warnings = []) {
|
|
17085
17213
|
const fontSize = theme.fonts.sizes.body;
|
|
17086
|
-
const
|
|
17214
|
+
const paddingX = cellPaddingX(density);
|
|
17215
|
+
const isFixed = columns.map((col) => !!(col.sparkline || col.image || col.flag || col.width));
|
|
17087
17216
|
const naturalWidths = columns.map((col) => {
|
|
17088
17217
|
if (col.width) {
|
|
17089
17218
|
if (col.width.endsWith("px")) {
|
|
17090
17219
|
return parseInt(col.width, 10) || 100;
|
|
17091
17220
|
}
|
|
17092
17221
|
if (col.width.endsWith("%")) {
|
|
17093
|
-
return parseFloat(col.width) / 100 * totalWidth || 100;
|
|
17222
|
+
return Math.round(parseFloat(col.width) / 100 * totalWidth) || 100;
|
|
17094
17223
|
}
|
|
17095
17224
|
return parseInt(col.width, 10) || 100;
|
|
17096
17225
|
}
|
|
17097
|
-
return estimateColumnWidth(col, data, fontSize);
|
|
17226
|
+
return estimateColumnWidth(col, data, fontSize, paddingX);
|
|
17098
17227
|
});
|
|
17099
|
-
const
|
|
17228
|
+
const explicitIndices = columns.map((_, i) => i).filter((i) => isFixed[i] && !!columns[i].width);
|
|
17229
|
+
const visualFixedTotal = columns.reduce(
|
|
17230
|
+
(sum, col, i) => sum + (isFixed[i] && !col.width ? naturalWidths[i] : 0),
|
|
17231
|
+
0
|
|
17232
|
+
);
|
|
17233
|
+
const explicitTotal = explicitIndices.reduce((sum, i) => sum + naturalWidths[i], 0);
|
|
17234
|
+
const budgetForExplicit = totalWidth - visualFixedTotal;
|
|
17235
|
+
const scaledExplicitWidths = /* @__PURE__ */ new Map();
|
|
17236
|
+
if (explicitTotal > 0 && budgetForExplicit > 0 && explicitTotal > budgetForExplicit) {
|
|
17237
|
+
const scale = budgetForExplicit / explicitTotal;
|
|
17238
|
+
let cumulative = 0;
|
|
17239
|
+
let cumulativeTarget = 0;
|
|
17240
|
+
let floored = false;
|
|
17241
|
+
for (const i of explicitIndices) {
|
|
17242
|
+
cumulativeTarget += naturalWidths[i] * scale;
|
|
17243
|
+
const target = Math.round(cumulativeTarget) - cumulative;
|
|
17244
|
+
const width = Math.max(MIN_COLUMN_WIDTH, target);
|
|
17245
|
+
if (width > target) floored = true;
|
|
17246
|
+
scaledExplicitWidths.set(i, width);
|
|
17247
|
+
cumulative += width;
|
|
17248
|
+
}
|
|
17249
|
+
const outcome = floored ? `scaled proportionally down, but at least one column hit the ${MIN_COLUMN_WIDTH}px minimum, so the table will still overflow.` : "scaled proportionally to fit.";
|
|
17250
|
+
warnings.push(
|
|
17251
|
+
`[openchart] TABLE_WIDTH_OVERFLOW: explicit column widths summed to ${explicitTotal}px, exceeding the ${budgetForExplicit}px available in a ${totalWidth}px-wide table; ${outcome}`
|
|
17252
|
+
);
|
|
17253
|
+
}
|
|
17254
|
+
const resolvedFixedWidths = naturalWidths.map((w, i) => scaledExplicitWidths.get(i) ?? w);
|
|
17255
|
+
const fixedTotal = resolvedFixedWidths.reduce((sum, w, i) => sum + (isFixed[i] ? w : 0), 0);
|
|
17100
17256
|
const flexTotal = naturalWidths.reduce((sum, w, i) => sum + (isFixed[i] ? 0 : w), 0);
|
|
17101
17257
|
const remainingWidth = totalWidth - fixedTotal;
|
|
17102
17258
|
const flexScale = flexTotal > 0 && remainingWidth > 0 ? remainingWidth / flexTotal : 1;
|
|
@@ -17105,7 +17261,10 @@ function resolveColumns(columns, data, totalWidth, theme) {
|
|
|
17105
17261
|
return {
|
|
17106
17262
|
key: col.key,
|
|
17107
17263
|
label: col.label ?? col.key,
|
|
17108
|
-
width: Math.max(
|
|
17264
|
+
width: Math.max(
|
|
17265
|
+
MIN_COLUMN_WIDTH,
|
|
17266
|
+
isFixed[i] ? resolvedFixedWidths[i] : Math.round(naturalWidths[i] * flexScale)
|
|
17267
|
+
),
|
|
17109
17268
|
sortable: col.sortable ?? true,
|
|
17110
17269
|
align: inferAlignment(col, type),
|
|
17111
17270
|
type,
|
|
@@ -17228,6 +17387,8 @@ function buildTotalRow(label, columns, resolvedColumns, rows) {
|
|
|
17228
17387
|
style: {},
|
|
17229
17388
|
cellType: "text"
|
|
17230
17389
|
};
|
|
17390
|
+
const col = columns[i];
|
|
17391
|
+
if (col.total === false) return blank;
|
|
17231
17392
|
if (resolved.type !== "quantitative" || !SUMMABLE.has(resolved.cellType)) return blank;
|
|
17232
17393
|
let sum = 0;
|
|
17233
17394
|
let seen = false;
|
|
@@ -17251,7 +17412,17 @@ function buildTotalRow(label, columns, resolvedColumns, rows) {
|
|
|
17251
17412
|
function compileTableLayout(spec, options, theme) {
|
|
17252
17413
|
const data = spec.data;
|
|
17253
17414
|
const darkMode = theme.isDark;
|
|
17254
|
-
const
|
|
17415
|
+
const columnWarnings = [];
|
|
17416
|
+
const resolvedColumns = resolveColumns(
|
|
17417
|
+
spec.columns,
|
|
17418
|
+
data,
|
|
17419
|
+
options.width,
|
|
17420
|
+
theme,
|
|
17421
|
+
// The deprecated `compact` flag renders condensed padding too.
|
|
17422
|
+
spec.density ?? (spec.compact ? "condensed" : void 0),
|
|
17423
|
+
columnWarnings
|
|
17424
|
+
);
|
|
17425
|
+
emitSpecWarnings(columnWarnings, options.onWarn);
|
|
17255
17426
|
const sort = resolveSort(spec, resolvedColumns, options.sort);
|
|
17256
17427
|
const searchIndex = spec.search ? buildSearchIndex(data, spec.columns) : /* @__PURE__ */ new Map();
|
|
17257
17428
|
let currentData = data;
|
|
@@ -17578,8 +17749,8 @@ function compileQuantitative(tilemapSpec, options, theme, chrome, fullArea, isDa
|
|
|
17578
17749
|
const hasEmptyTiles = tiles.some((t) => !t.hasData);
|
|
17579
17750
|
const noDataLabel = "No data";
|
|
17580
17751
|
const noDataLabelWidth = estimateTextWidth23(noDataLabel, 11);
|
|
17581
|
-
const
|
|
17582
|
-
const barWidth = Math.max(0, legendWidth -
|
|
17752
|
+
const noDataBlockWidth2 = hasEmptyTiles ? NO_DATA_BAR_GAP + legendBarHeight + NO_DATA_LABEL_GAP2 + noDataLabelWidth : 0;
|
|
17753
|
+
const barWidth = Math.max(0, legendWidth - noDataBlockWidth2);
|
|
17583
17754
|
const noDataX = legendX + barWidth + NO_DATA_BAR_GAP;
|
|
17584
17755
|
gradientLegend = {
|
|
17585
17756
|
type: "gradient",
|
|
@@ -18991,7 +19162,7 @@ function compileChart(spec, optionsInput) {
|
|
|
18991
19162
|
chartSpec = { ...chartSpec, data: runTransforms(chartSpec.data, rawTransforms) };
|
|
18992
19163
|
}
|
|
18993
19164
|
const breakpoint = getBreakpoint3(options.width);
|
|
18994
|
-
const heightClass =
|
|
19165
|
+
const heightClass = getHeightClass3(options.height);
|
|
18995
19166
|
let strategy = getLayoutStrategy(breakpoint, heightClass);
|
|
18996
19167
|
const economy = resolveChromeEconomy(options.width, options.height);
|
|
18997
19168
|
const rawSpec = expandedSpec;
|
|
@@ -19135,7 +19306,7 @@ function compileChart(spec, optionsInput) {
|
|
|
19135
19306
|
watermark = false;
|
|
19136
19307
|
chartSpec = { ...chartSpec, watermark: false };
|
|
19137
19308
|
}
|
|
19138
|
-
if (heightClass === "cramped" && !chartSpec.userExplicit.watermark) {
|
|
19309
|
+
if ((heightClass === "minimal" || heightClass === "cramped") && !chartSpec.userExplicit.watermark) {
|
|
19139
19310
|
watermark = false;
|
|
19140
19311
|
chartSpec = { ...chartSpec, watermark: false };
|
|
19141
19312
|
}
|
|
@@ -19333,6 +19504,16 @@ function compileChart(spec, optionsInput) {
|
|
|
19333
19504
|
if (endpointLabels.entries.length > 0 && endpointLabels.bounds.width > 0) {
|
|
19334
19505
|
obstacles.push({ ...endpointLabels.bounds, kind: "endpoint-label" });
|
|
19335
19506
|
}
|
|
19507
|
+
const chromeBottomY = dims.topPad + dims.chrome.topHeight;
|
|
19508
|
+
if (dims.chrome.topHeight > 0) {
|
|
19509
|
+
obstacles.push({
|
|
19510
|
+
x: 0,
|
|
19511
|
+
y: 0,
|
|
19512
|
+
width: dims.total.width,
|
|
19513
|
+
height: chromeBottomY,
|
|
19514
|
+
kind: "chrome"
|
|
19515
|
+
});
|
|
19516
|
+
}
|
|
19336
19517
|
const annotationMeasure = options.measureText ? (text, font) => options.measureText(text, font.fontSize, font.fontWeight).width : heuristicMeasure;
|
|
19337
19518
|
let annotations = computeAnnotations(chartSpec, {
|
|
19338
19519
|
scales,
|
|
@@ -19343,7 +19524,10 @@ function compileChart(spec, optionsInput) {
|
|
|
19343
19524
|
svg: { width: dims.total.width, height: dims.total.height },
|
|
19344
19525
|
measure: annotationMeasure,
|
|
19345
19526
|
fontFamily: theme.fonts.family,
|
|
19346
|
-
autoThin: chartSpec.autoThin
|
|
19527
|
+
autoThin: chartSpec.autoThin,
|
|
19528
|
+
// Hand-placed blocks skip every nudge pass, so the clamp is the only lever
|
|
19529
|
+
// that keeps an author's offset from parking a callout on the title.
|
|
19530
|
+
topBound: dims.chrome.topHeight > 0 ? chromeBottomY : void 0
|
|
19347
19531
|
});
|
|
19348
19532
|
if (options.dev) {
|
|
19349
19533
|
emitSpecWarnings(
|
|
@@ -19609,7 +19793,8 @@ function compileFaceted(chartSpec, renderSpec, facetChannel, facetDirection, opt
|
|
|
19609
19793
|
svg: { width: options.width, height: options.height },
|
|
19610
19794
|
measure: annotationMeasure,
|
|
19611
19795
|
fontFamily: theme.fonts.family,
|
|
19612
|
-
autoThin: panelSpecWithDomains.autoThin
|
|
19796
|
+
autoThin: panelSpecWithDomains.autoThin,
|
|
19797
|
+
topBound: dims.chrome.topHeight > 0 ? dims.topPad + dims.chrome.topHeight : void 0
|
|
19613
19798
|
});
|
|
19614
19799
|
if (chartSpec.autoThin && panelAnnotations.length > 1) {
|
|
19615
19800
|
const thinned = thinAnnotations(
|