@opendata-ai/openchart-engine 8.0.0-rc.11 → 8.0.0-rc.13
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 +139 -2
- package/dist/index.js +404 -84
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -10482,6 +10482,7 @@ function normalizeChartSpec(spec, warnings) {
|
|
|
10482
10482
|
data: spec.data,
|
|
10483
10483
|
encoding,
|
|
10484
10484
|
chrome: normalizeChrome(spec.chrome),
|
|
10485
|
+
chromeLayout: spec.chromeLayout,
|
|
10485
10486
|
metrics: spec.metrics,
|
|
10486
10487
|
seriesSearch: normalizeSeriesSearch(spec, encoding, warnings),
|
|
10487
10488
|
youDrawIt: normalizeYouDrawIt(spec),
|
|
@@ -10556,15 +10557,10 @@ function normalizeSankeySpec(spec, _warnings) {
|
|
|
10556
10557
|
};
|
|
10557
10558
|
}
|
|
10558
10559
|
function normalizeGraphSpec(spec) {
|
|
10559
|
-
const
|
|
10560
|
+
const layout = {
|
|
10560
10561
|
type: "force",
|
|
10561
|
-
chargeStrength: -300,
|
|
10562
|
-
linkDistance: 30
|
|
10563
|
-
};
|
|
10564
|
-
const layout = spec.layout ? {
|
|
10565
|
-
...defaultLayout,
|
|
10566
10562
|
...spec.layout
|
|
10567
|
-
}
|
|
10563
|
+
};
|
|
10568
10564
|
return {
|
|
10569
10565
|
type: "graph",
|
|
10570
10566
|
nodes: spec.nodes,
|
|
@@ -10576,7 +10572,10 @@ function normalizeGraphSpec(spec) {
|
|
|
10576
10572
|
annotations: normalizeAnnotations(spec.annotations),
|
|
10577
10573
|
theme: spec.theme ?? {},
|
|
10578
10574
|
darkMode: spec.darkMode ?? "off",
|
|
10579
|
-
watermark: spec.watermark ?? true
|
|
10575
|
+
watermark: spec.watermark ?? true,
|
|
10576
|
+
animation: spec.animation,
|
|
10577
|
+
interaction: spec.interaction,
|
|
10578
|
+
legend: spec.legend
|
|
10580
10579
|
};
|
|
10581
10580
|
}
|
|
10582
10581
|
function normalizeTileMapSpec(spec, warnings) {
|
|
@@ -11605,14 +11604,22 @@ function validateGraphSpec(spec, errors) {
|
|
|
11605
11604
|
}
|
|
11606
11605
|
if (spec.encoding && typeof spec.encoding === "object") {
|
|
11607
11606
|
const encoding = spec.encoding;
|
|
11608
|
-
const
|
|
11609
|
-
const
|
|
11610
|
-
|
|
11611
|
-
|
|
11612
|
-
|
|
11607
|
+
const nodeFields = /* @__PURE__ */ new Set();
|
|
11608
|
+
for (const node of nodes) {
|
|
11609
|
+
if (node && typeof node === "object") {
|
|
11610
|
+
for (const key of Object.keys(node)) nodeFields.add(key);
|
|
11611
|
+
}
|
|
11612
|
+
}
|
|
11613
|
+
const edgeFields = /* @__PURE__ */ new Set();
|
|
11614
|
+
for (const edge of edges) {
|
|
11615
|
+
if (edge && typeof edge === "object") {
|
|
11616
|
+
for (const key of Object.keys(edge)) edgeFields.add(key);
|
|
11617
|
+
}
|
|
11618
|
+
}
|
|
11619
|
+
const nodeChannels = ["nodeColor", "nodeSize", "nodeOpacity", "nodeLabel"];
|
|
11613
11620
|
for (const channel of nodeChannels) {
|
|
11614
11621
|
const ch = encoding[channel];
|
|
11615
|
-
if (ch?.field && typeof ch.field === "string" && !nodeFields.has(ch.field)) {
|
|
11622
|
+
if (ch?.field && typeof ch.field === "string" && nodes.length > 0 && !nodeFields.has(ch.field)) {
|
|
11616
11623
|
errors.push({
|
|
11617
11624
|
message: `Spec error: encoding.${channel}.field "${ch.field}" does not exist on nodes. Available fields: ${[...nodeFields].join(", ")}`,
|
|
11618
11625
|
path: `encoding.${channel}.field`,
|
|
@@ -11621,10 +11628,10 @@ function validateGraphSpec(spec, errors) {
|
|
|
11621
11628
|
});
|
|
11622
11629
|
}
|
|
11623
11630
|
}
|
|
11624
|
-
const edgeChannels = ["edgeColor", "edgeWidth"];
|
|
11631
|
+
const edgeChannels = ["edgeColor", "edgeWidth", "edgeStyle"];
|
|
11625
11632
|
for (const channel of edgeChannels) {
|
|
11626
11633
|
const ch = encoding[channel];
|
|
11627
|
-
if (ch?.field && typeof ch.field === "string" &&
|
|
11634
|
+
if (ch?.field && typeof ch.field === "string" && edges.length > 0 && !edgeFields.has(ch.field)) {
|
|
11628
11635
|
errors.push({
|
|
11629
11636
|
message: `Spec error: encoding.${channel}.field "${ch.field}" does not exist on edges. Available fields: ${[...edgeFields].join(", ")}`,
|
|
11630
11637
|
path: `encoding.${channel}.field`,
|
|
@@ -12348,6 +12355,36 @@ ${errorMessages}`);
|
|
|
12348
12355
|
return { spec: normalized, warnings };
|
|
12349
12356
|
}
|
|
12350
12357
|
|
|
12358
|
+
// src/layout/shared.ts
|
|
12359
|
+
function chromeToInput(chrome) {
|
|
12360
|
+
return {
|
|
12361
|
+
eyebrow: chrome.eyebrow,
|
|
12362
|
+
title: chrome.title,
|
|
12363
|
+
subtitle: chrome.subtitle,
|
|
12364
|
+
source: chrome.source,
|
|
12365
|
+
byline: chrome.byline,
|
|
12366
|
+
footer: chrome.footer,
|
|
12367
|
+
brand: chrome.brand
|
|
12368
|
+
};
|
|
12369
|
+
}
|
|
12370
|
+
function scalePadding(basePadding, width, height) {
|
|
12371
|
+
const minDim = Math.min(width, height);
|
|
12372
|
+
if (minDim >= 500) return basePadding;
|
|
12373
|
+
if (minDim <= 200) return Math.max(Math.round(basePadding * 0.5), 4);
|
|
12374
|
+
const t = (minDim - 200) / 300;
|
|
12375
|
+
return Math.max(Math.round(basePadding * (0.5 + t * 0.5)), 4);
|
|
12376
|
+
}
|
|
12377
|
+
function bottomMargin(bottomHeight, padding, xAxisHeight) {
|
|
12378
|
+
return padding + bottomHeight + xAxisHeight;
|
|
12379
|
+
}
|
|
12380
|
+
var INLINE_TICK_OVERHANG_PAD = 6;
|
|
12381
|
+
function resolveChromeLayout(spec, options) {
|
|
12382
|
+
const encoding = spec?.encoding;
|
|
12383
|
+
const isFaceted = !!(encoding?.facet || encoding?.row || encoding?.column);
|
|
12384
|
+
if (isFaceted) return "subtract";
|
|
12385
|
+
return spec?.chromeLayout ?? options?.chromeLayout ?? "subtract";
|
|
12386
|
+
}
|
|
12387
|
+
|
|
12351
12388
|
// src/barlist/compile-barlist.ts
|
|
12352
12389
|
var DEFAULT_ROW_GAP = 8;
|
|
12353
12390
|
var LABEL_BAR_GAP = 12;
|
|
@@ -12395,14 +12432,19 @@ function compileBarList(spec, options) {
|
|
|
12395
12432
|
watermark
|
|
12396
12433
|
);
|
|
12397
12434
|
const padding = theme.spacing.padding;
|
|
12435
|
+
const chromeLayout = resolveChromeLayout(
|
|
12436
|
+
spec,
|
|
12437
|
+
options
|
|
12438
|
+
);
|
|
12439
|
+
const grownHeight = chromeLayout === "grow" ? options.height + chrome.topHeight + chrome.bottomHeight : options.height;
|
|
12398
12440
|
const fullArea = {
|
|
12399
12441
|
x: padding,
|
|
12400
12442
|
y: padding + chrome.topHeight,
|
|
12401
12443
|
width: options.width - padding * 2,
|
|
12402
|
-
height: options.height - chrome.topHeight - chrome.bottomHeight - padding * 2
|
|
12444
|
+
height: chromeLayout === "grow" ? options.height - padding * 2 : options.height - chrome.topHeight - chrome.bottomHeight - padding * 2
|
|
12403
12445
|
};
|
|
12404
12446
|
if (fullArea.width <= 0 || fullArea.height <= 0) {
|
|
12405
|
-
return emptyLayout2(chrome, theme, options, watermark);
|
|
12447
|
+
return emptyLayout2(chrome, theme, { ...options, height: grownHeight }, watermark);
|
|
12406
12448
|
}
|
|
12407
12449
|
const labelField = barlistSpec.encoding.label.field;
|
|
12408
12450
|
const valueField = barlistSpec.encoding.value.field;
|
|
@@ -12587,7 +12629,7 @@ function compileBarList(spec, options) {
|
|
|
12587
12629
|
a11y,
|
|
12588
12630
|
theme,
|
|
12589
12631
|
width: options.width,
|
|
12590
|
-
height:
|
|
12632
|
+
height: grownHeight,
|
|
12591
12633
|
animation: resolvedAnimation,
|
|
12592
12634
|
watermark,
|
|
12593
12635
|
measureText
|
|
@@ -14881,30 +14923,6 @@ function computeAxes(scales, chartArea, strategy, theme, measureText, dataContex
|
|
|
14881
14923
|
return result;
|
|
14882
14924
|
}
|
|
14883
14925
|
|
|
14884
|
-
// src/layout/shared.ts
|
|
14885
|
-
function chromeToInput(chrome) {
|
|
14886
|
-
return {
|
|
14887
|
-
eyebrow: chrome.eyebrow,
|
|
14888
|
-
title: chrome.title,
|
|
14889
|
-
subtitle: chrome.subtitle,
|
|
14890
|
-
source: chrome.source,
|
|
14891
|
-
byline: chrome.byline,
|
|
14892
|
-
footer: chrome.footer,
|
|
14893
|
-
brand: chrome.brand
|
|
14894
|
-
};
|
|
14895
|
-
}
|
|
14896
|
-
function scalePadding(basePadding, width, height) {
|
|
14897
|
-
const minDim = Math.min(width, height);
|
|
14898
|
-
if (minDim >= 500) return basePadding;
|
|
14899
|
-
if (minDim <= 200) return Math.max(Math.round(basePadding * 0.5), 4);
|
|
14900
|
-
const t = (minDim - 200) / 300;
|
|
14901
|
-
return Math.max(Math.round(basePadding * (0.5 + t * 0.5)), 4);
|
|
14902
|
-
}
|
|
14903
|
-
function bottomMargin(bottomHeight, padding, xAxisHeight) {
|
|
14904
|
-
return padding + bottomHeight + xAxisHeight;
|
|
14905
|
-
}
|
|
14906
|
-
var INLINE_TICK_OVERHANG_PAD = 6;
|
|
14907
|
-
|
|
14908
14926
|
// src/layout/plan.ts
|
|
14909
14927
|
function createMeasureFn(measureText) {
|
|
14910
14928
|
if (measureText) {
|
|
@@ -15126,7 +15144,9 @@ function resolveLayoutPlan(chartSpec, renderSpec, options, theme, strategy, wate
|
|
|
15126
15144
|
if (hasTopLegend) topMargin += TOP_LEGEND_GAP_ABOVE + legendContent.height + gap;
|
|
15127
15145
|
topMargin += effectiveTopAxisGap;
|
|
15128
15146
|
const bMargin = bottomMargin(chrome.bottomHeight, padding, xAxisExtent);
|
|
15129
|
-
const
|
|
15147
|
+
const chromeLayout = resolveChromeLayout(renderSpec, options);
|
|
15148
|
+
const effectiveHeight = chromeLayout === "grow" ? height + chrome.topHeight + chrome.bottomHeight : height;
|
|
15149
|
+
const chartHeight = Math.max(0, effectiveHeight - topMargin - bMargin);
|
|
15130
15150
|
const rightMargin = hPad + (isRadial ? hPad : axisMargin);
|
|
15131
15151
|
const rightAxisReserve = options.rightAxisReserve ?? 0;
|
|
15132
15152
|
const provisionalArea = {
|
|
@@ -18006,11 +18026,15 @@ function compileMap(spec, options) {
|
|
|
18006
18026
|
watermark
|
|
18007
18027
|
);
|
|
18008
18028
|
const padding = getBreakpoint(options.width) === "compact" ? Math.max(HPAD_COMPACT_MIN2, Math.round(theme.spacing.padding * HPAD_COMPACT_FRACTION2)) : theme.spacing.padding;
|
|
18029
|
+
const chromeLayout = resolveChromeLayout(
|
|
18030
|
+
spec,
|
|
18031
|
+
options
|
|
18032
|
+
);
|
|
18009
18033
|
const fullArea = {
|
|
18010
18034
|
x: padding,
|
|
18011
18035
|
y: padding + chrome.topHeight,
|
|
18012
18036
|
width: options.width - padding * 2,
|
|
18013
|
-
height: options.height - chrome.topHeight - chrome.bottomHeight - padding * 2
|
|
18037
|
+
height: chromeLayout === "grow" ? options.height - padding * 2 : options.height - chrome.topHeight - chrome.bottomHeight - padding * 2
|
|
18014
18038
|
};
|
|
18015
18039
|
if (fullArea.width <= 0 || fullArea.height <= 0) {
|
|
18016
18040
|
return emptyLayout3(chrome, theme, options, watermark);
|
|
@@ -18907,6 +18931,65 @@ import {
|
|
|
18907
18931
|
resolveTheme as resolveTheme4
|
|
18908
18932
|
} from "@opendata-ai/openchart-core";
|
|
18909
18933
|
|
|
18934
|
+
// src/graphs/animation.ts
|
|
18935
|
+
var ENTER_DEFAULT = {
|
|
18936
|
+
duration: 600,
|
|
18937
|
+
ease: "smooth",
|
|
18938
|
+
stagger: true,
|
|
18939
|
+
cameraFit: true
|
|
18940
|
+
};
|
|
18941
|
+
var UPDATE_DEFAULT = { duration: 300, ease: "smooth" };
|
|
18942
|
+
var EXIT_DEFAULT = { duration: 300, ease: "smooth" };
|
|
18943
|
+
var CAMERA_DEFAULT = { duration: "auto", ease: "smooth" };
|
|
18944
|
+
var HOVER_DEFAULT = { duration: 150, ease: "smooth" };
|
|
18945
|
+
function fullDefaults() {
|
|
18946
|
+
return {
|
|
18947
|
+
enter: { ...ENTER_DEFAULT },
|
|
18948
|
+
update: { ...UPDATE_DEFAULT },
|
|
18949
|
+
exit: { ...EXIT_DEFAULT },
|
|
18950
|
+
camera: { ...CAMERA_DEFAULT },
|
|
18951
|
+
hover: { ...HOVER_DEFAULT }
|
|
18952
|
+
};
|
|
18953
|
+
}
|
|
18954
|
+
function resolveGraphAnimation(spec) {
|
|
18955
|
+
if (spec === void 0 || spec === true) return fullDefaults();
|
|
18956
|
+
if (spec === false) return void 0;
|
|
18957
|
+
return {
|
|
18958
|
+
enter: resolveEnter(spec.enter),
|
|
18959
|
+
update: resolveDurationPhase(spec.update, UPDATE_DEFAULT),
|
|
18960
|
+
exit: resolveDurationPhase(spec.exit, EXIT_DEFAULT),
|
|
18961
|
+
camera: resolveCamera(spec.camera),
|
|
18962
|
+
hover: resolveDurationPhase(spec.hover, HOVER_DEFAULT)
|
|
18963
|
+
};
|
|
18964
|
+
}
|
|
18965
|
+
function resolveEnter(phase) {
|
|
18966
|
+
if (phase === false) return null;
|
|
18967
|
+
if (phase === void 0 || phase === true) return { ...ENTER_DEFAULT };
|
|
18968
|
+
return {
|
|
18969
|
+
duration: phase.duration ?? ENTER_DEFAULT.duration,
|
|
18970
|
+
ease: phase.ease ?? ENTER_DEFAULT.ease,
|
|
18971
|
+
stagger: phase.stagger !== false,
|
|
18972
|
+
cameraFit: ENTER_DEFAULT.cameraFit
|
|
18973
|
+
};
|
|
18974
|
+
}
|
|
18975
|
+
function resolveDurationPhase(phase, defaults) {
|
|
18976
|
+
if (phase === false) return null;
|
|
18977
|
+
if (phase === void 0 || phase === true)
|
|
18978
|
+
return { duration: defaults.duration, ease: defaults.ease };
|
|
18979
|
+
return {
|
|
18980
|
+
duration: phase.duration ?? defaults.duration,
|
|
18981
|
+
ease: phase.ease ?? defaults.ease
|
|
18982
|
+
};
|
|
18983
|
+
}
|
|
18984
|
+
function resolveCamera(phase) {
|
|
18985
|
+
if (phase === false) return null;
|
|
18986
|
+
if (phase === void 0 || phase === true) return { ...CAMERA_DEFAULT };
|
|
18987
|
+
return {
|
|
18988
|
+
duration: phase.duration ?? CAMERA_DEFAULT.duration,
|
|
18989
|
+
ease: phase.ease ?? CAMERA_DEFAULT.ease
|
|
18990
|
+
};
|
|
18991
|
+
}
|
|
18992
|
+
|
|
18910
18993
|
// src/graphs/encoding.ts
|
|
18911
18994
|
var DEFAULT_NODE_RADIUS = 5;
|
|
18912
18995
|
var MIN_NODE_RADIUS = 3;
|
|
@@ -18946,16 +19029,42 @@ function computeDegrees(nodes, edges) {
|
|
|
18946
19029
|
}
|
|
18947
19030
|
return degrees2;
|
|
18948
19031
|
}
|
|
19032
|
+
function resolveCategoricalDomain(values, sort, scaleDomain) {
|
|
19033
|
+
if (Array.isArray(scaleDomain) && scaleDomain.length > 0) {
|
|
19034
|
+
return scaleDomain.map((v) => String(v));
|
|
19035
|
+
}
|
|
19036
|
+
const seen = [];
|
|
19037
|
+
const set = /* @__PURE__ */ new Set();
|
|
19038
|
+
for (const v of values) {
|
|
19039
|
+
if (!set.has(v)) {
|
|
19040
|
+
set.add(v);
|
|
19041
|
+
seen.push(v);
|
|
19042
|
+
}
|
|
19043
|
+
}
|
|
19044
|
+
if (sort === null) return seen;
|
|
19045
|
+
if (Array.isArray(sort)) {
|
|
19046
|
+
const pinned = sort.filter((v) => set.has(v));
|
|
19047
|
+
const pinnedSet = new Set(pinned);
|
|
19048
|
+
const rest = seen.filter((v) => !pinnedSet.has(v));
|
|
19049
|
+
return [...pinned, ...rest];
|
|
19050
|
+
}
|
|
19051
|
+
const sorted = [...seen].sort((a, b) => a.localeCompare(b));
|
|
19052
|
+
return sort === "descending" ? sorted.reverse() : sorted;
|
|
19053
|
+
}
|
|
18949
19054
|
function resolveNodeVisuals(nodes, encoding, edges, theme, nodeOverrides) {
|
|
18950
19055
|
const degrees2 = computeDegrees(nodes, edges);
|
|
18951
19056
|
const maxDegree = Math.max(1, ...degrees2.values());
|
|
18952
19057
|
let sizeScale;
|
|
18953
19058
|
if (encoding.nodeSize?.field) {
|
|
18954
19059
|
const field = encoding.nodeSize.field;
|
|
19060
|
+
const scaleConfig = encoding.nodeSize.scale;
|
|
18955
19061
|
const values = nodes.map((n) => Number(n[field])).filter((v) => Number.isFinite(v));
|
|
18956
19062
|
const sizeMin = min(values) ?? 0;
|
|
18957
19063
|
const sizeMax = max(values) ?? 1;
|
|
18958
|
-
|
|
19064
|
+
const domain = scaleConfig?.domain && scaleConfig.domain.length === 2 ? scaleConfig.domain : [sizeMin, sizeMax];
|
|
19065
|
+
const range3 = scaleConfig?.range && scaleConfig.range.length >= 2 ? [Number(scaleConfig.range[0]), Number(scaleConfig.range[1])] : [MIN_NODE_RADIUS, MAX_NODE_RADIUS];
|
|
19066
|
+
const ctor = scaleConfig?.type === "linear" ? linear2 : sqrt;
|
|
19067
|
+
sizeScale = ctor().domain(domain).range(range3);
|
|
18959
19068
|
}
|
|
18960
19069
|
let colorFn;
|
|
18961
19070
|
if (encoding.nodeColor?.field) {
|
|
@@ -18976,13 +19085,28 @@ function resolveNodeVisuals(nodes, encoding, edges, theme, nodeOverrides) {
|
|
|
18976
19085
|
return Number.isFinite(val) ? colorScale(val) : theme.colors.categorical[0];
|
|
18977
19086
|
};
|
|
18978
19087
|
} else {
|
|
18979
|
-
const domain =
|
|
19088
|
+
const domain = resolveCategoricalDomain(
|
|
19089
|
+
nodes.map((n) => String(n[field] ?? "")),
|
|
19090
|
+
encoding.nodeColor.sort,
|
|
19091
|
+
scaleConfig?.domain
|
|
19092
|
+
);
|
|
18980
19093
|
const range3 = scaleConfig?.range && scaleConfig.range.length > 0 ? scaleConfig.range : theme.colors.categorical;
|
|
18981
19094
|
const ordinalScale = ordinal().domain(domain).range(range3);
|
|
18982
19095
|
colorFn = (node) => ordinalScale(String(node[field] ?? ""));
|
|
18983
19096
|
}
|
|
18984
19097
|
}
|
|
18985
19098
|
const defaultColor = theme.colors.categorical[0];
|
|
19099
|
+
let opacityScale;
|
|
19100
|
+
if (encoding.nodeOpacity?.field) {
|
|
19101
|
+
const field = encoding.nodeOpacity.field;
|
|
19102
|
+
const scaleConfig = encoding.nodeOpacity.scale;
|
|
19103
|
+
const values = nodes.map((n) => Number(n[field])).filter((v) => Number.isFinite(v));
|
|
19104
|
+
const opMin = min(values) ?? 0;
|
|
19105
|
+
const opMax = max(values) ?? 1;
|
|
19106
|
+
const domain = scaleConfig?.domain && scaleConfig.domain.length === 2 ? scaleConfig.domain : [opMin, opMax];
|
|
19107
|
+
const range3 = scaleConfig?.range && scaleConfig.range.length >= 2 ? [Number(scaleConfig.range[0]), Number(scaleConfig.range[1])] : [0.25, 1];
|
|
19108
|
+
opacityScale = linear2().domain(domain).range(range3);
|
|
19109
|
+
}
|
|
18986
19110
|
return nodes.map((node) => {
|
|
18987
19111
|
let radius = DEFAULT_NODE_RADIUS;
|
|
18988
19112
|
if (sizeScale && encoding.nodeSize?.field) {
|
|
@@ -18991,6 +19115,13 @@ function resolveNodeVisuals(nodes, encoding, edges, theme, nodeOverrides) {
|
|
|
18991
19115
|
radius = sizeScale(val);
|
|
18992
19116
|
}
|
|
18993
19117
|
}
|
|
19118
|
+
let opacity = 1;
|
|
19119
|
+
if (opacityScale && encoding.nodeOpacity?.field) {
|
|
19120
|
+
const val = Number(node[encoding.nodeOpacity.field]);
|
|
19121
|
+
if (Number.isFinite(val)) {
|
|
19122
|
+
opacity = opacityScale(val);
|
|
19123
|
+
}
|
|
19124
|
+
}
|
|
18994
19125
|
const fill = colorFn ? colorFn(node) : defaultColor;
|
|
18995
19126
|
const stroke = darkenColor(fill);
|
|
18996
19127
|
let label;
|
|
@@ -19019,6 +19150,7 @@ function resolveNodeVisuals(nodes, encoding, edges, theme, nodeOverrides) {
|
|
|
19019
19150
|
label,
|
|
19020
19151
|
labelPriority: finalLabelPriority,
|
|
19021
19152
|
community: void 0,
|
|
19153
|
+
opacity,
|
|
19022
19154
|
data
|
|
19023
19155
|
};
|
|
19024
19156
|
});
|
|
@@ -19051,7 +19183,11 @@ function resolveEdgeVisuals(edges, encoding, theme) {
|
|
|
19051
19183
|
return Number.isFinite(val) ? colorScale(val) : hexWithOpacity(theme.colors.axis, 0.4);
|
|
19052
19184
|
};
|
|
19053
19185
|
} else {
|
|
19054
|
-
const domain =
|
|
19186
|
+
const domain = resolveCategoricalDomain(
|
|
19187
|
+
edges.map((e) => String(e[field] ?? "")),
|
|
19188
|
+
encoding.edgeColor.sort,
|
|
19189
|
+
scaleConfig?.domain
|
|
19190
|
+
);
|
|
19055
19191
|
const range3 = scaleConfig?.range && scaleConfig.range.length > 0 ? scaleConfig.range : theme.colors.categorical;
|
|
19056
19192
|
const ordinalScale = ordinal().domain(domain).range(range3);
|
|
19057
19193
|
edgeColorFn = (edge) => ordinalScale(String(edge[field] ?? ""));
|
|
@@ -19062,10 +19198,14 @@ function resolveEdgeVisuals(edges, encoding, theme) {
|
|
|
19062
19198
|
let styleFn;
|
|
19063
19199
|
if (encoding.edgeStyle?.field) {
|
|
19064
19200
|
const field = encoding.edgeStyle.field;
|
|
19065
|
-
const
|
|
19201
|
+
const domain = resolveCategoricalDomain(
|
|
19202
|
+
edges.map((e) => String(e[field] ?? "")),
|
|
19203
|
+
encoding.edgeStyle.sort,
|
|
19204
|
+
encoding.edgeStyle.scale?.domain
|
|
19205
|
+
);
|
|
19066
19206
|
const styleMap = /* @__PURE__ */ new Map();
|
|
19067
|
-
for (let i = 0; i <
|
|
19068
|
-
styleMap.set(
|
|
19207
|
+
for (let i = 0; i < domain.length; i++) {
|
|
19208
|
+
styleMap.set(domain[i], EDGE_STYLES[i % EDGE_STYLES.length]);
|
|
19069
19209
|
}
|
|
19070
19210
|
styleFn = (edge) => styleMap.get(String(edge[field] ?? "")) ?? "solid";
|
|
19071
19211
|
}
|
|
@@ -19123,12 +19263,49 @@ function applyCommunityColors(nodes, colorMap) {
|
|
|
19123
19263
|
}
|
|
19124
19264
|
}
|
|
19125
19265
|
|
|
19266
|
+
// src/graphs/interaction.ts
|
|
19267
|
+
var DEFAULT_DIM_OPACITY = 0.15;
|
|
19268
|
+
var DEFAULT_CURSOR_RADIUS = 80;
|
|
19269
|
+
var DEFAULT_CURSOR_STRENGTH = 30;
|
|
19270
|
+
function resolveGraphInteraction(cfg) {
|
|
19271
|
+
const hover = cfg?.hover;
|
|
19272
|
+
const cursor = cfg?.cursorRepulsion;
|
|
19273
|
+
let cursorRepulsion = null;
|
|
19274
|
+
if (cursor === true) {
|
|
19275
|
+
cursorRepulsion = { radius: DEFAULT_CURSOR_RADIUS, strength: DEFAULT_CURSOR_STRENGTH };
|
|
19276
|
+
} else if (cursor && typeof cursor === "object") {
|
|
19277
|
+
cursorRepulsion = {
|
|
19278
|
+
radius: cursor.radius ?? DEFAULT_CURSOR_RADIUS,
|
|
19279
|
+
strength: cursor.strength ?? DEFAULT_CURSOR_STRENGTH
|
|
19280
|
+
};
|
|
19281
|
+
}
|
|
19282
|
+
return {
|
|
19283
|
+
hoverMode: hover?.mode ?? "neighbors",
|
|
19284
|
+
dimOpacity: hover?.dimOpacity ?? DEFAULT_DIM_OPACITY,
|
|
19285
|
+
selectFlyTo: cfg?.select?.flyTo ?? false,
|
|
19286
|
+
cursorRepulsion,
|
|
19287
|
+
springyDrag: cfg?.springyDrag ?? false
|
|
19288
|
+
};
|
|
19289
|
+
}
|
|
19290
|
+
|
|
19126
19291
|
// src/graphs/compile-graph.ts
|
|
19127
19292
|
var graphNumberFormatter = defaultNumberFormatter8({ allIntegers: false, surface: "chart" });
|
|
19128
19293
|
var SWATCH_SIZE2 = 12;
|
|
19129
19294
|
var SWATCH_GAP2 = 6;
|
|
19130
19295
|
var ENTRY_GAP2 = 16;
|
|
19131
|
-
|
|
19296
|
+
var ENERGY_PRESETS = {
|
|
19297
|
+
gentle: { chargeStrength: -150, velocityDecay: 0.5 },
|
|
19298
|
+
balanced: { chargeStrength: -300, velocityDecay: 0.4 },
|
|
19299
|
+
energetic: { chargeStrength: -600, velocityDecay: 0.3 }
|
|
19300
|
+
};
|
|
19301
|
+
var SETTLE_PRESETS = {
|
|
19302
|
+
quick: 0.05,
|
|
19303
|
+
balanced: 0.0228,
|
|
19304
|
+
thorough: 0.01
|
|
19305
|
+
};
|
|
19306
|
+
var DEFAULT_WARMUP_TICKS = 100;
|
|
19307
|
+
var DEFAULT_WARMUP_BUDGET_MS = 250;
|
|
19308
|
+
function buildGraphLegend(nodes, communityColorMap, hasCommunities, theme, nodeColorField, legendOrder) {
|
|
19132
19309
|
const labelStyle = {
|
|
19133
19310
|
fontFamily: theme.fonts.family,
|
|
19134
19311
|
fontSize: theme.fonts.sizes.small,
|
|
@@ -19138,25 +19315,35 @@ function buildGraphLegend(nodes, communityColorMap, hasCommunities, theme, nodeC
|
|
|
19138
19315
|
};
|
|
19139
19316
|
let entries;
|
|
19140
19317
|
if (hasCommunities && communityColorMap.size > 0) {
|
|
19318
|
+
const counts = /* @__PURE__ */ new Map();
|
|
19319
|
+
for (const node of nodes) {
|
|
19320
|
+
if (node.community != null) {
|
|
19321
|
+
counts.set(node.community, (counts.get(node.community) ?? 0) + 1);
|
|
19322
|
+
}
|
|
19323
|
+
}
|
|
19141
19324
|
entries = [...communityColorMap.entries()].map(([label, color2]) => ({
|
|
19142
19325
|
label,
|
|
19143
19326
|
color: color2,
|
|
19144
19327
|
shape: "circle",
|
|
19145
|
-
active: true
|
|
19328
|
+
active: true,
|
|
19329
|
+
count: counts.get(label) ?? 0
|
|
19146
19330
|
}));
|
|
19147
19331
|
} else if (nodeColorField) {
|
|
19148
19332
|
const categoryColors = /* @__PURE__ */ new Map();
|
|
19333
|
+
const categoryCounts = /* @__PURE__ */ new Map();
|
|
19149
19334
|
for (const node of nodes) {
|
|
19150
19335
|
const category = String(node.data[nodeColorField] ?? node.label ?? node.id);
|
|
19151
19336
|
if (!categoryColors.has(category)) {
|
|
19152
19337
|
categoryColors.set(category, node.fill);
|
|
19153
19338
|
}
|
|
19339
|
+
categoryCounts.set(category, (categoryCounts.get(category) ?? 0) + 1);
|
|
19154
19340
|
}
|
|
19155
|
-
entries = categoryColors.size <= 1 ? [] : [...categoryColors.
|
|
19341
|
+
entries = categoryColors.size <= 1 ? [] : (legendOrder ?? [...categoryColors.keys()]).filter((label) => categoryColors.has(label)).map((label) => ({
|
|
19156
19342
|
label,
|
|
19157
|
-
color:
|
|
19343
|
+
color: categoryColors.get(label),
|
|
19158
19344
|
shape: "circle",
|
|
19159
|
-
active: true
|
|
19345
|
+
active: true,
|
|
19346
|
+
count: categoryCounts.get(label) ?? 0
|
|
19160
19347
|
}));
|
|
19161
19348
|
} else {
|
|
19162
19349
|
entries = [];
|
|
@@ -19172,6 +19359,30 @@ function buildGraphLegend(nodes, communityColorMap, hasCommunities, theme, nodeC
|
|
|
19172
19359
|
swatchChipFill: theme.colors.annotationFill
|
|
19173
19360
|
};
|
|
19174
19361
|
}
|
|
19362
|
+
function buildEdgeLegend(edges, encoding) {
|
|
19363
|
+
const field = encoding.edgeColor?.field;
|
|
19364
|
+
if (!field || (encoding.edgeColor?.type ?? "nominal") === "quantitative") return void 0;
|
|
19365
|
+
const categoryColors = /* @__PURE__ */ new Map();
|
|
19366
|
+
const categoryCounts = /* @__PURE__ */ new Map();
|
|
19367
|
+
for (const edge of edges) {
|
|
19368
|
+
const category = String(edge.data[field] ?? "");
|
|
19369
|
+
if (!categoryColors.has(category)) categoryColors.set(category, edge.stroke);
|
|
19370
|
+
categoryCounts.set(category, (categoryCounts.get(category) ?? 0) + 1);
|
|
19371
|
+
}
|
|
19372
|
+
if (categoryColors.size <= 1) return void 0;
|
|
19373
|
+
const order = resolveCategoricalDomain(
|
|
19374
|
+
edges.map((e) => String(e.data[field] ?? "")),
|
|
19375
|
+
encoding.edgeColor?.sort,
|
|
19376
|
+
encoding.edgeColor?.scale?.domain
|
|
19377
|
+
);
|
|
19378
|
+
return order.filter((label) => categoryColors.has(label)).map((label) => ({
|
|
19379
|
+
label,
|
|
19380
|
+
color: categoryColors.get(label),
|
|
19381
|
+
shape: "line",
|
|
19382
|
+
active: true,
|
|
19383
|
+
count: categoryCounts.get(label) ?? 0
|
|
19384
|
+
}));
|
|
19385
|
+
}
|
|
19175
19386
|
function buildGraphTooltips(nodes) {
|
|
19176
19387
|
const descriptors = /* @__PURE__ */ new Map();
|
|
19177
19388
|
for (const node of nodes) {
|
|
@@ -19198,6 +19409,21 @@ function buildGraphTooltips(nodes) {
|
|
|
19198
19409
|
}
|
|
19199
19410
|
return descriptors;
|
|
19200
19411
|
}
|
|
19412
|
+
function buildEdgeTooltip(edge) {
|
|
19413
|
+
const fields = [];
|
|
19414
|
+
for (const [key, value2] of Object.entries(edge.data)) {
|
|
19415
|
+
if (key === "source" || key === "target") continue;
|
|
19416
|
+
if (value2 == null) continue;
|
|
19417
|
+
fields.push({
|
|
19418
|
+
label: key,
|
|
19419
|
+
value: typeof value2 === "number" ? graphNumberFormatter(value2) : String(value2)
|
|
19420
|
+
});
|
|
19421
|
+
}
|
|
19422
|
+
return {
|
|
19423
|
+
title: `${edge.source} \u2192 ${edge.target}`,
|
|
19424
|
+
fields
|
|
19425
|
+
};
|
|
19426
|
+
}
|
|
19201
19427
|
function compileGraph(spec, options) {
|
|
19202
19428
|
const { spec: normalized, warnings } = compile(spec);
|
|
19203
19429
|
emitSpecWarnings(warnings, options.onWarn);
|
|
@@ -19207,6 +19433,16 @@ function compileGraph(spec, options) {
|
|
|
19207
19433
|
);
|
|
19208
19434
|
}
|
|
19209
19435
|
const graphSpec = normalized;
|
|
19436
|
+
for (const [name, ch] of [
|
|
19437
|
+
["nodeColor", graphSpec.encoding.nodeColor],
|
|
19438
|
+
["edgeColor", graphSpec.encoding.edgeColor]
|
|
19439
|
+
]) {
|
|
19440
|
+
if (ch?.sort != null && ch.type === "quantitative") {
|
|
19441
|
+
options.onWarn?.(
|
|
19442
|
+
`encoding.${name}.sort is ignored for a quantitative field (sort only orders categorical domains).`
|
|
19443
|
+
);
|
|
19444
|
+
}
|
|
19445
|
+
}
|
|
19210
19446
|
const rawWatermark = spec.watermark;
|
|
19211
19447
|
const watermark = rawWatermark !== void 0 ? graphSpec.watermark : options.watermark ?? true;
|
|
19212
19448
|
const mergedThemeConfig = options.theme ? { ...graphSpec.theme, ...options.theme } : graphSpec.theme;
|
|
@@ -19232,13 +19468,30 @@ function compileGraph(spec, options) {
|
|
|
19232
19468
|
}
|
|
19233
19469
|
const compiledEdges = resolveEdgeVisuals(graphSpec.edges, graphSpec.encoding, theme);
|
|
19234
19470
|
const useCommunitiesForLegend = hasCommunities && !hasNodeColorEncoding;
|
|
19471
|
+
const nodeColorField = graphSpec.encoding.nodeColor?.field;
|
|
19472
|
+
const legendOrder = nodeColorField ? resolveCategoricalDomain(
|
|
19473
|
+
compiledNodes.map((n) => String(n.data[nodeColorField] ?? n.label ?? n.id)),
|
|
19474
|
+
graphSpec.encoding.nodeColor?.sort,
|
|
19475
|
+
graphSpec.encoding.nodeColor?.scale?.domain
|
|
19476
|
+
) : void 0;
|
|
19235
19477
|
const legend = buildGraphLegend(
|
|
19236
19478
|
compiledNodes,
|
|
19237
19479
|
communityColorMap,
|
|
19238
19480
|
useCommunitiesForLegend,
|
|
19239
19481
|
theme,
|
|
19240
|
-
|
|
19482
|
+
nodeColorField,
|
|
19483
|
+
legendOrder
|
|
19241
19484
|
);
|
|
19485
|
+
const edgeLegend = buildEdgeLegend(compiledEdges, graphSpec.encoding);
|
|
19486
|
+
const legendField = nodeColorField ?? (useCommunitiesForLegend ? clusteringField ?? null : null);
|
|
19487
|
+
let initialHighlight;
|
|
19488
|
+
if (nodeColorField && graphSpec.encoding.nodeColor?.highlight != null) {
|
|
19489
|
+
const raw = graphSpec.encoding.nodeColor.highlight;
|
|
19490
|
+
const requested = Array.isArray(raw) ? raw : [raw];
|
|
19491
|
+
const available = new Set(legendOrder ?? []);
|
|
19492
|
+
const values = requested.filter((v) => available.has(v));
|
|
19493
|
+
if (values.length > 0) initialHighlight = { field: nodeColorField, values };
|
|
19494
|
+
}
|
|
19242
19495
|
const tooltipDescriptors = buildGraphTooltips(compiledNodes);
|
|
19243
19496
|
const communityCount = communityColorMap.size;
|
|
19244
19497
|
const altParts = [
|
|
@@ -19255,17 +19508,26 @@ function compileGraph(spec, options) {
|
|
|
19255
19508
|
};
|
|
19256
19509
|
const collisionPadding = graphSpec.layout.collisionPadding ?? 2;
|
|
19257
19510
|
const maxRadius = compiledNodes.length > 0 ? Math.max(...compiledNodes.map((n) => n.radius)) : DEFAULT_COLLISION_PADDING;
|
|
19511
|
+
const energyPreset = graphSpec.layout.energy ? ENERGY_PRESETS[graphSpec.layout.energy] : ENERGY_PRESETS.balanced;
|
|
19512
|
+
const settlePreset = graphSpec.layout.settle ? SETTLE_PRESETS[graphSpec.layout.settle] : SETTLE_PRESETS.balanced;
|
|
19513
|
+
const warmupRaw = graphSpec.layout.warmup;
|
|
19514
|
+
const warmupTicks = warmupRaw === false ? 0 : typeof warmupRaw === "number" ? Math.max(0, Math.floor(warmupRaw)) : DEFAULT_WARMUP_TICKS;
|
|
19258
19515
|
const simulationConfig = {
|
|
19259
|
-
chargeStrength: graphSpec.layout.chargeStrength ??
|
|
19516
|
+
chargeStrength: graphSpec.layout.chargeStrength ?? energyPreset.chargeStrength,
|
|
19260
19517
|
linkDistance: graphSpec.layout.linkDistance ?? 30,
|
|
19261
19518
|
clustering: clusteringField ? { field: clusteringField, strength: 0.5 } : null,
|
|
19262
|
-
alphaDecay:
|
|
19263
|
-
velocityDecay:
|
|
19519
|
+
alphaDecay: settlePreset,
|
|
19520
|
+
velocityDecay: energyPreset.velocityDecay,
|
|
19264
19521
|
collisionRadius: maxRadius + collisionPadding,
|
|
19265
19522
|
collisionPadding,
|
|
19266
19523
|
linkStrength: graphSpec.layout.linkStrength,
|
|
19267
|
-
centerForce: graphSpec.layout.centerForce
|
|
19524
|
+
centerForce: graphSpec.layout.centerForce,
|
|
19525
|
+
seed: graphSpec.layout.seed,
|
|
19526
|
+
warmupTicks,
|
|
19527
|
+
warmupBudgetMs: DEFAULT_WARMUP_BUDGET_MS
|
|
19268
19528
|
};
|
|
19529
|
+
const animation = resolveGraphAnimation(graphSpec.animation);
|
|
19530
|
+
const interaction = resolveGraphInteraction(graphSpec.interaction);
|
|
19269
19531
|
const chrome = computeChrome4(
|
|
19270
19532
|
{
|
|
19271
19533
|
title: graphSpec.chrome.title,
|
|
@@ -19294,7 +19556,12 @@ function compileGraph(spec, options) {
|
|
|
19294
19556
|
height: options.height
|
|
19295
19557
|
},
|
|
19296
19558
|
simulationConfig,
|
|
19297
|
-
watermark
|
|
19559
|
+
watermark,
|
|
19560
|
+
animation,
|
|
19561
|
+
interaction,
|
|
19562
|
+
legendField,
|
|
19563
|
+
initialHighlight,
|
|
19564
|
+
edgeLegend
|
|
19298
19565
|
};
|
|
19299
19566
|
}
|
|
19300
19567
|
var DEFAULT_COLLISION_PADDING = 5;
|
|
@@ -19387,6 +19654,7 @@ function legendLayoutHasContent(legendLayout) {
|
|
|
19387
19654
|
}
|
|
19388
19655
|
var MIN_CHART_WIDTH = 60;
|
|
19389
19656
|
var MIN_CHART_HEIGHT2 = 40;
|
|
19657
|
+
var PLOT_SHARE_MAX = 0.4;
|
|
19390
19658
|
var SERIES_SEARCH_INPUT_HEIGHT = 32;
|
|
19391
19659
|
var SERIES_SEARCH_GAP = 12;
|
|
19392
19660
|
function getMinChartDims(display) {
|
|
@@ -19429,8 +19697,10 @@ function computeDimensions(spec, options, legendLayout, theme, strategy, waterma
|
|
|
19429
19697
|
watermark,
|
|
19430
19698
|
bottomLegendReservation
|
|
19431
19699
|
);
|
|
19700
|
+
const chromeLayout = resolveChromeLayout(spec, options);
|
|
19701
|
+
const effectiveHeight = chromeLayout === "grow" ? height + chrome.topHeight + chrome.bottomHeight : height;
|
|
19432
19702
|
if (isSparkline) {
|
|
19433
|
-
const total2 = { x: 0, y: 0, width, height };
|
|
19703
|
+
const total2 = { x: 0, y: 0, width, height: effectiveHeight };
|
|
19434
19704
|
const sparkPad = getSparklinePad(spec);
|
|
19435
19705
|
const xAxisSpace = userExplicit.xAxis ? 26 : 0;
|
|
19436
19706
|
const yAxisSpace = userExplicit.yAxis ? 30 : 0;
|
|
@@ -19454,7 +19724,7 @@ function computeDimensions(spec, options, legendLayout, theme, strategy, waterma
|
|
|
19454
19724
|
x: margins2.left,
|
|
19455
19725
|
y: margins2.top,
|
|
19456
19726
|
width: Math.max(0, width - margins2.left - margins2.right),
|
|
19457
|
-
height: Math.max(0,
|
|
19727
|
+
height: Math.max(0, effectiveHeight - margins2.top - margins2.bottom)
|
|
19458
19728
|
};
|
|
19459
19729
|
return {
|
|
19460
19730
|
total: total2,
|
|
@@ -19466,7 +19736,7 @@ function computeDimensions(spec, options, legendLayout, theme, strategy, waterma
|
|
|
19466
19736
|
effectiveAxisGap: 0
|
|
19467
19737
|
};
|
|
19468
19738
|
}
|
|
19469
|
-
const total = { x: 0, y: 0, width, height };
|
|
19739
|
+
const total = { x: 0, y: 0, width, height: effectiveHeight };
|
|
19470
19740
|
const isRadial = isAxislessMark2(spec.markType);
|
|
19471
19741
|
const encoding = spec.encoding;
|
|
19472
19742
|
const xAxisSuppressed = encoding.x?.axis === false;
|
|
@@ -19696,10 +19966,11 @@ function computeDimensions(spec, options, legendLayout, theme, strategy, waterma
|
|
|
19696
19966
|
x: margins.left,
|
|
19697
19967
|
y: margins.top,
|
|
19698
19968
|
width: Math.max(0, width - margins.left - margins.right),
|
|
19699
|
-
height: Math.max(0,
|
|
19969
|
+
height: Math.max(0, effectiveHeight - margins.top - margins.bottom)
|
|
19700
19970
|
};
|
|
19701
19971
|
const minDims = getMinChartDims(spec.display);
|
|
19702
|
-
|
|
19972
|
+
const chromeEatsPlot = chromeLayout !== "grow" && chrome.topHeight > height * PLOT_SHARE_MAX;
|
|
19973
|
+
if ((chartArea.width < minDims.width || chartArea.height < minDims.height || chromeEatsPlot) && chromeMode !== "hidden") {
|
|
19703
19974
|
const fallbackMode = chromeMode === "full" ? "compact" : "hidden";
|
|
19704
19975
|
const fallbackChrome = computeChrome5(
|
|
19705
19976
|
chromeToInput(spec.chrome),
|
|
@@ -19725,7 +19996,7 @@ function computeDimensions(spec, options, legendLayout, theme, strategy, waterma
|
|
|
19725
19996
|
x: margins.left,
|
|
19726
19997
|
y: margins.top,
|
|
19727
19998
|
width: Math.max(0, width - margins.left - margins.right),
|
|
19728
|
-
height: Math.max(0,
|
|
19999
|
+
height: Math.max(0, effectiveHeight - margins.top - margins.bottom)
|
|
19729
20000
|
};
|
|
19730
20001
|
const fallbackMetricsTopY = topPad + fallbackChrome.topHeight;
|
|
19731
20002
|
const fallbackMetricsArea = { x: hPad, width: Math.max(0, width - hPad * 2) };
|
|
@@ -19742,7 +20013,7 @@ function computeDimensions(spec, options, legendLayout, theme, strategy, waterma
|
|
|
19742
20013
|
chartArea = {
|
|
19743
20014
|
...chartArea,
|
|
19744
20015
|
y: margins.top,
|
|
19745
|
-
height: Math.max(0,
|
|
20016
|
+
height: Math.max(0, effectiveHeight - margins.top - margins.bottom)
|
|
19746
20017
|
};
|
|
19747
20018
|
}
|
|
19748
20019
|
return {
|
|
@@ -19758,7 +20029,8 @@ function computeDimensions(spec, options, legendLayout, theme, strategy, waterma
|
|
|
19758
20029
|
fallbackMetricsArea
|
|
19759
20030
|
) : void 0,
|
|
19760
20031
|
xAxisHeight,
|
|
19761
|
-
effectiveAxisGap: fallbackEffectiveAxisGap
|
|
20032
|
+
effectiveAxisGap: fallbackEffectiveAxisGap,
|
|
20033
|
+
chromeStripped: true
|
|
19762
20034
|
};
|
|
19763
20035
|
}
|
|
19764
20036
|
}
|
|
@@ -19770,7 +20042,7 @@ function computeDimensions(spec, options, legendLayout, theme, strategy, waterma
|
|
|
19770
20042
|
chartArea = {
|
|
19771
20043
|
...chartArea,
|
|
19772
20044
|
y: margins.top,
|
|
19773
|
-
height: Math.max(0,
|
|
20045
|
+
height: Math.max(0, effectiveHeight - margins.top - margins.bottom)
|
|
19774
20046
|
};
|
|
19775
20047
|
}
|
|
19776
20048
|
return {
|
|
@@ -20522,14 +20794,19 @@ function compileSankey(spec, options) {
|
|
|
20522
20794
|
watermark
|
|
20523
20795
|
);
|
|
20524
20796
|
const padding = theme.spacing.padding;
|
|
20797
|
+
const chromeLayout = resolveChromeLayout(
|
|
20798
|
+
spec,
|
|
20799
|
+
options
|
|
20800
|
+
);
|
|
20801
|
+
const grownHeight = chromeLayout === "grow" ? options.height + chrome.topHeight + chrome.bottomHeight : options.height;
|
|
20525
20802
|
const fullArea = {
|
|
20526
20803
|
x: padding,
|
|
20527
20804
|
y: padding + chrome.topHeight,
|
|
20528
20805
|
width: options.width - padding * 2,
|
|
20529
|
-
height: options.height - chrome.topHeight - chrome.bottomHeight - padding * 2
|
|
20806
|
+
height: chromeLayout === "grow" ? options.height - padding * 2 : options.height - chrome.topHeight - chrome.bottomHeight - padding * 2
|
|
20530
20807
|
};
|
|
20531
20808
|
if (fullArea.width <= 0 || fullArea.height <= 0) {
|
|
20532
|
-
return emptyLayout4(fullArea, chrome, theme, options, watermark);
|
|
20809
|
+
return emptyLayout4(fullArea, chrome, theme, { ...options, height: grownHeight }, watermark);
|
|
20533
20810
|
}
|
|
20534
20811
|
const sourceField = sankeySpec.encoding.source.field;
|
|
20535
20812
|
const targetField = sankeySpec.encoding.target.field;
|
|
@@ -20569,7 +20846,7 @@ function compileSankey(spec, options) {
|
|
|
20569
20846
|
height: fullArea.height - legend.bounds.height - legendGap2
|
|
20570
20847
|
};
|
|
20571
20848
|
if (area.height <= 0) {
|
|
20572
|
-
return emptyLayout4(area, chrome, theme, options, watermark);
|
|
20849
|
+
return emptyLayout4(area, chrome, theme, { ...options, height: grownHeight }, watermark);
|
|
20573
20850
|
}
|
|
20574
20851
|
const labelFontSize = theme.fonts.sizes.small;
|
|
20575
20852
|
const labelFontWeight = theme.fonts.weights.normal;
|
|
@@ -20721,7 +20998,7 @@ function compileSankey(spec, options) {
|
|
|
20721
20998
|
theme,
|
|
20722
20999
|
dimensions: {
|
|
20723
21000
|
width: options.width,
|
|
20724
|
-
height:
|
|
21001
|
+
height: grownHeight
|
|
20725
21002
|
},
|
|
20726
21003
|
animation: resolvedAnimation,
|
|
20727
21004
|
watermark,
|
|
@@ -21540,6 +21817,10 @@ var LEGEND_ENTRY_GAP = 16;
|
|
|
21540
21817
|
function clamp(value2, min4, max4) {
|
|
21541
21818
|
return Math.min(max4, Math.max(min4, value2));
|
|
21542
21819
|
}
|
|
21820
|
+
function growContentHeight(contentHeight, chromeLayout, budgetHeight, chrome) {
|
|
21821
|
+
if (chromeLayout !== "grow") return contentHeight;
|
|
21822
|
+
return Math.max(contentHeight, budgetHeight + chrome.topHeight + chrome.bottomHeight);
|
|
21823
|
+
}
|
|
21543
21824
|
function compileTileMap(spec, options) {
|
|
21544
21825
|
const sugarWarnings = [];
|
|
21545
21826
|
const expandedSpec = spec && typeof spec === "object" && !Array.isArray(spec) ? expandSpecSugar(spec, sugarWarnings) : spec;
|
|
@@ -21576,22 +21857,44 @@ function compileTileMap(spec, options) {
|
|
|
21576
21857
|
watermark
|
|
21577
21858
|
);
|
|
21578
21859
|
const padding = getBreakpoint2(options.width) === "compact" ? Math.max(HPAD_COMPACT_MIN4, Math.round(theme.spacing.padding * HPAD_COMPACT_FRACTION4)) : theme.spacing.padding;
|
|
21860
|
+
const chromeLayout = resolveChromeLayout(
|
|
21861
|
+
spec,
|
|
21862
|
+
options
|
|
21863
|
+
);
|
|
21579
21864
|
const fullArea = {
|
|
21580
21865
|
x: padding,
|
|
21581
21866
|
y: padding + chrome.topHeight,
|
|
21582
21867
|
width: options.width - padding * 2,
|
|
21583
|
-
height: options.height - chrome.topHeight - chrome.bottomHeight - padding * 2
|
|
21868
|
+
height: chromeLayout === "grow" ? options.height - padding * 2 : options.height - chrome.topHeight - chrome.bottomHeight - padding * 2
|
|
21584
21869
|
};
|
|
21585
21870
|
if (fullArea.width <= 0 || fullArea.height <= 0) {
|
|
21586
21871
|
return emptyLayout5(chrome, theme, options, watermark);
|
|
21587
21872
|
}
|
|
21588
21873
|
const isCategorical = tilemapSpec.encoding.color !== void 0 || tilemapSpec.colors !== void 0;
|
|
21589
21874
|
if (isCategorical) {
|
|
21590
|
-
return compileCategorical(
|
|
21875
|
+
return compileCategorical(
|
|
21876
|
+
tilemapSpec,
|
|
21877
|
+
options,
|
|
21878
|
+
theme,
|
|
21879
|
+
chrome,
|
|
21880
|
+
fullArea,
|
|
21881
|
+
isDarkMode,
|
|
21882
|
+
watermark,
|
|
21883
|
+
chromeLayout
|
|
21884
|
+
);
|
|
21591
21885
|
}
|
|
21592
|
-
return compileQuantitative(
|
|
21886
|
+
return compileQuantitative(
|
|
21887
|
+
tilemapSpec,
|
|
21888
|
+
options,
|
|
21889
|
+
theme,
|
|
21890
|
+
chrome,
|
|
21891
|
+
fullArea,
|
|
21892
|
+
isDarkMode,
|
|
21893
|
+
watermark,
|
|
21894
|
+
chromeLayout
|
|
21895
|
+
);
|
|
21593
21896
|
}
|
|
21594
|
-
function compileQuantitative(tilemapSpec, options, theme, chrome, fullArea, isDarkMode, watermark) {
|
|
21897
|
+
function compileQuantitative(tilemapSpec, options, theme, chrome, fullArea, isDarkMode, watermark, chromeLayout) {
|
|
21595
21898
|
const stateField = tilemapSpec.encoding.state.field;
|
|
21596
21899
|
const valueField = tilemapSpec.encoding.value.field;
|
|
21597
21900
|
const stateValueMap = /* @__PURE__ */ new Map();
|
|
@@ -21692,7 +21995,12 @@ function compileQuantitative(tilemapSpec, options, theme, chrome, fullArea, isDa
|
|
|
21692
21995
|
};
|
|
21693
21996
|
const resolvedAnimation = resolveAnimation(tilemapSpec.animation);
|
|
21694
21997
|
const padding = fullArea.x;
|
|
21695
|
-
const contentHeight =
|
|
21998
|
+
const contentHeight = growContentHeight(
|
|
21999
|
+
tileGridOffsetY + tilePositions.gridHeight + legendGap2 + legendTotalHeight + chrome.bottomHeight + padding,
|
|
22000
|
+
chromeLayout,
|
|
22001
|
+
options.height,
|
|
22002
|
+
chrome
|
|
22003
|
+
);
|
|
21696
22004
|
return {
|
|
21697
22005
|
area: fullArea,
|
|
21698
22006
|
chrome,
|
|
@@ -21709,7 +22017,7 @@ function compileQuantitative(tilemapSpec, options, theme, chrome, fullArea, isDa
|
|
|
21709
22017
|
measureText: options.measureText ?? ((text, fontSize) => ({ width: estimateTextWidth23(text, fontSize), height: fontSize }))
|
|
21710
22018
|
};
|
|
21711
22019
|
}
|
|
21712
|
-
function compileCategorical(tilemapSpec, options, theme, chrome, fullArea, isDarkMode, watermark) {
|
|
22020
|
+
function compileCategorical(tilemapSpec, options, theme, chrome, fullArea, isDarkMode, watermark, chromeLayout) {
|
|
21713
22021
|
const stateField = tilemapSpec.encoding.state.field;
|
|
21714
22022
|
const colorField = tilemapSpec.encoding.color?.field ?? tilemapSpec.encoding.value.field;
|
|
21715
22023
|
const stateCategoryMap = /* @__PURE__ */ new Map();
|
|
@@ -21828,7 +22136,12 @@ function compileCategorical(tilemapSpec, options, theme, chrome, fullArea, isDar
|
|
|
21828
22136
|
};
|
|
21829
22137
|
const resolvedAnimation = resolveAnimation(tilemapSpec.animation);
|
|
21830
22138
|
const padding = fullArea.x;
|
|
21831
|
-
const contentHeight =
|
|
22139
|
+
const contentHeight = growContentHeight(
|
|
22140
|
+
tileGridOffsetY + tilePositions.gridHeight + legendGap2 + legendTotalHeight + chrome.bottomHeight + padding,
|
|
22141
|
+
chromeLayout,
|
|
22142
|
+
options.height,
|
|
22143
|
+
chrome
|
|
22144
|
+
);
|
|
21832
22145
|
return {
|
|
21833
22146
|
area: fullArea,
|
|
21834
22147
|
chrome,
|
|
@@ -23213,7 +23526,10 @@ function compileChart(spec, optionsInput) {
|
|
|
23213
23526
|
skipY,
|
|
23214
23527
|
markType: chartSpec.markType,
|
|
23215
23528
|
totalWidth: options.width,
|
|
23216
|
-
|
|
23529
|
+
// If the guardrail stripped chrome, the plan's y-ticks were sized
|
|
23530
|
+
// against the pre-strip (shorter) plot. Drop them so computeAxes
|
|
23531
|
+
// regenerates against the final (taller) chartArea.
|
|
23532
|
+
precomputedYTicks: !dims.chromeStripped && plan.yTickValues.length > 0 ? plan.yTickValues : void 0
|
|
23217
23533
|
});
|
|
23218
23534
|
const xAxisExtent = axes.x?.extent ?? 0;
|
|
23219
23535
|
dims.chrome.bottomAnchorY = chartArea.y + chartArea.height + xAxisExtent;
|
|
@@ -23336,7 +23652,10 @@ function compileChart(spec, optionsInput) {
|
|
|
23336
23652
|
theme,
|
|
23337
23653
|
dimensions: {
|
|
23338
23654
|
width: options.width,
|
|
23339
|
-
|
|
23655
|
+
// In chromeLayout 'grow' mode, computeDimensions grows total.height by the
|
|
23656
|
+
// chrome height so the plot keeps its full budget. In the default
|
|
23657
|
+
// 'subtract' mode total.height === options.height, so this is a no-op.
|
|
23658
|
+
height: dims.total.height
|
|
23340
23659
|
},
|
|
23341
23660
|
animation: resolvedAnimation,
|
|
23342
23661
|
watermark,
|
|
@@ -23669,6 +23988,7 @@ export {
|
|
|
23669
23988
|
EXIT_DEFAULTS,
|
|
23670
23989
|
UPDATE_DEFAULTS,
|
|
23671
23990
|
buildAreaPath,
|
|
23991
|
+
buildEdgeTooltip,
|
|
23672
23992
|
buildLinePath,
|
|
23673
23993
|
clampStaggerDelay,
|
|
23674
23994
|
clearRenderers,
|