@opendata-ai/openchart-engine 6.5.2 → 6.6.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.js CHANGED
@@ -1,6 +1,6 @@
1
1
  // src/compile.ts
2
2
  import {
3
- adaptTheme as adaptTheme2,
3
+ adaptTheme as adaptTheme3,
4
4
  BRAND_RESERVE_WIDTH as BRAND_RESERVE_WIDTH2,
5
5
  computeLabelBounds,
6
6
  generateAltText,
@@ -8,7 +8,7 @@ import {
8
8
  getBreakpoint,
9
9
  getHeightClass,
10
10
  getLayoutStrategy,
11
- resolveTheme as resolveTheme2
11
+ resolveTheme as resolveTheme3
12
12
  } from "@opendata-ai/openchart-core";
13
13
 
14
14
  // src/annotations/compute.ts
@@ -44,23 +44,23 @@ function interpolateInDomain(numValue, domain, positionOf) {
44
44
  const t = (numValue - sorted[lower].n) / (sorted[upper].n - sorted[lower].n);
45
45
  return lowerPos + t * (upperPos - lowerPos);
46
46
  }
47
- function resolvePosition(value, scale) {
47
+ function resolvePosition(value2, scale) {
48
48
  if (!scale) return null;
49
49
  const s = scale.scale;
50
50
  const type = scale.type;
51
51
  if (type === "time") {
52
- const date2 = new Date(String(value));
52
+ const date2 = new Date(String(value2));
53
53
  if (Number.isNaN(date2.getTime())) return null;
54
54
  return s(date2);
55
55
  }
56
56
  if (type === "linear" || type === "log") {
57
- const num = typeof value === "number" ? value : Number(value);
57
+ const num = typeof value2 === "number" ? value2 : Number(value2);
58
58
  if (!Number.isFinite(num)) return null;
59
59
  return s(num);
60
60
  }
61
61
  if (type === "band") {
62
62
  const bandScale = s;
63
- const strValue2 = String(value);
63
+ const strValue2 = String(value2);
64
64
  const pos = bandScale(strValue2);
65
65
  if (pos !== void 0) return pos + (bandScale.bandwidth?.() ?? 0) / 2;
66
66
  const bw = bandScale.bandwidth?.() ?? 0;
@@ -70,7 +70,7 @@ function resolvePosition(value, scale) {
70
70
  (entry) => (bandScale(entry) ?? 0) + bw / 2
71
71
  );
72
72
  }
73
- const strValue = String(value);
73
+ const strValue = String(value2);
74
74
  const directResult = s(strValue);
75
75
  if (directResult !== void 0) return directResult;
76
76
  if (type === "point" || type === "ordinal") {
@@ -555,15 +555,15 @@ function isFieldPredicate(pred) {
555
555
  return "field" in pred;
556
556
  }
557
557
  function evaluateFieldPredicate(datum, pred) {
558
- const value = datum[pred.field];
558
+ const value2 = datum[pred.field];
559
559
  if (pred.valid !== void 0) {
560
- const isValid = value !== null && value !== void 0 && !Number.isNaN(value);
560
+ const isValid = value2 !== null && value2 !== void 0 && !Number.isNaN(value2);
561
561
  return pred.valid ? isValid : !isValid;
562
562
  }
563
563
  if (pred.equal !== void 0) {
564
- return value === pred.equal;
564
+ return value2 === pred.equal;
565
565
  }
566
- const numValue = Number(value);
566
+ const numValue = Number(value2);
567
567
  if (pred.lt !== void 0) {
568
568
  return numValue < pred.lt;
569
569
  }
@@ -577,11 +577,11 @@ function evaluateFieldPredicate(datum, pred) {
577
577
  return numValue >= pred.gte;
578
578
  }
579
579
  if (pred.range !== void 0) {
580
- const [min3, max3] = pred.range;
581
- return numValue >= min3 && numValue <= max3;
580
+ const [min4, max4] = pred.range;
581
+ return numValue >= min4 && numValue <= max4;
582
582
  }
583
583
  if (pred.oneOf !== void 0) {
584
- return pred.oneOf.includes(value);
584
+ return pred.oneOf.includes(value2);
585
585
  }
586
586
  return true;
587
587
  }
@@ -620,18 +620,18 @@ function isConditionalValueDef(def) {
620
620
 
621
621
  // src/charts/utils.ts
622
622
  var DEFAULT_COLOR = "#1b7fa3";
623
- function scaleValue(scale, scaleType, value) {
624
- if (value == null) return null;
623
+ function scaleValue(scale, scaleType, value2) {
624
+ if (value2 == null) return null;
625
625
  if (scaleType === "time" || scaleType === "utc") {
626
- const date2 = value instanceof Date ? value : new Date(String(value));
626
+ const date2 = value2 instanceof Date ? value2 : new Date(String(value2));
627
627
  if (Number.isNaN(date2.getTime())) return null;
628
628
  return scale(date2);
629
629
  }
630
630
  if (scaleType === "point" || scaleType === "band" || scaleType === "ordinal") {
631
- const result = scale(String(value));
631
+ const result = scale(String(value2));
632
632
  return result ?? null;
633
633
  }
634
- const num = typeof value === "number" ? value : Number(value);
634
+ const num = typeof value2 === "number" ? value2 : Number(value2);
635
635
  if (!Number.isFinite(num)) return null;
636
636
  return scale(num);
637
637
  }
@@ -683,19 +683,19 @@ function getColor(scales, key, _index, fallback = DEFAULT_COLOR) {
683
683
  }
684
684
  return scales.defaultColor ?? fallback;
685
685
  }
686
- function getSequentialColor(scales, value, fallback = DEFAULT_COLOR) {
686
+ function getSequentialColor(scales, value2, fallback = DEFAULT_COLOR) {
687
687
  if (scales.color?.type === "sequential") {
688
688
  const colorScale = scales.color.scale;
689
- return colorScale(value);
689
+ return colorScale(value2);
690
690
  }
691
691
  return scales.defaultColor ?? fallback;
692
692
  }
693
693
 
694
694
  // src/charts/bar/compute.ts
695
695
  var MIN_BAR_WIDTH = 1;
696
- function formatBarValue(value) {
697
- if (Math.abs(value) >= 1e3) return abbreviateNumber(value);
698
- return formatNumber(value);
696
+ function formatBarValue(value2) {
697
+ if (Math.abs(value2) >= 1e3) return abbreviateNumber(value2);
698
+ return formatNumber(value2);
699
699
  }
700
700
  function computeBarMarks(spec, scales, _chartArea, _strategy) {
701
701
  const encoding = spec.encoding;
@@ -750,14 +750,14 @@ function computeStackedBars(data, valueField, categoryField, colorField, xScale,
750
750
  let cumulativeValue = 0;
751
751
  for (const row of rows) {
752
752
  const groupKey = String(row[colorField] ?? "");
753
- const value = Number(row[valueField] ?? 0);
754
- if (!Number.isFinite(value) || value <= 0) continue;
753
+ const value2 = Number(row[valueField] ?? 0);
754
+ if (!Number.isFinite(value2) || value2 <= 0) continue;
755
755
  const color2 = getColor(scales, groupKey);
756
756
  const xLeft = xScale(cumulativeValue);
757
- const xRight = xScale(cumulativeValue + value);
757
+ const xRight = xScale(cumulativeValue + value2);
758
758
  const barWidth = Math.max(Math.abs(xRight - xLeft), MIN_BAR_WIDTH);
759
759
  const aria = {
760
- label: `${category}, ${groupKey}: ${formatBarValue(value)}`
760
+ label: `${category}, ${groupKey}: ${formatBarValue(value2)}`
761
761
  };
762
762
  marks.push({
763
763
  type: "rect",
@@ -772,7 +772,7 @@ function computeStackedBars(data, valueField, categoryField, colorField, xScale,
772
772
  orient: "horizontal",
773
773
  stackGroup: category
774
774
  });
775
- cumulativeValue += value;
775
+ cumulativeValue += value2;
776
776
  }
777
777
  }
778
778
  return marks;
@@ -781,8 +781,8 @@ function computeSimpleBars(data, valueField, categoryField, xScale, yScale, band
781
781
  const marks = [];
782
782
  for (const row of data) {
783
783
  const category = String(row[categoryField] ?? "");
784
- const value = Number(row[valueField] ?? 0);
785
- if (!Number.isFinite(value)) continue;
784
+ const value2 = Number(row[valueField] ?? 0);
785
+ if (!Number.isFinite(value2)) continue;
786
786
  const bandY = yScale(category);
787
787
  if (bandY === void 0) continue;
788
788
  let color2;
@@ -791,14 +791,14 @@ function computeSimpleBars(data, valueField, categoryField, xScale, yScale, band
791
791
  resolveConditionalValue(row, conditionalColor) ?? getColor(scales, "__default__")
792
792
  );
793
793
  } else if (sequentialColor) {
794
- color2 = getSequentialColor(scales, value);
794
+ color2 = getSequentialColor(scales, value2);
795
795
  } else {
796
796
  color2 = getColor(scales, "__default__");
797
797
  }
798
- const xPos = value >= 0 ? baseline : xScale(value);
799
- const barWidth = Math.max(Math.abs(xScale(value) - baseline), MIN_BAR_WIDTH);
798
+ const xPos = value2 >= 0 ? baseline : xScale(value2);
799
+ const barWidth = Math.max(Math.abs(xScale(value2) - baseline), MIN_BAR_WIDTH);
800
800
  const aria = {
801
- label: `${category}: ${formatBarValue(value)}`
801
+ label: `${category}: ${formatBarValue(value2)}`
802
802
  };
803
803
  marks.push({
804
804
  type: "rect",
@@ -952,9 +952,9 @@ var barRenderer = (spec, scales, chartArea, strategy, _theme) => {
952
952
  // src/charts/column/compute.ts
953
953
  import { abbreviateNumber as abbreviateNumber2, formatNumber as formatNumber2 } from "@opendata-ai/openchart-core";
954
954
  var MIN_COLUMN_HEIGHT = 1;
955
- function formatColumnValue(value) {
956
- if (Math.abs(value) >= 1e3) return abbreviateNumber2(value);
957
- return formatNumber2(value);
955
+ function formatColumnValue(value2) {
956
+ if (Math.abs(value2) >= 1e3) return abbreviateNumber2(value2);
957
+ return formatNumber2(value2);
958
958
  }
959
959
  function computeColumnMarks(spec, scales, _chartArea, _strategy) {
960
960
  const encoding = spec.encoding;
@@ -1019,8 +1019,8 @@ function computeSimpleColumns(data, categoryField, valueField, xScale, yScale, b
1019
1019
  const marks = [];
1020
1020
  for (const row of data) {
1021
1021
  const category = String(row[categoryField] ?? "");
1022
- const value = Number(row[valueField] ?? 0);
1023
- if (!Number.isFinite(value)) continue;
1022
+ const value2 = Number(row[valueField] ?? 0);
1023
+ if (!Number.isFinite(value2)) continue;
1024
1024
  const bandX = xScale(category);
1025
1025
  if (bandX === void 0) continue;
1026
1026
  let color2;
@@ -1029,15 +1029,15 @@ function computeSimpleColumns(data, categoryField, valueField, xScale, yScale, b
1029
1029
  resolveConditionalValue(row, conditionalColor) ?? getColor(scales, "__default__")
1030
1030
  );
1031
1031
  } else if (sequentialColor) {
1032
- color2 = getSequentialColor(scales, value);
1032
+ color2 = getSequentialColor(scales, value2);
1033
1033
  } else {
1034
1034
  color2 = getColor(scales, "__default__");
1035
1035
  }
1036
- const yPos = yScale(value);
1036
+ const yPos = yScale(value2);
1037
1037
  const columnHeight = Math.max(Math.abs(baseline - yPos), MIN_COLUMN_HEIGHT);
1038
- const y2 = value >= 0 ? yPos : baseline;
1038
+ const y2 = value2 >= 0 ? yPos : baseline;
1039
1039
  const aria = {
1040
- label: `${category}: ${formatColumnValue(value)}`
1040
+ label: `${category}: ${formatColumnValue(value2)}`
1041
1041
  };
1042
1042
  marks.push({
1043
1043
  type: "rect",
@@ -1058,17 +1058,17 @@ function computeColoredColumns(data, categoryField, valueField, colorField, xSca
1058
1058
  const marks = [];
1059
1059
  for (const row of data) {
1060
1060
  const category = String(row[categoryField] ?? "");
1061
- const value = Number(row[valueField] ?? 0);
1062
- if (!Number.isFinite(value)) continue;
1061
+ const value2 = Number(row[valueField] ?? 0);
1062
+ if (!Number.isFinite(value2)) continue;
1063
1063
  const bandX = xScale(category);
1064
1064
  if (bandX === void 0) continue;
1065
1065
  const groupKey = String(row[colorField] ?? "");
1066
1066
  const color2 = getColor(scales, groupKey);
1067
- const yPos = yScale(value);
1067
+ const yPos = yScale(value2);
1068
1068
  const columnHeight = Math.max(Math.abs(baseline - yPos), MIN_COLUMN_HEIGHT);
1069
- const y2 = value >= 0 ? yPos : baseline;
1069
+ const y2 = value2 >= 0 ? yPos : baseline;
1070
1070
  const aria = {
1071
- label: `${category}, ${groupKey}: ${formatColumnValue(value)}`
1071
+ label: `${category}, ${groupKey}: ${formatColumnValue(value2)}`
1072
1072
  };
1073
1073
  marks.push({
1074
1074
  type: "rect",
@@ -1094,14 +1094,14 @@ function computeStackedColumns(data, categoryField, valueField, colorField, xSca
1094
1094
  let cumulativeValue = 0;
1095
1095
  for (const row of rows) {
1096
1096
  const groupKey = String(row[colorField] ?? "");
1097
- const value = Number(row[valueField] ?? 0);
1098
- if (!Number.isFinite(value) || value <= 0) continue;
1097
+ const value2 = Number(row[valueField] ?? 0);
1098
+ if (!Number.isFinite(value2) || value2 <= 0) continue;
1099
1099
  const color2 = getColor(scales, groupKey);
1100
- const yTop = yScale(cumulativeValue + value);
1100
+ const yTop = yScale(cumulativeValue + value2);
1101
1101
  const yBottom = yScale(cumulativeValue);
1102
1102
  const columnHeight = Math.max(Math.abs(yBottom - yTop), MIN_COLUMN_HEIGHT);
1103
1103
  const aria = {
1104
- label: `${category}, ${groupKey}: ${formatColumnValue(value)}`
1104
+ label: `${category}, ${groupKey}: ${formatColumnValue(value2)}`
1105
1105
  };
1106
1106
  marks.push({
1107
1107
  type: "rect",
@@ -1116,7 +1116,7 @@ function computeStackedColumns(data, categoryField, valueField, colorField, xSca
1116
1116
  orient: "vertical",
1117
1117
  stackGroup: category
1118
1118
  });
1119
- cumulativeValue += value;
1119
+ cumulativeValue += value2;
1120
1120
  }
1121
1121
  }
1122
1122
  return marks;
@@ -1247,8 +1247,8 @@ function computeDumbbellMarks(data, valueField, categoryField, colorField, xScal
1247
1247
  const cy = bandY + bandwidth / 2;
1248
1248
  const xValues = [];
1249
1249
  for (const row of rows) {
1250
- const value = Number(row[valueField] ?? 0);
1251
- if (Number.isFinite(value)) xValues.push(value);
1250
+ const value2 = Number(row[valueField] ?? 0);
1251
+ if (Number.isFinite(value2)) xValues.push(value2);
1252
1252
  }
1253
1253
  if (xValues.length === 0) continue;
1254
1254
  const minVal = Math.min(...xValues);
@@ -1272,13 +1272,13 @@ function computeDumbbellMarks(data, valueField, categoryField, colorField, xScal
1272
1272
  });
1273
1273
  }
1274
1274
  for (const row of rows) {
1275
- const value = Number(row[valueField] ?? 0);
1276
- if (!Number.isFinite(value)) continue;
1277
- const cx = xScale(value);
1275
+ const value2 = Number(row[valueField] ?? 0);
1276
+ if (!Number.isFinite(value2)) continue;
1277
+ const cx = xScale(value2);
1278
1278
  const colorCategory = String(row[colorField] ?? "");
1279
1279
  const color2 = getColor(scales, colorCategory);
1280
1280
  const dotAria = {
1281
- label: `${category}, ${colorCategory}: ${value}`
1281
+ label: `${category}, ${colorCategory}: ${value2}`
1282
1282
  };
1283
1283
  marks.push({
1284
1284
  type: "point",
@@ -1299,13 +1299,13 @@ function computeLollipopMarks(data, valueField, categoryField, xScale, yScale, b
1299
1299
  const marks = [];
1300
1300
  for (const row of data) {
1301
1301
  const category = String(row[categoryField] ?? "");
1302
- const value = Number(row[valueField] ?? 0);
1303
- if (!Number.isFinite(value)) continue;
1302
+ const value2 = Number(row[valueField] ?? 0);
1303
+ if (!Number.isFinite(value2)) continue;
1304
1304
  const bandY = yScale(category);
1305
1305
  if (bandY === void 0) continue;
1306
- const cx = xScale(value);
1306
+ const cx = xScale(value2);
1307
1307
  const cy = bandY + bandwidth / 2;
1308
- const color2 = isSequentialColor ? getSequentialColor(scales, value) : getColor(scales, "__default__");
1308
+ const color2 = isSequentialColor ? getSequentialColor(scales, value2) : getColor(scales, "__default__");
1309
1309
  const stemX = Math.min(baseline, cx);
1310
1310
  const stemWidth = Math.abs(cx - baseline);
1311
1311
  if (stemWidth > 0) {
@@ -1324,7 +1324,7 @@ function computeLollipopMarks(data, valueField, categoryField, xScale, yScale, b
1324
1324
  });
1325
1325
  }
1326
1326
  const dotAria = {
1327
- label: `${category}: ${value}`
1327
+ label: `${category}: ${value2}`
1328
1328
  };
1329
1329
  marks.push({
1330
1330
  type: "point",
@@ -1405,7 +1405,7 @@ var dotRenderer = (spec, scales, chartArea, strategy, _theme) => {
1405
1405
 
1406
1406
  // ../../node_modules/.bun/d3-shape@3.2.0/node_modules/d3-shape/src/constant.js
1407
1407
  function constant_default(x2) {
1408
- return function constant() {
1408
+ return function constant2() {
1409
1409
  return x2;
1410
1410
  };
1411
1411
  }
@@ -1842,12 +1842,12 @@ function identity_default(d) {
1842
1842
 
1843
1843
  // ../../node_modules/.bun/d3-shape@3.2.0/node_modules/d3-shape/src/pie.js
1844
1844
  function pie_default() {
1845
- var value = identity_default, sortValues = descending_default, sort = null, startAngle = constant_default(0), endAngle = constant_default(tau), padAngle = constant_default(0);
1845
+ var value2 = identity_default, sortValues = descending_default, sort = null, startAngle = constant_default(0), endAngle = constant_default(tau), padAngle = constant_default(0);
1846
1846
  function pie(data) {
1847
- var i, n = (data = array_default(data)).length, j, k, sum = 0, index = new Array(n), arcs = new Array(n), a0 = +startAngle.apply(this, arguments), da = Math.min(tau, Math.max(-tau, endAngle.apply(this, arguments) - a0)), a1, p = Math.min(Math.abs(da) / n, padAngle.apply(this, arguments)), pa = p * (da < 0 ? -1 : 1), v;
1847
+ var i, n = (data = array_default(data)).length, j, k, sum2 = 0, index = new Array(n), arcs = new Array(n), a0 = +startAngle.apply(this, arguments), da = Math.min(tau, Math.max(-tau, endAngle.apply(this, arguments) - a0)), a1, p = Math.min(Math.abs(da) / n, padAngle.apply(this, arguments)), pa = p * (da < 0 ? -1 : 1), v;
1848
1848
  for (i = 0; i < n; ++i) {
1849
- if ((v = arcs[index[i] = i] = +value(data[i], i, data)) > 0) {
1850
- sum += v;
1849
+ if ((v = arcs[index[i] = i] = +value2(data[i], i, data)) > 0) {
1850
+ sum2 += v;
1851
1851
  }
1852
1852
  }
1853
1853
  if (sortValues != null) index.sort(function(i2, j2) {
@@ -1856,7 +1856,7 @@ function pie_default() {
1856
1856
  else if (sort != null) index.sort(function(i2, j2) {
1857
1857
  return sort(data[i2], data[j2]);
1858
1858
  });
1859
- for (i = 0, k = sum ? (da - n * pa) / sum : 0; i < n; ++i, a0 = a1) {
1859
+ for (i = 0, k = sum2 ? (da - n * pa) / sum2 : 0; i < n; ++i, a0 = a1) {
1860
1860
  j = index[i], v = arcs[j], a1 = a0 + (v > 0 ? v * k : 0) + pa, arcs[j] = {
1861
1861
  data: data[j],
1862
1862
  index: i,
@@ -1869,7 +1869,7 @@ function pie_default() {
1869
1869
  return arcs;
1870
1870
  }
1871
1871
  pie.value = function(_) {
1872
- return arguments.length ? (value = typeof _ === "function" ? _ : constant_default(+_), pie) : value;
1872
+ return arguments.length ? (value2 = typeof _ === "function" ? _ : constant_default(+_), pie) : value2;
1873
1873
  };
1874
1874
  pie.sortValues = function(_) {
1875
1875
  return arguments.length ? (sortValues = _, sort = null, pie) : sortValues;
@@ -2253,12 +2253,12 @@ function stackSeries(key) {
2253
2253
  return series;
2254
2254
  }
2255
2255
  function stack_default() {
2256
- var keys = constant_default([]), order = none_default2, offset = none_default, value = stackValue;
2256
+ var keys = constant_default([]), order = none_default2, offset = none_default, value2 = stackValue;
2257
2257
  function stack(data) {
2258
2258
  var sz = Array.from(keys.apply(this, arguments), stackSeries), i, n = sz.length, j = -1, oz;
2259
2259
  for (const d of data) {
2260
2260
  for (i = 0, ++j; i < n; ++i) {
2261
- (sz[i][j] = [0, +value(d, sz[i].key, j, data)]).data = d;
2261
+ (sz[i][j] = [0, +value2(d, sz[i].key, j, data)]).data = d;
2262
2262
  }
2263
2263
  }
2264
2264
  for (i = 0, oz = array_default(order(sz)); i < n; ++i) {
@@ -2271,7 +2271,7 @@ function stack_default() {
2271
2271
  return arguments.length ? (keys = typeof _ === "function" ? _ : constant_default(Array.from(_)), stack) : keys;
2272
2272
  };
2273
2273
  stack.value = function(_) {
2274
- return arguments.length ? (value = typeof _ === "function" ? _ : constant_default(+_), stack) : value;
2274
+ return arguments.length ? (value2 = typeof _ === "function" ? _ : constant_default(+_), stack) : value2;
2275
2275
  };
2276
2276
  stack.order = function(_) {
2277
2277
  return arguments.length ? (order = _ == null ? none_default2 : typeof _ === "function" ? _ : constant_default(Array.from(_)), stack) : order;
@@ -2695,7 +2695,7 @@ var DEFAULT_PALETTE = [
2695
2695
  "#858078"
2696
2696
  ];
2697
2697
  function groupSmallSlices(slices, threshold2) {
2698
- const total = slices.reduce((sum, s) => sum + s.value, 0);
2698
+ const total = slices.reduce((sum2, s) => sum2 + s.value, 0);
2699
2699
  if (total === 0) return slices;
2700
2700
  const big = [];
2701
2701
  let otherValue = 0;
@@ -2733,13 +2733,13 @@ function computePieMarks(spec, scales, chartArea, _strategy, isDonut = false) {
2733
2733
  categoryRows.set(cat, row);
2734
2734
  }
2735
2735
  }
2736
- for (const [label, value] of categoryTotals) {
2736
+ for (const [label, value2] of categoryTotals) {
2737
2737
  slices.push({
2738
2738
  label,
2739
- value,
2739
+ value: value2,
2740
2740
  originalRow: categoryRows.get(label) ?? {
2741
2741
  [categoryField]: label,
2742
- [valueChannel.field]: value
2742
+ [valueChannel.field]: value2
2743
2743
  }
2744
2744
  });
2745
2745
  }
@@ -2763,8 +2763,8 @@ function computePieMarks(spec, scales, chartArea, _strategy, isDonut = false) {
2763
2763
  const innerRadius = isDonut ? outerRadius * 0.6 : 0;
2764
2764
  const arcGenerator = arc_default().innerRadius(innerRadius).outerRadius(outerRadius);
2765
2765
  const marks = [];
2766
- const center = { x: centerX, y: centerY };
2767
- const total = slices.reduce((sum, s) => sum + s.value, 0);
2766
+ const center2 = { x: centerX, y: centerY };
2767
+ const total = slices.reduce((sum2, s) => sum2 + s.value, 0);
2768
2768
  for (let i = 0; i < arcs.length; i++) {
2769
2769
  const arcDatum = arcs[i];
2770
2770
  const slice2 = arcDatum.data;
@@ -2788,7 +2788,7 @@ function computePieMarks(spec, scales, chartArea, _strategy, isDonut = false) {
2788
2788
  x: centroidResult[0] + centerX,
2789
2789
  y: centroidResult[1] + centerY
2790
2790
  },
2791
- center,
2791
+ center: center2,
2792
2792
  innerRadius,
2793
2793
  outerRadius,
2794
2794
  startAngle: arcDatum.startAngle,
@@ -2997,7 +2997,7 @@ function bisector(f) {
2997
2997
  compare2 = f;
2998
2998
  delta = f;
2999
2999
  }
3000
- function left(a, x2, lo = 0, hi = a.length) {
3000
+ function left2(a, x2, lo = 0, hi = a.length) {
3001
3001
  if (lo < hi) {
3002
3002
  if (compare1(x2, x2) !== 0) return hi;
3003
3003
  do {
@@ -3008,7 +3008,7 @@ function bisector(f) {
3008
3008
  }
3009
3009
  return lo;
3010
3010
  }
3011
- function right(a, x2, lo = 0, hi = a.length) {
3011
+ function right2(a, x2, lo = 0, hi = a.length) {
3012
3012
  if (lo < hi) {
3013
3013
  if (compare1(x2, x2) !== 0) return hi;
3014
3014
  do {
@@ -3019,11 +3019,11 @@ function bisector(f) {
3019
3019
  }
3020
3020
  return lo;
3021
3021
  }
3022
- function center(a, x2, lo = 0, hi = a.length) {
3023
- const i = left(a, x2, lo, hi - 1);
3022
+ function center2(a, x2, lo = 0, hi = a.length) {
3023
+ const i = left2(a, x2, lo, hi - 1);
3024
3024
  return i > lo && delta(a[i - 1], x2) > -delta(a[i], x2) ? i - 1 : i;
3025
3025
  }
3026
- return { left, center, right };
3026
+ return { left: left2, center: center2, right: right2 };
3027
3027
  }
3028
3028
  function zero() {
3029
3029
  return 0;
@@ -3043,33 +3043,33 @@ var bisect_default = bisectRight;
3043
3043
 
3044
3044
  // ../../node_modules/.bun/d3-array@3.2.4/node_modules/d3-array/src/extent.js
3045
3045
  function extent(values, valueof) {
3046
- let min3;
3047
- let max3;
3046
+ let min4;
3047
+ let max4;
3048
3048
  if (valueof === void 0) {
3049
- for (const value of values) {
3050
- if (value != null) {
3051
- if (min3 === void 0) {
3052
- if (value >= value) min3 = max3 = value;
3049
+ for (const value2 of values) {
3050
+ if (value2 != null) {
3051
+ if (min4 === void 0) {
3052
+ if (value2 >= value2) min4 = max4 = value2;
3053
3053
  } else {
3054
- if (min3 > value) min3 = value;
3055
- if (max3 < value) max3 = value;
3054
+ if (min4 > value2) min4 = value2;
3055
+ if (max4 < value2) max4 = value2;
3056
3056
  }
3057
3057
  }
3058
3058
  }
3059
3059
  } else {
3060
3060
  let index = -1;
3061
- for (let value of values) {
3062
- if ((value = valueof(value, ++index, values)) != null) {
3063
- if (min3 === void 0) {
3064
- if (value >= value) min3 = max3 = value;
3061
+ for (let value2 of values) {
3062
+ if ((value2 = valueof(value2, ++index, values)) != null) {
3063
+ if (min4 === void 0) {
3064
+ if (value2 >= value2) min4 = max4 = value2;
3065
3065
  } else {
3066
- if (min3 > value) min3 = value;
3067
- if (max3 < value) max3 = value;
3066
+ if (min4 > value2) min4 = value2;
3067
+ if (max4 < value2) max4 = value2;
3068
3068
  }
3069
3069
  }
3070
3070
  }
3071
3071
  }
3072
- return [min3, max3];
3072
+ return [min4, max4];
3073
3073
  }
3074
3074
 
3075
3075
  // ../../node_modules/.bun/internmap@2.0.3/node_modules/internmap/src/index.js
@@ -3077,7 +3077,7 @@ var InternMap = class extends Map {
3077
3077
  constructor(entries, key = keyof) {
3078
3078
  super();
3079
3079
  Object.defineProperties(this, { _intern: { value: /* @__PURE__ */ new Map() }, _key: { value: key } });
3080
- if (entries != null) for (const [key2, value] of entries) this.set(key2, value);
3080
+ if (entries != null) for (const [key2, value2] of entries) this.set(key2, value2);
3081
3081
  }
3082
3082
  get(key) {
3083
3083
  return super.get(intern_get(this, key));
@@ -3085,33 +3085,33 @@ var InternMap = class extends Map {
3085
3085
  has(key) {
3086
3086
  return super.has(intern_get(this, key));
3087
3087
  }
3088
- set(key, value) {
3089
- return super.set(intern_set(this, key), value);
3088
+ set(key, value2) {
3089
+ return super.set(intern_set(this, key), value2);
3090
3090
  }
3091
3091
  delete(key) {
3092
3092
  return super.delete(intern_delete(this, key));
3093
3093
  }
3094
3094
  };
3095
- function intern_get({ _intern, _key }, value) {
3096
- const key = _key(value);
3097
- return _intern.has(key) ? _intern.get(key) : value;
3095
+ function intern_get({ _intern, _key }, value2) {
3096
+ const key = _key(value2);
3097
+ return _intern.has(key) ? _intern.get(key) : value2;
3098
3098
  }
3099
- function intern_set({ _intern, _key }, value) {
3100
- const key = _key(value);
3099
+ function intern_set({ _intern, _key }, value2) {
3100
+ const key = _key(value2);
3101
3101
  if (_intern.has(key)) return _intern.get(key);
3102
- _intern.set(key, value);
3103
- return value;
3102
+ _intern.set(key, value2);
3103
+ return value2;
3104
3104
  }
3105
- function intern_delete({ _intern, _key }, value) {
3106
- const key = _key(value);
3105
+ function intern_delete({ _intern, _key }, value2) {
3106
+ const key = _key(value2);
3107
3107
  if (_intern.has(key)) {
3108
- value = _intern.get(key);
3108
+ value2 = _intern.get(key);
3109
3109
  _intern.delete(key);
3110
3110
  }
3111
- return value;
3111
+ return value2;
3112
3112
  }
3113
- function keyof(value) {
3114
- return value !== null && typeof value === "object" ? value.valueOf() : value;
3113
+ function keyof(value2) {
3114
+ return value2 !== null && typeof value2 === "object" ? value2.valueOf() : value2;
3115
3115
  }
3116
3116
 
3117
3117
  // ../../node_modules/.bun/d3-array@3.2.4/node_modules/d3-array/src/ticks.js
@@ -3166,42 +3166,42 @@ function tickStep(start, stop, count) {
3166
3166
 
3167
3167
  // ../../node_modules/.bun/d3-array@3.2.4/node_modules/d3-array/src/max.js
3168
3168
  function max2(values, valueof) {
3169
- let max3;
3169
+ let max4;
3170
3170
  if (valueof === void 0) {
3171
- for (const value of values) {
3172
- if (value != null && (max3 < value || max3 === void 0 && value >= value)) {
3173
- max3 = value;
3171
+ for (const value2 of values) {
3172
+ if (value2 != null && (max4 < value2 || max4 === void 0 && value2 >= value2)) {
3173
+ max4 = value2;
3174
3174
  }
3175
3175
  }
3176
3176
  } else {
3177
3177
  let index = -1;
3178
- for (let value of values) {
3179
- if ((value = valueof(value, ++index, values)) != null && (max3 < value || max3 === void 0 && value >= value)) {
3180
- max3 = value;
3178
+ for (let value2 of values) {
3179
+ if ((value2 = valueof(value2, ++index, values)) != null && (max4 < value2 || max4 === void 0 && value2 >= value2)) {
3180
+ max4 = value2;
3181
3181
  }
3182
3182
  }
3183
3183
  }
3184
- return max3;
3184
+ return max4;
3185
3185
  }
3186
3186
 
3187
3187
  // ../../node_modules/.bun/d3-array@3.2.4/node_modules/d3-array/src/min.js
3188
3188
  function min2(values, valueof) {
3189
- let min3;
3189
+ let min4;
3190
3190
  if (valueof === void 0) {
3191
- for (const value of values) {
3192
- if (value != null && (min3 > value || min3 === void 0 && value >= value)) {
3193
- min3 = value;
3191
+ for (const value2 of values) {
3192
+ if (value2 != null && (min4 > value2 || min4 === void 0 && value2 >= value2)) {
3193
+ min4 = value2;
3194
3194
  }
3195
3195
  }
3196
3196
  } else {
3197
3197
  let index = -1;
3198
- for (let value of values) {
3199
- if ((value = valueof(value, ++index, values)) != null && (min3 > value || min3 === void 0 && value >= value)) {
3200
- min3 = value;
3198
+ for (let value2 of values) {
3199
+ if ((value2 = valueof(value2, ++index, values)) != null && (min4 > value2 || min4 === void 0 && value2 >= value2)) {
3200
+ min4 = value2;
3201
3201
  }
3202
3202
  }
3203
3203
  }
3204
- return min3;
3204
+ return min4;
3205
3205
  }
3206
3206
 
3207
3207
  // ../../node_modules/.bun/d3-array@3.2.4/node_modules/d3-array/src/quantile.js
@@ -3271,9 +3271,9 @@ function ordinal() {
3271
3271
  scale.domain = function(_) {
3272
3272
  if (!arguments.length) return domain.slice();
3273
3273
  domain = [], index = new InternMap();
3274
- for (const value of _) {
3275
- if (index.has(value)) continue;
3276
- index.set(value, domain.push(value) - 1);
3274
+ for (const value2 of _) {
3275
+ if (index.has(value2)) continue;
3276
+ index.set(value2, domain.push(value2) - 1);
3277
3277
  }
3278
3278
  return scale;
3279
3279
  };
@@ -3623,12 +3623,12 @@ function rgb_formatRgb() {
3623
3623
  function clampa(opacity) {
3624
3624
  return isNaN(opacity) ? 1 : Math.max(0, Math.min(1, opacity));
3625
3625
  }
3626
- function clampi(value) {
3627
- return Math.max(0, Math.min(255, Math.round(value) || 0));
3626
+ function clampi(value2) {
3627
+ return Math.max(0, Math.min(255, Math.round(value2) || 0));
3628
3628
  }
3629
- function hex(value) {
3630
- value = clampi(value);
3631
- return (value < 16 ? "0" : "") + value.toString(16);
3629
+ function hex(value2) {
3630
+ value2 = clampi(value2);
3631
+ return (value2 < 16 ? "0" : "") + value2.toString(16);
3632
3632
  }
3633
3633
  function hsla(h, s, l, a) {
3634
3634
  if (a <= 0) h = s = l = NaN;
@@ -3642,12 +3642,12 @@ function hslConvert(o) {
3642
3642
  if (!o) return new Hsl();
3643
3643
  if (o instanceof Hsl) return o;
3644
3644
  o = o.rgb();
3645
- var r = o.r / 255, g = o.g / 255, b = o.b / 255, min3 = Math.min(r, g, b), max3 = Math.max(r, g, b), h = NaN, s = max3 - min3, l = (max3 + min3) / 2;
3645
+ var r = o.r / 255, g = o.g / 255, b = o.b / 255, min4 = Math.min(r, g, b), max4 = Math.max(r, g, b), h = NaN, s = max4 - min4, l = (max4 + min4) / 2;
3646
3646
  if (s) {
3647
- if (r === max3) h = (g - b) / s + (g < b) * 6;
3648
- else if (g === max3) h = (b - r) / s + 2;
3647
+ if (r === max4) h = (g - b) / s + (g < b) * 6;
3648
+ else if (g === max4) h = (b - r) / s + 2;
3649
3649
  else h = (r - g) / s + 4;
3650
- s /= l < 0.5 ? max3 + min3 : 2 - max3 - min3;
3650
+ s /= l < 0.5 ? max4 + min4 : 2 - max4 - min4;
3651
3651
  h *= 60;
3652
3652
  } else {
3653
3653
  s = l > 0 && l < 1 ? 0 : h;
@@ -3692,12 +3692,12 @@ define_default(Hsl, hsl, extend(Color, {
3692
3692
  return `${a === 1 ? "hsl(" : "hsla("}${clamph(this.h)}, ${clampt(this.s) * 100}%, ${clampt(this.l) * 100}%${a === 1 ? ")" : `, ${a})`}`;
3693
3693
  }
3694
3694
  }));
3695
- function clamph(value) {
3696
- value = (value || 0) % 360;
3697
- return value < 0 ? value + 360 : value;
3695
+ function clamph(value2) {
3696
+ value2 = (value2 || 0) % 360;
3697
+ return value2 < 0 ? value2 + 360 : value2;
3698
3698
  }
3699
- function clampt(value) {
3700
- return Math.max(0, Math.min(1, value || 0));
3699
+ function clampt(value2) {
3700
+ return Math.max(0, Math.min(1, value2 || 0));
3701
3701
  }
3702
3702
  function hsl2rgb(h, m1, m2) {
3703
3703
  return (h < 60 ? m1 + (m2 - m1) * h / 60 : h < 180 ? m2 : h < 240 ? m1 + (m2 - m1) * (240 - h) / 60 : m1) * 255;
@@ -4018,11 +4018,11 @@ function exponent_default(x2) {
4018
4018
 
4019
4019
  // ../../node_modules/.bun/d3-format@3.1.2/node_modules/d3-format/src/formatGroup.js
4020
4020
  function formatGroup_default(grouping, thousands) {
4021
- return function(value, width) {
4022
- var i = value.length, t = [], j = 0, g = grouping[0], length = 0;
4021
+ return function(value2, width) {
4022
+ var i = value2.length, t = [], j = 0, g = grouping[0], length = 0;
4023
4023
  while (i > 0 && g > 0) {
4024
4024
  if (length + g + 1 > width) g = Math.max(1, width - length);
4025
- t.push(value.substring(i -= g, i + g));
4025
+ t.push(value2.substring(i -= g, i + g));
4026
4026
  if ((length += g + 1) > width) break;
4027
4027
  g = grouping[j = (j + 1) % grouping.length];
4028
4028
  }
@@ -4032,8 +4032,8 @@ function formatGroup_default(grouping, thousands) {
4032
4032
 
4033
4033
  // ../../node_modules/.bun/d3-format@3.1.2/node_modules/d3-format/src/formatNumerals.js
4034
4034
  function formatNumerals_default(numerals) {
4035
- return function(value) {
4036
- return value.replace(/[0-9]/g, function(i) {
4035
+ return function(value2) {
4036
+ return value2.replace(/[0-9]/g, function(i) {
4037
4037
  return numerals[+i];
4038
4038
  });
4039
4039
  };
@@ -4147,58 +4147,58 @@ function locale_default(locale3) {
4147
4147
  var prefix = (options && options.prefix !== void 0 ? options.prefix : "") + (symbol === "$" ? currencyPrefix : symbol === "#" && /[boxX]/.test(type) ? "0" + type.toLowerCase() : ""), suffix = (symbol === "$" ? currencySuffix : /[%p]/.test(type) ? percent : "") + (options && options.suffix !== void 0 ? options.suffix : "");
4148
4148
  var formatType = formatTypes_default[type], maybeSuffix = /[defgprs%]/.test(type);
4149
4149
  precision = precision === void 0 ? 6 : /[gprs]/.test(type) ? Math.max(1, Math.min(21, precision)) : Math.max(0, Math.min(20, precision));
4150
- function format2(value) {
4150
+ function format2(value2) {
4151
4151
  var valuePrefix = prefix, valueSuffix = suffix, i, n, c;
4152
4152
  if (type === "c") {
4153
- valueSuffix = formatType(value) + valueSuffix;
4154
- value = "";
4153
+ valueSuffix = formatType(value2) + valueSuffix;
4154
+ value2 = "";
4155
4155
  } else {
4156
- value = +value;
4157
- var valueNegative = value < 0 || 1 / value < 0;
4158
- value = isNaN(value) ? nan : formatType(Math.abs(value), precision);
4159
- if (trim) value = formatTrim_default(value);
4160
- if (valueNegative && +value === 0 && sign2 !== "+") valueNegative = false;
4156
+ value2 = +value2;
4157
+ var valueNegative = value2 < 0 || 1 / value2 < 0;
4158
+ value2 = isNaN(value2) ? nan : formatType(Math.abs(value2), precision);
4159
+ if (trim) value2 = formatTrim_default(value2);
4160
+ if (valueNegative && +value2 === 0 && sign2 !== "+") valueNegative = false;
4161
4161
  valuePrefix = (valueNegative ? sign2 === "(" ? sign2 : minus : sign2 === "-" || sign2 === "(" ? "" : sign2) + valuePrefix;
4162
- valueSuffix = (type === "s" && !isNaN(value) && prefixExponent !== void 0 ? prefixes[8 + prefixExponent / 3] : "") + valueSuffix + (valueNegative && sign2 === "(" ? ")" : "");
4162
+ valueSuffix = (type === "s" && !isNaN(value2) && prefixExponent !== void 0 ? prefixes[8 + prefixExponent / 3] : "") + valueSuffix + (valueNegative && sign2 === "(" ? ")" : "");
4163
4163
  if (maybeSuffix) {
4164
- i = -1, n = value.length;
4164
+ i = -1, n = value2.length;
4165
4165
  while (++i < n) {
4166
- if (c = value.charCodeAt(i), 48 > c || c > 57) {
4167
- valueSuffix = (c === 46 ? decimal + value.slice(i + 1) : value.slice(i)) + valueSuffix;
4168
- value = value.slice(0, i);
4166
+ if (c = value2.charCodeAt(i), 48 > c || c > 57) {
4167
+ valueSuffix = (c === 46 ? decimal + value2.slice(i + 1) : value2.slice(i)) + valueSuffix;
4168
+ value2 = value2.slice(0, i);
4169
4169
  break;
4170
4170
  }
4171
4171
  }
4172
4172
  }
4173
4173
  }
4174
- if (comma && !zero3) value = group(value, Infinity);
4175
- var length = valuePrefix.length + value.length + valueSuffix.length, padding = length < width ? new Array(width - length + 1).join(fill) : "";
4176
- if (comma && zero3) value = group(padding + value, padding.length ? width - valueSuffix.length : Infinity), padding = "";
4174
+ if (comma && !zero3) value2 = group(value2, Infinity);
4175
+ var length = valuePrefix.length + value2.length + valueSuffix.length, padding = length < width ? new Array(width - length + 1).join(fill) : "";
4176
+ if (comma && zero3) value2 = group(padding + value2, padding.length ? width - valueSuffix.length : Infinity), padding = "";
4177
4177
  switch (align) {
4178
4178
  case "<":
4179
- value = valuePrefix + value + valueSuffix + padding;
4179
+ value2 = valuePrefix + value2 + valueSuffix + padding;
4180
4180
  break;
4181
4181
  case "=":
4182
- value = valuePrefix + padding + value + valueSuffix;
4182
+ value2 = valuePrefix + padding + value2 + valueSuffix;
4183
4183
  break;
4184
4184
  case "^":
4185
- value = padding.slice(0, length = padding.length >> 1) + valuePrefix + value + valueSuffix + padding.slice(length);
4185
+ value2 = padding.slice(0, length = padding.length >> 1) + valuePrefix + value2 + valueSuffix + padding.slice(length);
4186
4186
  break;
4187
4187
  default:
4188
- value = padding + valuePrefix + value + valueSuffix;
4188
+ value2 = padding + valuePrefix + value2 + valueSuffix;
4189
4189
  break;
4190
4190
  }
4191
- return numerals(value);
4191
+ return numerals(value2);
4192
4192
  }
4193
4193
  format2.toString = function() {
4194
4194
  return specifier + "";
4195
4195
  };
4196
4196
  return format2;
4197
4197
  }
4198
- function formatPrefix2(specifier, value) {
4199
- var e = Math.max(-8, Math.min(8, Math.floor(exponent_default(value) / 3))) * 3, k = Math.pow(10, -e), f = newFormat((specifier = formatSpecifier(specifier), specifier.type = "f", specifier), { suffix: prefixes[8 + e / 3] });
4200
- return function(value2) {
4201
- return f(k * value2);
4198
+ function formatPrefix2(specifier, value2) {
4199
+ var e = Math.max(-8, Math.min(8, Math.floor(exponent_default(value2) / 3))) * 3, k = Math.pow(10, -e), f = newFormat((specifier = formatSpecifier(specifier), specifier.type = "f", specifier), { suffix: prefixes[8 + e / 3] });
4200
+ return function(value3) {
4201
+ return f(k * value3);
4202
4202
  };
4203
4203
  }
4204
4204
  return {
@@ -4229,14 +4229,14 @@ function precisionFixed_default(step) {
4229
4229
  }
4230
4230
 
4231
4231
  // ../../node_modules/.bun/d3-format@3.1.2/node_modules/d3-format/src/precisionPrefix.js
4232
- function precisionPrefix_default(step, value) {
4233
- return Math.max(0, Math.max(-8, Math.min(8, Math.floor(exponent_default(value) / 3))) * 3 - exponent_default(Math.abs(step)));
4232
+ function precisionPrefix_default(step, value2) {
4233
+ return Math.max(0, Math.max(-8, Math.min(8, Math.floor(exponent_default(value2) / 3))) * 3 - exponent_default(Math.abs(step)));
4234
4234
  }
4235
4235
 
4236
4236
  // ../../node_modules/.bun/d3-format@3.1.2/node_modules/d3-format/src/precisionRound.js
4237
- function precisionRound_default(step, max3) {
4238
- step = Math.abs(step), max3 = Math.abs(max3) - step;
4239
- return Math.max(0, exponent_default(max3) - exponent_default(step)) + 1;
4237
+ function precisionRound_default(step, max4) {
4238
+ step = Math.abs(step), max4 = Math.abs(max4) - step;
4239
+ return Math.max(0, exponent_default(max4) - exponent_default(step)) + 1;
4240
4240
  }
4241
4241
 
4242
4242
  // ../../node_modules/.bun/d3-scale@4.0.2/node_modules/d3-scale/src/tickFormat.js
@@ -4245,9 +4245,9 @@ function tickFormat(start, stop, count, specifier) {
4245
4245
  specifier = formatSpecifier(specifier == null ? ",f" : specifier);
4246
4246
  switch (specifier.type) {
4247
4247
  case "s": {
4248
- var value = Math.max(Math.abs(start), Math.abs(stop));
4249
- if (specifier.precision == null && !isNaN(precision = precisionPrefix_default(step, value))) specifier.precision = precision;
4250
- return formatPrefix(specifier, value);
4248
+ var value2 = Math.max(Math.abs(start), Math.abs(stop));
4249
+ if (specifier.precision == null && !isNaN(precision = precisionPrefix_default(step, value2))) specifier.precision = precision;
4250
+ return formatPrefix(specifier, value2);
4251
4251
  }
4252
4252
  case "":
4253
4253
  case "e":
@@ -5246,8 +5246,8 @@ var pads = { "-": "", "_": " ", "0": "0" };
5246
5246
  var numberRe = /^\s*\d+/;
5247
5247
  var percentRe = /^%/;
5248
5248
  var requoteRe = /[\\^$*+?|[\]().{}]/g;
5249
- function pad(value, fill, width) {
5250
- var sign2 = value < 0 ? "-" : "", string = (sign2 ? -value : value) + "", length = string.length;
5249
+ function pad(value2, fill, width) {
5250
+ var sign2 = value2 < 0 ? "-" : "", string = (sign2 ? -value2 : value2) + "", length = string.length;
5251
5251
  return sign2 + (length < width ? new Array(width - length + 1).join(fill) + string : string);
5252
5252
  }
5253
5253
  function requote(s) {
@@ -5598,11 +5598,11 @@ function sequential() {
5598
5598
  var DEFAULT_POINT_RADIUS2 = 5;
5599
5599
  var MIN_BUBBLE_RADIUS = 3;
5600
5600
  var MAX_BUBBLE_RADIUS = 30;
5601
- function resolvePosition2(value, channelType, scale) {
5601
+ function resolvePosition2(value2, channelType, scale) {
5602
5602
  switch (channelType) {
5603
5603
  case "nominal":
5604
5604
  case "ordinal": {
5605
- const s = String(value);
5605
+ const s = String(value2);
5606
5606
  if ("bandwidth" in scale && typeof scale.bandwidth === "function") {
5607
5607
  const bw = scale.bandwidth();
5608
5608
  const pos = scale(s);
@@ -5612,11 +5612,11 @@ function resolvePosition2(value, channelType, scale) {
5612
5612
  return scale(s);
5613
5613
  }
5614
5614
  case "temporal": {
5615
- const px = scale(new Date(value));
5615
+ const px = scale(new Date(value2));
5616
5616
  return Number.isNaN(px) ? void 0 : px;
5617
5617
  }
5618
5618
  default: {
5619
- const num = Number(value);
5619
+ const num = Number(value2);
5620
5620
  if (!Number.isFinite(num)) return void 0;
5621
5621
  return scale(num);
5622
5622
  }
@@ -5849,14 +5849,15 @@ import {
5849
5849
  isChartSpec,
5850
5850
  isGraphSpec,
5851
5851
  isLayerSpec,
5852
+ isSankeySpec,
5852
5853
  isTableSpec,
5853
5854
  resolveMarkDef,
5854
5855
  resolveMarkType
5855
5856
  } from "@opendata-ai/openchart-core";
5856
- function normalizeChromeField(value) {
5857
- if (value === void 0) return void 0;
5858
- if (typeof value === "string") return { text: value };
5859
- return value;
5857
+ function normalizeChromeField(value2) {
5858
+ if (value2 === void 0) return void 0;
5859
+ if (typeof value2 === "string") return { text: value2 };
5860
+ return value2;
5860
5861
  }
5861
5862
  function normalizeChrome(chrome) {
5862
5863
  if (!chrome) return {};
@@ -5874,26 +5875,26 @@ function inferFieldType(data, field) {
5874
5875
  let dateCount = 0;
5875
5876
  let totalNonNull = 0;
5876
5877
  for (let i = 0; i < sampleSize; i++) {
5877
- const value = data[i][field];
5878
- if (value == null) continue;
5878
+ const value2 = data[i][field];
5879
+ if (value2 == null) continue;
5879
5880
  totalNonNull++;
5880
- if (typeof value === "number" && Number.isFinite(value)) {
5881
+ if (typeof value2 === "number" && Number.isFinite(value2)) {
5881
5882
  numericCount++;
5882
5883
  continue;
5883
5884
  }
5884
- if (typeof value === "string") {
5885
- const num = Number(value);
5886
- if (!Number.isNaN(num) && Number.isFinite(num) && value.trim() !== "") {
5885
+ if (typeof value2 === "string") {
5886
+ const num = Number(value2);
5887
+ if (!Number.isNaN(num) && Number.isFinite(num) && value2.trim() !== "") {
5887
5888
  numericCount++;
5888
5889
  continue;
5889
5890
  }
5890
- const date2 = new Date(value);
5891
+ const date2 = new Date(value2);
5891
5892
  if (!Number.isNaN(date2.getTime())) {
5892
5893
  dateCount++;
5893
5894
  continue;
5894
5895
  }
5895
5896
  }
5896
- if (value instanceof Date && !Number.isNaN(value.getTime())) {
5897
+ if (value2 instanceof Date && !Number.isNaN(value2.getTime())) {
5897
5898
  dateCount++;
5898
5899
  }
5899
5900
  }
@@ -5997,6 +5998,23 @@ function normalizeTableSpec(spec, _warnings) {
5997
5998
  animation: spec.animation
5998
5999
  };
5999
6000
  }
6001
+ function normalizeSankeySpec(spec, _warnings) {
6002
+ return {
6003
+ type: "sankey",
6004
+ data: spec.data,
6005
+ encoding: spec.encoding,
6006
+ nodeWidth: spec.nodeWidth ?? 12,
6007
+ nodePadding: spec.nodePadding ?? 16,
6008
+ nodeAlign: spec.nodeAlign ?? "justify",
6009
+ iterations: spec.iterations ?? 6,
6010
+ linkStyle: spec.linkStyle ?? "gradient",
6011
+ chrome: normalizeChrome(spec.chrome),
6012
+ legend: spec.legend,
6013
+ theme: spec.theme ?? {},
6014
+ darkMode: spec.darkMode ?? "off",
6015
+ animation: spec.animation
6016
+ };
6017
+ }
6000
6018
  function normalizeGraphSpec(spec, _warnings) {
6001
6019
  const defaultLayout = {
6002
6020
  type: "force",
@@ -6037,8 +6055,11 @@ function normalizeSpec(spec, warnings = []) {
6037
6055
  if (isGraphSpec(spec)) {
6038
6056
  return normalizeGraphSpec(spec, warnings);
6039
6057
  }
6058
+ if (isSankeySpec(spec)) {
6059
+ return normalizeSankeySpec(spec, warnings);
6060
+ }
6040
6061
  throw new Error(
6041
- `Unknown spec shape. Expected mark (chart), layer, type: 'table', or type: 'graph'.`
6062
+ `Unknown spec shape. Expected mark (chart), layer, type: 'table', type: 'graph', or type: 'sankey'.`
6042
6063
  );
6043
6064
  }
6044
6065
  function flattenLayers(spec, parentData, parentEncoding, parentTransforms) {
@@ -6071,19 +6092,19 @@ import {
6071
6092
  } from "@opendata-ai/openchart-core";
6072
6093
  var VALID_FIELD_TYPES = /* @__PURE__ */ new Set(["quantitative", "temporal", "nominal", "ordinal"]);
6073
6094
  var VALID_DARK_MODES = /* @__PURE__ */ new Set(["auto", "force", "off"]);
6074
- function isParseableDate(value) {
6075
- if (value instanceof Date) return !Number.isNaN(value.getTime());
6076
- if (typeof value === "string") {
6077
- const d = new Date(value);
6095
+ function isParseableDate(value2) {
6096
+ if (value2 instanceof Date) return !Number.isNaN(value2.getTime());
6097
+ if (typeof value2 === "string") {
6098
+ const d = new Date(value2);
6078
6099
  return !Number.isNaN(d.getTime());
6079
6100
  }
6080
- if (typeof value === "number") return true;
6101
+ if (typeof value2 === "number") return true;
6081
6102
  return false;
6082
6103
  }
6083
- function isNumeric(value) {
6084
- if (typeof value === "number") return Number.isFinite(value);
6085
- if (typeof value === "string") {
6086
- const n = Number(value);
6104
+ function isNumeric(value2) {
6105
+ if (typeof value2 === "number") return Number.isFinite(value2);
6106
+ if (typeof value2 === "string") {
6107
+ const n = Number(value2);
6087
6108
  return !Number.isNaN(n) && Number.isFinite(n);
6088
6109
  }
6089
6110
  return false;
@@ -6498,6 +6519,85 @@ function validateGraphSpec(spec, errors) {
6498
6519
  }
6499
6520
  }
6500
6521
  }
6522
+ function validateSankeySpec(spec, errors) {
6523
+ if (!Array.isArray(spec.data)) {
6524
+ errors.push({
6525
+ message: 'Spec error: sankey spec requires a "data" array',
6526
+ path: "data",
6527
+ code: "INVALID_TYPE",
6528
+ suggestion: 'Provide data as an array of objects, e.g. data: [{ source: "A", target: "B", value: 10 }]'
6529
+ });
6530
+ return;
6531
+ }
6532
+ if (spec.data.length === 0) {
6533
+ errors.push({
6534
+ message: 'Spec error: "data" must be a non-empty array',
6535
+ path: "data",
6536
+ code: "EMPTY_DATA",
6537
+ suggestion: 'Add at least one data row, e.g. data: [{ source: "A", target: "B", value: 10 }]'
6538
+ });
6539
+ return;
6540
+ }
6541
+ const firstRow = spec.data[0];
6542
+ if (typeof firstRow !== "object" || firstRow === null || Array.isArray(firstRow)) {
6543
+ errors.push({
6544
+ message: 'Spec error: each item in "data" must be a plain object',
6545
+ path: "data[0]",
6546
+ code: "INVALID_TYPE",
6547
+ suggestion: 'Each data item should be an object, e.g. { source: "A", target: "B", value: 10 }'
6548
+ });
6549
+ return;
6550
+ }
6551
+ if (!spec.encoding || typeof spec.encoding !== "object") {
6552
+ errors.push({
6553
+ message: 'Spec error: sankey spec requires an "encoding" object with source, target, and value channels',
6554
+ path: "encoding",
6555
+ code: "MISSING_FIELD",
6556
+ suggestion: 'Add an encoding object, e.g. encoding: { source: { field: "source", type: "nominal" }, target: { field: "target", type: "nominal" }, value: { field: "value", type: "quantitative" } }'
6557
+ });
6558
+ return;
6559
+ }
6560
+ const encoding = spec.encoding;
6561
+ const dataColumns = new Set(Object.keys(firstRow));
6562
+ const availableColumns = [...dataColumns].join(", ");
6563
+ for (const channel of ["source", "target", "value"]) {
6564
+ const ch = encoding[channel];
6565
+ if (!ch || typeof ch !== "object") {
6566
+ errors.push({
6567
+ message: `Spec error: sankey encoding requires "${channel}" channel`,
6568
+ path: `encoding.${channel}`,
6569
+ code: "MISSING_FIELD",
6570
+ suggestion: `Add encoding.${channel} with a field from your data (${availableColumns}). Example: ${channel}: { field: "${[...dataColumns][0] ?? "myField"}", type: "${channel === "value" ? "quantitative" : "nominal"}" }`
6571
+ });
6572
+ continue;
6573
+ }
6574
+ if (!ch.field || typeof ch.field !== "string") {
6575
+ errors.push({
6576
+ message: `Spec error: encoding.${channel} must have a "field" string`,
6577
+ path: `encoding.${channel}.field`,
6578
+ code: "MISSING_FIELD",
6579
+ suggestion: `Add a field name from your data columns: ${availableColumns}`
6580
+ });
6581
+ continue;
6582
+ }
6583
+ if (!dataColumns.has(ch.field)) {
6584
+ errors.push({
6585
+ message: `Spec error: encoding.${channel}.field "${ch.field}" does not exist in data. Available columns: ${availableColumns}`,
6586
+ path: `encoding.${channel}.field`,
6587
+ code: "DATA_FIELD_MISSING",
6588
+ suggestion: `Use one of the available data columns: ${availableColumns}`
6589
+ });
6590
+ }
6591
+ }
6592
+ if (spec.darkMode !== void 0 && !VALID_DARK_MODES.has(spec.darkMode)) {
6593
+ errors.push({
6594
+ message: 'Spec error: darkMode must be "auto", "force", or "off"',
6595
+ path: "darkMode",
6596
+ code: "INVALID_VALUE",
6597
+ suggestion: 'Use one of: "auto" (system preference), "force" (always dark), or "off" (always light)'
6598
+ });
6599
+ }
6600
+ }
6501
6601
  function validateLayerSpec(spec, errors) {
6502
6602
  const layer = spec.layer;
6503
6603
  if (layer.length === 0) {
@@ -6591,17 +6691,18 @@ function validateSpec(spec) {
6591
6691
  const hasMark = "mark" in obj;
6592
6692
  const isTable = obj.type === "table";
6593
6693
  const isGraph = obj.type === "graph";
6594
- const isLayer = hasLayer && !isTable && !isGraph;
6595
- const isChart = hasMark && !hasLayer && !isTable && !isGraph;
6596
- if (!isChart && !isTable && !isGraph && !isLayer) {
6694
+ const isSankey = obj.type === "sankey";
6695
+ const isLayer = hasLayer && !isTable && !isGraph && !isSankey;
6696
+ const isChart = hasMark && !hasLayer && !isTable && !isGraph && !isSankey;
6697
+ if (!isChart && !isTable && !isGraph && !isSankey && !isLayer) {
6597
6698
  return {
6598
6699
  valid: false,
6599
6700
  errors: [
6600
6701
  {
6601
- message: 'Spec error: spec must have a "mark" field for charts, a "layer" array for layered charts, or a "type" field for tables/graphs',
6702
+ message: 'Spec error: spec must have a "mark" field for charts, a "layer" array for layered charts, or a "type" field for tables/graphs/sankey',
6602
6703
  path: "mark",
6603
6704
  code: "MISSING_FIELD",
6604
- suggestion: `Add a "mark" field for charts (e.g. mark: "bar"), a "layer" array for layered charts, or a "type" field for tables/graphs (type: "table" or type: "graph"). Valid mark types: ${[...MARK_TYPES].join(", ")}`
6705
+ suggestion: `Add a "mark" field for charts (e.g. mark: "bar"), a "layer" array for layered charts, or a "type" field for tables/graphs/sankey (type: "table", type: "graph", or type: "sankey"). Valid mark types: ${[...MARK_TYPES].join(", ")}`
6605
6706
  }
6606
6707
  ],
6607
6708
  normalized: null
@@ -6637,6 +6738,8 @@ function validateSpec(spec) {
6637
6738
  validateTableSpec(obj, errors);
6638
6739
  } else if (isGraph) {
6639
6740
  validateGraphSpec(obj, errors);
6741
+ } else if (isSankey) {
6742
+ validateSankeySpec(obj, errors);
6640
6743
  }
6641
6744
  if (errors.length > 0) {
6642
6745
  return { valid: false, errors, normalized: null };
@@ -6923,8 +7026,8 @@ function resolveEdgeVisuals(edges, encoding, theme) {
6923
7026
  function assignCommunities(nodes, clusteringField) {
6924
7027
  if (!clusteringField) return;
6925
7028
  for (const node of nodes) {
6926
- const value = node.data[clusteringField];
6927
- node.community = value != null ? String(value) : void 0;
7029
+ const value2 = node.data[clusteringField];
7030
+ node.community = value2 != null ? String(value2) : void 0;
6928
7031
  }
6929
7032
  }
6930
7033
  function buildCommunityColorMap(nodes, theme) {
@@ -7011,12 +7114,12 @@ function buildGraphTooltips(nodes) {
7011
7114
  color: node.fill
7012
7115
  });
7013
7116
  }
7014
- for (const [key, value] of Object.entries(node.data)) {
7117
+ for (const [key, value2] of Object.entries(node.data)) {
7015
7118
  if (key === "id") continue;
7016
- if (value == null) continue;
7119
+ if (value2 == null) continue;
7017
7120
  fields.push({
7018
7121
  label: key,
7019
- value: typeof value === "number" ? value.toLocaleString() : String(value)
7122
+ value: typeof value2 === "number" ? value2.toLocaleString() : String(value2)
7020
7123
  });
7021
7124
  }
7022
7125
  descriptors.set(node.id, {
@@ -7185,19 +7288,19 @@ function continuousTicks(resolvedScale, density) {
7185
7288
  const scale = resolvedScale.scale;
7186
7289
  if (!("ticks" in scale) || typeof scale.ticks !== "function") {
7187
7290
  const domain = scale.domain();
7188
- return domain.map((value) => ({
7189
- value,
7190
- position: scale(value),
7191
- label: formatTickLabel(value, resolvedScale)
7291
+ return domain.map((value2) => ({
7292
+ value: value2,
7293
+ position: scale(value2),
7294
+ label: formatTickLabel(value2, resolvedScale)
7192
7295
  }));
7193
7296
  }
7194
7297
  const explicitCount = resolvedScale.channel.axis?.tickCount;
7195
7298
  const count = explicitCount ?? TICK_COUNTS[density];
7196
7299
  const rawTicks = scale.ticks(count);
7197
- const ticks2 = rawTicks.map((value) => ({
7198
- value,
7199
- position: scale(value),
7200
- label: formatTickLabel(value, resolvedScale)
7300
+ const ticks2 = rawTicks.map((value2) => ({
7301
+ value: value2,
7302
+ position: scale(value2),
7303
+ label: formatTickLabel(value2, resolvedScale)
7201
7304
  }));
7202
7305
  return ticks2;
7203
7306
  }
@@ -7211,13 +7314,13 @@ function categoricalTicks(resolvedScale, density) {
7211
7314
  const step = Math.ceil(domain.length / maxTicks);
7212
7315
  selectedValues = domain.filter((_, i) => i % step === 0);
7213
7316
  }
7214
- const ticks2 = selectedValues.map((value) => {
7317
+ const ticks2 = selectedValues.map((value2) => {
7215
7318
  const bandScale = resolvedScale.type === "band" ? scale : null;
7216
- const pos = bandScale ? (bandScale(value) ?? 0) + bandScale.bandwidth() / 2 : scale(value) ?? 0;
7319
+ const pos = bandScale ? (bandScale(value2) ?? 0) + bandScale.bandwidth() / 2 : scale(value2) ?? 0;
7217
7320
  return {
7218
- value,
7321
+ value: value2,
7219
7322
  position: pos,
7220
- label: value
7323
+ label: value2
7221
7324
  };
7222
7325
  });
7223
7326
  return ticks2;
@@ -7233,16 +7336,16 @@ var NUMERIC_SCALE_TYPES = /* @__PURE__ */ new Set([
7233
7336
  "threshold"
7234
7337
  ]);
7235
7338
  var TEMPORAL_SCALE_TYPES = /* @__PURE__ */ new Set(["time", "utc"]);
7236
- function formatTickLabel(value, resolvedScale) {
7339
+ function formatTickLabel(value2, resolvedScale) {
7237
7340
  const formatStr = resolvedScale.channel.axis?.format;
7238
7341
  if (TEMPORAL_SCALE_TYPES.has(resolvedScale.type)) {
7239
7342
  const temporalFmt = buildTemporalFormatter(formatStr);
7240
- if (temporalFmt) return temporalFmt(value);
7343
+ if (temporalFmt) return temporalFmt(value2);
7241
7344
  const useUtc = resolvedScale.type === "utc";
7242
- return formatDate(value, void 0, void 0, useUtc);
7345
+ return formatDate(value2, void 0, void 0, useUtc);
7243
7346
  }
7244
7347
  if (NUMERIC_SCALE_TYPES.has(resolvedScale.type)) {
7245
- const num = value;
7348
+ const num = value2;
7246
7349
  if (formatStr) {
7247
7350
  const fmt = buildD3Formatter3(formatStr);
7248
7351
  if (fmt) return fmt(num);
@@ -7250,26 +7353,26 @@ function formatTickLabel(value, resolvedScale) {
7250
7353
  if (Math.abs(num) >= 1e3) return abbreviateNumber3(num);
7251
7354
  return formatNumber3(num);
7252
7355
  }
7253
- return String(value);
7356
+ return String(value2);
7254
7357
  }
7255
7358
  function resolveExplicitTicks(values, resolvedScale) {
7256
7359
  const scale = resolvedScale.scale;
7257
- return values.map((value) => {
7360
+ return values.map((value2) => {
7258
7361
  let position;
7259
7362
  if (TEMPORAL_SCALE_TYPES.has(resolvedScale.type)) {
7260
- const d = value instanceof Date ? value : new Date(String(value));
7363
+ const d = value2 instanceof Date ? value2 : new Date(String(value2));
7261
7364
  position = scale(d);
7262
7365
  } else if (resolvedScale.type === "band" || resolvedScale.type === "point" || resolvedScale.type === "ordinal") {
7263
- const s = String(value);
7366
+ const s = String(value2);
7264
7367
  const bandScale = resolvedScale.type === "band" ? scale : null;
7265
7368
  position = bandScale ? (bandScale(s) ?? 0) + bandScale.bandwidth() / 2 : scale(s) ?? 0;
7266
7369
  } else {
7267
- position = scale(value);
7370
+ position = scale(value2);
7268
7371
  }
7269
7372
  return {
7270
- value,
7373
+ value: value2,
7271
7374
  position,
7272
- label: formatTickLabel(value, resolvedScale)
7375
+ label: formatTickLabel(value2, resolvedScale)
7273
7376
  };
7274
7377
  });
7275
7378
  }
@@ -8027,8 +8130,8 @@ function extractColorEntries(spec, theme) {
8027
8130
  const uniqueValues = [...new Set(spec.data.map((d) => String(d[colorEnc.field])))];
8028
8131
  const palette = theme.colors.categorical;
8029
8132
  const shape = swatchShapeForType(spec.markType);
8030
- return uniqueValues.map((value, i) => ({
8031
- label: value,
8133
+ return uniqueValues.map((value2, i) => ({
8134
+ label: value2,
8032
8135
  color: palette[i % palette.length],
8033
8136
  shape,
8034
8137
  active: true
@@ -8156,9 +8259,9 @@ function computeLegend(spec, strategy, theme, chartArea) {
8156
8259
  if (maxFit < entries.length) {
8157
8260
  entries = truncateEntries(entries, maxFit);
8158
8261
  }
8159
- const totalWidth = entries.reduce((sum, entry) => {
8262
+ const totalWidth = entries.reduce((sum2, entry) => {
8160
8263
  const labelWidth = estimateTextWidth9(entry.label, labelStyle.fontSize, labelStyle.fontWeight);
8161
- return sum + SWATCH_SIZE2 + SWATCH_GAP2 + labelWidth + ENTRY_GAP2;
8264
+ return sum2 + SWATCH_SIZE2 + SWATCH_GAP2 + labelWidth + ENTRY_GAP2;
8162
8265
  }, 0);
8163
8266
  let rowCount = 1;
8164
8267
  let rowWidth = 0;
@@ -8192,15 +8295,879 @@ function computeLegend(spec, strategy, theme, chartArea) {
8192
8295
  };
8193
8296
  }
8194
8297
 
8298
+ // src/sankey/compile-sankey.ts
8299
+ import {
8300
+ adaptTheme as adaptTheme2,
8301
+ computeChrome as computeChrome3,
8302
+ estimateTextWidth as estimateTextWidth10,
8303
+ formatNumber as formatNumber4,
8304
+ resolveTheme as resolveTheme2
8305
+ } from "@opendata-ai/openchart-core";
8306
+
8307
+ // ../../node_modules/.bun/d3-array@2.12.1/node_modules/d3-array/src/max.js
8308
+ function max3(values, valueof) {
8309
+ let max4;
8310
+ if (valueof === void 0) {
8311
+ for (const value2 of values) {
8312
+ if (value2 != null && (max4 < value2 || max4 === void 0 && value2 >= value2)) {
8313
+ max4 = value2;
8314
+ }
8315
+ }
8316
+ } else {
8317
+ let index = -1;
8318
+ for (let value2 of values) {
8319
+ if ((value2 = valueof(value2, ++index, values)) != null && (max4 < value2 || max4 === void 0 && value2 >= value2)) {
8320
+ max4 = value2;
8321
+ }
8322
+ }
8323
+ }
8324
+ return max4;
8325
+ }
8326
+
8327
+ // ../../node_modules/.bun/d3-array@2.12.1/node_modules/d3-array/src/min.js
8328
+ function min3(values, valueof) {
8329
+ let min4;
8330
+ if (valueof === void 0) {
8331
+ for (const value2 of values) {
8332
+ if (value2 != null && (min4 > value2 || min4 === void 0 && value2 >= value2)) {
8333
+ min4 = value2;
8334
+ }
8335
+ }
8336
+ } else {
8337
+ let index = -1;
8338
+ for (let value2 of values) {
8339
+ if ((value2 = valueof(value2, ++index, values)) != null && (min4 > value2 || min4 === void 0 && value2 >= value2)) {
8340
+ min4 = value2;
8341
+ }
8342
+ }
8343
+ }
8344
+ return min4;
8345
+ }
8346
+
8347
+ // ../../node_modules/.bun/d3-array@2.12.1/node_modules/d3-array/src/sum.js
8348
+ function sum(values, valueof) {
8349
+ let sum2 = 0;
8350
+ if (valueof === void 0) {
8351
+ for (let value2 of values) {
8352
+ if (value2 = +value2) {
8353
+ sum2 += value2;
8354
+ }
8355
+ }
8356
+ } else {
8357
+ let index = -1;
8358
+ for (let value2 of values) {
8359
+ if (value2 = +valueof(value2, ++index, values)) {
8360
+ sum2 += value2;
8361
+ }
8362
+ }
8363
+ }
8364
+ return sum2;
8365
+ }
8366
+
8367
+ // ../../node_modules/.bun/d3-sankey@0.12.3/node_modules/d3-sankey/src/align.js
8368
+ function targetDepth(d) {
8369
+ return d.target.depth;
8370
+ }
8371
+ function left(node) {
8372
+ return node.depth;
8373
+ }
8374
+ function right(node, n) {
8375
+ return n - 1 - node.height;
8376
+ }
8377
+ function justify(node, n) {
8378
+ return node.sourceLinks.length ? node.depth : n - 1;
8379
+ }
8380
+ function center(node) {
8381
+ return node.targetLinks.length ? node.depth : node.sourceLinks.length ? min3(node.sourceLinks, targetDepth) - 1 : 0;
8382
+ }
8383
+
8384
+ // ../../node_modules/.bun/d3-sankey@0.12.3/node_modules/d3-sankey/src/constant.js
8385
+ function constant(x2) {
8386
+ return function() {
8387
+ return x2;
8388
+ };
8389
+ }
8390
+
8391
+ // ../../node_modules/.bun/d3-sankey@0.12.3/node_modules/d3-sankey/src/sankey.js
8392
+ function ascendingSourceBreadth(a, b) {
8393
+ return ascendingBreadth(a.source, b.source) || a.index - b.index;
8394
+ }
8395
+ function ascendingTargetBreadth(a, b) {
8396
+ return ascendingBreadth(a.target, b.target) || a.index - b.index;
8397
+ }
8398
+ function ascendingBreadth(a, b) {
8399
+ return a.y0 - b.y0;
8400
+ }
8401
+ function value(d) {
8402
+ return d.value;
8403
+ }
8404
+ function defaultId(d) {
8405
+ return d.index;
8406
+ }
8407
+ function defaultNodes(graph) {
8408
+ return graph.nodes;
8409
+ }
8410
+ function defaultLinks(graph) {
8411
+ return graph.links;
8412
+ }
8413
+ function find(nodeById, id) {
8414
+ const node = nodeById.get(id);
8415
+ if (!node) throw new Error("missing: " + id);
8416
+ return node;
8417
+ }
8418
+ function computeLinkBreadths({ nodes }) {
8419
+ for (const node of nodes) {
8420
+ let y0 = node.y0;
8421
+ let y1 = y0;
8422
+ for (const link of node.sourceLinks) {
8423
+ link.y0 = y0 + link.width / 2;
8424
+ y0 += link.width;
8425
+ }
8426
+ for (const link of node.targetLinks) {
8427
+ link.y1 = y1 + link.width / 2;
8428
+ y1 += link.width;
8429
+ }
8430
+ }
8431
+ }
8432
+ function Sankey() {
8433
+ let x0 = 0, y0 = 0, x1 = 1, y1 = 1;
8434
+ let dx = 24;
8435
+ let dy = 8, py;
8436
+ let id = defaultId;
8437
+ let align = justify;
8438
+ let sort;
8439
+ let linkSort;
8440
+ let nodes = defaultNodes;
8441
+ let links = defaultLinks;
8442
+ let iterations = 6;
8443
+ function sankey() {
8444
+ const graph = { nodes: nodes.apply(null, arguments), links: links.apply(null, arguments) };
8445
+ computeNodeLinks(graph);
8446
+ computeNodeValues(graph);
8447
+ computeNodeDepths(graph);
8448
+ computeNodeHeights(graph);
8449
+ computeNodeBreadths(graph);
8450
+ computeLinkBreadths(graph);
8451
+ return graph;
8452
+ }
8453
+ sankey.update = function(graph) {
8454
+ computeLinkBreadths(graph);
8455
+ return graph;
8456
+ };
8457
+ sankey.nodeId = function(_) {
8458
+ return arguments.length ? (id = typeof _ === "function" ? _ : constant(_), sankey) : id;
8459
+ };
8460
+ sankey.nodeAlign = function(_) {
8461
+ return arguments.length ? (align = typeof _ === "function" ? _ : constant(_), sankey) : align;
8462
+ };
8463
+ sankey.nodeSort = function(_) {
8464
+ return arguments.length ? (sort = _, sankey) : sort;
8465
+ };
8466
+ sankey.nodeWidth = function(_) {
8467
+ return arguments.length ? (dx = +_, sankey) : dx;
8468
+ };
8469
+ sankey.nodePadding = function(_) {
8470
+ return arguments.length ? (dy = py = +_, sankey) : dy;
8471
+ };
8472
+ sankey.nodes = function(_) {
8473
+ return arguments.length ? (nodes = typeof _ === "function" ? _ : constant(_), sankey) : nodes;
8474
+ };
8475
+ sankey.links = function(_) {
8476
+ return arguments.length ? (links = typeof _ === "function" ? _ : constant(_), sankey) : links;
8477
+ };
8478
+ sankey.linkSort = function(_) {
8479
+ return arguments.length ? (linkSort = _, sankey) : linkSort;
8480
+ };
8481
+ sankey.size = function(_) {
8482
+ return arguments.length ? (x0 = y0 = 0, x1 = +_[0], y1 = +_[1], sankey) : [x1 - x0, y1 - y0];
8483
+ };
8484
+ sankey.extent = function(_) {
8485
+ return arguments.length ? (x0 = +_[0][0], x1 = +_[1][0], y0 = +_[0][1], y1 = +_[1][1], sankey) : [[x0, y0], [x1, y1]];
8486
+ };
8487
+ sankey.iterations = function(_) {
8488
+ return arguments.length ? (iterations = +_, sankey) : iterations;
8489
+ };
8490
+ function computeNodeLinks({ nodes: nodes2, links: links2 }) {
8491
+ for (const [i, node] of nodes2.entries()) {
8492
+ node.index = i;
8493
+ node.sourceLinks = [];
8494
+ node.targetLinks = [];
8495
+ }
8496
+ const nodeById = new Map(nodes2.map((d, i) => [id(d, i, nodes2), d]));
8497
+ for (const [i, link] of links2.entries()) {
8498
+ link.index = i;
8499
+ let { source, target } = link;
8500
+ if (typeof source !== "object") source = link.source = find(nodeById, source);
8501
+ if (typeof target !== "object") target = link.target = find(nodeById, target);
8502
+ source.sourceLinks.push(link);
8503
+ target.targetLinks.push(link);
8504
+ }
8505
+ if (linkSort != null) {
8506
+ for (const { sourceLinks, targetLinks } of nodes2) {
8507
+ sourceLinks.sort(linkSort);
8508
+ targetLinks.sort(linkSort);
8509
+ }
8510
+ }
8511
+ }
8512
+ function computeNodeValues({ nodes: nodes2 }) {
8513
+ for (const node of nodes2) {
8514
+ node.value = node.fixedValue === void 0 ? Math.max(sum(node.sourceLinks, value), sum(node.targetLinks, value)) : node.fixedValue;
8515
+ }
8516
+ }
8517
+ function computeNodeDepths({ nodes: nodes2 }) {
8518
+ const n = nodes2.length;
8519
+ let current = new Set(nodes2);
8520
+ let next = /* @__PURE__ */ new Set();
8521
+ let x2 = 0;
8522
+ while (current.size) {
8523
+ for (const node of current) {
8524
+ node.depth = x2;
8525
+ for (const { target } of node.sourceLinks) {
8526
+ next.add(target);
8527
+ }
8528
+ }
8529
+ if (++x2 > n) throw new Error("circular link");
8530
+ current = next;
8531
+ next = /* @__PURE__ */ new Set();
8532
+ }
8533
+ }
8534
+ function computeNodeHeights({ nodes: nodes2 }) {
8535
+ const n = nodes2.length;
8536
+ let current = new Set(nodes2);
8537
+ let next = /* @__PURE__ */ new Set();
8538
+ let x2 = 0;
8539
+ while (current.size) {
8540
+ for (const node of current) {
8541
+ node.height = x2;
8542
+ for (const { source } of node.targetLinks) {
8543
+ next.add(source);
8544
+ }
8545
+ }
8546
+ if (++x2 > n) throw new Error("circular link");
8547
+ current = next;
8548
+ next = /* @__PURE__ */ new Set();
8549
+ }
8550
+ }
8551
+ function computeNodeLayers({ nodes: nodes2 }) {
8552
+ const x2 = max3(nodes2, (d) => d.depth) + 1;
8553
+ const kx = (x1 - x0 - dx) / (x2 - 1);
8554
+ const columns = new Array(x2);
8555
+ for (const node of nodes2) {
8556
+ const i = Math.max(0, Math.min(x2 - 1, Math.floor(align.call(null, node, x2))));
8557
+ node.layer = i;
8558
+ node.x0 = x0 + i * kx;
8559
+ node.x1 = node.x0 + dx;
8560
+ if (columns[i]) columns[i].push(node);
8561
+ else columns[i] = [node];
8562
+ }
8563
+ if (sort) for (const column of columns) {
8564
+ column.sort(sort);
8565
+ }
8566
+ return columns;
8567
+ }
8568
+ function initializeNodeBreadths(columns) {
8569
+ const ky = min3(columns, (c) => (y1 - y0 - (c.length - 1) * py) / sum(c, value));
8570
+ for (const nodes2 of columns) {
8571
+ let y2 = y0;
8572
+ for (const node of nodes2) {
8573
+ node.y0 = y2;
8574
+ node.y1 = y2 + node.value * ky;
8575
+ y2 = node.y1 + py;
8576
+ for (const link of node.sourceLinks) {
8577
+ link.width = link.value * ky;
8578
+ }
8579
+ }
8580
+ y2 = (y1 - y2 + py) / (nodes2.length + 1);
8581
+ for (let i = 0; i < nodes2.length; ++i) {
8582
+ const node = nodes2[i];
8583
+ node.y0 += y2 * (i + 1);
8584
+ node.y1 += y2 * (i + 1);
8585
+ }
8586
+ reorderLinks(nodes2);
8587
+ }
8588
+ }
8589
+ function computeNodeBreadths(graph) {
8590
+ const columns = computeNodeLayers(graph);
8591
+ py = Math.min(dy, (y1 - y0) / (max3(columns, (c) => c.length) - 1));
8592
+ initializeNodeBreadths(columns);
8593
+ for (let i = 0; i < iterations; ++i) {
8594
+ const alpha = Math.pow(0.99, i);
8595
+ const beta = Math.max(1 - alpha, (i + 1) / iterations);
8596
+ relaxRightToLeft(columns, alpha, beta);
8597
+ relaxLeftToRight(columns, alpha, beta);
8598
+ }
8599
+ }
8600
+ function relaxLeftToRight(columns, alpha, beta) {
8601
+ for (let i = 1, n = columns.length; i < n; ++i) {
8602
+ const column = columns[i];
8603
+ for (const target of column) {
8604
+ let y2 = 0;
8605
+ let w = 0;
8606
+ for (const { source, value: value2 } of target.targetLinks) {
8607
+ let v = value2 * (target.layer - source.layer);
8608
+ y2 += targetTop(source, target) * v;
8609
+ w += v;
8610
+ }
8611
+ if (!(w > 0)) continue;
8612
+ let dy2 = (y2 / w - target.y0) * alpha;
8613
+ target.y0 += dy2;
8614
+ target.y1 += dy2;
8615
+ reorderNodeLinks(target);
8616
+ }
8617
+ if (sort === void 0) column.sort(ascendingBreadth);
8618
+ resolveCollisions6(column, beta);
8619
+ }
8620
+ }
8621
+ function relaxRightToLeft(columns, alpha, beta) {
8622
+ for (let n = columns.length, i = n - 2; i >= 0; --i) {
8623
+ const column = columns[i];
8624
+ for (const source of column) {
8625
+ let y2 = 0;
8626
+ let w = 0;
8627
+ for (const { target, value: value2 } of source.sourceLinks) {
8628
+ let v = value2 * (target.layer - source.layer);
8629
+ y2 += sourceTop(source, target) * v;
8630
+ w += v;
8631
+ }
8632
+ if (!(w > 0)) continue;
8633
+ let dy2 = (y2 / w - source.y0) * alpha;
8634
+ source.y0 += dy2;
8635
+ source.y1 += dy2;
8636
+ reorderNodeLinks(source);
8637
+ }
8638
+ if (sort === void 0) column.sort(ascendingBreadth);
8639
+ resolveCollisions6(column, beta);
8640
+ }
8641
+ }
8642
+ function resolveCollisions6(nodes2, alpha) {
8643
+ const i = nodes2.length >> 1;
8644
+ const subject = nodes2[i];
8645
+ resolveCollisionsBottomToTop(nodes2, subject.y0 - py, i - 1, alpha);
8646
+ resolveCollisionsTopToBottom(nodes2, subject.y1 + py, i + 1, alpha);
8647
+ resolveCollisionsBottomToTop(nodes2, y1, nodes2.length - 1, alpha);
8648
+ resolveCollisionsTopToBottom(nodes2, y0, 0, alpha);
8649
+ }
8650
+ function resolveCollisionsTopToBottom(nodes2, y2, i, alpha) {
8651
+ for (; i < nodes2.length; ++i) {
8652
+ const node = nodes2[i];
8653
+ const dy2 = (y2 - node.y0) * alpha;
8654
+ if (dy2 > 1e-6) node.y0 += dy2, node.y1 += dy2;
8655
+ y2 = node.y1 + py;
8656
+ }
8657
+ }
8658
+ function resolveCollisionsBottomToTop(nodes2, y2, i, alpha) {
8659
+ for (; i >= 0; --i) {
8660
+ const node = nodes2[i];
8661
+ const dy2 = (node.y1 - y2) * alpha;
8662
+ if (dy2 > 1e-6) node.y0 -= dy2, node.y1 -= dy2;
8663
+ y2 = node.y0 - py;
8664
+ }
8665
+ }
8666
+ function reorderNodeLinks({ sourceLinks, targetLinks }) {
8667
+ if (linkSort === void 0) {
8668
+ for (const { source: { sourceLinks: sourceLinks2 } } of targetLinks) {
8669
+ sourceLinks2.sort(ascendingTargetBreadth);
8670
+ }
8671
+ for (const { target: { targetLinks: targetLinks2 } } of sourceLinks) {
8672
+ targetLinks2.sort(ascendingSourceBreadth);
8673
+ }
8674
+ }
8675
+ }
8676
+ function reorderLinks(nodes2) {
8677
+ if (linkSort === void 0) {
8678
+ for (const { sourceLinks, targetLinks } of nodes2) {
8679
+ sourceLinks.sort(ascendingTargetBreadth);
8680
+ targetLinks.sort(ascendingSourceBreadth);
8681
+ }
8682
+ }
8683
+ }
8684
+ function targetTop(source, target) {
8685
+ let y2 = source.y0 - (source.sourceLinks.length - 1) * py / 2;
8686
+ for (const { target: node, width } of source.sourceLinks) {
8687
+ if (node === target) break;
8688
+ y2 += width + py;
8689
+ }
8690
+ for (const { source: node, width } of target.targetLinks) {
8691
+ if (node === source) break;
8692
+ y2 -= width;
8693
+ }
8694
+ return y2;
8695
+ }
8696
+ function sourceTop(source, target) {
8697
+ let y2 = target.y0 - (target.targetLinks.length - 1) * py / 2;
8698
+ for (const { source: node, width } of target.targetLinks) {
8699
+ if (node === source) break;
8700
+ y2 += width + py;
8701
+ }
8702
+ for (const { target: node, width } of source.sourceLinks) {
8703
+ if (node === target) break;
8704
+ y2 -= width;
8705
+ }
8706
+ return y2;
8707
+ }
8708
+ return sankey;
8709
+ }
8710
+
8711
+ // src/sankey/layout.ts
8712
+ var ALIGN_MAP = {
8713
+ justify,
8714
+ left,
8715
+ right,
8716
+ center
8717
+ };
8718
+ function computeSankeyLayout(data, sourceField, targetField, valueField, area, nodeWidth, nodePadding, nodeAlign, iterations) {
8719
+ const nodeSet = /* @__PURE__ */ new Set();
8720
+ for (const row of data) {
8721
+ nodeSet.add(String(row[sourceField]));
8722
+ nodeSet.add(String(row[targetField]));
8723
+ }
8724
+ const nodes = [...nodeSet].map((id) => ({
8725
+ id,
8726
+ label: id
8727
+ }));
8728
+ const links = data.map((row) => ({
8729
+ source: String(row[sourceField]),
8730
+ target: String(row[targetField]),
8731
+ value: Number(row[valueField]) || 0,
8732
+ data: { ...row }
8733
+ }));
8734
+ const alignFn = ALIGN_MAP[nodeAlign] ?? justify;
8735
+ const generator = Sankey().nodeId((d) => d.id).nodeAlign(alignFn).nodeWidth(nodeWidth).nodePadding(nodePadding).extent([
8736
+ [area.x, area.y],
8737
+ [area.x + area.width, area.y + area.height]
8738
+ ]).iterations(iterations);
8739
+ const graph = generator({
8740
+ nodes,
8741
+ links
8742
+ });
8743
+ return {
8744
+ nodes: graph.nodes,
8745
+ links: graph.links
8746
+ };
8747
+ }
8748
+ function generateLinkPath(link) {
8749
+ const source = link.source;
8750
+ const target = link.target;
8751
+ const x0 = source.x1 ?? 0;
8752
+ const x1 = target.x0 ?? 0;
8753
+ const y0 = link.y0 ?? 0;
8754
+ const y1 = link.y1 ?? 0;
8755
+ const halfWidth0 = (link.width ?? 0) / 2;
8756
+ const halfWidth1 = halfWidth0;
8757
+ const mx = (x0 + x1) / 2;
8758
+ const topY0 = y0 - halfWidth0;
8759
+ const topY1 = y1 - halfWidth1;
8760
+ const botY0 = y0 + halfWidth0;
8761
+ const botY1 = y1 + halfWidth1;
8762
+ return [
8763
+ `M${x0},${topY0}`,
8764
+ `C${mx},${topY0} ${mx},${topY1} ${x1},${topY1}`,
8765
+ `L${x1},${botY1}`,
8766
+ `C${mx},${botY1} ${mx},${botY0} ${x0},${botY0}`,
8767
+ "Z"
8768
+ ].join(" ");
8769
+ }
8770
+
8771
+ // src/sankey/compile-sankey.ts
8772
+ var SWATCH_SIZE3 = 12;
8773
+ var SWATCH_GAP3 = 6;
8774
+ var ENTRY_GAP3 = 16;
8775
+ var LABEL_GAP = 6;
8776
+ var LINK_OPACITY = 0.35;
8777
+ var NODE_CORNER_RADIUS = 2;
8778
+ function pickColor(palette, index) {
8779
+ return palette[index % palette.length];
8780
+ }
8781
+ function buildNodeColorMap(nodes, palette, colorField, data, sourceField, targetField) {
8782
+ const colorMap = /* @__PURE__ */ new Map();
8783
+ if (colorField) {
8784
+ const nodeCategoryMap = /* @__PURE__ */ new Map();
8785
+ for (const row of data) {
8786
+ const src = String(row[sourceField]);
8787
+ const tgt = String(row[targetField]);
8788
+ const cat = String(row[colorField]);
8789
+ if (!nodeCategoryMap.has(src)) nodeCategoryMap.set(src, cat);
8790
+ if (!nodeCategoryMap.has(tgt)) nodeCategoryMap.set(tgt, cat);
8791
+ }
8792
+ const categoryIndex = /* @__PURE__ */ new Map();
8793
+ let nextIdx = 0;
8794
+ for (const node of nodes) {
8795
+ const category = nodeCategoryMap.get(node.id) ?? node.id;
8796
+ if (!categoryIndex.has(category)) {
8797
+ categoryIndex.set(category, nextIdx++);
8798
+ }
8799
+ colorMap.set(node.id, pickColor(palette, categoryIndex.get(category)));
8800
+ }
8801
+ } else {
8802
+ for (let i = 0; i < nodes.length; i++) {
8803
+ colorMap.set(nodes[i].id, pickColor(palette, i));
8804
+ }
8805
+ }
8806
+ return colorMap;
8807
+ }
8808
+ function getLinkColors(linkStyle, sourceColor, targetColor, neutralColor) {
8809
+ switch (linkStyle) {
8810
+ case "source":
8811
+ return { sourceColor, targetColor: sourceColor };
8812
+ case "target":
8813
+ return { sourceColor: targetColor, targetColor };
8814
+ case "neutral":
8815
+ return { sourceColor: neutralColor, targetColor: neutralColor };
8816
+ default:
8817
+ return { sourceColor, targetColor };
8818
+ }
8819
+ }
8820
+ function computeNodeLabel(node, maxDepth, theme, nodeWidth) {
8821
+ const depth = node.depth ?? 0;
8822
+ const isRightmost = depth === maxDepth;
8823
+ const style = {
8824
+ fontFamily: theme.fonts.family,
8825
+ fontSize: theme.fonts.sizes.small,
8826
+ fontWeight: theme.fonts.weights.normal,
8827
+ fill: theme.colors.text,
8828
+ lineHeight: 1.3
8829
+ };
8830
+ const x0 = node.x0 ?? 0;
8831
+ const x1 = node.x1 ?? nodeWidth;
8832
+ const y0 = node.y0 ?? 0;
8833
+ const y1 = node.y1 ?? 0;
8834
+ const midY = (y0 + y1) / 2;
8835
+ if (isRightmost) {
8836
+ return {
8837
+ text: node.label ?? node.id,
8838
+ x: x0 - LABEL_GAP,
8839
+ y: midY,
8840
+ style: { ...style, textAnchor: "end", dominantBaseline: "central" },
8841
+ visible: true
8842
+ };
8843
+ }
8844
+ return {
8845
+ text: node.label ?? node.id,
8846
+ x: x1 + LABEL_GAP,
8847
+ y: midY,
8848
+ style: { ...style, textAnchor: "start", dominantBaseline: "central" },
8849
+ visible: true
8850
+ };
8851
+ }
8852
+ function compileSankey(spec, options) {
8853
+ const { spec: normalized } = compile(spec);
8854
+ if (!("type" in normalized) || normalized.type !== "sankey") {
8855
+ throw new Error(
8856
+ "compileSankey received a non-sankey spec. Use compileChart, compileTable, or compileGraph instead."
8857
+ );
8858
+ }
8859
+ const sankeySpec = normalized;
8860
+ const mergedThemeConfig = options.theme ? { ...sankeySpec.theme, ...options.theme } : sankeySpec.theme;
8861
+ let theme = resolveTheme2(mergedThemeConfig);
8862
+ if (options.darkMode) {
8863
+ theme = adaptTheme2(theme);
8864
+ }
8865
+ const chrome = computeChrome3(
8866
+ {
8867
+ title: sankeySpec.chrome.title,
8868
+ subtitle: sankeySpec.chrome.subtitle,
8869
+ source: sankeySpec.chrome.source,
8870
+ byline: sankeySpec.chrome.byline,
8871
+ footer: sankeySpec.chrome.footer
8872
+ },
8873
+ theme,
8874
+ options.width,
8875
+ options.measureText
8876
+ );
8877
+ const padding = theme.spacing.padding;
8878
+ const fullArea = {
8879
+ x: padding,
8880
+ y: padding + chrome.topHeight,
8881
+ width: options.width - padding * 2,
8882
+ height: options.height - chrome.topHeight - chrome.bottomHeight - padding * 2
8883
+ };
8884
+ if (fullArea.width <= 0 || fullArea.height <= 0) {
8885
+ return emptyLayout(fullArea, chrome, theme, options);
8886
+ }
8887
+ const sourceField = sankeySpec.encoding.source.field;
8888
+ const targetField = sankeySpec.encoding.target.field;
8889
+ const valueField = sankeySpec.encoding.value.field;
8890
+ const colorField = sankeySpec.encoding.color?.field;
8891
+ const tempNodeIds = /* @__PURE__ */ new Set();
8892
+ for (const row of sankeySpec.data) {
8893
+ tempNodeIds.add(String(row[sourceField]));
8894
+ tempNodeIds.add(String(row[targetField]));
8895
+ }
8896
+ const tempColorMap = buildNodeColorMap(
8897
+ [...tempNodeIds].map((id) => ({ id })),
8898
+ theme.colors.categorical,
8899
+ colorField,
8900
+ sankeySpec.data,
8901
+ sourceField,
8902
+ targetField
8903
+ );
8904
+ const legend = buildSankeyLegend(
8905
+ tempColorMap,
8906
+ colorField,
8907
+ sankeySpec.data,
8908
+ sourceField,
8909
+ targetField,
8910
+ theme,
8911
+ fullArea
8912
+ );
8913
+ const legendGap = legend.entries.length > 0 ? 4 : 0;
8914
+ const area = {
8915
+ x: fullArea.x,
8916
+ y: fullArea.y + legend.bounds.height + legendGap,
8917
+ width: fullArea.width,
8918
+ height: fullArea.height - legend.bounds.height - legendGap
8919
+ };
8920
+ if (area.height <= 0) {
8921
+ return emptyLayout(area, chrome, theme, options);
8922
+ }
8923
+ const { nodes, links } = computeSankeyLayout(
8924
+ sankeySpec.data,
8925
+ sourceField,
8926
+ targetField,
8927
+ valueField,
8928
+ area,
8929
+ sankeySpec.nodeWidth,
8930
+ sankeySpec.nodePadding,
8931
+ sankeySpec.nodeAlign,
8932
+ sankeySpec.iterations
8933
+ );
8934
+ const nodeColorMap = buildNodeColorMap(
8935
+ nodes,
8936
+ theme.colors.categorical,
8937
+ colorField,
8938
+ sankeySpec.data,
8939
+ sourceField,
8940
+ targetField
8941
+ );
8942
+ const maxDepth = nodes.reduce((max4, n) => Math.max(max4, n.depth ?? 0), 0);
8943
+ const nodeMarks = nodes.map((node) => {
8944
+ const fill = nodeColorMap.get(node.id) ?? theme.colors.categorical[0];
8945
+ const depth = node.depth ?? 0;
8946
+ return {
8947
+ type: "sankeyNode",
8948
+ x: node.x0 ?? 0,
8949
+ y: node.y0 ?? 0,
8950
+ width: (node.x1 ?? 0) - (node.x0 ?? 0),
8951
+ height: (node.y1 ?? 0) - (node.y0 ?? 0),
8952
+ fill,
8953
+ cornerRadius: NODE_CORNER_RADIUS,
8954
+ label: computeNodeLabel(node, maxDepth, theme, sankeySpec.nodeWidth),
8955
+ nodeId: node.id,
8956
+ value: node.value ?? 0,
8957
+ depth,
8958
+ data: { id: node.id, label: node.label },
8959
+ aria: {
8960
+ role: "img",
8961
+ label: `${node.label}: ${formatNumber4(node.value ?? 0)}`
8962
+ },
8963
+ animationIndex: 0
8964
+ // Reassigned below after sorting by depth
8965
+ };
8966
+ });
8967
+ nodeMarks.sort((a, b) => a.depth - b.depth || a.y - b.y);
8968
+ for (let i = 0; i < nodeMarks.length; i++) {
8969
+ nodeMarks[i].animationIndex = i;
8970
+ }
8971
+ const neutralColor = theme.colors.gridline;
8972
+ const linkMarks = links.map((link, i) => {
8973
+ const sourceNode = link.source;
8974
+ const targetNode = link.target;
8975
+ const srcColor = nodeColorMap.get(sourceNode.id) ?? theme.colors.categorical[0];
8976
+ const tgtColor = nodeColorMap.get(targetNode.id) ?? theme.colors.categorical[0];
8977
+ const colors = getLinkColors(sankeySpec.linkStyle, srcColor, tgtColor, neutralColor);
8978
+ return {
8979
+ type: "sankeyLink",
8980
+ path: generateLinkPath(link),
8981
+ sourceColor: colors.sourceColor,
8982
+ targetColor: colors.targetColor,
8983
+ fillOpacity: LINK_OPACITY,
8984
+ sourceId: sourceNode.id,
8985
+ targetId: targetNode.id,
8986
+ width: link.width ?? 0,
8987
+ value: link.value,
8988
+ data: link.data ?? {},
8989
+ aria: {
8990
+ role: "img",
8991
+ label: `${sourceNode.label} to ${targetNode.label}: ${formatNumber4(link.value)}`
8992
+ },
8993
+ // Links animate after nodes
8994
+ animationIndex: nodeMarks.length + i
8995
+ };
8996
+ });
8997
+ const finalLegend = buildSankeyLegend(
8998
+ nodeColorMap,
8999
+ colorField,
9000
+ sankeySpec.data,
9001
+ sourceField,
9002
+ targetField,
9003
+ theme,
9004
+ fullArea
9005
+ );
9006
+ const tooltipDescriptors = buildTooltipDescriptors(nodeMarks, linkMarks);
9007
+ const a11y = {
9008
+ altText: `Sankey diagram with ${nodeMarks.length} nodes and ${linkMarks.length} links`,
9009
+ dataTableFallback: linkMarks.map((l) => [l.sourceId, l.targetId, String(l.value)]),
9010
+ role: "img",
9011
+ keyboardNavigable: nodeMarks.length > 0
9012
+ };
9013
+ const resolvedAnimation = resolveAnimation(sankeySpec.animation);
9014
+ return {
9015
+ area,
9016
+ chrome,
9017
+ nodes: nodeMarks,
9018
+ links: linkMarks,
9019
+ legend: finalLegend,
9020
+ tooltipDescriptors,
9021
+ a11y,
9022
+ theme,
9023
+ dimensions: {
9024
+ width: options.width,
9025
+ height: options.height
9026
+ },
9027
+ animation: resolvedAnimation
9028
+ };
9029
+ }
9030
+ function buildSankeyLegend(nodeColorMap, colorField, data, sourceField, targetField, theme, area) {
9031
+ const labelStyle = {
9032
+ fontFamily: theme.fonts.family,
9033
+ fontSize: theme.fonts.sizes.small,
9034
+ fontWeight: theme.fonts.weights.normal,
9035
+ fill: theme.colors.text,
9036
+ lineHeight: 1.3
9037
+ };
9038
+ let entries;
9039
+ if (colorField) {
9040
+ const categoryColors = /* @__PURE__ */ new Map();
9041
+ const nodeCategoryMap = /* @__PURE__ */ new Map();
9042
+ for (const row of data) {
9043
+ const src = String(row[sourceField]);
9044
+ const tgt = String(row[targetField]);
9045
+ const cat = String(row[colorField]);
9046
+ if (!nodeCategoryMap.has(src)) nodeCategoryMap.set(src, cat);
9047
+ if (!nodeCategoryMap.has(tgt)) nodeCategoryMap.set(tgt, cat);
9048
+ }
9049
+ for (const [nodeId, category] of nodeCategoryMap) {
9050
+ if (!categoryColors.has(category)) {
9051
+ categoryColors.set(category, nodeColorMap.get(nodeId) ?? theme.colors.categorical[0]);
9052
+ }
9053
+ }
9054
+ entries = [...categoryColors.entries()].map(([label, color2]) => ({
9055
+ label,
9056
+ color: color2,
9057
+ shape: "square",
9058
+ active: true
9059
+ }));
9060
+ } else {
9061
+ entries = [];
9062
+ }
9063
+ let bounds = { x: 0, y: 0, width: 0, height: 0 };
9064
+ if (entries.length > 0) {
9065
+ const ROW_HEIGHT = SWATCH_SIZE3 + 4;
9066
+ const availableWidth = area.width;
9067
+ let rowCount = 1;
9068
+ let rowX = 0;
9069
+ for (const entry of entries) {
9070
+ const labelWidth = estimateTextWidth10(entry.label, labelStyle.fontSize, labelStyle.fontWeight);
9071
+ const entryWidth = SWATCH_SIZE3 + SWATCH_GAP3 + labelWidth + ENTRY_GAP3;
9072
+ if (rowX > 0 && rowX + entryWidth > availableWidth) {
9073
+ rowCount++;
9074
+ rowX = entryWidth;
9075
+ } else {
9076
+ rowX += entryWidth;
9077
+ }
9078
+ }
9079
+ rowCount = Math.min(rowCount, 2);
9080
+ const legendHeight = rowCount * ROW_HEIGHT;
9081
+ bounds = {
9082
+ x: area.x,
9083
+ y: area.y,
9084
+ width: availableWidth,
9085
+ height: legendHeight
9086
+ };
9087
+ }
9088
+ return {
9089
+ position: "top",
9090
+ entries,
9091
+ bounds,
9092
+ labelStyle,
9093
+ swatchSize: SWATCH_SIZE3,
9094
+ swatchGap: SWATCH_GAP3,
9095
+ entryGap: ENTRY_GAP3
9096
+ };
9097
+ }
9098
+ function buildTooltipDescriptors(nodes, links) {
9099
+ const descriptors = /* @__PURE__ */ new Map();
9100
+ for (const node of nodes) {
9101
+ const fields = [
9102
+ {
9103
+ label: "Total flow",
9104
+ value: formatNumber4(node.value)
9105
+ }
9106
+ ];
9107
+ descriptors.set(`node-${node.nodeId}`, {
9108
+ title: node.label.text,
9109
+ fields
9110
+ });
9111
+ }
9112
+ for (const link of links) {
9113
+ const fields = [
9114
+ {
9115
+ label: "Flow",
9116
+ value: formatNumber4(link.value)
9117
+ }
9118
+ ];
9119
+ descriptors.set(`link-${link.sourceId}-${link.targetId}`, {
9120
+ title: `${link.sourceId} \u2192 ${link.targetId}`,
9121
+ fields
9122
+ });
9123
+ }
9124
+ return descriptors;
9125
+ }
9126
+ function emptyLayout(area, chrome, theme, options) {
9127
+ return {
9128
+ area,
9129
+ chrome,
9130
+ nodes: [],
9131
+ links: [],
9132
+ legend: {
9133
+ position: "top",
9134
+ entries: [],
9135
+ bounds: { x: 0, y: 0, width: 0, height: 0 },
9136
+ labelStyle: {
9137
+ fontFamily: theme.fonts.family,
9138
+ fontSize: theme.fonts.sizes.small,
9139
+ fontWeight: theme.fonts.weights.normal,
9140
+ fill: theme.colors.text,
9141
+ lineHeight: 1.3
9142
+ },
9143
+ swatchSize: SWATCH_SIZE3,
9144
+ swatchGap: SWATCH_GAP3,
9145
+ entryGap: ENTRY_GAP3
9146
+ },
9147
+ tooltipDescriptors: /* @__PURE__ */ new Map(),
9148
+ a11y: {
9149
+ altText: "Empty sankey diagram",
9150
+ dataTableFallback: [],
9151
+ role: "img",
9152
+ keyboardNavigable: false
9153
+ },
9154
+ theme,
9155
+ dimensions: {
9156
+ width: options.width,
9157
+ height: options.height
9158
+ }
9159
+ };
9160
+ }
9161
+
8195
9162
  // src/tables/compile-table.ts
8196
- import { computeChrome as computeChrome3, estimateTextWidth as estimateTextWidth10 } from "@opendata-ai/openchart-core";
9163
+ import { computeChrome as computeChrome4, estimateTextWidth as estimateTextWidth11 } from "@opendata-ai/openchart-core";
8197
9164
 
8198
9165
  // src/tables/bar-column.ts
8199
9166
  var NEGATIVE_BAR_COLOR = "#c44e52";
8200
- function computeBarCell(value, config, columnMax, columnMin, theme, _darkMode) {
9167
+ function computeBarCell(value2, config, columnMax, columnMin, theme, _darkMode) {
8201
9168
  const barColor = config.color ?? theme.colors.categorical[0];
8202
9169
  const hasNegatives = columnMin < 0;
8203
- if (!Number.isFinite(value)) {
9170
+ if (!Number.isFinite(value2)) {
8204
9171
  return { barPercent: 0, barOffset: 0, barColor, isNegative: false };
8205
9172
  }
8206
9173
  if (!hasNegatives) {
@@ -8208,7 +9175,7 @@ function computeBarCell(value, config, columnMax, columnMin, theme, _darkMode) {
8208
9175
  if (maxValue <= 0) {
8209
9176
  return { barPercent: 0, barOffset: 0, barColor, isNegative: false };
8210
9177
  }
8211
- const barPercent2 = Math.max(0, Math.min(1, value / maxValue));
9178
+ const barPercent2 = Math.max(0, Math.min(1, value2 / maxValue));
8212
9179
  return { barPercent: barPercent2, barOffset: 0, barColor, isNegative: false };
8213
9180
  }
8214
9181
  const maxPos = config.maxValue ?? columnMax;
@@ -8218,11 +9185,11 @@ function computeBarCell(value, config, columnMax, columnMin, theme, _darkMode) {
8218
9185
  return { barPercent: 0, barOffset: 0, barColor, isNegative: false };
8219
9186
  }
8220
9187
  const zeroPos = absMin / totalRange;
8221
- if (value >= 0) {
8222
- const barPercent2 = value / totalRange;
9188
+ if (value2 >= 0) {
9189
+ const barPercent2 = value2 / totalRange;
8223
9190
  return { barPercent: barPercent2, barOffset: zeroPos, barColor, isNegative: false };
8224
9191
  }
8225
- const barPercent = Math.abs(value) / totalRange;
9192
+ const barPercent = Math.abs(value2) / totalRange;
8226
9193
  return {
8227
9194
  barPercent,
8228
9195
  barOffset: zeroPos - barPercent,
@@ -8231,24 +9198,24 @@ function computeBarCell(value, config, columnMax, columnMin, theme, _darkMode) {
8231
9198
  };
8232
9199
  }
8233
9200
  function computeColumnMax(data, key) {
8234
- let max3 = 0;
9201
+ let max4 = 0;
8235
9202
  for (const row of data) {
8236
9203
  const val = row[key];
8237
- if (typeof val === "number" && Number.isFinite(val) && val > max3) {
8238
- max3 = val;
9204
+ if (typeof val === "number" && Number.isFinite(val) && val > max4) {
9205
+ max4 = val;
8239
9206
  }
8240
9207
  }
8241
- return max3;
9208
+ return max4;
8242
9209
  }
8243
9210
  function computeColumnMin(data, key) {
8244
- let min3 = 0;
9211
+ let min4 = 0;
8245
9212
  for (const row of data) {
8246
9213
  const val = row[key];
8247
- if (typeof val === "number" && Number.isFinite(val) && val < min3) {
8248
- min3 = val;
9214
+ if (typeof val === "number" && Number.isFinite(val) && val < min4) {
9215
+ min4 = val;
8249
9216
  }
8250
9217
  }
8251
- return min3;
9218
+ return min4;
8252
9219
  }
8253
9220
 
8254
9221
  // src/tables/category-colors.ts
@@ -8301,67 +9268,67 @@ function computeCategoryColors(data, column, theme, darkMode) {
8301
9268
  }
8302
9269
 
8303
9270
  // src/tables/format-cells.ts
8304
- import { formatDate as formatDate2, formatNumber as formatNumber4 } from "@opendata-ai/openchart-core";
8305
- function isNumericValue(value) {
8306
- if (typeof value === "number") return Number.isFinite(value);
9271
+ import { formatDate as formatDate2, formatNumber as formatNumber5 } from "@opendata-ai/openchart-core";
9272
+ function isNumericValue(value2) {
9273
+ if (typeof value2 === "number") return Number.isFinite(value2);
8307
9274
  return false;
8308
9275
  }
8309
- function isDateValue(value) {
8310
- if (value instanceof Date) return !Number.isNaN(value.getTime());
9276
+ function isDateValue(value2) {
9277
+ if (value2 instanceof Date) return !Number.isNaN(value2.getTime());
8311
9278
  return false;
8312
9279
  }
8313
- function formatCell(value, column) {
9280
+ function formatCell(value2, column) {
8314
9281
  const style = {};
8315
- if (value == null) {
9282
+ if (value2 == null) {
8316
9283
  return {
8317
- value,
9284
+ value: value2,
8318
9285
  formattedValue: "",
8319
9286
  style
8320
9287
  };
8321
9288
  }
8322
- if (column.format && isNumericValue(value)) {
9289
+ if (column.format && isNumericValue(value2)) {
8323
9290
  try {
8324
9291
  const formatter = format(column.format);
8325
9292
  return {
8326
- value,
8327
- formattedValue: formatter(value),
9293
+ value: value2,
9294
+ formattedValue: formatter(value2),
8328
9295
  style
8329
9296
  };
8330
9297
  } catch {
8331
9298
  }
8332
9299
  }
8333
- if (isNumericValue(value)) {
9300
+ if (isNumericValue(value2)) {
8334
9301
  return {
8335
- value,
8336
- formattedValue: formatNumber4(value),
9302
+ value: value2,
9303
+ formattedValue: formatNumber5(value2),
8337
9304
  style
8338
9305
  };
8339
9306
  }
8340
- if (isDateValue(value)) {
9307
+ if (isDateValue(value2)) {
8341
9308
  return {
8342
- value,
8343
- formattedValue: formatDate2(value),
9309
+ value: value2,
9310
+ formattedValue: formatDate2(value2),
8344
9311
  style
8345
9312
  };
8346
9313
  }
8347
9314
  return {
8348
- value,
8349
- formattedValue: String(value),
9315
+ value: value2,
9316
+ formattedValue: String(value2),
8350
9317
  style
8351
9318
  };
8352
9319
  }
8353
- function formatValueForSearch(value, column) {
8354
- if (value == null) return "";
8355
- if (column.format && isNumericValue(value)) {
9320
+ function formatValueForSearch(value2, column) {
9321
+ if (value2 == null) return "";
9322
+ if (column.format && isNumericValue(value2)) {
8356
9323
  try {
8357
- return format(column.format)(value);
9324
+ return format(column.format)(value2);
8358
9325
  } catch {
8359
9326
  }
8360
9327
  }
8361
- if (isNumericValue(value)) {
8362
- return formatNumber4(value);
9328
+ if (isNumericValue(value2)) {
9329
+ return formatNumber5(value2);
8363
9330
  }
8364
- return String(value);
9331
+ return String(value2);
8365
9332
  }
8366
9333
 
8367
9334
  // src/tables/heatmap.ts
@@ -8406,13 +9373,13 @@ function computeHeatmapColors(data, column, theme, darkMode) {
8406
9373
  if (config.domain) {
8407
9374
  domain = config.domain;
8408
9375
  } else {
8409
- let min3 = Infinity;
8410
- let max3 = -Infinity;
8411
- for (const { value } of numericValues) {
8412
- if (value < min3) min3 = value;
8413
- if (value > max3) max3 = value;
9376
+ let min4 = Infinity;
9377
+ let max4 = -Infinity;
9378
+ for (const { value: value2 } of numericValues) {
9379
+ if (value2 < min4) min4 = value2;
9380
+ if (value2 > max4) max4 = value2;
8414
9381
  }
8415
- domain = [min3, max3];
9382
+ domain = [min4, max4];
8416
9383
  }
8417
9384
  let stops = resolvePalette(config.palette, theme);
8418
9385
  if (darkMode) {
@@ -8422,8 +9389,8 @@ function computeHeatmapColors(data, column, theme, darkMode) {
8422
9389
  }
8423
9390
  const interpolator = interpolatorFromStops(stops);
8424
9391
  const scale = sequential(interpolator).domain(domain).clamp(true);
8425
- for (const { index, value } of numericValues) {
8426
- const bg = scale(value);
9392
+ for (const { index, value: value2 } of numericValues) {
9393
+ const bg = scale(value2);
8427
9394
  const textColor = accessibleTextColor(bg);
8428
9395
  result.set(index, {
8429
9396
  backgroundColor: bg,
@@ -8528,14 +9495,14 @@ function computeSparkline(values, config, theme, _darkMode) {
8528
9495
  if (values.length === 0) return null;
8529
9496
  const type = config.type ?? "line";
8530
9497
  const color2 = config.color ?? theme.colors.categorical[0];
8531
- let min3 = Infinity;
8532
- let max3 = -Infinity;
9498
+ let min4 = Infinity;
9499
+ let max4 = -Infinity;
8533
9500
  for (const v of values) {
8534
- if (v < min3) min3 = v;
8535
- if (v > max3) max3 = v;
9501
+ if (v < min4) min4 = v;
9502
+ if (v > max4) max4 = v;
8536
9503
  }
8537
- const range2 = max3 - min3;
8538
- const normalize2 = (v) => range2 === 0 ? 0.5 : (v - min3) / range2;
9504
+ const range2 = max4 - min4;
9505
+ const normalize2 = (v) => range2 === 0 ? 0.5 : (v - min4) / range2;
8539
9506
  const startValue = values[0];
8540
9507
  const endValue = values[values.length - 1];
8541
9508
  if (type === "line") {
@@ -8600,13 +9567,13 @@ function estimateColumnWidth(col, data, fontSize) {
8600
9567
  if (col.image) return (col.image.width ?? 24) + PADDING;
8601
9568
  if (col.flag) return 60;
8602
9569
  const label = col.label ?? col.key;
8603
- const headerWidth = estimateTextWidth10(label, fontSize, 600) + PADDING;
9570
+ const headerWidth = estimateTextWidth11(label, fontSize, 600) + PADDING;
8604
9571
  const sampleSize = Math.min(100, data.length);
8605
9572
  let maxDataWidth = 0;
8606
9573
  for (let i = 0; i < sampleSize; i++) {
8607
9574
  const val = data[i][col.key];
8608
9575
  const text = val == null ? "" : String(val);
8609
- const width = estimateTextWidth10(text, fontSize, 400) + PADDING;
9576
+ const width = estimateTextWidth11(text, fontSize, 400) + PADDING;
8610
9577
  if (width > maxDataWidth) maxDataWidth = width;
8611
9578
  }
8612
9579
  return Math.max(MIN_WIDTH, headerWidth, maxDataWidth);
@@ -8626,8 +9593,8 @@ function resolveColumns(columns, data, totalWidth, theme) {
8626
9593
  }
8627
9594
  return estimateColumnWidth(col, data, fontSize);
8628
9595
  });
8629
- const fixedTotal = naturalWidths.reduce((sum, w, i) => sum + (isFixed[i] ? w : 0), 0);
8630
- const flexTotal = naturalWidths.reduce((sum, w, i) => sum + (isFixed[i] ? 0 : w), 0);
9596
+ const fixedTotal = naturalWidths.reduce((sum2, w, i) => sum2 + (isFixed[i] ? w : 0), 0);
9597
+ const flexTotal = naturalWidths.reduce((sum2, w, i) => sum2 + (isFixed[i] ? 0 : w), 0);
8631
9598
  const remainingWidth = totalWidth - fixedTotal;
8632
9599
  const flexScale = flexTotal > 0 && remainingWidth > 0 ? remainingWidth / flexTotal : 1;
8633
9600
  return columns.map((col, i) => ({
@@ -8639,9 +9606,9 @@ function resolveColumns(columns, data, totalWidth, theme) {
8639
9606
  cellType: determineCellType(col)
8640
9607
  }));
8641
9608
  }
8642
- function buildCell(value, column, resolvedColumn, heatmapStyle, categoryStyle, barData, sparklineData) {
8643
- const base = formatCell(value, column);
8644
- if (typeof value === "number") {
9609
+ function buildCell(value2, column, resolvedColumn, heatmapStyle, categoryStyle, barData, sparklineData) {
9610
+ const base = formatCell(value2, column);
9611
+ if (typeof value2 === "number") {
8645
9612
  base.style = { ...base.style, fontVariant: "tabular-nums" };
8646
9613
  }
8647
9614
  const cellType = resolvedColumn.cellType;
@@ -8680,7 +9647,7 @@ function buildCell(value, column, resolvedColumn, heatmapStyle, categoryStyle, b
8680
9647
  };
8681
9648
  }
8682
9649
  case "image": {
8683
- const src = typeof value === "string" ? value : "";
9650
+ const src = typeof value2 === "string" ? value2 : "";
8684
9651
  const imgConfig = column.image ?? {};
8685
9652
  return {
8686
9653
  ...base,
@@ -8692,7 +9659,7 @@ function buildCell(value, column, resolvedColumn, heatmapStyle, categoryStyle, b
8692
9659
  };
8693
9660
  }
8694
9661
  case "flag": {
8695
- const code = typeof value === "string" ? value : "";
9662
+ const code = typeof value2 === "string" ? value2 : "";
8696
9663
  return {
8697
9664
  ...base,
8698
9665
  cellType: "flag",
@@ -8767,13 +9734,13 @@ function compileTableLayout(spec, options, theme) {
8767
9734
  const rowId = spec.rowKey ? String(row[spec.rowKey] ?? origIdx) : String(origIdx);
8768
9735
  const cells = spec.columns.map((col, c) => {
8769
9736
  const resolved = resolvedColumns[c];
8770
- const value = row[col.key];
9737
+ const value2 = row[col.key];
8771
9738
  const heatmapStyle = heatmapMaps.get(col.key)?.get(origIdx);
8772
9739
  const categoryStyle = categoryMaps.get(col.key)?.get(origIdx);
8773
9740
  let barData;
8774
- if (resolved.cellType === "bar" && col.bar && typeof value === "number") {
9741
+ if (resolved.cellType === "bar" && col.bar && typeof value2 === "number") {
8775
9742
  barData = computeBarCell(
8776
- value,
9743
+ value2,
8777
9744
  col.bar,
8778
9745
  barMaxes.get(col.key) ?? 0,
8779
9746
  barMins.get(col.key) ?? 0,
@@ -8785,11 +9752,11 @@ function compileTableLayout(spec, options, theme) {
8785
9752
  if (resolved.cellType === "sparkline" && col.sparkline) {
8786
9753
  sparklineData = computeSparklineForRow(row, col.key, col.sparkline, theme, darkMode);
8787
9754
  }
8788
- return buildCell(value, col, resolved, heatmapStyle, categoryStyle, barData, sparklineData);
9755
+ return buildCell(value2, col, resolved, heatmapStyle, categoryStyle, barData, sparklineData);
8789
9756
  });
8790
9757
  return { id: rowId, cells, data: row };
8791
9758
  });
8792
- const chrome = computeChrome3(
9759
+ const chrome = computeChrome4(
8793
9760
  {
8794
9761
  title: spec.chrome.title,
8795
9762
  subtitle: spec.chrome.subtitle,
@@ -8826,25 +9793,25 @@ function compileTableLayout(spec, options, theme) {
8826
9793
  }
8827
9794
 
8828
9795
  // src/tooltips/compute.ts
8829
- import { buildTemporalFormatter as buildTemporalFormatter2, formatDate as formatDate3, formatNumber as formatNumber5 } from "@opendata-ai/openchart-core";
8830
- function formatValue(value, fieldType, format2) {
8831
- if (value == null) return "";
8832
- if (fieldType === "temporal" || value instanceof Date) {
9796
+ import { buildTemporalFormatter as buildTemporalFormatter2, formatDate as formatDate3, formatNumber as formatNumber6 } from "@opendata-ai/openchart-core";
9797
+ function formatValue(value2, fieldType, format2) {
9798
+ if (value2 == null) return "";
9799
+ if (fieldType === "temporal" || value2 instanceof Date) {
8833
9800
  const temporalFmt = buildTemporalFormatter2(format2);
8834
- if (temporalFmt) return temporalFmt(value);
8835
- return formatDate3(value);
9801
+ if (temporalFmt) return temporalFmt(value2);
9802
+ return formatDate3(value2);
8836
9803
  }
8837
- if (typeof value === "number") {
9804
+ if (typeof value2 === "number") {
8838
9805
  if (format2) {
8839
9806
  try {
8840
- return format(format2)(value);
9807
+ return format(format2)(value2);
8841
9808
  } catch {
8842
- return formatNumber5(value);
9809
+ return formatNumber6(value2);
8843
9810
  }
8844
9811
  }
8845
- return formatNumber5(value);
9812
+ return formatNumber6(value2);
8846
9813
  }
8847
- return String(value);
9814
+ return String(value2);
8848
9815
  }
8849
9816
  function buildExplicitTooltipFields(row, channels) {
8850
9817
  return channels.map((ch) => ({
@@ -9009,16 +9976,16 @@ function runBin(data, transform) {
9009
9976
  const field = transform.field;
9010
9977
  let extent2 = params.extent;
9011
9978
  if (!extent2) {
9012
- let min3 = Infinity;
9013
- let max3 = -Infinity;
9979
+ let min4 = Infinity;
9980
+ let max4 = -Infinity;
9014
9981
  for (const row of data) {
9015
9982
  const v = Number(row[field]);
9016
9983
  if (Number.isFinite(v)) {
9017
- if (v < min3) min3 = v;
9018
- if (v > max3) max3 = v;
9984
+ if (v < min4) min4 = v;
9985
+ if (v > max4) max4 = v;
9019
9986
  }
9020
9987
  }
9021
- extent2 = [min3 === Infinity ? 0 : min3, max3 === -Infinity ? 0 : max3];
9988
+ extent2 = [min4 === Infinity ? 0 : min4, max4 === -Infinity ? 0 : max4];
9022
9989
  }
9023
9990
  const step = params.step ?? computeStep(extent2, maxbins, nice2);
9024
9991
  const [startAs, endAs] = Array.isArray(transform.as) ? transform.as : [transform.as, void 0];
@@ -9125,10 +10092,10 @@ function extractTimeUnit(date2, unit2) {
9125
10092
  return `${String(date2.getHours()).padStart(2, "0")}:${String(date2.getMinutes()).padStart(2, "0")}`;
9126
10093
  }
9127
10094
  }
9128
- function toDate(value) {
9129
- if (value instanceof Date) return value;
9130
- if (typeof value === "string" || typeof value === "number") {
9131
- const d = new Date(value);
10095
+ function toDate(value2) {
10096
+ if (value2 instanceof Date) return value2;
10097
+ if (typeof value2 === "string" || typeof value2 === "number") {
10098
+ const d = new Date(value2);
9132
10099
  return Number.isNaN(d.getTime()) ? null : d;
9133
10100
  }
9134
10101
  return null;
@@ -9212,28 +10179,28 @@ function computeBandRowObstacles(marks, scales) {
9212
10179
  const rows = /* @__PURE__ */ new Map();
9213
10180
  for (const mark of marks) {
9214
10181
  let cy;
9215
- let left;
9216
- let right;
10182
+ let left2;
10183
+ let right2;
9217
10184
  if (mark.type === "point") {
9218
10185
  const pm = mark;
9219
10186
  cy = pm.cy;
9220
- left = pm.cx - pm.r;
9221
- right = pm.cx + pm.r;
10187
+ left2 = pm.cx - pm.r;
10188
+ right2 = pm.cx + pm.r;
9222
10189
  } else if (mark.type === "rect") {
9223
10190
  const rm = mark;
9224
10191
  cy = rm.y + rm.height / 2;
9225
- left = rm.x;
9226
- right = rm.x + rm.width;
10192
+ left2 = rm.x;
10193
+ right2 = rm.x + rm.width;
9227
10194
  } else {
9228
10195
  continue;
9229
10196
  }
9230
10197
  const key = Math.round(cy);
9231
10198
  const existing = rows.get(key);
9232
10199
  if (existing) {
9233
- existing.minX = Math.min(existing.minX, left);
9234
- existing.maxX = Math.max(existing.maxX, right);
10200
+ existing.minX = Math.min(existing.minX, left2);
10201
+ existing.maxX = Math.max(existing.maxX, right2);
9235
10202
  } else {
9236
- rows.set(key, { minX: left, maxX: right, bandY: cy });
10203
+ rows.set(key, { minX: left2, maxX: right2, bandY: cy });
9237
10204
  }
9238
10205
  }
9239
10206
  const bandScale = scales.y.scale;
@@ -9258,6 +10225,9 @@ function compileChart(spec, options) {
9258
10225
  if ("type" in normalized && normalized.type === "graph") {
9259
10226
  throw new Error("compileChart received a graph spec. Use compileGraph instead.");
9260
10227
  }
10228
+ if ("type" in normalized && normalized.type === "sankey") {
10229
+ throw new Error("compileChart received a sankey spec. Use compileSankey instead.");
10230
+ }
9261
10231
  let chartSpec = normalized;
9262
10232
  const rawTransforms = spec.transform;
9263
10233
  if (rawTransforms && rawTransforms.length > 0) {
@@ -9307,9 +10277,9 @@ function compileChart(spec, options) {
9307
10277
  const rawAnimationSpec = overrides?.[breakpoint]?.animation ?? rawSpec.animation;
9308
10278
  const resolvedAnimation = resolveAnimation(rawAnimationSpec);
9309
10279
  const mergedThemeConfig = options.theme ? { ...chartSpec.theme, ...options.theme } : chartSpec.theme;
9310
- let theme = resolveTheme2(mergedThemeConfig);
10280
+ let theme = resolveTheme3(mergedThemeConfig);
9311
10281
  if (options.darkMode) {
9312
- theme = adaptTheme2(theme);
10282
+ theme = adaptTheme3(theme);
9313
10283
  }
9314
10284
  const preliminaryArea = {
9315
10285
  x: 0,
@@ -9571,15 +10541,18 @@ function compileTable(spec, options) {
9571
10541
  }
9572
10542
  const tableSpec = normalized;
9573
10543
  const mergedThemeConfig = options.theme ? { ...tableSpec.theme, ...options.theme } : tableSpec.theme;
9574
- let theme = resolveTheme2(mergedThemeConfig);
10544
+ let theme = resolveTheme3(mergedThemeConfig);
9575
10545
  if (options.darkMode) {
9576
- theme = adaptTheme2(theme);
10546
+ theme = adaptTheme3(theme);
9577
10547
  }
9578
10548
  return compileTableLayout(tableSpec, options, theme);
9579
10549
  }
9580
10550
  function compileGraph2(spec, options) {
9581
10551
  return compileGraph(spec, options);
9582
10552
  }
10553
+ function compileSankey2(spec, options) {
10554
+ return compileSankey(spec, options);
10555
+ }
9583
10556
  export {
9584
10557
  clampStaggerDelay,
9585
10558
  clearRenderers,
@@ -9587,6 +10560,7 @@ export {
9587
10560
  compileChart,
9588
10561
  compileGraph2 as compileGraph,
9589
10562
  compileLayer,
10563
+ compileSankey2 as compileSankey,
9590
10564
  compileTable,
9591
10565
  evaluatePredicate,
9592
10566
  getChartRenderer,