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