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