@opendata-ai/openchart-engine 6.13.0 → 6.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +178 -76
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/src/__tests__/encoding-sugar.test.ts +3 -2
- package/src/charts/bar/index.ts +3 -0
- package/src/charts/bar/labels.ts +31 -13
- package/src/charts/column/index.ts +3 -0
- package/src/charts/column/labels.ts +35 -13
- package/src/charts/dot/index.ts +10 -1
- package/src/charts/dot/labels.ts +37 -6
- package/src/charts/line/area.ts +12 -4
- package/src/charts/line/compute.ts +7 -2
- package/src/charts/line/index.ts +33 -2
- package/src/compile.ts +1 -0
- package/src/layout/axes.ts +2 -2
- package/src/layout/scales.ts +15 -12
- package/src/legend/compute.ts +2 -4
- package/src/tooltips/compute.ts +29 -1
package/dist/index.js
CHANGED
|
@@ -968,11 +968,17 @@ function computeSimpleBars(data, valueField, categoryField, xScale, yScale, band
|
|
|
968
968
|
|
|
969
969
|
// src/charts/bar/labels.ts
|
|
970
970
|
import {
|
|
971
|
+
abbreviateNumber as abbreviateNumber2,
|
|
971
972
|
buildD3Formatter,
|
|
972
973
|
estimateTextWidth as estimateTextWidth2,
|
|
974
|
+
formatNumber as formatNumber2,
|
|
973
975
|
getRepresentativeColor,
|
|
974
976
|
resolveCollisions
|
|
975
977
|
} from "@opendata-ai/openchart-core";
|
|
978
|
+
function formatBarValue2(value2) {
|
|
979
|
+
if (Math.abs(value2) >= 1e3) return abbreviateNumber2(value2);
|
|
980
|
+
return formatNumber2(value2);
|
|
981
|
+
}
|
|
976
982
|
var SUFFIX_MULTIPLIERS = {
|
|
977
983
|
K: 1e3,
|
|
978
984
|
M: 1e6,
|
|
@@ -998,21 +1004,30 @@ var LABEL_FONT_SIZE = 11;
|
|
|
998
1004
|
var LABEL_FONT_WEIGHT = 600;
|
|
999
1005
|
var LABEL_PADDING = 6;
|
|
1000
1006
|
var MIN_WIDTH_FOR_INSIDE_LABEL = 40;
|
|
1001
|
-
function computeBarLabels(marks, _chartArea, density = "auto", labelFormat, labelPrefix) {
|
|
1007
|
+
function computeBarLabels(marks, _chartArea, density = "auto", labelFormat, labelPrefix, valueField) {
|
|
1002
1008
|
if (density === "none") return [];
|
|
1003
1009
|
const targetMarks = density === "endpoints" && marks.length > 1 ? [marks[0], marks[marks.length - 1]] : marks;
|
|
1004
1010
|
const candidates = [];
|
|
1005
1011
|
const fitsInSegment = [];
|
|
1006
1012
|
const formatter = buildD3Formatter(labelFormat);
|
|
1007
1013
|
for (const mark of targetMarks) {
|
|
1008
|
-
|
|
1009
|
-
const
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1014
|
+
let valuePart;
|
|
1015
|
+
const rawNum = valueField != null ? Number(mark.data[valueField]) : NaN;
|
|
1016
|
+
if (formatter && Number.isFinite(rawNum)) {
|
|
1017
|
+
valuePart = formatter(rawNum);
|
|
1018
|
+
} else if (Number.isFinite(rawNum)) {
|
|
1019
|
+
valuePart = formatBarValue2(rawNum);
|
|
1020
|
+
} else {
|
|
1021
|
+
const ariaLabel = mark.aria.label;
|
|
1022
|
+
const lastColon = ariaLabel.lastIndexOf(":");
|
|
1023
|
+
const rawValue = lastColon >= 0 ? ariaLabel.slice(lastColon + 1).trim() : "";
|
|
1024
|
+
if (!rawValue) continue;
|
|
1025
|
+
if (formatter) {
|
|
1026
|
+
const num = parseDisplayNumber(rawValue);
|
|
1027
|
+
valuePart = !Number.isNaN(num) ? formatter(num) : rawValue;
|
|
1028
|
+
} else {
|
|
1029
|
+
valuePart = rawValue;
|
|
1030
|
+
}
|
|
1016
1031
|
}
|
|
1017
1032
|
if (labelPrefix) valuePart = labelPrefix + valuePart;
|
|
1018
1033
|
const textWidth = estimateTextWidth2(valuePart, LABEL_FONT_SIZE, LABEL_FONT_WEIGHT);
|
|
@@ -1097,12 +1112,14 @@ function computeBarLabels(marks, _chartArea, density = "auto", labelFormat, labe
|
|
|
1097
1112
|
// src/charts/bar/index.ts
|
|
1098
1113
|
var barRenderer = (spec, scales, chartArea, strategy, _theme) => {
|
|
1099
1114
|
const marks = computeBarMarks(spec, scales, chartArea, strategy);
|
|
1115
|
+
const valueField = spec.encoding?.x && "field" in spec.encoding.x ? spec.encoding.x.field : void 0;
|
|
1100
1116
|
const labels = computeBarLabels(
|
|
1101
1117
|
marks,
|
|
1102
1118
|
chartArea,
|
|
1103
1119
|
spec.labels.density,
|
|
1104
1120
|
spec.labels.format,
|
|
1105
|
-
spec.labels.prefix
|
|
1121
|
+
spec.labels.prefix,
|
|
1122
|
+
valueField
|
|
1106
1123
|
);
|
|
1107
1124
|
for (let i = 0; i < marks.length && i < labels.length; i++) {
|
|
1108
1125
|
marks[i].label = labels[i];
|
|
@@ -1111,11 +1128,11 @@ var barRenderer = (spec, scales, chartArea, strategy, _theme) => {
|
|
|
1111
1128
|
};
|
|
1112
1129
|
|
|
1113
1130
|
// src/charts/column/compute.ts
|
|
1114
|
-
import { abbreviateNumber as
|
|
1131
|
+
import { abbreviateNumber as abbreviateNumber3, formatNumber as formatNumber3, isGradientDef as isGradientDef2 } from "@opendata-ai/openchart-core";
|
|
1115
1132
|
var MIN_COLUMN_HEIGHT = 1;
|
|
1116
1133
|
function formatColumnValue(value2) {
|
|
1117
|
-
if (Math.abs(value2) >= 1e3) return
|
|
1118
|
-
return
|
|
1134
|
+
if (Math.abs(value2) >= 1e3) return abbreviateNumber3(value2);
|
|
1135
|
+
return formatNumber3(value2);
|
|
1119
1136
|
}
|
|
1120
1137
|
function computeColumnMarks(spec, scales, _chartArea, _strategy) {
|
|
1121
1138
|
const encoding = spec.encoding;
|
|
@@ -1359,28 +1376,43 @@ function computeStackedColumns(data, categoryField, valueField, colorField, xSca
|
|
|
1359
1376
|
|
|
1360
1377
|
// src/charts/column/labels.ts
|
|
1361
1378
|
import {
|
|
1379
|
+
abbreviateNumber as abbreviateNumber4,
|
|
1362
1380
|
buildD3Formatter as buildD3Formatter2,
|
|
1363
1381
|
estimateTextWidth as estimateTextWidth3,
|
|
1382
|
+
formatNumber as formatNumber4,
|
|
1364
1383
|
getRepresentativeColor as getRepresentativeColor2,
|
|
1365
1384
|
resolveCollisions as resolveCollisions2
|
|
1366
1385
|
} from "@opendata-ai/openchart-core";
|
|
1386
|
+
function formatColumnValue2(value2) {
|
|
1387
|
+
if (Math.abs(value2) >= 1e3) return abbreviateNumber4(value2);
|
|
1388
|
+
return formatNumber4(value2);
|
|
1389
|
+
}
|
|
1367
1390
|
var LABEL_FONT_SIZE2 = 10;
|
|
1368
1391
|
var LABEL_FONT_WEIGHT2 = 600;
|
|
1369
1392
|
var LABEL_OFFSET_Y = 6;
|
|
1370
|
-
function computeColumnLabels(marks, _chartArea, density = "auto", labelFormat, labelPrefix) {
|
|
1393
|
+
function computeColumnLabels(marks, _chartArea, density = "auto", labelFormat, labelPrefix, valueField) {
|
|
1371
1394
|
if (density === "none") return [];
|
|
1372
1395
|
const targetMarks = density === "endpoints" && marks.length > 1 ? [marks[0], marks[marks.length - 1]] : marks;
|
|
1373
1396
|
const formatter = buildD3Formatter2(labelFormat);
|
|
1374
1397
|
const candidates = [];
|
|
1375
1398
|
for (const mark of targetMarks) {
|
|
1376
|
-
|
|
1377
|
-
const
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1399
|
+
let valuePart;
|
|
1400
|
+
const rawNum = valueField != null ? Number(mark.data[valueField]) : NaN;
|
|
1401
|
+
if (formatter && Number.isFinite(rawNum)) {
|
|
1402
|
+
valuePart = formatter(rawNum);
|
|
1403
|
+
} else if (Number.isFinite(rawNum)) {
|
|
1404
|
+
valuePart = formatColumnValue2(rawNum);
|
|
1405
|
+
} else {
|
|
1406
|
+
const ariaLabel = mark.aria.label;
|
|
1407
|
+
const lastColon = ariaLabel.lastIndexOf(":");
|
|
1408
|
+
const rawValue = lastColon >= 0 ? ariaLabel.slice(lastColon + 1).trim() : "";
|
|
1409
|
+
if (!rawValue) continue;
|
|
1410
|
+
if (formatter) {
|
|
1411
|
+
const num = Number(rawValue.replace(/[^0-9.-]/g, ""));
|
|
1412
|
+
valuePart = !Number.isNaN(num) ? formatter(num) : rawValue;
|
|
1413
|
+
} else {
|
|
1414
|
+
valuePart = rawValue;
|
|
1415
|
+
}
|
|
1384
1416
|
}
|
|
1385
1417
|
if (labelPrefix) valuePart = labelPrefix + valuePart;
|
|
1386
1418
|
const numericValue = parseFloat(valuePart);
|
|
@@ -1423,12 +1455,14 @@ function computeColumnLabels(marks, _chartArea, density = "auto", labelFormat, l
|
|
|
1423
1455
|
// src/charts/column/index.ts
|
|
1424
1456
|
var columnRenderer = (spec, scales, chartArea, strategy, _theme) => {
|
|
1425
1457
|
const marks = computeColumnMarks(spec, scales, chartArea, strategy);
|
|
1458
|
+
const valueField = spec.encoding?.y && "field" in spec.encoding.y ? spec.encoding.y.field : void 0;
|
|
1426
1459
|
const labels = computeColumnLabels(
|
|
1427
1460
|
marks,
|
|
1428
1461
|
chartArea,
|
|
1429
1462
|
spec.labels.density,
|
|
1430
1463
|
spec.labels.format,
|
|
1431
|
-
spec.labels.prefix
|
|
1464
|
+
spec.labels.prefix,
|
|
1465
|
+
valueField
|
|
1432
1466
|
);
|
|
1433
1467
|
for (let i = 0; i < marks.length && i < labels.length; i++) {
|
|
1434
1468
|
marks[i].label = labels[i];
|
|
@@ -1586,22 +1620,42 @@ function computeLollipopMarks(data, valueField, categoryField, xScale, yScale, b
|
|
|
1586
1620
|
|
|
1587
1621
|
// src/charts/dot/labels.ts
|
|
1588
1622
|
import {
|
|
1623
|
+
abbreviateNumber as abbreviateNumber5,
|
|
1624
|
+
buildD3Formatter as buildD3Formatter3,
|
|
1589
1625
|
estimateTextWidth as estimateTextWidth4,
|
|
1626
|
+
formatNumber as formatNumber5,
|
|
1590
1627
|
getRepresentativeColor as getRepresentativeColor3,
|
|
1591
1628
|
resolveCollisions as resolveCollisions3
|
|
1592
1629
|
} from "@opendata-ai/openchart-core";
|
|
1630
|
+
function formatDotValue(value2) {
|
|
1631
|
+
if (Math.abs(value2) >= 1e3) return abbreviateNumber5(value2);
|
|
1632
|
+
return formatNumber5(value2);
|
|
1633
|
+
}
|
|
1593
1634
|
var LABEL_FONT_SIZE3 = 11;
|
|
1594
1635
|
var LABEL_FONT_WEIGHT3 = 600;
|
|
1595
1636
|
var LABEL_OFFSET_X = 10;
|
|
1596
|
-
function computeDotLabels(marks, _chartArea, density = "auto", labelPrefix) {
|
|
1637
|
+
function computeDotLabels(marks, _chartArea, density = "auto", labelPrefix, labelFormat, valueField) {
|
|
1597
1638
|
if (density === "none") return [];
|
|
1598
1639
|
const targetMarks = density === "endpoints" && marks.length > 1 ? [marks[0], marks[marks.length - 1]] : marks;
|
|
1640
|
+
const formatter = buildD3Formatter3(labelFormat);
|
|
1599
1641
|
const candidates = [];
|
|
1600
1642
|
for (const mark of targetMarks) {
|
|
1601
|
-
|
|
1602
|
-
const
|
|
1603
|
-
|
|
1604
|
-
|
|
1643
|
+
let valuePart;
|
|
1644
|
+
const rawNum = valueField != null ? Number(mark.data[valueField]) : NaN;
|
|
1645
|
+
if (formatter && Number.isFinite(rawNum)) {
|
|
1646
|
+
valuePart = formatter(rawNum);
|
|
1647
|
+
} else if (Number.isFinite(rawNum)) {
|
|
1648
|
+
valuePart = formatDotValue(rawNum);
|
|
1649
|
+
} else {
|
|
1650
|
+
const ariaLabel = mark.aria.label;
|
|
1651
|
+
const lastColon = ariaLabel.lastIndexOf(":");
|
|
1652
|
+
valuePart = lastColon >= 0 ? ariaLabel.slice(lastColon + 1).trim() : "";
|
|
1653
|
+
if (!valuePart) continue;
|
|
1654
|
+
if (formatter) {
|
|
1655
|
+
const num = Number(valuePart.replace(/[^0-9.-]/g, ""));
|
|
1656
|
+
if (!Number.isNaN(num)) valuePart = formatter(num);
|
|
1657
|
+
}
|
|
1658
|
+
}
|
|
1605
1659
|
if (labelPrefix) valuePart = labelPrefix + valuePart;
|
|
1606
1660
|
const textWidth = estimateTextWidth4(valuePart, LABEL_FONT_SIZE3, LABEL_FONT_WEIGHT3);
|
|
1607
1661
|
const textHeight = LABEL_FONT_SIZE3 * 1.2;
|
|
@@ -1640,7 +1694,15 @@ function computeDotLabels(marks, _chartArea, density = "auto", labelPrefix) {
|
|
|
1640
1694
|
var dotRenderer = (spec, scales, chartArea, strategy, _theme) => {
|
|
1641
1695
|
const marks = computeDotMarks(spec, scales, chartArea, strategy);
|
|
1642
1696
|
const pointMarks = marks.filter((m) => m.type === "point");
|
|
1643
|
-
const
|
|
1697
|
+
const valueField = spec.encoding?.x && "field" in spec.encoding.x ? spec.encoding.x.field : void 0;
|
|
1698
|
+
const labels = computeDotLabels(
|
|
1699
|
+
pointMarks,
|
|
1700
|
+
chartArea,
|
|
1701
|
+
spec.labels.density,
|
|
1702
|
+
spec.labels.prefix,
|
|
1703
|
+
spec.labels.format,
|
|
1704
|
+
valueField
|
|
1705
|
+
);
|
|
1644
1706
|
let labelIdx = 0;
|
|
1645
1707
|
for (const mark of marks) {
|
|
1646
1708
|
if (mark.type === "point" && labelIdx < labels.length) {
|
|
@@ -1651,6 +1713,9 @@ var dotRenderer = (spec, scales, chartArea, strategy, _theme) => {
|
|
|
1651
1713
|
return marks;
|
|
1652
1714
|
};
|
|
1653
1715
|
|
|
1716
|
+
// src/charts/line/index.ts
|
|
1717
|
+
import { getRepresentativeColor as getRepresentativeColor6 } from "@opendata-ai/openchart-core";
|
|
1718
|
+
|
|
1654
1719
|
// src/charts/line/area.ts
|
|
1655
1720
|
import { getRepresentativeColor as getRepresentativeColor4 } from "@opendata-ai/openchart-core";
|
|
1656
1721
|
|
|
@@ -2597,7 +2662,7 @@ function computeSingleArea(spec, scales, _chartArea) {
|
|
|
2597
2662
|
const marks = [];
|
|
2598
2663
|
for (const [seriesKey, rows] of groups) {
|
|
2599
2664
|
const color2 = getColor(scales, seriesKey);
|
|
2600
|
-
const sortedRows = sortByField(rows, xChannel.field);
|
|
2665
|
+
const sortedRows = xChannel.type === "nominal" || xChannel.type === "ordinal" ? rows : sortByField(rows, xChannel.field);
|
|
2601
2666
|
const validPoints = [];
|
|
2602
2667
|
for (const row of sortedRows) {
|
|
2603
2668
|
const xVal = scaleValue(scales.x.scale, scales.x.type, row[xChannel.field]);
|
|
@@ -2646,7 +2711,7 @@ function computeStackedArea(spec, scales, chartArea) {
|
|
|
2646
2711
|
if (!xChannel || !yChannel || !scales.x || !scales.y || !colorField) {
|
|
2647
2712
|
return computeSingleArea(spec, scales, chartArea);
|
|
2648
2713
|
}
|
|
2649
|
-
const sortedData = sortByField(spec.data, xChannel.field);
|
|
2714
|
+
const sortedData = xChannel.type === "nominal" || xChannel.type === "ordinal" ? spec.data : sortByField(spec.data, xChannel.field);
|
|
2650
2715
|
const seriesKeys = /* @__PURE__ */ new Set();
|
|
2651
2716
|
const xValueSet = /* @__PURE__ */ new Set();
|
|
2652
2717
|
const rowsByXSeries = /* @__PURE__ */ new Map();
|
|
@@ -2763,7 +2828,7 @@ function computeLineMarks(spec, scales, _chartArea, _strategy) {
|
|
|
2763
2828
|
for (const [seriesKey, rows] of groups) {
|
|
2764
2829
|
const color2 = isSequentialColor ? getSequentialColor(scales, _getMidValue(rows, sequentialColorField)) : getColor(scales, seriesKey);
|
|
2765
2830
|
const strokeColor = getRepresentativeColor5(color2);
|
|
2766
|
-
const sortedRows = sortByField(rows, xChannel.field);
|
|
2831
|
+
const sortedRows = xChannel.type === "nominal" || xChannel.type === "ordinal" ? rows : sortByField(rows, xChannel.field);
|
|
2767
2832
|
const pointsWithData = [];
|
|
2768
2833
|
const segments = [];
|
|
2769
2834
|
let currentSegment = [];
|
|
@@ -2951,9 +3016,24 @@ var lineRenderer = (spec, scales, chartArea, strategy, _theme) => {
|
|
|
2951
3016
|
};
|
|
2952
3017
|
var areaRenderer = (spec, scales, chartArea, strategy, _theme) => {
|
|
2953
3018
|
const areas = computeAreaMarks(spec, scales, chartArea);
|
|
2954
|
-
const
|
|
3019
|
+
const encoding = spec.encoding;
|
|
3020
|
+
const hasColor = !!(encoding.color && "field" in encoding.color);
|
|
3021
|
+
const lines = hasColor ? linesFromAreas(areas) : computeLineMarks(spec, scales, chartArea, strategy);
|
|
2955
3022
|
return [...areas, ...lines];
|
|
2956
3023
|
};
|
|
3024
|
+
function linesFromAreas(areas) {
|
|
3025
|
+
return areas.map((a) => ({
|
|
3026
|
+
type: "line",
|
|
3027
|
+
points: a.topPoints,
|
|
3028
|
+
path: a.topPath,
|
|
3029
|
+
stroke: getRepresentativeColor6(a.fill),
|
|
3030
|
+
strokeWidth: a.strokeWidth ?? 1,
|
|
3031
|
+
seriesKey: a.seriesKey,
|
|
3032
|
+
data: a.data,
|
|
3033
|
+
dataPoints: a.dataPoints,
|
|
3034
|
+
aria: { label: `${a.seriesKey ?? "Series"}: line with ${a.topPoints.length} data points` }
|
|
3035
|
+
}));
|
|
3036
|
+
}
|
|
2957
3037
|
|
|
2958
3038
|
// src/charts/pie/compute.ts
|
|
2959
3039
|
import { isConditionalDef, isGradientDef as isGradientDef3 } from "@opendata-ai/openchart-core";
|
|
@@ -3329,7 +3409,7 @@ function clearRenderers() {
|
|
|
3329
3409
|
}
|
|
3330
3410
|
|
|
3331
3411
|
// src/charts/rule/index.ts
|
|
3332
|
-
import { getRepresentativeColor as
|
|
3412
|
+
import { getRepresentativeColor as getRepresentativeColor7 } from "@opendata-ai/openchart-core";
|
|
3333
3413
|
function computeRuleMarks(spec, scales, chartArea) {
|
|
3334
3414
|
const encoding = spec.encoding;
|
|
3335
3415
|
const xChannel = encoding.x;
|
|
@@ -3372,7 +3452,7 @@ function computeRuleMarks(spec, scales, chartArea) {
|
|
|
3372
3452
|
const y2Val = scaleValue(scales.y.scale, scales.y.type, row[y2Channel.field]);
|
|
3373
3453
|
if (y2Val != null) y2 = y2Val;
|
|
3374
3454
|
}
|
|
3375
|
-
const color2 =
|
|
3455
|
+
const color2 = getRepresentativeColor7(
|
|
3376
3456
|
colorField ? getColor(scales, String(row[colorField] ?? "__default__")) : getColor(scales, "__default__")
|
|
3377
3457
|
);
|
|
3378
3458
|
const strokeDashEncoding = encoding.strokeDash && "field" in encoding.strokeDash ? encoding.strokeDash : void 0;
|
|
@@ -6181,7 +6261,7 @@ var scatterRenderer = (spec, scales, chartArea, strategy, _theme) => {
|
|
|
6181
6261
|
};
|
|
6182
6262
|
|
|
6183
6263
|
// src/charts/text/index.ts
|
|
6184
|
-
import { getRepresentativeColor as
|
|
6264
|
+
import { getRepresentativeColor as getRepresentativeColor8 } from "@opendata-ai/openchart-core";
|
|
6185
6265
|
function computeTextMarks(spec, scales) {
|
|
6186
6266
|
const encoding = spec.encoding;
|
|
6187
6267
|
const xChannel = encoding.x;
|
|
@@ -6207,7 +6287,7 @@ function computeTextMarks(spec, scales) {
|
|
|
6207
6287
|
}
|
|
6208
6288
|
const text = String(row[textChannel.field] ?? "");
|
|
6209
6289
|
if (!text) continue;
|
|
6210
|
-
const color2 =
|
|
6290
|
+
const color2 = getRepresentativeColor8(
|
|
6211
6291
|
colorField ? getColor(scales, String(row[colorField] ?? "__default__")) : getColor(scales, "__default__")
|
|
6212
6292
|
);
|
|
6213
6293
|
const fontSize = sizeEncoding ? Math.max(8, Math.min(48, Number(row[sizeEncoding.field]) || 12)) : 12;
|
|
@@ -6234,7 +6314,7 @@ var textRenderer = (spec, scales, _chartArea, _strategy, _theme) => {
|
|
|
6234
6314
|
};
|
|
6235
6315
|
|
|
6236
6316
|
// src/charts/tick/index.ts
|
|
6237
|
-
import { getRepresentativeColor as
|
|
6317
|
+
import { getRepresentativeColor as getRepresentativeColor9 } from "@opendata-ai/openchart-core";
|
|
6238
6318
|
var DEFAULT_TICK_LENGTH = 18;
|
|
6239
6319
|
function computeTickMarks(spec, scales, _chartArea) {
|
|
6240
6320
|
const encoding = spec.encoding;
|
|
@@ -6250,7 +6330,7 @@ function computeTickMarks(spec, scales, _chartArea) {
|
|
|
6250
6330
|
const xVal = scaleValue(scales.x.scale, scales.x.type, row[xChannel.field]);
|
|
6251
6331
|
const yVal = scaleValue(scales.y.scale, scales.y.type, row[yChannel.field]);
|
|
6252
6332
|
if (xVal == null || yVal == null) continue;
|
|
6253
|
-
const color2 =
|
|
6333
|
+
const color2 = getRepresentativeColor9(
|
|
6254
6334
|
colorField ? getColor(scales, String(row[colorField] ?? "__default__")) : getColor(scales, "__default__")
|
|
6255
6335
|
);
|
|
6256
6336
|
const aria = {
|
|
@@ -7681,16 +7761,16 @@ var DEFAULT_COLLISION_PADDING = 5;
|
|
|
7681
7761
|
|
|
7682
7762
|
// src/layout/axes.ts
|
|
7683
7763
|
import {
|
|
7684
|
-
abbreviateNumber as
|
|
7685
|
-
buildD3Formatter as
|
|
7764
|
+
abbreviateNumber as abbreviateNumber6,
|
|
7765
|
+
buildD3Formatter as buildD3Formatter4,
|
|
7686
7766
|
buildTemporalFormatter,
|
|
7687
7767
|
estimateTextWidth as estimateTextWidth7,
|
|
7688
7768
|
formatDate,
|
|
7689
|
-
formatNumber as
|
|
7769
|
+
formatNumber as formatNumber6
|
|
7690
7770
|
} from "@opendata-ai/openchart-core";
|
|
7691
7771
|
var TICK_COUNTS = {
|
|
7692
|
-
full:
|
|
7693
|
-
reduced:
|
|
7772
|
+
full: 10,
|
|
7773
|
+
reduced: 7,
|
|
7694
7774
|
minimal: 3
|
|
7695
7775
|
};
|
|
7696
7776
|
var HEIGHT_MINIMAL_THRESHOLD = 120;
|
|
@@ -7803,11 +7883,11 @@ function formatTickLabel(value2, resolvedScale) {
|
|
|
7803
7883
|
if (NUMERIC_SCALE_TYPES.has(resolvedScale.type)) {
|
|
7804
7884
|
const num = value2;
|
|
7805
7885
|
if (formatStr) {
|
|
7806
|
-
const fmt =
|
|
7886
|
+
const fmt = buildD3Formatter4(formatStr);
|
|
7807
7887
|
if (fmt) return fmt(num);
|
|
7808
7888
|
}
|
|
7809
|
-
if (Math.abs(num) >= 1e3) return
|
|
7810
|
-
return
|
|
7889
|
+
if (Math.abs(num) >= 1e3) return abbreviateNumber6(num);
|
|
7890
|
+
return formatNumber6(num);
|
|
7811
7891
|
}
|
|
7812
7892
|
return String(value2);
|
|
7813
7893
|
}
|
|
@@ -8218,7 +8298,7 @@ function uniqueStrings(values) {
|
|
|
8218
8298
|
return result;
|
|
8219
8299
|
}
|
|
8220
8300
|
function applyCategoricalSort(values, sort) {
|
|
8221
|
-
if (sort
|
|
8301
|
+
if (!sort) return values;
|
|
8222
8302
|
const sorted = [...values].sort((a, b) => a.localeCompare(b, void 0, { numeric: true }));
|
|
8223
8303
|
if (sort === "descending") sorted.reverse();
|
|
8224
8304
|
return sorted;
|
|
@@ -8236,7 +8316,7 @@ function buildTimeScale(channel, data, rangeStart, rangeEnd) {
|
|
|
8236
8316
|
const values = parseDates(fieldValues(data, channel.field));
|
|
8237
8317
|
const domain = channel.scale?.domain ? [new Date(channel.scale.domain[0]), new Date(channel.scale.domain[1])] : extent(values);
|
|
8238
8318
|
const scale = time().domain(domain).range([rangeStart, rangeEnd]);
|
|
8239
|
-
if (channel.scale?.nice
|
|
8319
|
+
if (!channel.scale?.domain && channel.scale?.nice === true) {
|
|
8240
8320
|
scale.nice();
|
|
8241
8321
|
}
|
|
8242
8322
|
applyContinuousConfig(scale, channel);
|
|
@@ -8246,7 +8326,7 @@ function buildUtcScale(channel, data, rangeStart, rangeEnd) {
|
|
|
8246
8326
|
const values = parseDates(fieldValues(data, channel.field));
|
|
8247
8327
|
const domain = channel.scale?.domain ? [new Date(channel.scale.domain[0]), new Date(channel.scale.domain[1])] : extent(values);
|
|
8248
8328
|
const scale = utcTime().domain(domain).range([rangeStart, rangeEnd]);
|
|
8249
|
-
if (channel.scale?.nice
|
|
8329
|
+
if (!channel.scale?.domain && channel.scale?.nice === true) {
|
|
8250
8330
|
scale.nice();
|
|
8251
8331
|
}
|
|
8252
8332
|
applyContinuousConfig(scale, channel);
|
|
@@ -8269,7 +8349,7 @@ function buildLinearScale(channel, data, rangeStart, rangeEnd) {
|
|
|
8269
8349
|
}
|
|
8270
8350
|
}
|
|
8271
8351
|
const scale = linear2().domain([domainMin, domainMax]).range([rangeStart, rangeEnd]);
|
|
8272
|
-
if (channel.scale?.nice !== false) {
|
|
8352
|
+
if (!channel.scale?.domain && channel.scale?.nice !== false) {
|
|
8273
8353
|
scale.nice();
|
|
8274
8354
|
}
|
|
8275
8355
|
applyContinuousConfig(scale, channel);
|
|
@@ -8283,7 +8363,7 @@ function buildLogScale(channel, data, rangeStart, rangeEnd) {
|
|
|
8283
8363
|
if (channel.scale?.base !== void 0) {
|
|
8284
8364
|
scale.base(channel.scale.base);
|
|
8285
8365
|
}
|
|
8286
|
-
if (channel.scale?.nice !== false) {
|
|
8366
|
+
if (!channel.scale?.domain && channel.scale?.nice !== false) {
|
|
8287
8367
|
scale.nice();
|
|
8288
8368
|
}
|
|
8289
8369
|
applyContinuousConfig(scale, channel);
|
|
@@ -8307,7 +8387,7 @@ function buildPowScale(channel, data, rangeStart, rangeEnd) {
|
|
|
8307
8387
|
if (channel.scale?.exponent !== void 0) {
|
|
8308
8388
|
scale.exponent(channel.scale.exponent);
|
|
8309
8389
|
}
|
|
8310
|
-
if (channel.scale?.nice !== false) {
|
|
8390
|
+
if (!channel.scale?.domain && channel.scale?.nice !== false) {
|
|
8311
8391
|
scale.nice();
|
|
8312
8392
|
}
|
|
8313
8393
|
applyContinuousConfig(scale, channel);
|
|
@@ -8328,7 +8408,7 @@ function buildSqrtScale(channel, data, rangeStart, rangeEnd) {
|
|
|
8328
8408
|
}
|
|
8329
8409
|
}
|
|
8330
8410
|
const scale = sqrt2().domain([domainMin, domainMax]).range([rangeStart, rangeEnd]);
|
|
8331
|
-
if (channel.scale?.nice !== false) {
|
|
8411
|
+
if (!channel.scale?.domain && channel.scale?.nice !== false) {
|
|
8332
8412
|
scale.nice();
|
|
8333
8413
|
}
|
|
8334
8414
|
applyContinuousConfig(scale, channel);
|
|
@@ -8352,7 +8432,7 @@ function buildSymlogScale(channel, data, rangeStart, rangeEnd) {
|
|
|
8352
8432
|
if (channel.scale?.constant !== void 0) {
|
|
8353
8433
|
scale.constant(channel.scale.constant);
|
|
8354
8434
|
}
|
|
8355
|
-
if (channel.scale?.nice !== false) {
|
|
8435
|
+
if (!channel.scale?.domain && channel.scale?.nice !== false) {
|
|
8356
8436
|
scale.nice();
|
|
8357
8437
|
}
|
|
8358
8438
|
applyContinuousConfig(scale, channel);
|
|
@@ -8738,7 +8818,7 @@ function computeLegend(spec, strategy, theme, chartArea, watermark = true) {
|
|
|
8738
8818
|
1,
|
|
8739
8819
|
Math.floor((maxLegendHeight - LEGEND_PADDING * 2) / (entryHeight + 4))
|
|
8740
8820
|
);
|
|
8741
|
-
const maxEntries = spec.legend?.symbolLimit != null ? Math.
|
|
8821
|
+
const maxEntries = spec.legend?.symbolLimit != null ? Math.max(1, spec.legend.symbolLimit) : maxFromSpace;
|
|
8742
8822
|
if (entries.length > maxEntries) {
|
|
8743
8823
|
entries = truncateEntries(entries, maxEntries);
|
|
8744
8824
|
}
|
|
@@ -8813,10 +8893,10 @@ function computeLegend(spec, strategy, theme, chartArea, watermark = true) {
|
|
|
8813
8893
|
// src/sankey/compile-sankey.ts
|
|
8814
8894
|
import {
|
|
8815
8895
|
adaptTheme as adaptTheme2,
|
|
8816
|
-
buildD3Formatter as
|
|
8896
|
+
buildD3Formatter as buildD3Formatter5,
|
|
8817
8897
|
computeChrome as computeChrome3,
|
|
8818
8898
|
estimateTextWidth as estimateTextWidth10,
|
|
8819
|
-
formatNumber as
|
|
8899
|
+
formatNumber as formatNumber7,
|
|
8820
8900
|
resolveTheme as resolveTheme2
|
|
8821
8901
|
} from "@opendata-ai/openchart-core";
|
|
8822
8902
|
|
|
@@ -9670,10 +9750,10 @@ function buildSankeyLegend(nodeColorMap, colorField, data, sourceField, targetFi
|
|
|
9670
9750
|
}
|
|
9671
9751
|
function formatFlowValue(value2, valueFormat) {
|
|
9672
9752
|
if (valueFormat) {
|
|
9673
|
-
const fmt =
|
|
9753
|
+
const fmt = buildD3Formatter5(valueFormat);
|
|
9674
9754
|
if (fmt) return fmt(value2);
|
|
9675
9755
|
}
|
|
9676
|
-
return
|
|
9756
|
+
return formatNumber7(value2);
|
|
9677
9757
|
}
|
|
9678
9758
|
function buildTooltipDescriptors(nodes, links, valueFormat) {
|
|
9679
9759
|
const descriptors = /* @__PURE__ */ new Map();
|
|
@@ -9850,7 +9930,7 @@ function computeCategoryColors(data, column, theme, darkMode) {
|
|
|
9850
9930
|
}
|
|
9851
9931
|
|
|
9852
9932
|
// src/tables/format-cells.ts
|
|
9853
|
-
import { buildD3Formatter as
|
|
9933
|
+
import { buildD3Formatter as buildD3Formatter6, formatDate as formatDate2, formatNumber as formatNumber8 } from "@opendata-ai/openchart-core";
|
|
9854
9934
|
function isNumericValue(value2) {
|
|
9855
9935
|
if (typeof value2 === "number") return Number.isFinite(value2);
|
|
9856
9936
|
return false;
|
|
@@ -9869,7 +9949,7 @@ function formatCell(value2, column) {
|
|
|
9869
9949
|
};
|
|
9870
9950
|
}
|
|
9871
9951
|
if (column.format && isNumericValue(value2)) {
|
|
9872
|
-
const formatter =
|
|
9952
|
+
const formatter = buildD3Formatter6(column.format);
|
|
9873
9953
|
if (formatter) {
|
|
9874
9954
|
return {
|
|
9875
9955
|
value: value2,
|
|
@@ -9881,7 +9961,7 @@ function formatCell(value2, column) {
|
|
|
9881
9961
|
if (isNumericValue(value2)) {
|
|
9882
9962
|
return {
|
|
9883
9963
|
value: value2,
|
|
9884
|
-
formattedValue:
|
|
9964
|
+
formattedValue: formatNumber8(value2),
|
|
9885
9965
|
style
|
|
9886
9966
|
};
|
|
9887
9967
|
}
|
|
@@ -9901,13 +9981,13 @@ function formatCell(value2, column) {
|
|
|
9901
9981
|
function formatValueForSearch(value2, column) {
|
|
9902
9982
|
if (value2 == null) return "";
|
|
9903
9983
|
if (column.format && isNumericValue(value2)) {
|
|
9904
|
-
const formatter =
|
|
9984
|
+
const formatter = buildD3Formatter6(column.format);
|
|
9905
9985
|
if (formatter) {
|
|
9906
9986
|
return formatter(value2);
|
|
9907
9987
|
}
|
|
9908
9988
|
}
|
|
9909
9989
|
if (isNumericValue(value2)) {
|
|
9910
|
-
return
|
|
9990
|
+
return formatNumber8(value2);
|
|
9911
9991
|
}
|
|
9912
9992
|
return String(value2);
|
|
9913
9993
|
}
|
|
@@ -10382,8 +10462,8 @@ function compileTableLayout(spec, options, theme) {
|
|
|
10382
10462
|
import {
|
|
10383
10463
|
buildTemporalFormatter as buildTemporalFormatter2,
|
|
10384
10464
|
formatDate as formatDate3,
|
|
10385
|
-
formatNumber as
|
|
10386
|
-
getRepresentativeColor as
|
|
10465
|
+
formatNumber as formatNumber9,
|
|
10466
|
+
getRepresentativeColor as getRepresentativeColor10
|
|
10387
10467
|
} from "@opendata-ai/openchart-core";
|
|
10388
10468
|
function formatValue(value2, fieldType, format2) {
|
|
10389
10469
|
if (value2 == null) return "";
|
|
@@ -10397,10 +10477,10 @@ function formatValue(value2, fieldType, format2) {
|
|
|
10397
10477
|
try {
|
|
10398
10478
|
return format(format2)(value2);
|
|
10399
10479
|
} catch {
|
|
10400
|
-
return
|
|
10480
|
+
return formatNumber9(value2);
|
|
10401
10481
|
}
|
|
10402
10482
|
}
|
|
10403
|
-
return
|
|
10483
|
+
return formatNumber9(value2);
|
|
10404
10484
|
}
|
|
10405
10485
|
return String(value2);
|
|
10406
10486
|
}
|
|
@@ -10422,11 +10502,22 @@ function buildFields(row, encoding, color2) {
|
|
|
10422
10502
|
return buildExplicitTooltipFields(row, channels);
|
|
10423
10503
|
}
|
|
10424
10504
|
const fields = [];
|
|
10505
|
+
if (encoding.color && "field" in encoding.color) {
|
|
10506
|
+
fields.push({
|
|
10507
|
+
label: resolveLabel(encoding.color),
|
|
10508
|
+
value: formatValue(
|
|
10509
|
+
row[encoding.color.field],
|
|
10510
|
+
encoding.color.type,
|
|
10511
|
+
resolveFormat(encoding.color)
|
|
10512
|
+
),
|
|
10513
|
+
color: color2
|
|
10514
|
+
});
|
|
10515
|
+
}
|
|
10425
10516
|
if (encoding.y) {
|
|
10426
10517
|
fields.push({
|
|
10427
10518
|
label: resolveLabel(encoding.y),
|
|
10428
10519
|
value: formatValue(row[encoding.y.field], encoding.y.type, resolveFormat(encoding.y)),
|
|
10429
|
-
color: color2
|
|
10520
|
+
color: encoding.color ? void 0 : color2
|
|
10430
10521
|
});
|
|
10431
10522
|
}
|
|
10432
10523
|
if (encoding.x) {
|
|
@@ -10460,6 +10551,16 @@ function getTooltipTitle(row, encoding) {
|
|
|
10460
10551
|
if (encoding.y?.type === "nominal" || encoding.y?.type === "ordinal") {
|
|
10461
10552
|
return String(row[encoding.y.field] ?? "");
|
|
10462
10553
|
}
|
|
10554
|
+
if (encoding.x?.type === "quantitative" && encoding.y?.type === "quantitative") {
|
|
10555
|
+
const encodedFields = new Set(
|
|
10556
|
+
[encoding.x, encoding.y, encoding.color, encoding.size, encoding.detail].filter((ch) => !!ch && "field" in ch).map((ch) => ch.field)
|
|
10557
|
+
);
|
|
10558
|
+
for (const [key, value2] of Object.entries(row)) {
|
|
10559
|
+
if (!encodedFields.has(key) && typeof value2 === "string") {
|
|
10560
|
+
return value2;
|
|
10561
|
+
}
|
|
10562
|
+
}
|
|
10563
|
+
}
|
|
10463
10564
|
if (encoding.color && "field" in encoding.color) {
|
|
10464
10565
|
return String(row[encoding.color.field] ?? "");
|
|
10465
10566
|
}
|
|
@@ -10478,12 +10579,12 @@ function tooltipsForLine(mark, encoding, _markIndex) {
|
|
|
10478
10579
|
}
|
|
10479
10580
|
function tooltipsForPoint(mark, encoding, markIndex) {
|
|
10480
10581
|
const title = getTooltipTitle(mark.data, encoding);
|
|
10481
|
-
const fields = buildFields(mark.data, encoding,
|
|
10582
|
+
const fields = buildFields(mark.data, encoding, getRepresentativeColor10(mark.fill));
|
|
10482
10583
|
return [[`point-${markIndex}`, { title, fields }]];
|
|
10483
10584
|
}
|
|
10484
10585
|
function tooltipsForRect(mark, encoding, markIndex) {
|
|
10485
10586
|
const title = getTooltipTitle(mark.data, encoding);
|
|
10486
|
-
const fields = buildFields(mark.data, encoding,
|
|
10587
|
+
const fields = buildFields(mark.data, encoding, getRepresentativeColor10(mark.fill));
|
|
10487
10588
|
return [[`rect-${markIndex}`, { title, fields }]];
|
|
10488
10589
|
}
|
|
10489
10590
|
function tooltipsForArc(mark, encoding, markIndex) {
|
|
@@ -10496,14 +10597,14 @@ function tooltipsForArc(mark, encoding, markIndex) {
|
|
|
10496
10597
|
fields.push({
|
|
10497
10598
|
label: categoryName,
|
|
10498
10599
|
value: formatValue(row[encoding.y.field], encoding.y.type, resolveFormat(encoding.y)),
|
|
10499
|
-
color:
|
|
10600
|
+
color: getRepresentativeColor10(mark.fill)
|
|
10500
10601
|
});
|
|
10501
10602
|
}
|
|
10502
10603
|
} else if (encoding.y) {
|
|
10503
10604
|
fields.push({
|
|
10504
10605
|
label: resolveLabel(encoding.y),
|
|
10505
10606
|
value: formatValue(row[encoding.y.field], encoding.y.type, resolveFormat(encoding.y)),
|
|
10506
|
-
color:
|
|
10607
|
+
color: getRepresentativeColor10(mark.fill)
|
|
10507
10608
|
});
|
|
10508
10609
|
}
|
|
10509
10610
|
const title = colorEnc ? String(row[colorEnc.field] ?? "") : void 0;
|
|
@@ -10514,7 +10615,7 @@ function tooltipsForArea(mark, encoding, _markIndex) {
|
|
|
10514
10615
|
for (const dp of mark.dataPoints) {
|
|
10515
10616
|
dp.tooltip = {
|
|
10516
10617
|
title: getTooltipTitle(dp.datum, encoding),
|
|
10517
|
-
fields: buildFields(dp.datum, encoding,
|
|
10618
|
+
fields: buildFields(dp.datum, encoding, getRepresentativeColor10(mark.fill))
|
|
10518
10619
|
};
|
|
10519
10620
|
}
|
|
10520
10621
|
}
|
|
@@ -11125,7 +11226,8 @@ function compileChart(spec, options) {
|
|
|
11125
11226
|
height: options.height
|
|
11126
11227
|
},
|
|
11127
11228
|
animation: resolvedAnimation,
|
|
11128
|
-
watermark
|
|
11229
|
+
watermark,
|
|
11230
|
+
measureText: options.measureText
|
|
11129
11231
|
};
|
|
11130
11232
|
}
|
|
11131
11233
|
function compileLayer(spec, options) {
|