@opendata-ai/openchart-engine 6.5.2 → 6.7.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",
@@ -844,7 +844,7 @@ var LABEL_FONT_SIZE = 11;
844
844
  var LABEL_FONT_WEIGHT = 600;
845
845
  var LABEL_PADDING = 6;
846
846
  var MIN_WIDTH_FOR_INSIDE_LABEL = 40;
847
- function computeBarLabels(marks, _chartArea, density = "auto", labelFormat) {
847
+ function computeBarLabels(marks, _chartArea, density = "auto", labelFormat, labelPrefix) {
848
848
  if (density === "none") return [];
849
849
  const targetMarks = density === "endpoints" && marks.length > 1 ? [marks[0], marks[marks.length - 1]] : marks;
850
850
  const candidates = [];
@@ -860,6 +860,7 @@ function computeBarLabels(marks, _chartArea, density = "auto", labelFormat) {
860
860
  const num = parseDisplayNumber(rawValue);
861
861
  if (!Number.isNaN(num)) valuePart = formatter(num);
862
862
  }
863
+ if (labelPrefix) valuePart = labelPrefix + valuePart;
863
864
  const textWidth = estimateTextWidth2(valuePart, LABEL_FONT_SIZE, LABEL_FONT_WEIGHT);
864
865
  const textHeight = LABEL_FONT_SIZE * 1.2;
865
866
  const isStacked = mark.cornerRadius === 0;
@@ -942,7 +943,13 @@ function computeBarLabels(marks, _chartArea, density = "auto", labelFormat) {
942
943
  // src/charts/bar/index.ts
943
944
  var barRenderer = (spec, scales, chartArea, strategy, _theme) => {
944
945
  const marks = computeBarMarks(spec, scales, chartArea, strategy);
945
- const labels = computeBarLabels(marks, chartArea, spec.labels.density, spec.labels.format);
946
+ const labels = computeBarLabels(
947
+ marks,
948
+ chartArea,
949
+ spec.labels.density,
950
+ spec.labels.format,
951
+ spec.labels.prefix
952
+ );
946
953
  for (let i = 0; i < marks.length && i < labels.length; i++) {
947
954
  marks[i].label = labels[i];
948
955
  }
@@ -952,9 +959,9 @@ var barRenderer = (spec, scales, chartArea, strategy, _theme) => {
952
959
  // src/charts/column/compute.ts
953
960
  import { abbreviateNumber as abbreviateNumber2, formatNumber as formatNumber2 } from "@opendata-ai/openchart-core";
954
961
  var MIN_COLUMN_HEIGHT = 1;
955
- function formatColumnValue(value) {
956
- if (Math.abs(value) >= 1e3) return abbreviateNumber2(value);
957
- return formatNumber2(value);
962
+ function formatColumnValue(value2) {
963
+ if (Math.abs(value2) >= 1e3) return abbreviateNumber2(value2);
964
+ return formatNumber2(value2);
958
965
  }
959
966
  function computeColumnMarks(spec, scales, _chartArea, _strategy) {
960
967
  const encoding = spec.encoding;
@@ -1019,8 +1026,8 @@ function computeSimpleColumns(data, categoryField, valueField, xScale, yScale, b
1019
1026
  const marks = [];
1020
1027
  for (const row of data) {
1021
1028
  const category = String(row[categoryField] ?? "");
1022
- const value = Number(row[valueField] ?? 0);
1023
- if (!Number.isFinite(value)) continue;
1029
+ const value2 = Number(row[valueField] ?? 0);
1030
+ if (!Number.isFinite(value2)) continue;
1024
1031
  const bandX = xScale(category);
1025
1032
  if (bandX === void 0) continue;
1026
1033
  let color2;
@@ -1029,15 +1036,15 @@ function computeSimpleColumns(data, categoryField, valueField, xScale, yScale, b
1029
1036
  resolveConditionalValue(row, conditionalColor) ?? getColor(scales, "__default__")
1030
1037
  );
1031
1038
  } else if (sequentialColor) {
1032
- color2 = getSequentialColor(scales, value);
1039
+ color2 = getSequentialColor(scales, value2);
1033
1040
  } else {
1034
1041
  color2 = getColor(scales, "__default__");
1035
1042
  }
1036
- const yPos = yScale(value);
1043
+ const yPos = yScale(value2);
1037
1044
  const columnHeight = Math.max(Math.abs(baseline - yPos), MIN_COLUMN_HEIGHT);
1038
- const y2 = value >= 0 ? yPos : baseline;
1045
+ const y2 = value2 >= 0 ? yPos : baseline;
1039
1046
  const aria = {
1040
- label: `${category}: ${formatColumnValue(value)}`
1047
+ label: `${category}: ${formatColumnValue(value2)}`
1041
1048
  };
1042
1049
  marks.push({
1043
1050
  type: "rect",
@@ -1058,17 +1065,17 @@ function computeColoredColumns(data, categoryField, valueField, colorField, xSca
1058
1065
  const marks = [];
1059
1066
  for (const row of data) {
1060
1067
  const category = String(row[categoryField] ?? "");
1061
- const value = Number(row[valueField] ?? 0);
1062
- if (!Number.isFinite(value)) continue;
1068
+ const value2 = Number(row[valueField] ?? 0);
1069
+ if (!Number.isFinite(value2)) continue;
1063
1070
  const bandX = xScale(category);
1064
1071
  if (bandX === void 0) continue;
1065
1072
  const groupKey = String(row[colorField] ?? "");
1066
1073
  const color2 = getColor(scales, groupKey);
1067
- const yPos = yScale(value);
1074
+ const yPos = yScale(value2);
1068
1075
  const columnHeight = Math.max(Math.abs(baseline - yPos), MIN_COLUMN_HEIGHT);
1069
- const y2 = value >= 0 ? yPos : baseline;
1076
+ const y2 = value2 >= 0 ? yPos : baseline;
1070
1077
  const aria = {
1071
- label: `${category}, ${groupKey}: ${formatColumnValue(value)}`
1078
+ label: `${category}, ${groupKey}: ${formatColumnValue(value2)}`
1072
1079
  };
1073
1080
  marks.push({
1074
1081
  type: "rect",
@@ -1094,14 +1101,14 @@ function computeStackedColumns(data, categoryField, valueField, colorField, xSca
1094
1101
  let cumulativeValue = 0;
1095
1102
  for (const row of rows) {
1096
1103
  const groupKey = String(row[colorField] ?? "");
1097
- const value = Number(row[valueField] ?? 0);
1098
- if (!Number.isFinite(value) || value <= 0) continue;
1104
+ const value2 = Number(row[valueField] ?? 0);
1105
+ if (!Number.isFinite(value2) || value2 <= 0) continue;
1099
1106
  const color2 = getColor(scales, groupKey);
1100
- const yTop = yScale(cumulativeValue + value);
1107
+ const yTop = yScale(cumulativeValue + value2);
1101
1108
  const yBottom = yScale(cumulativeValue);
1102
1109
  const columnHeight = Math.max(Math.abs(yBottom - yTop), MIN_COLUMN_HEIGHT);
1103
1110
  const aria = {
1104
- label: `${category}, ${groupKey}: ${formatColumnValue(value)}`
1111
+ label: `${category}, ${groupKey}: ${formatColumnValue(value2)}`
1105
1112
  };
1106
1113
  marks.push({
1107
1114
  type: "rect",
@@ -1116,7 +1123,7 @@ function computeStackedColumns(data, categoryField, valueField, colorField, xSca
1116
1123
  orient: "vertical",
1117
1124
  stackGroup: category
1118
1125
  });
1119
- cumulativeValue += value;
1126
+ cumulativeValue += value2;
1120
1127
  }
1121
1128
  }
1122
1129
  return marks;
@@ -1131,7 +1138,7 @@ import {
1131
1138
  var LABEL_FONT_SIZE2 = 10;
1132
1139
  var LABEL_FONT_WEIGHT2 = 600;
1133
1140
  var LABEL_OFFSET_Y = 6;
1134
- function computeColumnLabels(marks, _chartArea, density = "auto", labelFormat) {
1141
+ function computeColumnLabels(marks, _chartArea, density = "auto", labelFormat, labelPrefix) {
1135
1142
  if (density === "none") return [];
1136
1143
  const targetMarks = density === "endpoints" && marks.length > 1 ? [marks[0], marks[marks.length - 1]] : marks;
1137
1144
  const formatter = buildD3Formatter2(labelFormat);
@@ -1146,6 +1153,7 @@ function computeColumnLabels(marks, _chartArea, density = "auto", labelFormat) {
1146
1153
  const num = Number(rawValue.replace(/[^0-9.-]/g, ""));
1147
1154
  if (!Number.isNaN(num)) valuePart = formatter(num);
1148
1155
  }
1156
+ if (labelPrefix) valuePart = labelPrefix + valuePart;
1149
1157
  const numericValue = parseFloat(valuePart);
1150
1158
  const isNegative = Number.isFinite(numericValue) && numericValue < 0;
1151
1159
  const textWidth = estimateTextWidth3(valuePart, LABEL_FONT_SIZE2, LABEL_FONT_WEIGHT2);
@@ -1186,7 +1194,13 @@ function computeColumnLabels(marks, _chartArea, density = "auto", labelFormat) {
1186
1194
  // src/charts/column/index.ts
1187
1195
  var columnRenderer = (spec, scales, chartArea, strategy, _theme) => {
1188
1196
  const marks = computeColumnMarks(spec, scales, chartArea, strategy);
1189
- const labels = computeColumnLabels(marks, chartArea, spec.labels.density, spec.labels.format);
1197
+ const labels = computeColumnLabels(
1198
+ marks,
1199
+ chartArea,
1200
+ spec.labels.density,
1201
+ spec.labels.format,
1202
+ spec.labels.prefix
1203
+ );
1190
1204
  for (let i = 0; i < marks.length && i < labels.length; i++) {
1191
1205
  marks[i].label = labels[i];
1192
1206
  }
@@ -1247,8 +1261,8 @@ function computeDumbbellMarks(data, valueField, categoryField, colorField, xScal
1247
1261
  const cy = bandY + bandwidth / 2;
1248
1262
  const xValues = [];
1249
1263
  for (const row of rows) {
1250
- const value = Number(row[valueField] ?? 0);
1251
- if (Number.isFinite(value)) xValues.push(value);
1264
+ const value2 = Number(row[valueField] ?? 0);
1265
+ if (Number.isFinite(value2)) xValues.push(value2);
1252
1266
  }
1253
1267
  if (xValues.length === 0) continue;
1254
1268
  const minVal = Math.min(...xValues);
@@ -1272,13 +1286,13 @@ function computeDumbbellMarks(data, valueField, categoryField, colorField, xScal
1272
1286
  });
1273
1287
  }
1274
1288
  for (const row of rows) {
1275
- const value = Number(row[valueField] ?? 0);
1276
- if (!Number.isFinite(value)) continue;
1277
- const cx = xScale(value);
1289
+ const value2 = Number(row[valueField] ?? 0);
1290
+ if (!Number.isFinite(value2)) continue;
1291
+ const cx = xScale(value2);
1278
1292
  const colorCategory = String(row[colorField] ?? "");
1279
1293
  const color2 = getColor(scales, colorCategory);
1280
1294
  const dotAria = {
1281
- label: `${category}, ${colorCategory}: ${value}`
1295
+ label: `${category}, ${colorCategory}: ${value2}`
1282
1296
  };
1283
1297
  marks.push({
1284
1298
  type: "point",
@@ -1299,13 +1313,13 @@ function computeLollipopMarks(data, valueField, categoryField, xScale, yScale, b
1299
1313
  const marks = [];
1300
1314
  for (const row of data) {
1301
1315
  const category = String(row[categoryField] ?? "");
1302
- const value = Number(row[valueField] ?? 0);
1303
- if (!Number.isFinite(value)) continue;
1316
+ const value2 = Number(row[valueField] ?? 0);
1317
+ if (!Number.isFinite(value2)) continue;
1304
1318
  const bandY = yScale(category);
1305
1319
  if (bandY === void 0) continue;
1306
- const cx = xScale(value);
1320
+ const cx = xScale(value2);
1307
1321
  const cy = bandY + bandwidth / 2;
1308
- const color2 = isSequentialColor ? getSequentialColor(scales, value) : getColor(scales, "__default__");
1322
+ const color2 = isSequentialColor ? getSequentialColor(scales, value2) : getColor(scales, "__default__");
1309
1323
  const stemX = Math.min(baseline, cx);
1310
1324
  const stemWidth = Math.abs(cx - baseline);
1311
1325
  if (stemWidth > 0) {
@@ -1324,7 +1338,7 @@ function computeLollipopMarks(data, valueField, categoryField, xScale, yScale, b
1324
1338
  });
1325
1339
  }
1326
1340
  const dotAria = {
1327
- label: `${category}: ${value}`
1341
+ label: `${category}: ${value2}`
1328
1342
  };
1329
1343
  marks.push({
1330
1344
  type: "point",
@@ -1346,15 +1360,16 @@ import { estimateTextWidth as estimateTextWidth4, resolveCollisions as resolveCo
1346
1360
  var LABEL_FONT_SIZE3 = 11;
1347
1361
  var LABEL_FONT_WEIGHT3 = 600;
1348
1362
  var LABEL_OFFSET_X = 10;
1349
- function computeDotLabels(marks, _chartArea, density = "auto") {
1363
+ function computeDotLabels(marks, _chartArea, density = "auto", labelPrefix) {
1350
1364
  if (density === "none") return [];
1351
1365
  const targetMarks = density === "endpoints" && marks.length > 1 ? [marks[0], marks[marks.length - 1]] : marks;
1352
1366
  const candidates = [];
1353
1367
  for (const mark of targetMarks) {
1354
1368
  const ariaLabel = mark.aria.label;
1355
1369
  const lastColon = ariaLabel.lastIndexOf(":");
1356
- const valuePart = lastColon >= 0 ? ariaLabel.slice(lastColon + 1).trim() : "";
1370
+ let valuePart = lastColon >= 0 ? ariaLabel.slice(lastColon + 1).trim() : "";
1357
1371
  if (!valuePart) continue;
1372
+ if (labelPrefix) valuePart = labelPrefix + valuePart;
1358
1373
  const textWidth = estimateTextWidth4(valuePart, LABEL_FONT_SIZE3, LABEL_FONT_WEIGHT3);
1359
1374
  const textHeight = LABEL_FONT_SIZE3 * 1.2;
1360
1375
  candidates.push({
@@ -1392,7 +1407,7 @@ function computeDotLabels(marks, _chartArea, density = "auto") {
1392
1407
  var dotRenderer = (spec, scales, chartArea, strategy, _theme) => {
1393
1408
  const marks = computeDotMarks(spec, scales, chartArea, strategy);
1394
1409
  const pointMarks = marks.filter((m) => m.type === "point");
1395
- const labels = computeDotLabels(pointMarks, chartArea, spec.labels.density);
1410
+ const labels = computeDotLabels(pointMarks, chartArea, spec.labels.density, spec.labels.prefix);
1396
1411
  let labelIdx = 0;
1397
1412
  for (const mark of marks) {
1398
1413
  if (mark.type === "point" && labelIdx < labels.length) {
@@ -1405,7 +1420,7 @@ var dotRenderer = (spec, scales, chartArea, strategy, _theme) => {
1405
1420
 
1406
1421
  // ../../node_modules/.bun/d3-shape@3.2.0/node_modules/d3-shape/src/constant.js
1407
1422
  function constant_default(x2) {
1408
- return function constant() {
1423
+ return function constant2() {
1409
1424
  return x2;
1410
1425
  };
1411
1426
  }
@@ -1842,12 +1857,12 @@ function identity_default(d) {
1842
1857
 
1843
1858
  // ../../node_modules/.bun/d3-shape@3.2.0/node_modules/d3-shape/src/pie.js
1844
1859
  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);
1860
+ var value2 = identity_default, sortValues = descending_default, sort = null, startAngle = constant_default(0), endAngle = constant_default(tau), padAngle = constant_default(0);
1846
1861
  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;
1862
+ 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
1863
  for (i = 0; i < n; ++i) {
1849
- if ((v = arcs[index[i] = i] = +value(data[i], i, data)) > 0) {
1850
- sum += v;
1864
+ if ((v = arcs[index[i] = i] = +value2(data[i], i, data)) > 0) {
1865
+ sum2 += v;
1851
1866
  }
1852
1867
  }
1853
1868
  if (sortValues != null) index.sort(function(i2, j2) {
@@ -1856,7 +1871,7 @@ function pie_default() {
1856
1871
  else if (sort != null) index.sort(function(i2, j2) {
1857
1872
  return sort(data[i2], data[j2]);
1858
1873
  });
1859
- for (i = 0, k = sum ? (da - n * pa) / sum : 0; i < n; ++i, a0 = a1) {
1874
+ for (i = 0, k = sum2 ? (da - n * pa) / sum2 : 0; i < n; ++i, a0 = a1) {
1860
1875
  j = index[i], v = arcs[j], a1 = a0 + (v > 0 ? v * k : 0) + pa, arcs[j] = {
1861
1876
  data: data[j],
1862
1877
  index: i,
@@ -1869,7 +1884,7 @@ function pie_default() {
1869
1884
  return arcs;
1870
1885
  }
1871
1886
  pie.value = function(_) {
1872
- return arguments.length ? (value = typeof _ === "function" ? _ : constant_default(+_), pie) : value;
1887
+ return arguments.length ? (value2 = typeof _ === "function" ? _ : constant_default(+_), pie) : value2;
1873
1888
  };
1874
1889
  pie.sortValues = function(_) {
1875
1890
  return arguments.length ? (sortValues = _, sort = null, pie) : sortValues;
@@ -2253,12 +2268,12 @@ function stackSeries(key) {
2253
2268
  return series;
2254
2269
  }
2255
2270
  function stack_default() {
2256
- var keys = constant_default([]), order = none_default2, offset = none_default, value = stackValue;
2271
+ var keys = constant_default([]), order = none_default2, offset = none_default, value2 = stackValue;
2257
2272
  function stack(data) {
2258
2273
  var sz = Array.from(keys.apply(this, arguments), stackSeries), i, n = sz.length, j = -1, oz;
2259
2274
  for (const d of data) {
2260
2275
  for (i = 0, ++j; i < n; ++i) {
2261
- (sz[i][j] = [0, +value(d, sz[i].key, j, data)]).data = d;
2276
+ (sz[i][j] = [0, +value2(d, sz[i].key, j, data)]).data = d;
2262
2277
  }
2263
2278
  }
2264
2279
  for (i = 0, oz = array_default(order(sz)); i < n; ++i) {
@@ -2271,7 +2286,7 @@ function stack_default() {
2271
2286
  return arguments.length ? (keys = typeof _ === "function" ? _ : constant_default(Array.from(_)), stack) : keys;
2272
2287
  };
2273
2288
  stack.value = function(_) {
2274
- return arguments.length ? (value = typeof _ === "function" ? _ : constant_default(+_), stack) : value;
2289
+ return arguments.length ? (value2 = typeof _ === "function" ? _ : constant_default(+_), stack) : value2;
2275
2290
  };
2276
2291
  stack.order = function(_) {
2277
2292
  return arguments.length ? (order = _ == null ? none_default2 : typeof _ === "function" ? _ : constant_default(Array.from(_)), stack) : order;
@@ -2695,7 +2710,7 @@ var DEFAULT_PALETTE = [
2695
2710
  "#858078"
2696
2711
  ];
2697
2712
  function groupSmallSlices(slices, threshold2) {
2698
- const total = slices.reduce((sum, s) => sum + s.value, 0);
2713
+ const total = slices.reduce((sum2, s) => sum2 + s.value, 0);
2699
2714
  if (total === 0) return slices;
2700
2715
  const big = [];
2701
2716
  let otherValue = 0;
@@ -2733,13 +2748,13 @@ function computePieMarks(spec, scales, chartArea, _strategy, isDonut = false) {
2733
2748
  categoryRows.set(cat, row);
2734
2749
  }
2735
2750
  }
2736
- for (const [label, value] of categoryTotals) {
2751
+ for (const [label, value2] of categoryTotals) {
2737
2752
  slices.push({
2738
2753
  label,
2739
- value,
2754
+ value: value2,
2740
2755
  originalRow: categoryRows.get(label) ?? {
2741
2756
  [categoryField]: label,
2742
- [valueChannel.field]: value
2757
+ [valueChannel.field]: value2
2743
2758
  }
2744
2759
  });
2745
2760
  }
@@ -2763,8 +2778,8 @@ function computePieMarks(spec, scales, chartArea, _strategy, isDonut = false) {
2763
2778
  const innerRadius = isDonut ? outerRadius * 0.6 : 0;
2764
2779
  const arcGenerator = arc_default().innerRadius(innerRadius).outerRadius(outerRadius);
2765
2780
  const marks = [];
2766
- const center = { x: centerX, y: centerY };
2767
- const total = slices.reduce((sum, s) => sum + s.value, 0);
2781
+ const center2 = { x: centerX, y: centerY };
2782
+ const total = slices.reduce((sum2, s) => sum2 + s.value, 0);
2768
2783
  for (let i = 0; i < arcs.length; i++) {
2769
2784
  const arcDatum = arcs[i];
2770
2785
  const slice2 = arcDatum.data;
@@ -2788,7 +2803,7 @@ function computePieMarks(spec, scales, chartArea, _strategy, isDonut = false) {
2788
2803
  x: centroidResult[0] + centerX,
2789
2804
  y: centroidResult[1] + centerY
2790
2805
  },
2791
- center,
2806
+ center: center2,
2792
2807
  innerRadius,
2793
2808
  outerRadius,
2794
2809
  startAngle: arcDatum.startAngle,
@@ -2997,7 +3012,7 @@ function bisector(f) {
2997
3012
  compare2 = f;
2998
3013
  delta = f;
2999
3014
  }
3000
- function left(a, x2, lo = 0, hi = a.length) {
3015
+ function left2(a, x2, lo = 0, hi = a.length) {
3001
3016
  if (lo < hi) {
3002
3017
  if (compare1(x2, x2) !== 0) return hi;
3003
3018
  do {
@@ -3008,7 +3023,7 @@ function bisector(f) {
3008
3023
  }
3009
3024
  return lo;
3010
3025
  }
3011
- function right(a, x2, lo = 0, hi = a.length) {
3026
+ function right2(a, x2, lo = 0, hi = a.length) {
3012
3027
  if (lo < hi) {
3013
3028
  if (compare1(x2, x2) !== 0) return hi;
3014
3029
  do {
@@ -3019,11 +3034,11 @@ function bisector(f) {
3019
3034
  }
3020
3035
  return lo;
3021
3036
  }
3022
- function center(a, x2, lo = 0, hi = a.length) {
3023
- const i = left(a, x2, lo, hi - 1);
3037
+ function center2(a, x2, lo = 0, hi = a.length) {
3038
+ const i = left2(a, x2, lo, hi - 1);
3024
3039
  return i > lo && delta(a[i - 1], x2) > -delta(a[i], x2) ? i - 1 : i;
3025
3040
  }
3026
- return { left, center, right };
3041
+ return { left: left2, center: center2, right: right2 };
3027
3042
  }
3028
3043
  function zero() {
3029
3044
  return 0;
@@ -3043,33 +3058,33 @@ var bisect_default = bisectRight;
3043
3058
 
3044
3059
  // ../../node_modules/.bun/d3-array@3.2.4/node_modules/d3-array/src/extent.js
3045
3060
  function extent(values, valueof) {
3046
- let min3;
3047
- let max3;
3061
+ let min4;
3062
+ let max4;
3048
3063
  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;
3064
+ for (const value2 of values) {
3065
+ if (value2 != null) {
3066
+ if (min4 === void 0) {
3067
+ if (value2 >= value2) min4 = max4 = value2;
3053
3068
  } else {
3054
- if (min3 > value) min3 = value;
3055
- if (max3 < value) max3 = value;
3069
+ if (min4 > value2) min4 = value2;
3070
+ if (max4 < value2) max4 = value2;
3056
3071
  }
3057
3072
  }
3058
3073
  }
3059
3074
  } else {
3060
3075
  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;
3076
+ for (let value2 of values) {
3077
+ if ((value2 = valueof(value2, ++index, values)) != null) {
3078
+ if (min4 === void 0) {
3079
+ if (value2 >= value2) min4 = max4 = value2;
3065
3080
  } else {
3066
- if (min3 > value) min3 = value;
3067
- if (max3 < value) max3 = value;
3081
+ if (min4 > value2) min4 = value2;
3082
+ if (max4 < value2) max4 = value2;
3068
3083
  }
3069
3084
  }
3070
3085
  }
3071
3086
  }
3072
- return [min3, max3];
3087
+ return [min4, max4];
3073
3088
  }
3074
3089
 
3075
3090
  // ../../node_modules/.bun/internmap@2.0.3/node_modules/internmap/src/index.js
@@ -3077,7 +3092,7 @@ var InternMap = class extends Map {
3077
3092
  constructor(entries, key = keyof) {
3078
3093
  super();
3079
3094
  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);
3095
+ if (entries != null) for (const [key2, value2] of entries) this.set(key2, value2);
3081
3096
  }
3082
3097
  get(key) {
3083
3098
  return super.get(intern_get(this, key));
@@ -3085,33 +3100,33 @@ var InternMap = class extends Map {
3085
3100
  has(key) {
3086
3101
  return super.has(intern_get(this, key));
3087
3102
  }
3088
- set(key, value) {
3089
- return super.set(intern_set(this, key), value);
3103
+ set(key, value2) {
3104
+ return super.set(intern_set(this, key), value2);
3090
3105
  }
3091
3106
  delete(key) {
3092
3107
  return super.delete(intern_delete(this, key));
3093
3108
  }
3094
3109
  };
3095
- function intern_get({ _intern, _key }, value) {
3096
- const key = _key(value);
3097
- return _intern.has(key) ? _intern.get(key) : value;
3110
+ function intern_get({ _intern, _key }, value2) {
3111
+ const key = _key(value2);
3112
+ return _intern.has(key) ? _intern.get(key) : value2;
3098
3113
  }
3099
- function intern_set({ _intern, _key }, value) {
3100
- const key = _key(value);
3114
+ function intern_set({ _intern, _key }, value2) {
3115
+ const key = _key(value2);
3101
3116
  if (_intern.has(key)) return _intern.get(key);
3102
- _intern.set(key, value);
3103
- return value;
3117
+ _intern.set(key, value2);
3118
+ return value2;
3104
3119
  }
3105
- function intern_delete({ _intern, _key }, value) {
3106
- const key = _key(value);
3120
+ function intern_delete({ _intern, _key }, value2) {
3121
+ const key = _key(value2);
3107
3122
  if (_intern.has(key)) {
3108
- value = _intern.get(key);
3123
+ value2 = _intern.get(key);
3109
3124
  _intern.delete(key);
3110
3125
  }
3111
- return value;
3126
+ return value2;
3112
3127
  }
3113
- function keyof(value) {
3114
- return value !== null && typeof value === "object" ? value.valueOf() : value;
3128
+ function keyof(value2) {
3129
+ return value2 !== null && typeof value2 === "object" ? value2.valueOf() : value2;
3115
3130
  }
3116
3131
 
3117
3132
  // ../../node_modules/.bun/d3-array@3.2.4/node_modules/d3-array/src/ticks.js
@@ -3166,42 +3181,42 @@ function tickStep(start, stop, count) {
3166
3181
 
3167
3182
  // ../../node_modules/.bun/d3-array@3.2.4/node_modules/d3-array/src/max.js
3168
3183
  function max2(values, valueof) {
3169
- let max3;
3184
+ let max4;
3170
3185
  if (valueof === void 0) {
3171
- for (const value of values) {
3172
- if (value != null && (max3 < value || max3 === void 0 && value >= value)) {
3173
- max3 = value;
3186
+ for (const value2 of values) {
3187
+ if (value2 != null && (max4 < value2 || max4 === void 0 && value2 >= value2)) {
3188
+ max4 = value2;
3174
3189
  }
3175
3190
  }
3176
3191
  } else {
3177
3192
  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;
3193
+ for (let value2 of values) {
3194
+ if ((value2 = valueof(value2, ++index, values)) != null && (max4 < value2 || max4 === void 0 && value2 >= value2)) {
3195
+ max4 = value2;
3181
3196
  }
3182
3197
  }
3183
3198
  }
3184
- return max3;
3199
+ return max4;
3185
3200
  }
3186
3201
 
3187
3202
  // ../../node_modules/.bun/d3-array@3.2.4/node_modules/d3-array/src/min.js
3188
3203
  function min2(values, valueof) {
3189
- let min3;
3204
+ let min4;
3190
3205
  if (valueof === void 0) {
3191
- for (const value of values) {
3192
- if (value != null && (min3 > value || min3 === void 0 && value >= value)) {
3193
- min3 = value;
3206
+ for (const value2 of values) {
3207
+ if (value2 != null && (min4 > value2 || min4 === void 0 && value2 >= value2)) {
3208
+ min4 = value2;
3194
3209
  }
3195
3210
  }
3196
3211
  } else {
3197
3212
  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;
3213
+ for (let value2 of values) {
3214
+ if ((value2 = valueof(value2, ++index, values)) != null && (min4 > value2 || min4 === void 0 && value2 >= value2)) {
3215
+ min4 = value2;
3201
3216
  }
3202
3217
  }
3203
3218
  }
3204
- return min3;
3219
+ return min4;
3205
3220
  }
3206
3221
 
3207
3222
  // ../../node_modules/.bun/d3-array@3.2.4/node_modules/d3-array/src/quantile.js
@@ -3271,9 +3286,9 @@ function ordinal() {
3271
3286
  scale.domain = function(_) {
3272
3287
  if (!arguments.length) return domain.slice();
3273
3288
  domain = [], index = new InternMap();
3274
- for (const value of _) {
3275
- if (index.has(value)) continue;
3276
- index.set(value, domain.push(value) - 1);
3289
+ for (const value2 of _) {
3290
+ if (index.has(value2)) continue;
3291
+ index.set(value2, domain.push(value2) - 1);
3277
3292
  }
3278
3293
  return scale;
3279
3294
  };
@@ -3623,12 +3638,12 @@ function rgb_formatRgb() {
3623
3638
  function clampa(opacity) {
3624
3639
  return isNaN(opacity) ? 1 : Math.max(0, Math.min(1, opacity));
3625
3640
  }
3626
- function clampi(value) {
3627
- return Math.max(0, Math.min(255, Math.round(value) || 0));
3641
+ function clampi(value2) {
3642
+ return Math.max(0, Math.min(255, Math.round(value2) || 0));
3628
3643
  }
3629
- function hex(value) {
3630
- value = clampi(value);
3631
- return (value < 16 ? "0" : "") + value.toString(16);
3644
+ function hex(value2) {
3645
+ value2 = clampi(value2);
3646
+ return (value2 < 16 ? "0" : "") + value2.toString(16);
3632
3647
  }
3633
3648
  function hsla(h, s, l, a) {
3634
3649
  if (a <= 0) h = s = l = NaN;
@@ -3642,12 +3657,12 @@ function hslConvert(o) {
3642
3657
  if (!o) return new Hsl();
3643
3658
  if (o instanceof Hsl) return o;
3644
3659
  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;
3660
+ 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
3661
  if (s) {
3647
- if (r === max3) h = (g - b) / s + (g < b) * 6;
3648
- else if (g === max3) h = (b - r) / s + 2;
3662
+ if (r === max4) h = (g - b) / s + (g < b) * 6;
3663
+ else if (g === max4) h = (b - r) / s + 2;
3649
3664
  else h = (r - g) / s + 4;
3650
- s /= l < 0.5 ? max3 + min3 : 2 - max3 - min3;
3665
+ s /= l < 0.5 ? max4 + min4 : 2 - max4 - min4;
3651
3666
  h *= 60;
3652
3667
  } else {
3653
3668
  s = l > 0 && l < 1 ? 0 : h;
@@ -3692,12 +3707,12 @@ define_default(Hsl, hsl, extend(Color, {
3692
3707
  return `${a === 1 ? "hsl(" : "hsla("}${clamph(this.h)}, ${clampt(this.s) * 100}%, ${clampt(this.l) * 100}%${a === 1 ? ")" : `, ${a})`}`;
3693
3708
  }
3694
3709
  }));
3695
- function clamph(value) {
3696
- value = (value || 0) % 360;
3697
- return value < 0 ? value + 360 : value;
3710
+ function clamph(value2) {
3711
+ value2 = (value2 || 0) % 360;
3712
+ return value2 < 0 ? value2 + 360 : value2;
3698
3713
  }
3699
- function clampt(value) {
3700
- return Math.max(0, Math.min(1, value || 0));
3714
+ function clampt(value2) {
3715
+ return Math.max(0, Math.min(1, value2 || 0));
3701
3716
  }
3702
3717
  function hsl2rgb(h, m1, m2) {
3703
3718
  return (h < 60 ? m1 + (m2 - m1) * h / 60 : h < 180 ? m2 : h < 240 ? m1 + (m2 - m1) * (240 - h) / 60 : m1) * 255;
@@ -4018,11 +4033,11 @@ function exponent_default(x2) {
4018
4033
 
4019
4034
  // ../../node_modules/.bun/d3-format@3.1.2/node_modules/d3-format/src/formatGroup.js
4020
4035
  function formatGroup_default(grouping, thousands) {
4021
- return function(value, width) {
4022
- var i = value.length, t = [], j = 0, g = grouping[0], length = 0;
4036
+ return function(value2, width) {
4037
+ var i = value2.length, t = [], j = 0, g = grouping[0], length = 0;
4023
4038
  while (i > 0 && g > 0) {
4024
4039
  if (length + g + 1 > width) g = Math.max(1, width - length);
4025
- t.push(value.substring(i -= g, i + g));
4040
+ t.push(value2.substring(i -= g, i + g));
4026
4041
  if ((length += g + 1) > width) break;
4027
4042
  g = grouping[j = (j + 1) % grouping.length];
4028
4043
  }
@@ -4032,8 +4047,8 @@ function formatGroup_default(grouping, thousands) {
4032
4047
 
4033
4048
  // ../../node_modules/.bun/d3-format@3.1.2/node_modules/d3-format/src/formatNumerals.js
4034
4049
  function formatNumerals_default(numerals) {
4035
- return function(value) {
4036
- return value.replace(/[0-9]/g, function(i) {
4050
+ return function(value2) {
4051
+ return value2.replace(/[0-9]/g, function(i) {
4037
4052
  return numerals[+i];
4038
4053
  });
4039
4054
  };
@@ -4147,58 +4162,58 @@ function locale_default(locale3) {
4147
4162
  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
4163
  var formatType = formatTypes_default[type], maybeSuffix = /[defgprs%]/.test(type);
4149
4164
  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) {
4165
+ function format2(value2) {
4151
4166
  var valuePrefix = prefix, valueSuffix = suffix, i, n, c;
4152
4167
  if (type === "c") {
4153
- valueSuffix = formatType(value) + valueSuffix;
4154
- value = "";
4168
+ valueSuffix = formatType(value2) + valueSuffix;
4169
+ value2 = "";
4155
4170
  } 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;
4171
+ value2 = +value2;
4172
+ var valueNegative = value2 < 0 || 1 / value2 < 0;
4173
+ value2 = isNaN(value2) ? nan : formatType(Math.abs(value2), precision);
4174
+ if (trim) value2 = formatTrim_default(value2);
4175
+ if (valueNegative && +value2 === 0 && sign2 !== "+") valueNegative = false;
4161
4176
  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 === "(" ? ")" : "");
4177
+ valueSuffix = (type === "s" && !isNaN(value2) && prefixExponent !== void 0 ? prefixes[8 + prefixExponent / 3] : "") + valueSuffix + (valueNegative && sign2 === "(" ? ")" : "");
4163
4178
  if (maybeSuffix) {
4164
- i = -1, n = value.length;
4179
+ i = -1, n = value2.length;
4165
4180
  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);
4181
+ if (c = value2.charCodeAt(i), 48 > c || c > 57) {
4182
+ valueSuffix = (c === 46 ? decimal + value2.slice(i + 1) : value2.slice(i)) + valueSuffix;
4183
+ value2 = value2.slice(0, i);
4169
4184
  break;
4170
4185
  }
4171
4186
  }
4172
4187
  }
4173
4188
  }
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 = "";
4189
+ if (comma && !zero3) value2 = group(value2, Infinity);
4190
+ var length = valuePrefix.length + value2.length + valueSuffix.length, padding = length < width ? new Array(width - length + 1).join(fill) : "";
4191
+ if (comma && zero3) value2 = group(padding + value2, padding.length ? width - valueSuffix.length : Infinity), padding = "";
4177
4192
  switch (align) {
4178
4193
  case "<":
4179
- value = valuePrefix + value + valueSuffix + padding;
4194
+ value2 = valuePrefix + value2 + valueSuffix + padding;
4180
4195
  break;
4181
4196
  case "=":
4182
- value = valuePrefix + padding + value + valueSuffix;
4197
+ value2 = valuePrefix + padding + value2 + valueSuffix;
4183
4198
  break;
4184
4199
  case "^":
4185
- value = padding.slice(0, length = padding.length >> 1) + valuePrefix + value + valueSuffix + padding.slice(length);
4200
+ value2 = padding.slice(0, length = padding.length >> 1) + valuePrefix + value2 + valueSuffix + padding.slice(length);
4186
4201
  break;
4187
4202
  default:
4188
- value = padding + valuePrefix + value + valueSuffix;
4203
+ value2 = padding + valuePrefix + value2 + valueSuffix;
4189
4204
  break;
4190
4205
  }
4191
- return numerals(value);
4206
+ return numerals(value2);
4192
4207
  }
4193
4208
  format2.toString = function() {
4194
4209
  return specifier + "";
4195
4210
  };
4196
4211
  return format2;
4197
4212
  }
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);
4213
+ function formatPrefix2(specifier, value2) {
4214
+ 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] });
4215
+ return function(value3) {
4216
+ return f(k * value3);
4202
4217
  };
4203
4218
  }
4204
4219
  return {
@@ -4229,14 +4244,14 @@ function precisionFixed_default(step) {
4229
4244
  }
4230
4245
 
4231
4246
  // ../../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)));
4247
+ function precisionPrefix_default(step, value2) {
4248
+ return Math.max(0, Math.max(-8, Math.min(8, Math.floor(exponent_default(value2) / 3))) * 3 - exponent_default(Math.abs(step)));
4234
4249
  }
4235
4250
 
4236
4251
  // ../../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;
4252
+ function precisionRound_default(step, max4) {
4253
+ step = Math.abs(step), max4 = Math.abs(max4) - step;
4254
+ return Math.max(0, exponent_default(max4) - exponent_default(step)) + 1;
4240
4255
  }
4241
4256
 
4242
4257
  // ../../node_modules/.bun/d3-scale@4.0.2/node_modules/d3-scale/src/tickFormat.js
@@ -4245,9 +4260,9 @@ function tickFormat(start, stop, count, specifier) {
4245
4260
  specifier = formatSpecifier(specifier == null ? ",f" : specifier);
4246
4261
  switch (specifier.type) {
4247
4262
  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);
4263
+ var value2 = Math.max(Math.abs(start), Math.abs(stop));
4264
+ if (specifier.precision == null && !isNaN(precision = precisionPrefix_default(step, value2))) specifier.precision = precision;
4265
+ return formatPrefix(specifier, value2);
4251
4266
  }
4252
4267
  case "":
4253
4268
  case "e":
@@ -5246,8 +5261,8 @@ var pads = { "-": "", "_": " ", "0": "0" };
5246
5261
  var numberRe = /^\s*\d+/;
5247
5262
  var percentRe = /^%/;
5248
5263
  var requoteRe = /[\\^$*+?|[\]().{}]/g;
5249
- function pad(value, fill, width) {
5250
- var sign2 = value < 0 ? "-" : "", string = (sign2 ? -value : value) + "", length = string.length;
5264
+ function pad(value2, fill, width) {
5265
+ var sign2 = value2 < 0 ? "-" : "", string = (sign2 ? -value2 : value2) + "", length = string.length;
5251
5266
  return sign2 + (length < width ? new Array(width - length + 1).join(fill) + string : string);
5252
5267
  }
5253
5268
  function requote(s) {
@@ -5598,11 +5613,11 @@ function sequential() {
5598
5613
  var DEFAULT_POINT_RADIUS2 = 5;
5599
5614
  var MIN_BUBBLE_RADIUS = 3;
5600
5615
  var MAX_BUBBLE_RADIUS = 30;
5601
- function resolvePosition2(value, channelType, scale) {
5616
+ function resolvePosition2(value2, channelType, scale) {
5602
5617
  switch (channelType) {
5603
5618
  case "nominal":
5604
5619
  case "ordinal": {
5605
- const s = String(value);
5620
+ const s = String(value2);
5606
5621
  if ("bandwidth" in scale && typeof scale.bandwidth === "function") {
5607
5622
  const bw = scale.bandwidth();
5608
5623
  const pos = scale(s);
@@ -5612,11 +5627,11 @@ function resolvePosition2(value, channelType, scale) {
5612
5627
  return scale(s);
5613
5628
  }
5614
5629
  case "temporal": {
5615
- const px = scale(new Date(value));
5630
+ const px = scale(new Date(value2));
5616
5631
  return Number.isNaN(px) ? void 0 : px;
5617
5632
  }
5618
5633
  default: {
5619
- const num = Number(value);
5634
+ const num = Number(value2);
5620
5635
  if (!Number.isFinite(num)) return void 0;
5621
5636
  return scale(num);
5622
5637
  }
@@ -5849,14 +5864,15 @@ import {
5849
5864
  isChartSpec,
5850
5865
  isGraphSpec,
5851
5866
  isLayerSpec,
5867
+ isSankeySpec,
5852
5868
  isTableSpec,
5853
5869
  resolveMarkDef,
5854
5870
  resolveMarkType
5855
5871
  } 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;
5872
+ function normalizeChromeField(value2) {
5873
+ if (value2 === void 0) return void 0;
5874
+ if (typeof value2 === "string") return { text: value2 };
5875
+ return value2;
5860
5876
  }
5861
5877
  function normalizeChrome(chrome) {
5862
5878
  if (!chrome) return {};
@@ -5874,26 +5890,26 @@ function inferFieldType(data, field) {
5874
5890
  let dateCount = 0;
5875
5891
  let totalNonNull = 0;
5876
5892
  for (let i = 0; i < sampleSize; i++) {
5877
- const value = data[i][field];
5878
- if (value == null) continue;
5893
+ const value2 = data[i][field];
5894
+ if (value2 == null) continue;
5879
5895
  totalNonNull++;
5880
- if (typeof value === "number" && Number.isFinite(value)) {
5896
+ if (typeof value2 === "number" && Number.isFinite(value2)) {
5881
5897
  numericCount++;
5882
5898
  continue;
5883
5899
  }
5884
- if (typeof value === "string") {
5885
- const num = Number(value);
5886
- if (!Number.isNaN(num) && Number.isFinite(num) && value.trim() !== "") {
5900
+ if (typeof value2 === "string") {
5901
+ const num = Number(value2);
5902
+ if (!Number.isNaN(num) && Number.isFinite(num) && value2.trim() !== "") {
5887
5903
  numericCount++;
5888
5904
  continue;
5889
5905
  }
5890
- const date2 = new Date(value);
5906
+ const date2 = new Date(value2);
5891
5907
  if (!Number.isNaN(date2.getTime())) {
5892
5908
  dateCount++;
5893
5909
  continue;
5894
5910
  }
5895
5911
  }
5896
- if (value instanceof Date && !Number.isNaN(value.getTime())) {
5912
+ if (value2 instanceof Date && !Number.isNaN(value2.getTime())) {
5897
5913
  dateCount++;
5898
5914
  }
5899
5915
  }
@@ -5970,6 +5986,7 @@ function normalizeChartSpec(spec, warnings) {
5970
5986
  labels: {
5971
5987
  density: spec.labels?.density ?? "auto",
5972
5988
  format: spec.labels?.format ?? "",
5989
+ prefix: spec.labels?.prefix ?? "",
5973
5990
  offsets: spec.labels?.offsets
5974
5991
  },
5975
5992
  legend: spec.legend,
@@ -5997,6 +6014,23 @@ function normalizeTableSpec(spec, _warnings) {
5997
6014
  animation: spec.animation
5998
6015
  };
5999
6016
  }
6017
+ function normalizeSankeySpec(spec, _warnings) {
6018
+ return {
6019
+ type: "sankey",
6020
+ data: spec.data,
6021
+ encoding: spec.encoding,
6022
+ nodeWidth: spec.nodeWidth ?? 12,
6023
+ nodePadding: spec.nodePadding ?? 16,
6024
+ nodeAlign: spec.nodeAlign ?? "justify",
6025
+ iterations: spec.iterations ?? 6,
6026
+ linkStyle: spec.linkStyle ?? "gradient",
6027
+ chrome: normalizeChrome(spec.chrome),
6028
+ legend: spec.legend,
6029
+ theme: spec.theme ?? {},
6030
+ darkMode: spec.darkMode ?? "off",
6031
+ animation: spec.animation
6032
+ };
6033
+ }
6000
6034
  function normalizeGraphSpec(spec, _warnings) {
6001
6035
  const defaultLayout = {
6002
6036
  type: "force",
@@ -6037,8 +6071,11 @@ function normalizeSpec(spec, warnings = []) {
6037
6071
  if (isGraphSpec(spec)) {
6038
6072
  return normalizeGraphSpec(spec, warnings);
6039
6073
  }
6074
+ if (isSankeySpec(spec)) {
6075
+ return normalizeSankeySpec(spec, warnings);
6076
+ }
6040
6077
  throw new Error(
6041
- `Unknown spec shape. Expected mark (chart), layer, type: 'table', or type: 'graph'.`
6078
+ `Unknown spec shape. Expected mark (chart), layer, type: 'table', type: 'graph', or type: 'sankey'.`
6042
6079
  );
6043
6080
  }
6044
6081
  function flattenLayers(spec, parentData, parentEncoding, parentTransforms) {
@@ -6071,19 +6108,19 @@ import {
6071
6108
  } from "@opendata-ai/openchart-core";
6072
6109
  var VALID_FIELD_TYPES = /* @__PURE__ */ new Set(["quantitative", "temporal", "nominal", "ordinal"]);
6073
6110
  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);
6111
+ function isParseableDate(value2) {
6112
+ if (value2 instanceof Date) return !Number.isNaN(value2.getTime());
6113
+ if (typeof value2 === "string") {
6114
+ const d = new Date(value2);
6078
6115
  return !Number.isNaN(d.getTime());
6079
6116
  }
6080
- if (typeof value === "number") return true;
6117
+ if (typeof value2 === "number") return true;
6081
6118
  return false;
6082
6119
  }
6083
- function isNumeric(value) {
6084
- if (typeof value === "number") return Number.isFinite(value);
6085
- if (typeof value === "string") {
6086
- const n = Number(value);
6120
+ function isNumeric(value2) {
6121
+ if (typeof value2 === "number") return Number.isFinite(value2);
6122
+ if (typeof value2 === "string") {
6123
+ const n = Number(value2);
6087
6124
  return !Number.isNaN(n) && Number.isFinite(n);
6088
6125
  }
6089
6126
  return false;
@@ -6498,6 +6535,85 @@ function validateGraphSpec(spec, errors) {
6498
6535
  }
6499
6536
  }
6500
6537
  }
6538
+ function validateSankeySpec(spec, errors) {
6539
+ if (!Array.isArray(spec.data)) {
6540
+ errors.push({
6541
+ message: 'Spec error: sankey spec requires a "data" array',
6542
+ path: "data",
6543
+ code: "INVALID_TYPE",
6544
+ suggestion: 'Provide data as an array of objects, e.g. data: [{ source: "A", target: "B", value: 10 }]'
6545
+ });
6546
+ return;
6547
+ }
6548
+ if (spec.data.length === 0) {
6549
+ errors.push({
6550
+ message: 'Spec error: "data" must be a non-empty array',
6551
+ path: "data",
6552
+ code: "EMPTY_DATA",
6553
+ suggestion: 'Add at least one data row, e.g. data: [{ source: "A", target: "B", value: 10 }]'
6554
+ });
6555
+ return;
6556
+ }
6557
+ const firstRow = spec.data[0];
6558
+ if (typeof firstRow !== "object" || firstRow === null || Array.isArray(firstRow)) {
6559
+ errors.push({
6560
+ message: 'Spec error: each item in "data" must be a plain object',
6561
+ path: "data[0]",
6562
+ code: "INVALID_TYPE",
6563
+ suggestion: 'Each data item should be an object, e.g. { source: "A", target: "B", value: 10 }'
6564
+ });
6565
+ return;
6566
+ }
6567
+ if (!spec.encoding || typeof spec.encoding !== "object") {
6568
+ errors.push({
6569
+ message: 'Spec error: sankey spec requires an "encoding" object with source, target, and value channels',
6570
+ path: "encoding",
6571
+ code: "MISSING_FIELD",
6572
+ suggestion: 'Add an encoding object, e.g. encoding: { source: { field: "source", type: "nominal" }, target: { field: "target", type: "nominal" }, value: { field: "value", type: "quantitative" } }'
6573
+ });
6574
+ return;
6575
+ }
6576
+ const encoding = spec.encoding;
6577
+ const dataColumns = new Set(Object.keys(firstRow));
6578
+ const availableColumns = [...dataColumns].join(", ");
6579
+ for (const channel of ["source", "target", "value"]) {
6580
+ const ch = encoding[channel];
6581
+ if (!ch || typeof ch !== "object") {
6582
+ errors.push({
6583
+ message: `Spec error: sankey encoding requires "${channel}" channel`,
6584
+ path: `encoding.${channel}`,
6585
+ code: "MISSING_FIELD",
6586
+ suggestion: `Add encoding.${channel} with a field from your data (${availableColumns}). Example: ${channel}: { field: "${[...dataColumns][0] ?? "myField"}", type: "${channel === "value" ? "quantitative" : "nominal"}" }`
6587
+ });
6588
+ continue;
6589
+ }
6590
+ if (!ch.field || typeof ch.field !== "string") {
6591
+ errors.push({
6592
+ message: `Spec error: encoding.${channel} must have a "field" string`,
6593
+ path: `encoding.${channel}.field`,
6594
+ code: "MISSING_FIELD",
6595
+ suggestion: `Add a field name from your data columns: ${availableColumns}`
6596
+ });
6597
+ continue;
6598
+ }
6599
+ if (!dataColumns.has(ch.field)) {
6600
+ errors.push({
6601
+ message: `Spec error: encoding.${channel}.field "${ch.field}" does not exist in data. Available columns: ${availableColumns}`,
6602
+ path: `encoding.${channel}.field`,
6603
+ code: "DATA_FIELD_MISSING",
6604
+ suggestion: `Use one of the available data columns: ${availableColumns}`
6605
+ });
6606
+ }
6607
+ }
6608
+ if (spec.darkMode !== void 0 && !VALID_DARK_MODES.has(spec.darkMode)) {
6609
+ errors.push({
6610
+ message: 'Spec error: darkMode must be "auto", "force", or "off"',
6611
+ path: "darkMode",
6612
+ code: "INVALID_VALUE",
6613
+ suggestion: 'Use one of: "auto" (system preference), "force" (always dark), or "off" (always light)'
6614
+ });
6615
+ }
6616
+ }
6501
6617
  function validateLayerSpec(spec, errors) {
6502
6618
  const layer = spec.layer;
6503
6619
  if (layer.length === 0) {
@@ -6591,17 +6707,18 @@ function validateSpec(spec) {
6591
6707
  const hasMark = "mark" in obj;
6592
6708
  const isTable = obj.type === "table";
6593
6709
  const isGraph = obj.type === "graph";
6594
- const isLayer = hasLayer && !isTable && !isGraph;
6595
- const isChart = hasMark && !hasLayer && !isTable && !isGraph;
6596
- if (!isChart && !isTable && !isGraph && !isLayer) {
6710
+ const isSankey = obj.type === "sankey";
6711
+ const isLayer = hasLayer && !isTable && !isGraph && !isSankey;
6712
+ const isChart = hasMark && !hasLayer && !isTable && !isGraph && !isSankey;
6713
+ if (!isChart && !isTable && !isGraph && !isSankey && !isLayer) {
6597
6714
  return {
6598
6715
  valid: false,
6599
6716
  errors: [
6600
6717
  {
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',
6718
+ 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
6719
  path: "mark",
6603
6720
  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(", ")}`
6721
+ 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
6722
  }
6606
6723
  ],
6607
6724
  normalized: null
@@ -6637,6 +6754,8 @@ function validateSpec(spec) {
6637
6754
  validateTableSpec(obj, errors);
6638
6755
  } else if (isGraph) {
6639
6756
  validateGraphSpec(obj, errors);
6757
+ } else if (isSankey) {
6758
+ validateSankeySpec(obj, errors);
6640
6759
  }
6641
6760
  if (errors.length > 0) {
6642
6761
  return { valid: false, errors, normalized: null };
@@ -6923,8 +7042,8 @@ function resolveEdgeVisuals(edges, encoding, theme) {
6923
7042
  function assignCommunities(nodes, clusteringField) {
6924
7043
  if (!clusteringField) return;
6925
7044
  for (const node of nodes) {
6926
- const value = node.data[clusteringField];
6927
- node.community = value != null ? String(value) : void 0;
7045
+ const value2 = node.data[clusteringField];
7046
+ node.community = value2 != null ? String(value2) : void 0;
6928
7047
  }
6929
7048
  }
6930
7049
  function buildCommunityColorMap(nodes, theme) {
@@ -7011,12 +7130,12 @@ function buildGraphTooltips(nodes) {
7011
7130
  color: node.fill
7012
7131
  });
7013
7132
  }
7014
- for (const [key, value] of Object.entries(node.data)) {
7133
+ for (const [key, value2] of Object.entries(node.data)) {
7015
7134
  if (key === "id") continue;
7016
- if (value == null) continue;
7135
+ if (value2 == null) continue;
7017
7136
  fields.push({
7018
7137
  label: key,
7019
- value: typeof value === "number" ? value.toLocaleString() : String(value)
7138
+ value: typeof value2 === "number" ? value2.toLocaleString() : String(value2)
7020
7139
  });
7021
7140
  }
7022
7141
  descriptors.set(node.id, {
@@ -7185,19 +7304,19 @@ function continuousTicks(resolvedScale, density) {
7185
7304
  const scale = resolvedScale.scale;
7186
7305
  if (!("ticks" in scale) || typeof scale.ticks !== "function") {
7187
7306
  const domain = scale.domain();
7188
- return domain.map((value) => ({
7189
- value,
7190
- position: scale(value),
7191
- label: formatTickLabel(value, resolvedScale)
7307
+ return domain.map((value2) => ({
7308
+ value: value2,
7309
+ position: scale(value2),
7310
+ label: formatTickLabel(value2, resolvedScale)
7192
7311
  }));
7193
7312
  }
7194
7313
  const explicitCount = resolvedScale.channel.axis?.tickCount;
7195
7314
  const count = explicitCount ?? TICK_COUNTS[density];
7196
7315
  const rawTicks = scale.ticks(count);
7197
- const ticks2 = rawTicks.map((value) => ({
7198
- value,
7199
- position: scale(value),
7200
- label: formatTickLabel(value, resolvedScale)
7316
+ const ticks2 = rawTicks.map((value2) => ({
7317
+ value: value2,
7318
+ position: scale(value2),
7319
+ label: formatTickLabel(value2, resolvedScale)
7201
7320
  }));
7202
7321
  return ticks2;
7203
7322
  }
@@ -7211,13 +7330,13 @@ function categoricalTicks(resolvedScale, density) {
7211
7330
  const step = Math.ceil(domain.length / maxTicks);
7212
7331
  selectedValues = domain.filter((_, i) => i % step === 0);
7213
7332
  }
7214
- const ticks2 = selectedValues.map((value) => {
7333
+ const ticks2 = selectedValues.map((value2) => {
7215
7334
  const bandScale = resolvedScale.type === "band" ? scale : null;
7216
- const pos = bandScale ? (bandScale(value) ?? 0) + bandScale.bandwidth() / 2 : scale(value) ?? 0;
7335
+ const pos = bandScale ? (bandScale(value2) ?? 0) + bandScale.bandwidth() / 2 : scale(value2) ?? 0;
7217
7336
  return {
7218
- value,
7337
+ value: value2,
7219
7338
  position: pos,
7220
- label: value
7339
+ label: value2
7221
7340
  };
7222
7341
  });
7223
7342
  return ticks2;
@@ -7233,16 +7352,16 @@ var NUMERIC_SCALE_TYPES = /* @__PURE__ */ new Set([
7233
7352
  "threshold"
7234
7353
  ]);
7235
7354
  var TEMPORAL_SCALE_TYPES = /* @__PURE__ */ new Set(["time", "utc"]);
7236
- function formatTickLabel(value, resolvedScale) {
7355
+ function formatTickLabel(value2, resolvedScale) {
7237
7356
  const formatStr = resolvedScale.channel.axis?.format;
7238
7357
  if (TEMPORAL_SCALE_TYPES.has(resolvedScale.type)) {
7239
7358
  const temporalFmt = buildTemporalFormatter(formatStr);
7240
- if (temporalFmt) return temporalFmt(value);
7359
+ if (temporalFmt) return temporalFmt(value2);
7241
7360
  const useUtc = resolvedScale.type === "utc";
7242
- return formatDate(value, void 0, void 0, useUtc);
7361
+ return formatDate(value2, void 0, void 0, useUtc);
7243
7362
  }
7244
7363
  if (NUMERIC_SCALE_TYPES.has(resolvedScale.type)) {
7245
- const num = value;
7364
+ const num = value2;
7246
7365
  if (formatStr) {
7247
7366
  const fmt = buildD3Formatter3(formatStr);
7248
7367
  if (fmt) return fmt(num);
@@ -7250,26 +7369,26 @@ function formatTickLabel(value, resolvedScale) {
7250
7369
  if (Math.abs(num) >= 1e3) return abbreviateNumber3(num);
7251
7370
  return formatNumber3(num);
7252
7371
  }
7253
- return String(value);
7372
+ return String(value2);
7254
7373
  }
7255
7374
  function resolveExplicitTicks(values, resolvedScale) {
7256
7375
  const scale = resolvedScale.scale;
7257
- return values.map((value) => {
7376
+ return values.map((value2) => {
7258
7377
  let position;
7259
7378
  if (TEMPORAL_SCALE_TYPES.has(resolvedScale.type)) {
7260
- const d = value instanceof Date ? value : new Date(String(value));
7379
+ const d = value2 instanceof Date ? value2 : new Date(String(value2));
7261
7380
  position = scale(d);
7262
7381
  } else if (resolvedScale.type === "band" || resolvedScale.type === "point" || resolvedScale.type === "ordinal") {
7263
- const s = String(value);
7382
+ const s = String(value2);
7264
7383
  const bandScale = resolvedScale.type === "band" ? scale : null;
7265
7384
  position = bandScale ? (bandScale(s) ?? 0) + bandScale.bandwidth() / 2 : scale(s) ?? 0;
7266
7385
  } else {
7267
- position = scale(value);
7386
+ position = scale(value2);
7268
7387
  }
7269
7388
  return {
7270
- value,
7389
+ value: value2,
7271
7390
  position,
7272
- label: formatTickLabel(value, resolvedScale)
7391
+ label: formatTickLabel(value2, resolvedScale)
7273
7392
  };
7274
7393
  });
7275
7394
  }
@@ -8027,8 +8146,8 @@ function extractColorEntries(spec, theme) {
8027
8146
  const uniqueValues = [...new Set(spec.data.map((d) => String(d[colorEnc.field])))];
8028
8147
  const palette = theme.colors.categorical;
8029
8148
  const shape = swatchShapeForType(spec.markType);
8030
- return uniqueValues.map((value, i) => ({
8031
- label: value,
8149
+ return uniqueValues.map((value2, i) => ({
8150
+ label: value2,
8032
8151
  color: palette[i % palette.length],
8033
8152
  shape,
8034
8153
  active: true
@@ -8156,9 +8275,9 @@ function computeLegend(spec, strategy, theme, chartArea) {
8156
8275
  if (maxFit < entries.length) {
8157
8276
  entries = truncateEntries(entries, maxFit);
8158
8277
  }
8159
- const totalWidth = entries.reduce((sum, entry) => {
8278
+ const totalWidth = entries.reduce((sum2, entry) => {
8160
8279
  const labelWidth = estimateTextWidth9(entry.label, labelStyle.fontSize, labelStyle.fontWeight);
8161
- return sum + SWATCH_SIZE2 + SWATCH_GAP2 + labelWidth + ENTRY_GAP2;
8280
+ return sum2 + SWATCH_SIZE2 + SWATCH_GAP2 + labelWidth + ENTRY_GAP2;
8162
8281
  }, 0);
8163
8282
  let rowCount = 1;
8164
8283
  let rowWidth = 0;
@@ -8192,15 +8311,879 @@ function computeLegend(spec, strategy, theme, chartArea) {
8192
8311
  };
8193
8312
  }
8194
8313
 
8314
+ // src/sankey/compile-sankey.ts
8315
+ import {
8316
+ adaptTheme as adaptTheme2,
8317
+ computeChrome as computeChrome3,
8318
+ estimateTextWidth as estimateTextWidth10,
8319
+ formatNumber as formatNumber4,
8320
+ resolveTheme as resolveTheme2
8321
+ } from "@opendata-ai/openchart-core";
8322
+
8323
+ // ../../node_modules/.bun/d3-array@2.12.1/node_modules/d3-array/src/max.js
8324
+ function max3(values, valueof) {
8325
+ let max4;
8326
+ if (valueof === void 0) {
8327
+ for (const value2 of values) {
8328
+ if (value2 != null && (max4 < value2 || max4 === void 0 && value2 >= value2)) {
8329
+ max4 = value2;
8330
+ }
8331
+ }
8332
+ } else {
8333
+ let index = -1;
8334
+ for (let value2 of values) {
8335
+ if ((value2 = valueof(value2, ++index, values)) != null && (max4 < value2 || max4 === void 0 && value2 >= value2)) {
8336
+ max4 = value2;
8337
+ }
8338
+ }
8339
+ }
8340
+ return max4;
8341
+ }
8342
+
8343
+ // ../../node_modules/.bun/d3-array@2.12.1/node_modules/d3-array/src/min.js
8344
+ function min3(values, valueof) {
8345
+ let min4;
8346
+ if (valueof === void 0) {
8347
+ for (const value2 of values) {
8348
+ if (value2 != null && (min4 > value2 || min4 === void 0 && value2 >= value2)) {
8349
+ min4 = value2;
8350
+ }
8351
+ }
8352
+ } else {
8353
+ let index = -1;
8354
+ for (let value2 of values) {
8355
+ if ((value2 = valueof(value2, ++index, values)) != null && (min4 > value2 || min4 === void 0 && value2 >= value2)) {
8356
+ min4 = value2;
8357
+ }
8358
+ }
8359
+ }
8360
+ return min4;
8361
+ }
8362
+
8363
+ // ../../node_modules/.bun/d3-array@2.12.1/node_modules/d3-array/src/sum.js
8364
+ function sum(values, valueof) {
8365
+ let sum2 = 0;
8366
+ if (valueof === void 0) {
8367
+ for (let value2 of values) {
8368
+ if (value2 = +value2) {
8369
+ sum2 += value2;
8370
+ }
8371
+ }
8372
+ } else {
8373
+ let index = -1;
8374
+ for (let value2 of values) {
8375
+ if (value2 = +valueof(value2, ++index, values)) {
8376
+ sum2 += value2;
8377
+ }
8378
+ }
8379
+ }
8380
+ return sum2;
8381
+ }
8382
+
8383
+ // ../../node_modules/.bun/d3-sankey@0.12.3/node_modules/d3-sankey/src/align.js
8384
+ function targetDepth(d) {
8385
+ return d.target.depth;
8386
+ }
8387
+ function left(node) {
8388
+ return node.depth;
8389
+ }
8390
+ function right(node, n) {
8391
+ return n - 1 - node.height;
8392
+ }
8393
+ function justify(node, n) {
8394
+ return node.sourceLinks.length ? node.depth : n - 1;
8395
+ }
8396
+ function center(node) {
8397
+ return node.targetLinks.length ? node.depth : node.sourceLinks.length ? min3(node.sourceLinks, targetDepth) - 1 : 0;
8398
+ }
8399
+
8400
+ // ../../node_modules/.bun/d3-sankey@0.12.3/node_modules/d3-sankey/src/constant.js
8401
+ function constant(x2) {
8402
+ return function() {
8403
+ return x2;
8404
+ };
8405
+ }
8406
+
8407
+ // ../../node_modules/.bun/d3-sankey@0.12.3/node_modules/d3-sankey/src/sankey.js
8408
+ function ascendingSourceBreadth(a, b) {
8409
+ return ascendingBreadth(a.source, b.source) || a.index - b.index;
8410
+ }
8411
+ function ascendingTargetBreadth(a, b) {
8412
+ return ascendingBreadth(a.target, b.target) || a.index - b.index;
8413
+ }
8414
+ function ascendingBreadth(a, b) {
8415
+ return a.y0 - b.y0;
8416
+ }
8417
+ function value(d) {
8418
+ return d.value;
8419
+ }
8420
+ function defaultId(d) {
8421
+ return d.index;
8422
+ }
8423
+ function defaultNodes(graph) {
8424
+ return graph.nodes;
8425
+ }
8426
+ function defaultLinks(graph) {
8427
+ return graph.links;
8428
+ }
8429
+ function find(nodeById, id) {
8430
+ const node = nodeById.get(id);
8431
+ if (!node) throw new Error("missing: " + id);
8432
+ return node;
8433
+ }
8434
+ function computeLinkBreadths({ nodes }) {
8435
+ for (const node of nodes) {
8436
+ let y0 = node.y0;
8437
+ let y1 = y0;
8438
+ for (const link of node.sourceLinks) {
8439
+ link.y0 = y0 + link.width / 2;
8440
+ y0 += link.width;
8441
+ }
8442
+ for (const link of node.targetLinks) {
8443
+ link.y1 = y1 + link.width / 2;
8444
+ y1 += link.width;
8445
+ }
8446
+ }
8447
+ }
8448
+ function Sankey() {
8449
+ let x0 = 0, y0 = 0, x1 = 1, y1 = 1;
8450
+ let dx = 24;
8451
+ let dy = 8, py;
8452
+ let id = defaultId;
8453
+ let align = justify;
8454
+ let sort;
8455
+ let linkSort;
8456
+ let nodes = defaultNodes;
8457
+ let links = defaultLinks;
8458
+ let iterations = 6;
8459
+ function sankey() {
8460
+ const graph = { nodes: nodes.apply(null, arguments), links: links.apply(null, arguments) };
8461
+ computeNodeLinks(graph);
8462
+ computeNodeValues(graph);
8463
+ computeNodeDepths(graph);
8464
+ computeNodeHeights(graph);
8465
+ computeNodeBreadths(graph);
8466
+ computeLinkBreadths(graph);
8467
+ return graph;
8468
+ }
8469
+ sankey.update = function(graph) {
8470
+ computeLinkBreadths(graph);
8471
+ return graph;
8472
+ };
8473
+ sankey.nodeId = function(_) {
8474
+ return arguments.length ? (id = typeof _ === "function" ? _ : constant(_), sankey) : id;
8475
+ };
8476
+ sankey.nodeAlign = function(_) {
8477
+ return arguments.length ? (align = typeof _ === "function" ? _ : constant(_), sankey) : align;
8478
+ };
8479
+ sankey.nodeSort = function(_) {
8480
+ return arguments.length ? (sort = _, sankey) : sort;
8481
+ };
8482
+ sankey.nodeWidth = function(_) {
8483
+ return arguments.length ? (dx = +_, sankey) : dx;
8484
+ };
8485
+ sankey.nodePadding = function(_) {
8486
+ return arguments.length ? (dy = py = +_, sankey) : dy;
8487
+ };
8488
+ sankey.nodes = function(_) {
8489
+ return arguments.length ? (nodes = typeof _ === "function" ? _ : constant(_), sankey) : nodes;
8490
+ };
8491
+ sankey.links = function(_) {
8492
+ return arguments.length ? (links = typeof _ === "function" ? _ : constant(_), sankey) : links;
8493
+ };
8494
+ sankey.linkSort = function(_) {
8495
+ return arguments.length ? (linkSort = _, sankey) : linkSort;
8496
+ };
8497
+ sankey.size = function(_) {
8498
+ return arguments.length ? (x0 = y0 = 0, x1 = +_[0], y1 = +_[1], sankey) : [x1 - x0, y1 - y0];
8499
+ };
8500
+ sankey.extent = function(_) {
8501
+ return arguments.length ? (x0 = +_[0][0], x1 = +_[1][0], y0 = +_[0][1], y1 = +_[1][1], sankey) : [[x0, y0], [x1, y1]];
8502
+ };
8503
+ sankey.iterations = function(_) {
8504
+ return arguments.length ? (iterations = +_, sankey) : iterations;
8505
+ };
8506
+ function computeNodeLinks({ nodes: nodes2, links: links2 }) {
8507
+ for (const [i, node] of nodes2.entries()) {
8508
+ node.index = i;
8509
+ node.sourceLinks = [];
8510
+ node.targetLinks = [];
8511
+ }
8512
+ const nodeById = new Map(nodes2.map((d, i) => [id(d, i, nodes2), d]));
8513
+ for (const [i, link] of links2.entries()) {
8514
+ link.index = i;
8515
+ let { source, target } = link;
8516
+ if (typeof source !== "object") source = link.source = find(nodeById, source);
8517
+ if (typeof target !== "object") target = link.target = find(nodeById, target);
8518
+ source.sourceLinks.push(link);
8519
+ target.targetLinks.push(link);
8520
+ }
8521
+ if (linkSort != null) {
8522
+ for (const { sourceLinks, targetLinks } of nodes2) {
8523
+ sourceLinks.sort(linkSort);
8524
+ targetLinks.sort(linkSort);
8525
+ }
8526
+ }
8527
+ }
8528
+ function computeNodeValues({ nodes: nodes2 }) {
8529
+ for (const node of nodes2) {
8530
+ node.value = node.fixedValue === void 0 ? Math.max(sum(node.sourceLinks, value), sum(node.targetLinks, value)) : node.fixedValue;
8531
+ }
8532
+ }
8533
+ function computeNodeDepths({ nodes: nodes2 }) {
8534
+ const n = nodes2.length;
8535
+ let current = new Set(nodes2);
8536
+ let next = /* @__PURE__ */ new Set();
8537
+ let x2 = 0;
8538
+ while (current.size) {
8539
+ for (const node of current) {
8540
+ node.depth = x2;
8541
+ for (const { target } of node.sourceLinks) {
8542
+ next.add(target);
8543
+ }
8544
+ }
8545
+ if (++x2 > n) throw new Error("circular link");
8546
+ current = next;
8547
+ next = /* @__PURE__ */ new Set();
8548
+ }
8549
+ }
8550
+ function computeNodeHeights({ nodes: nodes2 }) {
8551
+ const n = nodes2.length;
8552
+ let current = new Set(nodes2);
8553
+ let next = /* @__PURE__ */ new Set();
8554
+ let x2 = 0;
8555
+ while (current.size) {
8556
+ for (const node of current) {
8557
+ node.height = x2;
8558
+ for (const { source } of node.targetLinks) {
8559
+ next.add(source);
8560
+ }
8561
+ }
8562
+ if (++x2 > n) throw new Error("circular link");
8563
+ current = next;
8564
+ next = /* @__PURE__ */ new Set();
8565
+ }
8566
+ }
8567
+ function computeNodeLayers({ nodes: nodes2 }) {
8568
+ const x2 = max3(nodes2, (d) => d.depth) + 1;
8569
+ const kx = (x1 - x0 - dx) / (x2 - 1);
8570
+ const columns = new Array(x2);
8571
+ for (const node of nodes2) {
8572
+ const i = Math.max(0, Math.min(x2 - 1, Math.floor(align.call(null, node, x2))));
8573
+ node.layer = i;
8574
+ node.x0 = x0 + i * kx;
8575
+ node.x1 = node.x0 + dx;
8576
+ if (columns[i]) columns[i].push(node);
8577
+ else columns[i] = [node];
8578
+ }
8579
+ if (sort) for (const column of columns) {
8580
+ column.sort(sort);
8581
+ }
8582
+ return columns;
8583
+ }
8584
+ function initializeNodeBreadths(columns) {
8585
+ const ky = min3(columns, (c) => (y1 - y0 - (c.length - 1) * py) / sum(c, value));
8586
+ for (const nodes2 of columns) {
8587
+ let y2 = y0;
8588
+ for (const node of nodes2) {
8589
+ node.y0 = y2;
8590
+ node.y1 = y2 + node.value * ky;
8591
+ y2 = node.y1 + py;
8592
+ for (const link of node.sourceLinks) {
8593
+ link.width = link.value * ky;
8594
+ }
8595
+ }
8596
+ y2 = (y1 - y2 + py) / (nodes2.length + 1);
8597
+ for (let i = 0; i < nodes2.length; ++i) {
8598
+ const node = nodes2[i];
8599
+ node.y0 += y2 * (i + 1);
8600
+ node.y1 += y2 * (i + 1);
8601
+ }
8602
+ reorderLinks(nodes2);
8603
+ }
8604
+ }
8605
+ function computeNodeBreadths(graph) {
8606
+ const columns = computeNodeLayers(graph);
8607
+ py = Math.min(dy, (y1 - y0) / (max3(columns, (c) => c.length) - 1));
8608
+ initializeNodeBreadths(columns);
8609
+ for (let i = 0; i < iterations; ++i) {
8610
+ const alpha = Math.pow(0.99, i);
8611
+ const beta = Math.max(1 - alpha, (i + 1) / iterations);
8612
+ relaxRightToLeft(columns, alpha, beta);
8613
+ relaxLeftToRight(columns, alpha, beta);
8614
+ }
8615
+ }
8616
+ function relaxLeftToRight(columns, alpha, beta) {
8617
+ for (let i = 1, n = columns.length; i < n; ++i) {
8618
+ const column = columns[i];
8619
+ for (const target of column) {
8620
+ let y2 = 0;
8621
+ let w = 0;
8622
+ for (const { source, value: value2 } of target.targetLinks) {
8623
+ let v = value2 * (target.layer - source.layer);
8624
+ y2 += targetTop(source, target) * v;
8625
+ w += v;
8626
+ }
8627
+ if (!(w > 0)) continue;
8628
+ let dy2 = (y2 / w - target.y0) * alpha;
8629
+ target.y0 += dy2;
8630
+ target.y1 += dy2;
8631
+ reorderNodeLinks(target);
8632
+ }
8633
+ if (sort === void 0) column.sort(ascendingBreadth);
8634
+ resolveCollisions6(column, beta);
8635
+ }
8636
+ }
8637
+ function relaxRightToLeft(columns, alpha, beta) {
8638
+ for (let n = columns.length, i = n - 2; i >= 0; --i) {
8639
+ const column = columns[i];
8640
+ for (const source of column) {
8641
+ let y2 = 0;
8642
+ let w = 0;
8643
+ for (const { target, value: value2 } of source.sourceLinks) {
8644
+ let v = value2 * (target.layer - source.layer);
8645
+ y2 += sourceTop(source, target) * v;
8646
+ w += v;
8647
+ }
8648
+ if (!(w > 0)) continue;
8649
+ let dy2 = (y2 / w - source.y0) * alpha;
8650
+ source.y0 += dy2;
8651
+ source.y1 += dy2;
8652
+ reorderNodeLinks(source);
8653
+ }
8654
+ if (sort === void 0) column.sort(ascendingBreadth);
8655
+ resolveCollisions6(column, beta);
8656
+ }
8657
+ }
8658
+ function resolveCollisions6(nodes2, alpha) {
8659
+ const i = nodes2.length >> 1;
8660
+ const subject = nodes2[i];
8661
+ resolveCollisionsBottomToTop(nodes2, subject.y0 - py, i - 1, alpha);
8662
+ resolveCollisionsTopToBottom(nodes2, subject.y1 + py, i + 1, alpha);
8663
+ resolveCollisionsBottomToTop(nodes2, y1, nodes2.length - 1, alpha);
8664
+ resolveCollisionsTopToBottom(nodes2, y0, 0, alpha);
8665
+ }
8666
+ function resolveCollisionsTopToBottom(nodes2, y2, i, alpha) {
8667
+ for (; i < nodes2.length; ++i) {
8668
+ const node = nodes2[i];
8669
+ const dy2 = (y2 - node.y0) * alpha;
8670
+ if (dy2 > 1e-6) node.y0 += dy2, node.y1 += dy2;
8671
+ y2 = node.y1 + py;
8672
+ }
8673
+ }
8674
+ function resolveCollisionsBottomToTop(nodes2, y2, i, alpha) {
8675
+ for (; i >= 0; --i) {
8676
+ const node = nodes2[i];
8677
+ const dy2 = (node.y1 - y2) * alpha;
8678
+ if (dy2 > 1e-6) node.y0 -= dy2, node.y1 -= dy2;
8679
+ y2 = node.y0 - py;
8680
+ }
8681
+ }
8682
+ function reorderNodeLinks({ sourceLinks, targetLinks }) {
8683
+ if (linkSort === void 0) {
8684
+ for (const { source: { sourceLinks: sourceLinks2 } } of targetLinks) {
8685
+ sourceLinks2.sort(ascendingTargetBreadth);
8686
+ }
8687
+ for (const { target: { targetLinks: targetLinks2 } } of sourceLinks) {
8688
+ targetLinks2.sort(ascendingSourceBreadth);
8689
+ }
8690
+ }
8691
+ }
8692
+ function reorderLinks(nodes2) {
8693
+ if (linkSort === void 0) {
8694
+ for (const { sourceLinks, targetLinks } of nodes2) {
8695
+ sourceLinks.sort(ascendingTargetBreadth);
8696
+ targetLinks.sort(ascendingSourceBreadth);
8697
+ }
8698
+ }
8699
+ }
8700
+ function targetTop(source, target) {
8701
+ let y2 = source.y0 - (source.sourceLinks.length - 1) * py / 2;
8702
+ for (const { target: node, width } of source.sourceLinks) {
8703
+ if (node === target) break;
8704
+ y2 += width + py;
8705
+ }
8706
+ for (const { source: node, width } of target.targetLinks) {
8707
+ if (node === source) break;
8708
+ y2 -= width;
8709
+ }
8710
+ return y2;
8711
+ }
8712
+ function sourceTop(source, target) {
8713
+ let y2 = target.y0 - (target.targetLinks.length - 1) * py / 2;
8714
+ for (const { source: node, width } of target.targetLinks) {
8715
+ if (node === source) break;
8716
+ y2 += width + py;
8717
+ }
8718
+ for (const { target: node, width } of source.sourceLinks) {
8719
+ if (node === target) break;
8720
+ y2 -= width;
8721
+ }
8722
+ return y2;
8723
+ }
8724
+ return sankey;
8725
+ }
8726
+
8727
+ // src/sankey/layout.ts
8728
+ var ALIGN_MAP = {
8729
+ justify,
8730
+ left,
8731
+ right,
8732
+ center
8733
+ };
8734
+ function computeSankeyLayout(data, sourceField, targetField, valueField, area, nodeWidth, nodePadding, nodeAlign, iterations) {
8735
+ const nodeSet = /* @__PURE__ */ new Set();
8736
+ for (const row of data) {
8737
+ nodeSet.add(String(row[sourceField]));
8738
+ nodeSet.add(String(row[targetField]));
8739
+ }
8740
+ const nodes = [...nodeSet].map((id) => ({
8741
+ id,
8742
+ label: id
8743
+ }));
8744
+ const links = data.map((row) => ({
8745
+ source: String(row[sourceField]),
8746
+ target: String(row[targetField]),
8747
+ value: Number(row[valueField]) || 0,
8748
+ data: { ...row }
8749
+ }));
8750
+ const alignFn = ALIGN_MAP[nodeAlign] ?? justify;
8751
+ const generator = Sankey().nodeId((d) => d.id).nodeAlign(alignFn).nodeWidth(nodeWidth).nodePadding(nodePadding).extent([
8752
+ [area.x, area.y],
8753
+ [area.x + area.width, area.y + area.height]
8754
+ ]).iterations(iterations);
8755
+ const graph = generator({
8756
+ nodes,
8757
+ links
8758
+ });
8759
+ return {
8760
+ nodes: graph.nodes,
8761
+ links: graph.links
8762
+ };
8763
+ }
8764
+ function generateLinkPath(link) {
8765
+ const source = link.source;
8766
+ const target = link.target;
8767
+ const x0 = source.x1 ?? 0;
8768
+ const x1 = target.x0 ?? 0;
8769
+ const y0 = link.y0 ?? 0;
8770
+ const y1 = link.y1 ?? 0;
8771
+ const halfWidth0 = (link.width ?? 0) / 2;
8772
+ const halfWidth1 = halfWidth0;
8773
+ const mx = (x0 + x1) / 2;
8774
+ const topY0 = y0 - halfWidth0;
8775
+ const topY1 = y1 - halfWidth1;
8776
+ const botY0 = y0 + halfWidth0;
8777
+ const botY1 = y1 + halfWidth1;
8778
+ return [
8779
+ `M${x0},${topY0}`,
8780
+ `C${mx},${topY0} ${mx},${topY1} ${x1},${topY1}`,
8781
+ `L${x1},${botY1}`,
8782
+ `C${mx},${botY1} ${mx},${botY0} ${x0},${botY0}`,
8783
+ "Z"
8784
+ ].join(" ");
8785
+ }
8786
+
8787
+ // src/sankey/compile-sankey.ts
8788
+ var SWATCH_SIZE3 = 12;
8789
+ var SWATCH_GAP3 = 6;
8790
+ var ENTRY_GAP3 = 16;
8791
+ var LABEL_GAP = 6;
8792
+ var LINK_OPACITY = 0.35;
8793
+ var NODE_CORNER_RADIUS = 2;
8794
+ function pickColor(palette, index) {
8795
+ return palette[index % palette.length];
8796
+ }
8797
+ function buildNodeColorMap(nodes, palette, colorField, data, sourceField, targetField) {
8798
+ const colorMap = /* @__PURE__ */ new Map();
8799
+ if (colorField) {
8800
+ const nodeCategoryMap = /* @__PURE__ */ new Map();
8801
+ for (const row of data) {
8802
+ const src = String(row[sourceField]);
8803
+ const tgt = String(row[targetField]);
8804
+ const cat = String(row[colorField]);
8805
+ if (!nodeCategoryMap.has(src)) nodeCategoryMap.set(src, cat);
8806
+ if (!nodeCategoryMap.has(tgt)) nodeCategoryMap.set(tgt, cat);
8807
+ }
8808
+ const categoryIndex = /* @__PURE__ */ new Map();
8809
+ let nextIdx = 0;
8810
+ for (const node of nodes) {
8811
+ const category = nodeCategoryMap.get(node.id) ?? node.id;
8812
+ if (!categoryIndex.has(category)) {
8813
+ categoryIndex.set(category, nextIdx++);
8814
+ }
8815
+ colorMap.set(node.id, pickColor(palette, categoryIndex.get(category)));
8816
+ }
8817
+ } else {
8818
+ for (let i = 0; i < nodes.length; i++) {
8819
+ colorMap.set(nodes[i].id, pickColor(palette, i));
8820
+ }
8821
+ }
8822
+ return colorMap;
8823
+ }
8824
+ function getLinkColors(linkStyle, sourceColor, targetColor, neutralColor) {
8825
+ switch (linkStyle) {
8826
+ case "source":
8827
+ return { sourceColor, targetColor: sourceColor };
8828
+ case "target":
8829
+ return { sourceColor: targetColor, targetColor };
8830
+ case "neutral":
8831
+ return { sourceColor: neutralColor, targetColor: neutralColor };
8832
+ default:
8833
+ return { sourceColor, targetColor };
8834
+ }
8835
+ }
8836
+ function computeNodeLabel(node, maxDepth, theme, nodeWidth) {
8837
+ const depth = node.depth ?? 0;
8838
+ const isRightmost = depth === maxDepth;
8839
+ const style = {
8840
+ fontFamily: theme.fonts.family,
8841
+ fontSize: theme.fonts.sizes.small,
8842
+ fontWeight: theme.fonts.weights.normal,
8843
+ fill: theme.colors.text,
8844
+ lineHeight: 1.3
8845
+ };
8846
+ const x0 = node.x0 ?? 0;
8847
+ const x1 = node.x1 ?? nodeWidth;
8848
+ const y0 = node.y0 ?? 0;
8849
+ const y1 = node.y1 ?? 0;
8850
+ const midY = (y0 + y1) / 2;
8851
+ if (isRightmost) {
8852
+ return {
8853
+ text: node.label ?? node.id,
8854
+ x: x0 - LABEL_GAP,
8855
+ y: midY,
8856
+ style: { ...style, textAnchor: "end", dominantBaseline: "central" },
8857
+ visible: true
8858
+ };
8859
+ }
8860
+ return {
8861
+ text: node.label ?? node.id,
8862
+ x: x1 + LABEL_GAP,
8863
+ y: midY,
8864
+ style: { ...style, textAnchor: "start", dominantBaseline: "central" },
8865
+ visible: true
8866
+ };
8867
+ }
8868
+ function compileSankey(spec, options) {
8869
+ const { spec: normalized } = compile(spec);
8870
+ if (!("type" in normalized) || normalized.type !== "sankey") {
8871
+ throw new Error(
8872
+ "compileSankey received a non-sankey spec. Use compileChart, compileTable, or compileGraph instead."
8873
+ );
8874
+ }
8875
+ const sankeySpec = normalized;
8876
+ const mergedThemeConfig = options.theme ? { ...sankeySpec.theme, ...options.theme } : sankeySpec.theme;
8877
+ let theme = resolveTheme2(mergedThemeConfig);
8878
+ if (options.darkMode) {
8879
+ theme = adaptTheme2(theme);
8880
+ }
8881
+ const chrome = computeChrome3(
8882
+ {
8883
+ title: sankeySpec.chrome.title,
8884
+ subtitle: sankeySpec.chrome.subtitle,
8885
+ source: sankeySpec.chrome.source,
8886
+ byline: sankeySpec.chrome.byline,
8887
+ footer: sankeySpec.chrome.footer
8888
+ },
8889
+ theme,
8890
+ options.width,
8891
+ options.measureText
8892
+ );
8893
+ const padding = theme.spacing.padding;
8894
+ const fullArea = {
8895
+ x: padding,
8896
+ y: padding + chrome.topHeight,
8897
+ width: options.width - padding * 2,
8898
+ height: options.height - chrome.topHeight - chrome.bottomHeight - padding * 2
8899
+ };
8900
+ if (fullArea.width <= 0 || fullArea.height <= 0) {
8901
+ return emptyLayout(fullArea, chrome, theme, options);
8902
+ }
8903
+ const sourceField = sankeySpec.encoding.source.field;
8904
+ const targetField = sankeySpec.encoding.target.field;
8905
+ const valueField = sankeySpec.encoding.value.field;
8906
+ const colorField = sankeySpec.encoding.color?.field;
8907
+ const tempNodeIds = /* @__PURE__ */ new Set();
8908
+ for (const row of sankeySpec.data) {
8909
+ tempNodeIds.add(String(row[sourceField]));
8910
+ tempNodeIds.add(String(row[targetField]));
8911
+ }
8912
+ const tempColorMap = buildNodeColorMap(
8913
+ [...tempNodeIds].map((id) => ({ id })),
8914
+ theme.colors.categorical,
8915
+ colorField,
8916
+ sankeySpec.data,
8917
+ sourceField,
8918
+ targetField
8919
+ );
8920
+ const legend = buildSankeyLegend(
8921
+ tempColorMap,
8922
+ colorField,
8923
+ sankeySpec.data,
8924
+ sourceField,
8925
+ targetField,
8926
+ theme,
8927
+ fullArea
8928
+ );
8929
+ const legendGap = legend.entries.length > 0 ? 4 : 0;
8930
+ const area = {
8931
+ x: fullArea.x,
8932
+ y: fullArea.y + legend.bounds.height + legendGap,
8933
+ width: fullArea.width,
8934
+ height: fullArea.height - legend.bounds.height - legendGap
8935
+ };
8936
+ if (area.height <= 0) {
8937
+ return emptyLayout(area, chrome, theme, options);
8938
+ }
8939
+ const { nodes, links } = computeSankeyLayout(
8940
+ sankeySpec.data,
8941
+ sourceField,
8942
+ targetField,
8943
+ valueField,
8944
+ area,
8945
+ sankeySpec.nodeWidth,
8946
+ sankeySpec.nodePadding,
8947
+ sankeySpec.nodeAlign,
8948
+ sankeySpec.iterations
8949
+ );
8950
+ const nodeColorMap = buildNodeColorMap(
8951
+ nodes,
8952
+ theme.colors.categorical,
8953
+ colorField,
8954
+ sankeySpec.data,
8955
+ sourceField,
8956
+ targetField
8957
+ );
8958
+ const maxDepth = nodes.reduce((max4, n) => Math.max(max4, n.depth ?? 0), 0);
8959
+ const nodeMarks = nodes.map((node) => {
8960
+ const fill = nodeColorMap.get(node.id) ?? theme.colors.categorical[0];
8961
+ const depth = node.depth ?? 0;
8962
+ return {
8963
+ type: "sankeyNode",
8964
+ x: node.x0 ?? 0,
8965
+ y: node.y0 ?? 0,
8966
+ width: (node.x1 ?? 0) - (node.x0 ?? 0),
8967
+ height: (node.y1 ?? 0) - (node.y0 ?? 0),
8968
+ fill,
8969
+ cornerRadius: NODE_CORNER_RADIUS,
8970
+ label: computeNodeLabel(node, maxDepth, theme, sankeySpec.nodeWidth),
8971
+ nodeId: node.id,
8972
+ value: node.value ?? 0,
8973
+ depth,
8974
+ data: { id: node.id, label: node.label },
8975
+ aria: {
8976
+ role: "img",
8977
+ label: `${node.label}: ${formatNumber4(node.value ?? 0)}`
8978
+ },
8979
+ animationIndex: 0
8980
+ // Reassigned below after sorting by depth
8981
+ };
8982
+ });
8983
+ nodeMarks.sort((a, b) => a.depth - b.depth || a.y - b.y);
8984
+ for (let i = 0; i < nodeMarks.length; i++) {
8985
+ nodeMarks[i].animationIndex = i;
8986
+ }
8987
+ const neutralColor = theme.colors.gridline;
8988
+ const linkMarks = links.map((link, i) => {
8989
+ const sourceNode = link.source;
8990
+ const targetNode = link.target;
8991
+ const srcColor = nodeColorMap.get(sourceNode.id) ?? theme.colors.categorical[0];
8992
+ const tgtColor = nodeColorMap.get(targetNode.id) ?? theme.colors.categorical[0];
8993
+ const colors = getLinkColors(sankeySpec.linkStyle, srcColor, tgtColor, neutralColor);
8994
+ return {
8995
+ type: "sankeyLink",
8996
+ path: generateLinkPath(link),
8997
+ sourceColor: colors.sourceColor,
8998
+ targetColor: colors.targetColor,
8999
+ fillOpacity: LINK_OPACITY,
9000
+ sourceId: sourceNode.id,
9001
+ targetId: targetNode.id,
9002
+ width: link.width ?? 0,
9003
+ value: link.value,
9004
+ data: link.data ?? {},
9005
+ aria: {
9006
+ role: "img",
9007
+ label: `${sourceNode.label} to ${targetNode.label}: ${formatNumber4(link.value)}`
9008
+ },
9009
+ // Links animate after nodes
9010
+ animationIndex: nodeMarks.length + i
9011
+ };
9012
+ });
9013
+ const finalLegend = buildSankeyLegend(
9014
+ nodeColorMap,
9015
+ colorField,
9016
+ sankeySpec.data,
9017
+ sourceField,
9018
+ targetField,
9019
+ theme,
9020
+ fullArea
9021
+ );
9022
+ const tooltipDescriptors = buildTooltipDescriptors(nodeMarks, linkMarks);
9023
+ const a11y = {
9024
+ altText: `Sankey diagram with ${nodeMarks.length} nodes and ${linkMarks.length} links`,
9025
+ dataTableFallback: linkMarks.map((l) => [l.sourceId, l.targetId, String(l.value)]),
9026
+ role: "img",
9027
+ keyboardNavigable: nodeMarks.length > 0
9028
+ };
9029
+ const resolvedAnimation = resolveAnimation(sankeySpec.animation);
9030
+ return {
9031
+ area,
9032
+ chrome,
9033
+ nodes: nodeMarks,
9034
+ links: linkMarks,
9035
+ legend: finalLegend,
9036
+ tooltipDescriptors,
9037
+ a11y,
9038
+ theme,
9039
+ dimensions: {
9040
+ width: options.width,
9041
+ height: options.height
9042
+ },
9043
+ animation: resolvedAnimation
9044
+ };
9045
+ }
9046
+ function buildSankeyLegend(nodeColorMap, colorField, data, sourceField, targetField, theme, area) {
9047
+ const labelStyle = {
9048
+ fontFamily: theme.fonts.family,
9049
+ fontSize: theme.fonts.sizes.small,
9050
+ fontWeight: theme.fonts.weights.normal,
9051
+ fill: theme.colors.text,
9052
+ lineHeight: 1.3
9053
+ };
9054
+ let entries;
9055
+ if (colorField) {
9056
+ const categoryColors = /* @__PURE__ */ new Map();
9057
+ const nodeCategoryMap = /* @__PURE__ */ new Map();
9058
+ for (const row of data) {
9059
+ const src = String(row[sourceField]);
9060
+ const tgt = String(row[targetField]);
9061
+ const cat = String(row[colorField]);
9062
+ if (!nodeCategoryMap.has(src)) nodeCategoryMap.set(src, cat);
9063
+ if (!nodeCategoryMap.has(tgt)) nodeCategoryMap.set(tgt, cat);
9064
+ }
9065
+ for (const [nodeId, category] of nodeCategoryMap) {
9066
+ if (!categoryColors.has(category)) {
9067
+ categoryColors.set(category, nodeColorMap.get(nodeId) ?? theme.colors.categorical[0]);
9068
+ }
9069
+ }
9070
+ entries = [...categoryColors.entries()].map(([label, color2]) => ({
9071
+ label,
9072
+ color: color2,
9073
+ shape: "square",
9074
+ active: true
9075
+ }));
9076
+ } else {
9077
+ entries = [];
9078
+ }
9079
+ let bounds = { x: 0, y: 0, width: 0, height: 0 };
9080
+ if (entries.length > 0) {
9081
+ const ROW_HEIGHT = SWATCH_SIZE3 + 4;
9082
+ const availableWidth = area.width;
9083
+ let rowCount = 1;
9084
+ let rowX = 0;
9085
+ for (const entry of entries) {
9086
+ const labelWidth = estimateTextWidth10(entry.label, labelStyle.fontSize, labelStyle.fontWeight);
9087
+ const entryWidth = SWATCH_SIZE3 + SWATCH_GAP3 + labelWidth + ENTRY_GAP3;
9088
+ if (rowX > 0 && rowX + entryWidth > availableWidth) {
9089
+ rowCount++;
9090
+ rowX = entryWidth;
9091
+ } else {
9092
+ rowX += entryWidth;
9093
+ }
9094
+ }
9095
+ rowCount = Math.min(rowCount, 2);
9096
+ const legendHeight = rowCount * ROW_HEIGHT;
9097
+ bounds = {
9098
+ x: area.x,
9099
+ y: area.y,
9100
+ width: availableWidth,
9101
+ height: legendHeight
9102
+ };
9103
+ }
9104
+ return {
9105
+ position: "top",
9106
+ entries,
9107
+ bounds,
9108
+ labelStyle,
9109
+ swatchSize: SWATCH_SIZE3,
9110
+ swatchGap: SWATCH_GAP3,
9111
+ entryGap: ENTRY_GAP3
9112
+ };
9113
+ }
9114
+ function buildTooltipDescriptors(nodes, links) {
9115
+ const descriptors = /* @__PURE__ */ new Map();
9116
+ for (const node of nodes) {
9117
+ const fields = [
9118
+ {
9119
+ label: "Total flow",
9120
+ value: formatNumber4(node.value)
9121
+ }
9122
+ ];
9123
+ descriptors.set(`node-${node.nodeId}`, {
9124
+ title: node.label.text,
9125
+ fields
9126
+ });
9127
+ }
9128
+ for (const link of links) {
9129
+ const fields = [
9130
+ {
9131
+ label: "Flow",
9132
+ value: formatNumber4(link.value)
9133
+ }
9134
+ ];
9135
+ descriptors.set(`link-${link.sourceId}-${link.targetId}`, {
9136
+ title: `${link.sourceId} \u2192 ${link.targetId}`,
9137
+ fields
9138
+ });
9139
+ }
9140
+ return descriptors;
9141
+ }
9142
+ function emptyLayout(area, chrome, theme, options) {
9143
+ return {
9144
+ area,
9145
+ chrome,
9146
+ nodes: [],
9147
+ links: [],
9148
+ legend: {
9149
+ position: "top",
9150
+ entries: [],
9151
+ bounds: { x: 0, y: 0, width: 0, height: 0 },
9152
+ labelStyle: {
9153
+ fontFamily: theme.fonts.family,
9154
+ fontSize: theme.fonts.sizes.small,
9155
+ fontWeight: theme.fonts.weights.normal,
9156
+ fill: theme.colors.text,
9157
+ lineHeight: 1.3
9158
+ },
9159
+ swatchSize: SWATCH_SIZE3,
9160
+ swatchGap: SWATCH_GAP3,
9161
+ entryGap: ENTRY_GAP3
9162
+ },
9163
+ tooltipDescriptors: /* @__PURE__ */ new Map(),
9164
+ a11y: {
9165
+ altText: "Empty sankey diagram",
9166
+ dataTableFallback: [],
9167
+ role: "img",
9168
+ keyboardNavigable: false
9169
+ },
9170
+ theme,
9171
+ dimensions: {
9172
+ width: options.width,
9173
+ height: options.height
9174
+ }
9175
+ };
9176
+ }
9177
+
8195
9178
  // src/tables/compile-table.ts
8196
- import { computeChrome as computeChrome3, estimateTextWidth as estimateTextWidth10 } from "@opendata-ai/openchart-core";
9179
+ import { computeChrome as computeChrome4, estimateTextWidth as estimateTextWidth11 } from "@opendata-ai/openchart-core";
8197
9180
 
8198
9181
  // src/tables/bar-column.ts
8199
9182
  var NEGATIVE_BAR_COLOR = "#c44e52";
8200
- function computeBarCell(value, config, columnMax, columnMin, theme, _darkMode) {
9183
+ function computeBarCell(value2, config, columnMax, columnMin, theme, _darkMode) {
8201
9184
  const barColor = config.color ?? theme.colors.categorical[0];
8202
9185
  const hasNegatives = columnMin < 0;
8203
- if (!Number.isFinite(value)) {
9186
+ if (!Number.isFinite(value2)) {
8204
9187
  return { barPercent: 0, barOffset: 0, barColor, isNegative: false };
8205
9188
  }
8206
9189
  if (!hasNegatives) {
@@ -8208,7 +9191,7 @@ function computeBarCell(value, config, columnMax, columnMin, theme, _darkMode) {
8208
9191
  if (maxValue <= 0) {
8209
9192
  return { barPercent: 0, barOffset: 0, barColor, isNegative: false };
8210
9193
  }
8211
- const barPercent2 = Math.max(0, Math.min(1, value / maxValue));
9194
+ const barPercent2 = Math.max(0, Math.min(1, value2 / maxValue));
8212
9195
  return { barPercent: barPercent2, barOffset: 0, barColor, isNegative: false };
8213
9196
  }
8214
9197
  const maxPos = config.maxValue ?? columnMax;
@@ -8218,11 +9201,11 @@ function computeBarCell(value, config, columnMax, columnMin, theme, _darkMode) {
8218
9201
  return { barPercent: 0, barOffset: 0, barColor, isNegative: false };
8219
9202
  }
8220
9203
  const zeroPos = absMin / totalRange;
8221
- if (value >= 0) {
8222
- const barPercent2 = value / totalRange;
9204
+ if (value2 >= 0) {
9205
+ const barPercent2 = value2 / totalRange;
8223
9206
  return { barPercent: barPercent2, barOffset: zeroPos, barColor, isNegative: false };
8224
9207
  }
8225
- const barPercent = Math.abs(value) / totalRange;
9208
+ const barPercent = Math.abs(value2) / totalRange;
8226
9209
  return {
8227
9210
  barPercent,
8228
9211
  barOffset: zeroPos - barPercent,
@@ -8231,24 +9214,24 @@ function computeBarCell(value, config, columnMax, columnMin, theme, _darkMode) {
8231
9214
  };
8232
9215
  }
8233
9216
  function computeColumnMax(data, key) {
8234
- let max3 = 0;
9217
+ let max4 = 0;
8235
9218
  for (const row of data) {
8236
9219
  const val = row[key];
8237
- if (typeof val === "number" && Number.isFinite(val) && val > max3) {
8238
- max3 = val;
9220
+ if (typeof val === "number" && Number.isFinite(val) && val > max4) {
9221
+ max4 = val;
8239
9222
  }
8240
9223
  }
8241
- return max3;
9224
+ return max4;
8242
9225
  }
8243
9226
  function computeColumnMin(data, key) {
8244
- let min3 = 0;
9227
+ let min4 = 0;
8245
9228
  for (const row of data) {
8246
9229
  const val = row[key];
8247
- if (typeof val === "number" && Number.isFinite(val) && val < min3) {
8248
- min3 = val;
9230
+ if (typeof val === "number" && Number.isFinite(val) && val < min4) {
9231
+ min4 = val;
8249
9232
  }
8250
9233
  }
8251
- return min3;
9234
+ return min4;
8252
9235
  }
8253
9236
 
8254
9237
  // src/tables/category-colors.ts
@@ -8301,67 +9284,67 @@ function computeCategoryColors(data, column, theme, darkMode) {
8301
9284
  }
8302
9285
 
8303
9286
  // 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);
9287
+ import { formatDate as formatDate2, formatNumber as formatNumber5 } from "@opendata-ai/openchart-core";
9288
+ function isNumericValue(value2) {
9289
+ if (typeof value2 === "number") return Number.isFinite(value2);
8307
9290
  return false;
8308
9291
  }
8309
- function isDateValue(value) {
8310
- if (value instanceof Date) return !Number.isNaN(value.getTime());
9292
+ function isDateValue(value2) {
9293
+ if (value2 instanceof Date) return !Number.isNaN(value2.getTime());
8311
9294
  return false;
8312
9295
  }
8313
- function formatCell(value, column) {
9296
+ function formatCell(value2, column) {
8314
9297
  const style = {};
8315
- if (value == null) {
9298
+ if (value2 == null) {
8316
9299
  return {
8317
- value,
9300
+ value: value2,
8318
9301
  formattedValue: "",
8319
9302
  style
8320
9303
  };
8321
9304
  }
8322
- if (column.format && isNumericValue(value)) {
9305
+ if (column.format && isNumericValue(value2)) {
8323
9306
  try {
8324
9307
  const formatter = format(column.format);
8325
9308
  return {
8326
- value,
8327
- formattedValue: formatter(value),
9309
+ value: value2,
9310
+ formattedValue: formatter(value2),
8328
9311
  style
8329
9312
  };
8330
9313
  } catch {
8331
9314
  }
8332
9315
  }
8333
- if (isNumericValue(value)) {
9316
+ if (isNumericValue(value2)) {
8334
9317
  return {
8335
- value,
8336
- formattedValue: formatNumber4(value),
9318
+ value: value2,
9319
+ formattedValue: formatNumber5(value2),
8337
9320
  style
8338
9321
  };
8339
9322
  }
8340
- if (isDateValue(value)) {
9323
+ if (isDateValue(value2)) {
8341
9324
  return {
8342
- value,
8343
- formattedValue: formatDate2(value),
9325
+ value: value2,
9326
+ formattedValue: formatDate2(value2),
8344
9327
  style
8345
9328
  };
8346
9329
  }
8347
9330
  return {
8348
- value,
8349
- formattedValue: String(value),
9331
+ value: value2,
9332
+ formattedValue: String(value2),
8350
9333
  style
8351
9334
  };
8352
9335
  }
8353
- function formatValueForSearch(value, column) {
8354
- if (value == null) return "";
8355
- if (column.format && isNumericValue(value)) {
9336
+ function formatValueForSearch(value2, column) {
9337
+ if (value2 == null) return "";
9338
+ if (column.format && isNumericValue(value2)) {
8356
9339
  try {
8357
- return format(column.format)(value);
9340
+ return format(column.format)(value2);
8358
9341
  } catch {
8359
9342
  }
8360
9343
  }
8361
- if (isNumericValue(value)) {
8362
- return formatNumber4(value);
9344
+ if (isNumericValue(value2)) {
9345
+ return formatNumber5(value2);
8363
9346
  }
8364
- return String(value);
9347
+ return String(value2);
8365
9348
  }
8366
9349
 
8367
9350
  // src/tables/heatmap.ts
@@ -8406,13 +9389,13 @@ function computeHeatmapColors(data, column, theme, darkMode) {
8406
9389
  if (config.domain) {
8407
9390
  domain = config.domain;
8408
9391
  } 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;
9392
+ let min4 = Infinity;
9393
+ let max4 = -Infinity;
9394
+ for (const { value: value2 } of numericValues) {
9395
+ if (value2 < min4) min4 = value2;
9396
+ if (value2 > max4) max4 = value2;
8414
9397
  }
8415
- domain = [min3, max3];
9398
+ domain = [min4, max4];
8416
9399
  }
8417
9400
  let stops = resolvePalette(config.palette, theme);
8418
9401
  if (darkMode) {
@@ -8422,8 +9405,8 @@ function computeHeatmapColors(data, column, theme, darkMode) {
8422
9405
  }
8423
9406
  const interpolator = interpolatorFromStops(stops);
8424
9407
  const scale = sequential(interpolator).domain(domain).clamp(true);
8425
- for (const { index, value } of numericValues) {
8426
- const bg = scale(value);
9408
+ for (const { index, value: value2 } of numericValues) {
9409
+ const bg = scale(value2);
8427
9410
  const textColor = accessibleTextColor(bg);
8428
9411
  result.set(index, {
8429
9412
  backgroundColor: bg,
@@ -8528,14 +9511,14 @@ function computeSparkline(values, config, theme, _darkMode) {
8528
9511
  if (values.length === 0) return null;
8529
9512
  const type = config.type ?? "line";
8530
9513
  const color2 = config.color ?? theme.colors.categorical[0];
8531
- let min3 = Infinity;
8532
- let max3 = -Infinity;
9514
+ let min4 = Infinity;
9515
+ let max4 = -Infinity;
8533
9516
  for (const v of values) {
8534
- if (v < min3) min3 = v;
8535
- if (v > max3) max3 = v;
9517
+ if (v < min4) min4 = v;
9518
+ if (v > max4) max4 = v;
8536
9519
  }
8537
- const range2 = max3 - min3;
8538
- const normalize2 = (v) => range2 === 0 ? 0.5 : (v - min3) / range2;
9520
+ const range2 = max4 - min4;
9521
+ const normalize2 = (v) => range2 === 0 ? 0.5 : (v - min4) / range2;
8539
9522
  const startValue = values[0];
8540
9523
  const endValue = values[values.length - 1];
8541
9524
  if (type === "line") {
@@ -8600,13 +9583,13 @@ function estimateColumnWidth(col, data, fontSize) {
8600
9583
  if (col.image) return (col.image.width ?? 24) + PADDING;
8601
9584
  if (col.flag) return 60;
8602
9585
  const label = col.label ?? col.key;
8603
- const headerWidth = estimateTextWidth10(label, fontSize, 600) + PADDING;
9586
+ const headerWidth = estimateTextWidth11(label, fontSize, 600) + PADDING;
8604
9587
  const sampleSize = Math.min(100, data.length);
8605
9588
  let maxDataWidth = 0;
8606
9589
  for (let i = 0; i < sampleSize; i++) {
8607
9590
  const val = data[i][col.key];
8608
9591
  const text = val == null ? "" : String(val);
8609
- const width = estimateTextWidth10(text, fontSize, 400) + PADDING;
9592
+ const width = estimateTextWidth11(text, fontSize, 400) + PADDING;
8610
9593
  if (width > maxDataWidth) maxDataWidth = width;
8611
9594
  }
8612
9595
  return Math.max(MIN_WIDTH, headerWidth, maxDataWidth);
@@ -8626,8 +9609,8 @@ function resolveColumns(columns, data, totalWidth, theme) {
8626
9609
  }
8627
9610
  return estimateColumnWidth(col, data, fontSize);
8628
9611
  });
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);
9612
+ const fixedTotal = naturalWidths.reduce((sum2, w, i) => sum2 + (isFixed[i] ? w : 0), 0);
9613
+ const flexTotal = naturalWidths.reduce((sum2, w, i) => sum2 + (isFixed[i] ? 0 : w), 0);
8631
9614
  const remainingWidth = totalWidth - fixedTotal;
8632
9615
  const flexScale = flexTotal > 0 && remainingWidth > 0 ? remainingWidth / flexTotal : 1;
8633
9616
  return columns.map((col, i) => ({
@@ -8639,9 +9622,9 @@ function resolveColumns(columns, data, totalWidth, theme) {
8639
9622
  cellType: determineCellType(col)
8640
9623
  }));
8641
9624
  }
8642
- function buildCell(value, column, resolvedColumn, heatmapStyle, categoryStyle, barData, sparklineData) {
8643
- const base = formatCell(value, column);
8644
- if (typeof value === "number") {
9625
+ function buildCell(value2, column, resolvedColumn, heatmapStyle, categoryStyle, barData, sparklineData) {
9626
+ const base = formatCell(value2, column);
9627
+ if (typeof value2 === "number") {
8645
9628
  base.style = { ...base.style, fontVariant: "tabular-nums" };
8646
9629
  }
8647
9630
  const cellType = resolvedColumn.cellType;
@@ -8680,7 +9663,7 @@ function buildCell(value, column, resolvedColumn, heatmapStyle, categoryStyle, b
8680
9663
  };
8681
9664
  }
8682
9665
  case "image": {
8683
- const src = typeof value === "string" ? value : "";
9666
+ const src = typeof value2 === "string" ? value2 : "";
8684
9667
  const imgConfig = column.image ?? {};
8685
9668
  return {
8686
9669
  ...base,
@@ -8692,7 +9675,7 @@ function buildCell(value, column, resolvedColumn, heatmapStyle, categoryStyle, b
8692
9675
  };
8693
9676
  }
8694
9677
  case "flag": {
8695
- const code = typeof value === "string" ? value : "";
9678
+ const code = typeof value2 === "string" ? value2 : "";
8696
9679
  return {
8697
9680
  ...base,
8698
9681
  cellType: "flag",
@@ -8767,13 +9750,13 @@ function compileTableLayout(spec, options, theme) {
8767
9750
  const rowId = spec.rowKey ? String(row[spec.rowKey] ?? origIdx) : String(origIdx);
8768
9751
  const cells = spec.columns.map((col, c) => {
8769
9752
  const resolved = resolvedColumns[c];
8770
- const value = row[col.key];
9753
+ const value2 = row[col.key];
8771
9754
  const heatmapStyle = heatmapMaps.get(col.key)?.get(origIdx);
8772
9755
  const categoryStyle = categoryMaps.get(col.key)?.get(origIdx);
8773
9756
  let barData;
8774
- if (resolved.cellType === "bar" && col.bar && typeof value === "number") {
9757
+ if (resolved.cellType === "bar" && col.bar && typeof value2 === "number") {
8775
9758
  barData = computeBarCell(
8776
- value,
9759
+ value2,
8777
9760
  col.bar,
8778
9761
  barMaxes.get(col.key) ?? 0,
8779
9762
  barMins.get(col.key) ?? 0,
@@ -8785,11 +9768,11 @@ function compileTableLayout(spec, options, theme) {
8785
9768
  if (resolved.cellType === "sparkline" && col.sparkline) {
8786
9769
  sparklineData = computeSparklineForRow(row, col.key, col.sparkline, theme, darkMode);
8787
9770
  }
8788
- return buildCell(value, col, resolved, heatmapStyle, categoryStyle, barData, sparklineData);
9771
+ return buildCell(value2, col, resolved, heatmapStyle, categoryStyle, barData, sparklineData);
8789
9772
  });
8790
9773
  return { id: rowId, cells, data: row };
8791
9774
  });
8792
- const chrome = computeChrome3(
9775
+ const chrome = computeChrome4(
8793
9776
  {
8794
9777
  title: spec.chrome.title,
8795
9778
  subtitle: spec.chrome.subtitle,
@@ -8826,25 +9809,25 @@ function compileTableLayout(spec, options, theme) {
8826
9809
  }
8827
9810
 
8828
9811
  // 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) {
9812
+ import { buildTemporalFormatter as buildTemporalFormatter2, formatDate as formatDate3, formatNumber as formatNumber6 } from "@opendata-ai/openchart-core";
9813
+ function formatValue(value2, fieldType, format2) {
9814
+ if (value2 == null) return "";
9815
+ if (fieldType === "temporal" || value2 instanceof Date) {
8833
9816
  const temporalFmt = buildTemporalFormatter2(format2);
8834
- if (temporalFmt) return temporalFmt(value);
8835
- return formatDate3(value);
9817
+ if (temporalFmt) return temporalFmt(value2);
9818
+ return formatDate3(value2);
8836
9819
  }
8837
- if (typeof value === "number") {
9820
+ if (typeof value2 === "number") {
8838
9821
  if (format2) {
8839
9822
  try {
8840
- return format(format2)(value);
9823
+ return format(format2)(value2);
8841
9824
  } catch {
8842
- return formatNumber5(value);
9825
+ return formatNumber6(value2);
8843
9826
  }
8844
9827
  }
8845
- return formatNumber5(value);
9828
+ return formatNumber6(value2);
8846
9829
  }
8847
- return String(value);
9830
+ return String(value2);
8848
9831
  }
8849
9832
  function buildExplicitTooltipFields(row, channels) {
8850
9833
  return channels.map((ch) => ({
@@ -9009,16 +9992,16 @@ function runBin(data, transform) {
9009
9992
  const field = transform.field;
9010
9993
  let extent2 = params.extent;
9011
9994
  if (!extent2) {
9012
- let min3 = Infinity;
9013
- let max3 = -Infinity;
9995
+ let min4 = Infinity;
9996
+ let max4 = -Infinity;
9014
9997
  for (const row of data) {
9015
9998
  const v = Number(row[field]);
9016
9999
  if (Number.isFinite(v)) {
9017
- if (v < min3) min3 = v;
9018
- if (v > max3) max3 = v;
10000
+ if (v < min4) min4 = v;
10001
+ if (v > max4) max4 = v;
9019
10002
  }
9020
10003
  }
9021
- extent2 = [min3 === Infinity ? 0 : min3, max3 === -Infinity ? 0 : max3];
10004
+ extent2 = [min4 === Infinity ? 0 : min4, max4 === -Infinity ? 0 : max4];
9022
10005
  }
9023
10006
  const step = params.step ?? computeStep(extent2, maxbins, nice2);
9024
10007
  const [startAs, endAs] = Array.isArray(transform.as) ? transform.as : [transform.as, void 0];
@@ -9125,10 +10108,10 @@ function extractTimeUnit(date2, unit2) {
9125
10108
  return `${String(date2.getHours()).padStart(2, "0")}:${String(date2.getMinutes()).padStart(2, "0")}`;
9126
10109
  }
9127
10110
  }
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);
10111
+ function toDate(value2) {
10112
+ if (value2 instanceof Date) return value2;
10113
+ if (typeof value2 === "string" || typeof value2 === "number") {
10114
+ const d = new Date(value2);
9132
10115
  return Number.isNaN(d.getTime()) ? null : d;
9133
10116
  }
9134
10117
  return null;
@@ -9212,28 +10195,28 @@ function computeBandRowObstacles(marks, scales) {
9212
10195
  const rows = /* @__PURE__ */ new Map();
9213
10196
  for (const mark of marks) {
9214
10197
  let cy;
9215
- let left;
9216
- let right;
10198
+ let left2;
10199
+ let right2;
9217
10200
  if (mark.type === "point") {
9218
10201
  const pm = mark;
9219
10202
  cy = pm.cy;
9220
- left = pm.cx - pm.r;
9221
- right = pm.cx + pm.r;
10203
+ left2 = pm.cx - pm.r;
10204
+ right2 = pm.cx + pm.r;
9222
10205
  } else if (mark.type === "rect") {
9223
10206
  const rm = mark;
9224
10207
  cy = rm.y + rm.height / 2;
9225
- left = rm.x;
9226
- right = rm.x + rm.width;
10208
+ left2 = rm.x;
10209
+ right2 = rm.x + rm.width;
9227
10210
  } else {
9228
10211
  continue;
9229
10212
  }
9230
10213
  const key = Math.round(cy);
9231
10214
  const existing = rows.get(key);
9232
10215
  if (existing) {
9233
- existing.minX = Math.min(existing.minX, left);
9234
- existing.maxX = Math.max(existing.maxX, right);
10216
+ existing.minX = Math.min(existing.minX, left2);
10217
+ existing.maxX = Math.max(existing.maxX, right2);
9235
10218
  } else {
9236
- rows.set(key, { minX: left, maxX: right, bandY: cy });
10219
+ rows.set(key, { minX: left2, maxX: right2, bandY: cy });
9237
10220
  }
9238
10221
  }
9239
10222
  const bandScale = scales.y.scale;
@@ -9258,6 +10241,9 @@ function compileChart(spec, options) {
9258
10241
  if ("type" in normalized && normalized.type === "graph") {
9259
10242
  throw new Error("compileChart received a graph spec. Use compileGraph instead.");
9260
10243
  }
10244
+ if ("type" in normalized && normalized.type === "sankey") {
10245
+ throw new Error("compileChart received a sankey spec. Use compileSankey instead.");
10246
+ }
9261
10247
  let chartSpec = normalized;
9262
10248
  const rawTransforms = spec.transform;
9263
10249
  if (rawTransforms && rawTransforms.length > 0) {
@@ -9307,9 +10293,9 @@ function compileChart(spec, options) {
9307
10293
  const rawAnimationSpec = overrides?.[breakpoint]?.animation ?? rawSpec.animation;
9308
10294
  const resolvedAnimation = resolveAnimation(rawAnimationSpec);
9309
10295
  const mergedThemeConfig = options.theme ? { ...chartSpec.theme, ...options.theme } : chartSpec.theme;
9310
- let theme = resolveTheme2(mergedThemeConfig);
10296
+ let theme = resolveTheme3(mergedThemeConfig);
9311
10297
  if (options.darkMode) {
9312
- theme = adaptTheme2(theme);
10298
+ theme = adaptTheme3(theme);
9313
10299
  }
9314
10300
  const preliminaryArea = {
9315
10301
  x: 0,
@@ -9571,15 +10557,18 @@ function compileTable(spec, options) {
9571
10557
  }
9572
10558
  const tableSpec = normalized;
9573
10559
  const mergedThemeConfig = options.theme ? { ...tableSpec.theme, ...options.theme } : tableSpec.theme;
9574
- let theme = resolveTheme2(mergedThemeConfig);
10560
+ let theme = resolveTheme3(mergedThemeConfig);
9575
10561
  if (options.darkMode) {
9576
- theme = adaptTheme2(theme);
10562
+ theme = adaptTheme3(theme);
9577
10563
  }
9578
10564
  return compileTableLayout(tableSpec, options, theme);
9579
10565
  }
9580
10566
  function compileGraph2(spec, options) {
9581
10567
  return compileGraph(spec, options);
9582
10568
  }
10569
+ function compileSankey2(spec, options) {
10570
+ return compileSankey(spec, options);
10571
+ }
9583
10572
  export {
9584
10573
  clampStaggerDelay,
9585
10574
  clearRenderers,
@@ -9587,6 +10576,7 @@ export {
9587
10576
  compileChart,
9588
10577
  compileGraph2 as compileGraph,
9589
10578
  compileLayer,
10579
+ compileSankey2 as compileSankey,
9590
10580
  compileTable,
9591
10581
  evaluatePredicate,
9592
10582
  getChartRenderer,