@rowsncolumns/charts 28.1.6 → 28.1.8
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/cjs/basic-chart/basic-chart.d.ts +1 -1
- package/dist/cjs/basic-chart/basic-chart.d.ts.map +1 -1
- package/dist/cjs/basic-chart/basic-chart.js +207 -152
- package/dist/cjs/components/editors/chart-editor.d.ts.map +1 -1
- package/dist/cjs/components/editors/chart-editor.js +5 -1
- package/dist/cjs/plotly/basic-chart/basic-chart.d.ts +1 -1
- package/dist/cjs/plotly/basic-chart/basic-chart.d.ts.map +1 -1
- package/dist/cjs/plotly/basic-chart/basic-chart.js +169 -96
- package/dist/cjs/tsconfig.cjs.tsbuildinfo +1 -1
- package/dist/cjs/utils/axis-number-format.d.ts +26 -7
- package/dist/cjs/utils/axis-number-format.d.ts.map +1 -1
- package/dist/cjs/utils/axis-number-format.js +94 -16
- package/dist/cjs/utils/doughnut.d.ts +19 -0
- package/dist/cjs/utils/doughnut.d.ts.map +1 -0
- package/dist/cjs/utils/doughnut.js +28 -0
- package/dist/cjs/utils/overrides.d.ts +12 -3
- package/dist/cjs/utils/overrides.d.ts.map +1 -1
- package/dist/cjs/utils/overrides.js +41 -16
- package/dist/cjs/utils/radar.d.ts +31 -5
- package/dist/cjs/utils/radar.d.ts.map +1 -1
- package/dist/cjs/utils/radar.js +67 -27
- package/dist/esm/basic-chart/basic-chart.d.ts +1 -1
- package/dist/esm/basic-chart/basic-chart.d.ts.map +1 -1
- package/dist/esm/basic-chart/basic-chart.js +129 -63
- package/dist/esm/components/editors/chart-editor.d.ts.map +1 -1
- package/dist/esm/components/editors/chart-editor.js +5 -1
- package/dist/esm/plotly/basic-chart/basic-chart.d.ts +1 -1
- package/dist/esm/plotly/basic-chart/basic-chart.d.ts.map +1 -1
- package/dist/esm/plotly/basic-chart/basic-chart.js +99 -23
- package/dist/esm/tsconfig.esm.tsbuildinfo +1 -1
- package/dist/esm/utils/axis-number-format.d.ts +26 -7
- package/dist/esm/utils/axis-number-format.d.ts.map +1 -1
- package/dist/esm/utils/axis-number-format.js +83 -13
- package/dist/esm/utils/doughnut.d.ts +19 -0
- package/dist/esm/utils/doughnut.d.ts.map +1 -0
- package/dist/esm/utils/doughnut.js +21 -0
- package/dist/esm/utils/overrides.d.ts +12 -3
- package/dist/esm/utils/overrides.d.ts.map +1 -1
- package/dist/esm/utils/overrides.js +40 -16
- package/dist/esm/utils/radar.d.ts +31 -5
- package/dist/esm/utils/radar.d.ts.map +1 -1
- package/dist/esm/utils/radar.js +44 -16
- package/package.json +4 -4
|
@@ -27,7 +27,8 @@ import { buildHierarchyTree, extractHierarchyRows, getHierarchyHeaderTitle, } fr
|
|
|
27
27
|
import { binHistogram, computePareto, isParetoSpec, } from "../utils/histogram";
|
|
28
28
|
import { categoryAxisNameGap, legendLabelsFrom, reserveEchartsLegendBand, } from "../utils/legend-layout";
|
|
29
29
|
import { clampSecondPieSize, isOfPieChartSpec, otherSliceHalfAngle, resolveOfPieType, splitOfPie, } from "../utils/of-pie";
|
|
30
|
-
import {
|
|
30
|
+
import { clampDoughnutHole, doughnutRings } from "../utils/doughnut";
|
|
31
|
+
import { applyAxisOverrides, applyLegendOverrides, buildSeriesLabelOption, resolveSeriesDataLabels, } from "../utils/overrides";
|
|
31
32
|
import { buildRadarIndicators, buildRadarSeriesData } from "../utils/radar";
|
|
32
33
|
import { buildRegionMapData, buildSequentialColorRamp, isRegionMapSpec, resolveGeoScope, warnOnceForUnmatchedRegions, } from "../utils/region-map";
|
|
33
34
|
import { loadRegionMapGeo } from "../utils/region-map-loader";
|
|
@@ -183,7 +184,7 @@ const defaultLegendConfig = {
|
|
|
183
184
|
};
|
|
184
185
|
/** Category-axis title gap: clears one row of tick labels (#986). */
|
|
185
186
|
const CATEGORY_AXIS_NAME_GAP = categoryAxisNameGap();
|
|
186
|
-
export const BasicChart = ({ width, height, chart, theme, isDarkMode, sheetId, readonly, getDomainValuesFromRange, getSeriesValuesFromRange, getFormattingFromRange, onDeleteChart, onUpdateChart, onRequestEdit, onRequestCalculate, isSelected, fieldButtons, }) => {
|
|
187
|
+
export const BasicChart = ({ width, height, chart, theme, isDarkMode, sheetId, readonly, getDomainValuesFromRange, getSeriesValuesFromRange, getFormattingFromRange, onDeleteChart, onUpdateChart, onRequestEdit, onRequestCalculate, isSelected, fieldButtons, locale, }) => {
|
|
187
188
|
const spec = chart.spec;
|
|
188
189
|
const explicitChartTitle = chart.spec.title ?? undefined;
|
|
189
190
|
const hierarchyTitleRef = useRef(explicitChartTitle);
|
|
@@ -454,7 +455,7 @@ export const BasicChart = ({ width, height, chart, theme, isDarkMode, sheetId, r
|
|
|
454
455
|
? "rgba(255,255,255,0.08)"
|
|
455
456
|
: "rgba(0,0,0,0.06)";
|
|
456
457
|
const borderColor = isDarkMode ? "rgba(255,255,255,0.3)" : "#FFFFFF";
|
|
457
|
-
const regionSeriesLabel = buildSeriesLabelOption(spec.dataLabels);
|
|
458
|
+
const regionSeriesLabel = buildSeriesLabelOption(spec.dataLabels, undefined, locale);
|
|
458
459
|
const seriesName = seriesEntry?.dataLabel && !isAFormula(seriesEntry.dataLabel)
|
|
459
460
|
? seriesEntry.dataLabel
|
|
460
461
|
: "";
|
|
@@ -581,8 +582,9 @@ export const BasicChart = ({ width, height, chart, theme, isDarkMode, sheetId, r
|
|
|
581
582
|
};
|
|
582
583
|
// Spec-level overrides — axis min/max/visibility/textFormat, legend
|
|
583
584
|
// position/visibility, dataLabel toggles. Same helpers as the
|
|
584
|
-
// non-bubble layout below.
|
|
585
|
-
|
|
585
|
+
// non-bubble layout below. A series' own `dataLabels` replace the
|
|
586
|
+
// chart-level ones for it (#1059).
|
|
587
|
+
const bubbleSeriesLabelFor = (index) => buildSeriesLabelOption(resolveSeriesDataLabels(spec.dataLabels, spec.series?.[index]), undefined, locale);
|
|
586
588
|
chartRef.current?.setOption({
|
|
587
589
|
xAxis: [
|
|
588
590
|
applyAxisOverrides({ ...xAxisConfig }, spec.categoryAxisOptions),
|
|
@@ -593,7 +595,7 @@ export const BasicChart = ({ width, height, chart, theme, isDarkMode, sheetId, r
|
|
|
593
595
|
name: spec.verticalAxisTitle ?? "",
|
|
594
596
|
nameLocation: "middle",
|
|
595
597
|
nameGap: 45,
|
|
596
|
-
}, spec.valueAxisOptions),
|
|
598
|
+
}, spec.valueAxisOptions, undefined, locale),
|
|
597
599
|
],
|
|
598
600
|
legend: applyLegendOverrides({
|
|
599
601
|
...legend,
|
|
@@ -635,15 +637,22 @@ export const BasicChart = ({ width, height, chart, theme, isDarkMode, sheetId, r
|
|
|
635
637
|
scatterStyle === "smoothMarker" ||
|
|
636
638
|
!scatterStyle);
|
|
637
639
|
const smooth = scatterStyle === "smooth" || scatterStyle === "smoothMarker";
|
|
640
|
+
// Labels hang off the point symbols: a marker-less line keeps
|
|
641
|
+
// an invisible 0-size symbol per point when they show (#1049).
|
|
642
|
+
const labelsWithoutMarkers = !wantsMarkers &&
|
|
643
|
+
Boolean(resolveSeriesDataLabels(spec.dataLabels, seriesEntry)
|
|
644
|
+
?.show);
|
|
638
645
|
return wantsLine
|
|
639
646
|
? {
|
|
640
647
|
type: "line",
|
|
641
648
|
name: entry.name,
|
|
642
649
|
data: entry.points,
|
|
643
|
-
showSymbol: wantsMarkers,
|
|
650
|
+
showSymbol: wantsMarkers || labelsWithoutMarkers,
|
|
644
651
|
smooth,
|
|
645
652
|
symbol: mapMarkerSymbolToEcharts(symbol) ?? "circle",
|
|
646
|
-
symbolSize:
|
|
653
|
+
symbolSize: labelsWithoutMarkers
|
|
654
|
+
? 0
|
|
655
|
+
: perMarker?.size ?? 6,
|
|
647
656
|
...(seriesColor
|
|
648
657
|
? {
|
|
649
658
|
itemStyle: { color: seriesColor },
|
|
@@ -673,9 +682,12 @@ export const BasicChart = ({ width, height, chart, theme, isDarkMode, sheetId, r
|
|
|
673
682
|
},
|
|
674
683
|
...(seriesColor ? { itemStyle: { color: seriesColor } } : {}),
|
|
675
684
|
};
|
|
676
|
-
}).map((s) =>
|
|
677
|
-
|
|
678
|
-
|
|
685
|
+
}).map((s, index) => {
|
|
686
|
+
const bubbleSeriesLabel = bubbleSeriesLabelFor(index);
|
|
687
|
+
return bubbleSeriesLabel
|
|
688
|
+
? { ...s, label: { ...(s.label ?? {}), ...bubbleSeriesLabel } }
|
|
689
|
+
: s;
|
|
690
|
+
}),
|
|
679
691
|
}, {
|
|
680
692
|
replaceMerge: [
|
|
681
693
|
"series",
|
|
@@ -715,14 +727,14 @@ export const BasicChart = ({ width, height, chart, theme, isDarkMode, sheetId, r
|
|
|
715
727
|
const value = Array.isArray(params.value)
|
|
716
728
|
? params.value[params.value.length - 1]
|
|
717
729
|
: params.value ?? "";
|
|
718
|
-
return `${params.name}: ${formatAxisValue(sizeNumberFormat, value)}`;
|
|
730
|
+
return `${params.name}: ${formatAxisValue(sizeNumberFormat, value, locale)}`;
|
|
719
731
|
};
|
|
720
732
|
// Spec-level overrides — treemap/sunburst default to no legend,
|
|
721
733
|
// but an authored legend (visibility/position) still wins.
|
|
722
734
|
const hierarchyDataLabels = spec.dataLabels;
|
|
723
735
|
const hierarchySeriesLabel = buildSeriesLabelOption(hierarchyDataLabels && !hierarchyDataLabels.numberFormatPattern
|
|
724
736
|
? { ...hierarchyDataLabels, numberFormatPattern: sizeNumberFormat }
|
|
725
|
-
: hierarchyDataLabels);
|
|
737
|
+
: hierarchyDataLabels, undefined, locale);
|
|
726
738
|
chartRef.current?.setOption({
|
|
727
739
|
xAxis: [
|
|
728
740
|
{
|
|
@@ -818,7 +830,7 @@ export const BasicChart = ({ width, height, chart, theme, isDarkMode, sheetId, r
|
|
|
818
830
|
const [zMin, zMax] = getValueExtent(contourPoints.filter((point) => typeof point[2] === "number"));
|
|
819
831
|
// Values format like the cells of the series (row) they came from.
|
|
820
832
|
const contourFormats = resolveSeriesNumberFormats(spec.series, getFormattingFromRange, spec.hiddenDimensionStrategy);
|
|
821
|
-
const contourLabel = buildSeriesLabelOption(spec.dataLabels);
|
|
833
|
+
const contourLabel = buildSeriesLabelOption(spec.dataLabels, undefined, locale);
|
|
822
834
|
if (!renderedAsContour.current && chartRef.current) {
|
|
823
835
|
chartRef.current.dispose();
|
|
824
836
|
chartRef.current = undefined;
|
|
@@ -835,7 +847,7 @@ export const BasicChart = ({ width, height, chart, theme, isDarkMode, sheetId, r
|
|
|
835
847
|
const [x, y, z] = (params?.value ?? []);
|
|
836
848
|
const value = z === "-" || z === undefined
|
|
837
849
|
? ""
|
|
838
|
-
: formatAxisValue(contourFormats[y], z);
|
|
850
|
+
: formatAxisValue(contourFormats[y], z, locale);
|
|
839
851
|
return `${seriesNames[y] ?? ""}<br/>${categories[x] ?? ""}: ${value}`;
|
|
840
852
|
},
|
|
841
853
|
},
|
|
@@ -871,7 +883,7 @@ export const BasicChart = ({ width, height, chart, theme, isDarkMode, sheetId, r
|
|
|
871
883
|
right: 0,
|
|
872
884
|
top: "center",
|
|
873
885
|
inRange: { color: [...SURFACE_COLOR_RAMP] },
|
|
874
|
-
formatter: (value) => formatAxisValue(contourFormats[0], value),
|
|
886
|
+
formatter: (value) => formatAxisValue(contourFormats[0], value, locale),
|
|
875
887
|
},
|
|
876
888
|
],
|
|
877
889
|
series: [
|
|
@@ -888,7 +900,7 @@ export const BasicChart = ({ width, height, chart, theme, isDarkMode, sheetId, r
|
|
|
888
900
|
const [, y, z] = (params?.value ?? []);
|
|
889
901
|
return z === "-" || z === undefined
|
|
890
902
|
? ""
|
|
891
|
-
: formatAxisValue(contourFormats[y], z);
|
|
903
|
+
: formatAxisValue(contourFormats[y], z, locale);
|
|
892
904
|
},
|
|
893
905
|
},
|
|
894
906
|
}
|
|
@@ -980,7 +992,7 @@ export const BasicChart = ({ width, height, chart, theme, isDarkMode, sheetId, r
|
|
|
980
992
|
: seriesNames[Math.round(value[1] ?? 0)] ?? params?.seriesName ?? "";
|
|
981
993
|
const valueLabel = spec.stackedType === "PERCENT_STACKED" && stackedBar3D
|
|
982
994
|
? `${Math.round((value[2] ?? 0) * 10) / 10}%`
|
|
983
|
-
: formatAxisValue(threeDFormats[seriesIndex], value[2]);
|
|
995
|
+
: formatAxisValue(threeDFormats[seriesIndex], value[2], locale);
|
|
984
996
|
return `${seriesLabel ? `${seriesLabel}<br/>` : ""}${categoryLabel}: ${valueLabel}`;
|
|
985
997
|
};
|
|
986
998
|
let threeDSeries;
|
|
@@ -1137,7 +1149,10 @@ export const BasicChart = ({ width, height, chart, theme, isDarkMode, sheetId, r
|
|
|
1137
1149
|
const values = flattenChartDataValues([seriesEntry], getSeriesValuesFromRange, spec.hiddenDimensionStrategy).map((v) => (typeof v === "number" ? v : Number(v)));
|
|
1138
1150
|
radarSeriesInputs.push({ name: label, values });
|
|
1139
1151
|
}
|
|
1140
|
-
|
|
1152
|
+
// One value scale for every axis (Excel), from the spec's value-axis
|
|
1153
|
+
// min / max when set (#1066).
|
|
1154
|
+
const radarAxisOptions = spec.valueAxisOptions;
|
|
1155
|
+
const indicators = buildRadarIndicators(categories, radarSeriesInputs, radarAxisOptions);
|
|
1141
1156
|
const radarData = buildRadarSeriesData(radarSeriesInputs, indicators.length);
|
|
1142
1157
|
const radarStyle = spec.radarStyle ?? "standard";
|
|
1143
1158
|
const radarColors = radarSeriesInputs.map((_, i) => spec.series?.[i]?.color);
|
|
@@ -1152,18 +1167,25 @@ export const BasicChart = ({ width, height, chart, theme, isDarkMode, sheetId, r
|
|
|
1152
1167
|
...radarDataLabels,
|
|
1153
1168
|
numberFormatPattern: radarFormats[seriesIndex],
|
|
1154
1169
|
}
|
|
1155
|
-
: radarDataLabels);
|
|
1170
|
+
: radarDataLabels, undefined, locale);
|
|
1156
1171
|
const radarTooltipFormatter = (params) => {
|
|
1157
1172
|
const values = Array.isArray(params?.value) ? params.value : [];
|
|
1158
1173
|
const pattern = radarFormats[params?.dataIndex ?? 0];
|
|
1159
|
-
const lines = indicators.map((indicator, i) => `${indicator.name}: ${formatAxisValue(pattern, values[i])}`);
|
|
1174
|
+
const lines = indicators.map((indicator, i) => `${indicator.name}: ${formatAxisValue(pattern, values[i], locale)}`);
|
|
1160
1175
|
return [params?.name ?? "", ...lines].filter(Boolean).join("<br/>");
|
|
1161
1176
|
};
|
|
1162
1177
|
chartRef.current?.setOption({
|
|
1163
1178
|
radar: {
|
|
1164
1179
|
indicator: indicators.length
|
|
1165
1180
|
? indicators
|
|
1166
|
-
: [{ name: "", max: 1 }],
|
|
1181
|
+
: [{ name: "", min: 0, max: 1 }],
|
|
1182
|
+
// The common scale's tick labels along one axis, as Excel draws
|
|
1183
|
+
// them (echarts labels the first indicator axis only); hidden
|
|
1184
|
+
// with the spec's value axis.
|
|
1185
|
+
axisLabel: {
|
|
1186
|
+
show: radarAxisOptions?.visible !== false,
|
|
1187
|
+
formatter: (value) => formatAxisValue(radarFormats[0], value, locale),
|
|
1188
|
+
},
|
|
1167
1189
|
},
|
|
1168
1190
|
legend: applyLegendOverrides({
|
|
1169
1191
|
...legend,
|
|
@@ -1230,7 +1252,7 @@ export const BasicChart = ({ width, height, chart, theme, isDarkMode, sheetId, r
|
|
|
1230
1252
|
const stockDataLabels = spec.dataLabels;
|
|
1231
1253
|
const stockSeriesLabelFor = (role) => buildSeriesLabelOption(stockDataLabels && !stockDataLabels.numberFormatPattern
|
|
1232
1254
|
? { ...stockDataLabels, numberFormatPattern: stockFormatFor(role) }
|
|
1233
|
-
: stockDataLabels);
|
|
1255
|
+
: stockDataLabels, undefined, locale);
|
|
1234
1256
|
// V-variants (VHLC / VOHLC) carry a volume series that renders as
|
|
1235
1257
|
// a column sub-pane under the price plot: two grids stacked
|
|
1236
1258
|
// vertically (price ~70% of the plot, volume below on its own
|
|
@@ -1295,10 +1317,10 @@ export const BasicChart = ({ width, height, chart, theme, isDarkMode, sheetId, r
|
|
|
1295
1317
|
value: p.value,
|
|
1296
1318
|
itemStyle: { color: p.up ? upColor : downColor },
|
|
1297
1319
|
})),
|
|
1298
|
-
...(tooltipValueFormatter(stockFormatFor("volume"))
|
|
1320
|
+
...(tooltipValueFormatter(stockFormatFor("volume"), locale)
|
|
1299
1321
|
? {
|
|
1300
1322
|
tooltip: {
|
|
1301
|
-
valueFormatter: tooltipValueFormatter(stockFormatFor("volume")),
|
|
1323
|
+
valueFormatter: tooltipValueFormatter(stockFormatFor("volume"), locale),
|
|
1302
1324
|
},
|
|
1303
1325
|
}
|
|
1304
1326
|
: {}),
|
|
@@ -1326,7 +1348,7 @@ export const BasicChart = ({ width, height, chart, theme, isDarkMode, sheetId, r
|
|
|
1326
1348
|
nameLocation: "middle",
|
|
1327
1349
|
nameGap: 50,
|
|
1328
1350
|
gridIndex: 0,
|
|
1329
|
-
}, spec.valueAxisOptions),
|
|
1351
|
+
}, spec.valueAxisOptions, undefined, locale),
|
|
1330
1352
|
...(hasVolume ? [volumeYAxis] : []),
|
|
1331
1353
|
],
|
|
1332
1354
|
legend: applyLegendOverrides({ ...legend, show: false }, spec.legend),
|
|
@@ -1344,10 +1366,10 @@ export const BasicChart = ({ width, height, chart, theme, isDarkMode, sheetId, r
|
|
|
1344
1366
|
borderColor: upColor,
|
|
1345
1367
|
borderColor0: downColor,
|
|
1346
1368
|
},
|
|
1347
|
-
...(tooltipValueFormatter(stockFormatFor("close"))
|
|
1369
|
+
...(tooltipValueFormatter(stockFormatFor("close"), locale)
|
|
1348
1370
|
? {
|
|
1349
1371
|
tooltip: {
|
|
1350
|
-
valueFormatter: tooltipValueFormatter(stockFormatFor("close")),
|
|
1372
|
+
valueFormatter: tooltipValueFormatter(stockFormatFor("close"), locale),
|
|
1351
1373
|
},
|
|
1352
1374
|
}
|
|
1353
1375
|
: {}),
|
|
@@ -1385,7 +1407,7 @@ export const BasicChart = ({ width, height, chart, theme, isDarkMode, sheetId, r
|
|
|
1385
1407
|
nameLocation: "middle",
|
|
1386
1408
|
nameGap: 50,
|
|
1387
1409
|
gridIndex: 0,
|
|
1388
|
-
}, spec.valueAxisOptions),
|
|
1410
|
+
}, spec.valueAxisOptions, undefined, locale),
|
|
1389
1411
|
...(hasVolume ? [volumeYAxis] : []),
|
|
1390
1412
|
],
|
|
1391
1413
|
legend: applyLegendOverrides({
|
|
@@ -1407,10 +1429,10 @@ export const BasicChart = ({ width, height, chart, theme, isDarkMode, sheetId, r
|
|
|
1407
1429
|
...(stockSeriesLabelFor(s.role)
|
|
1408
1430
|
? { label: stockSeriesLabelFor(s.role) }
|
|
1409
1431
|
: {}),
|
|
1410
|
-
...(tooltipValueFormatter(stockFormatFor(s.role))
|
|
1432
|
+
...(tooltipValueFormatter(stockFormatFor(s.role), locale)
|
|
1411
1433
|
? {
|
|
1412
1434
|
tooltip: {
|
|
1413
|
-
valueFormatter: tooltipValueFormatter(stockFormatFor(s.role)),
|
|
1435
|
+
valueFormatter: tooltipValueFormatter(stockFormatFor(s.role), locale),
|
|
1414
1436
|
},
|
|
1415
1437
|
}
|
|
1416
1438
|
: {}),
|
|
@@ -1779,26 +1801,39 @@ export const BasicChart = ({ width, height, chart, theme, isDarkMode, sheetId, r
|
|
|
1779
1801
|
const wantsMarkers = markerSymbol === "none"
|
|
1780
1802
|
? false
|
|
1781
1803
|
: Boolean(spec.showMarkers) || !isNil(markerSymbol);
|
|
1782
|
-
|
|
1804
|
+
// echarts draws a line's data labels on its point symbols, so a
|
|
1805
|
+
// marker-less line with labels (Excel's default "Line" with values
|
|
1806
|
+
// shown) keeps an invisible 0-size symbol per point for the label
|
|
1807
|
+
// to hang off (#1049).
|
|
1808
|
+
const labelsWithoutMarkers = !wantsMarkers &&
|
|
1809
|
+
Boolean(resolveSeriesDataLabels(spec.dataLabels, seriesAny)?.show);
|
|
1810
|
+
seriesEntry.showSymbol = wantsMarkers || labelsWithoutMarkers;
|
|
1783
1811
|
if (wantsMarkers) {
|
|
1784
1812
|
seriesEntry.symbol =
|
|
1785
1813
|
mapMarkerSymbolToEcharts(markerSymbol) ?? "circle";
|
|
1786
1814
|
seriesEntry.symbolSize = seriesAny.marker?.size ?? 6;
|
|
1787
1815
|
}
|
|
1788
|
-
else
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1816
|
+
else {
|
|
1817
|
+
if (labelsWithoutMarkers) {
|
|
1818
|
+
seriesEntry.symbol = "circle";
|
|
1819
|
+
seriesEntry.symbolSize = 0;
|
|
1820
|
+
}
|
|
1821
|
+
if (Array.isArray(data)) {
|
|
1822
|
+
// A marker-less line draws nothing for a point with a gap on both
|
|
1823
|
+
// sides (a data row followed by a blank row), so that row vanishes
|
|
1824
|
+
// from the chart. Excel plots an isolated marker there: keep the
|
|
1825
|
+
// series symbol-less and mark only those points.
|
|
1826
|
+
const isolated = isolatedPointIndexes(data, connectsAcrossEmptyCells(spec, lineLike));
|
|
1827
|
+
if (isolated.length) {
|
|
1828
|
+
seriesEntry.showSymbol = true;
|
|
1829
|
+
if (!labelsWithoutMarkers)
|
|
1830
|
+
seriesEntry.symbol = "none";
|
|
1831
|
+
const marked = [...data];
|
|
1832
|
+
for (const i of isolated) {
|
|
1833
|
+
marked[i] = { value: marked[i], symbol: "circle", symbolSize: 6 };
|
|
1834
|
+
}
|
|
1835
|
+
seriesEntry.data = marked;
|
|
1800
1836
|
}
|
|
1801
|
-
seriesEntry.data = marked;
|
|
1802
1837
|
}
|
|
1803
1838
|
}
|
|
1804
1839
|
}
|
|
@@ -2389,7 +2424,7 @@ export const BasicChart = ({ width, height, chart, theme, isDarkMode, sheetId, r
|
|
|
2389
2424
|
trigger: isCircularChart ? "item" : "axis",
|
|
2390
2425
|
formatter: isCircularChart
|
|
2391
2426
|
? primaryAxisNumberFormat
|
|
2392
|
-
? circularTooltipFormatter(primaryAxisNumberFormat)
|
|
2427
|
+
? circularTooltipFormatter(primaryAxisNumberFormat, locale)
|
|
2393
2428
|
: "{b}: {c} ({d}%)"
|
|
2394
2429
|
: undefined,
|
|
2395
2430
|
};
|
|
@@ -2439,19 +2474,37 @@ export const BasicChart = ({ width, height, chart, theme, isDarkMode, sheetId, r
|
|
|
2439
2474
|
}
|
|
2440
2475
|
: legendBand.grid;
|
|
2441
2476
|
// Data labels fall back to the series' axis format when the spec has
|
|
2442
|
-
// no explicit `<c:dLbls><c:numFmt>` — Excel's "Linked to source".
|
|
2443
|
-
|
|
2444
|
-
const
|
|
2445
|
-
|
|
2446
|
-
|
|
2447
|
-
|
|
2448
|
-
|
|
2449
|
-
|
|
2477
|
+
// no explicit `<c:dLbls><c:numFmt>` — Excel's "Linked to source". A
|
|
2478
|
+
// series' own `dataLabels` replace the chart-level ones for it (#1059).
|
|
2479
|
+
const chartDataLabels = spec.dataLabels;
|
|
2480
|
+
const seriesLabelOptionFor = (s) => {
|
|
2481
|
+
const specIndex = chartSeriesSpecIndex(s?.id);
|
|
2482
|
+
const dataLabelOptions = resolveSeriesDataLabels(chartDataLabels, specIndex === undefined ? undefined : spec.series?.[specIndex]);
|
|
2483
|
+
return buildSeriesLabelOption(dataLabelOptions && !dataLabelOptions.numberFormatPattern
|
|
2484
|
+
? {
|
|
2485
|
+
...dataLabelOptions,
|
|
2486
|
+
numberFormatPattern: seriesNumberFormatFor(s),
|
|
2487
|
+
}
|
|
2488
|
+
: dataLabelOptions, s?.type, locale);
|
|
2489
|
+
};
|
|
2450
2490
|
// For doughnut, surface the inner-radius hole on each pie series.
|
|
2451
2491
|
// Excel persists `holeSize` as a 0-90 percentage; we normalize to a
|
|
2452
2492
|
// 0-1 fraction (doughnutHoleSize). Default to 0.5 when unset.
|
|
2453
2493
|
const isDoughnut = spec.chartType === "doughnut";
|
|
2454
2494
|
const doughnutHoleSize = spec.doughnutHoleSize;
|
|
2495
|
+
// Excel nests a doughnut's series as concentric rings, series 0
|
|
2496
|
+
// innermost (#1065): the ring each pie series draws is its rank among
|
|
2497
|
+
// the spec-tagged pie series.
|
|
2498
|
+
const doughnutSeriesOrder = isDoughnut
|
|
2499
|
+
? chartSeries
|
|
2500
|
+
.filter((s) => s?.type === "pie")
|
|
2501
|
+
.map((s) => chartSeriesSpecIndex(s?.id))
|
|
2502
|
+
.filter((i) => i !== undefined)
|
|
2503
|
+
.sort((a, b) => a - b)
|
|
2504
|
+
: [];
|
|
2505
|
+
const doughnutRingSet = isDoughnut
|
|
2506
|
+
? doughnutRings(clampDoughnutHole(doughnutHoleSize), doughnutSeriesOrder.length)
|
|
2507
|
+
: [];
|
|
2455
2508
|
// Exploded pie / doughnut: every slice sits in the `select` state,
|
|
2456
2509
|
// offset outward by the spec's percentage of the pie radius.
|
|
2457
2510
|
const explosion = isCircularChart && !isOfPie ? resolveExplosion(spec) : 0;
|
|
@@ -2502,10 +2555,16 @@ export const BasicChart = ({ width, height, chart, theme, isDarkMode, sheetId, r
|
|
|
2502
2555
|
if (seriesLabelOption) {
|
|
2503
2556
|
next.label = { ...(s?.label ?? {}), ...seriesLabelOption };
|
|
2504
2557
|
}
|
|
2558
|
+
else if (s?.type === "pie") {
|
|
2559
|
+
// echarts labels every pie slice by default (category name on a
|
|
2560
|
+
// leader line); Excel draws nothing until data labels are on (#1062).
|
|
2561
|
+
next.label = { ...(s?.label ?? {}), show: false };
|
|
2562
|
+
next.labelLine = { ...(s?.labelLine ?? {}), show: false };
|
|
2563
|
+
}
|
|
2505
2564
|
// Tooltip values of the value-axis series (a boxplot / candlestick
|
|
2506
2565
|
// tooltip lists its own statistics and keeps echarts' default).
|
|
2507
2566
|
const seriesTooltipValueFormatter = VALUE_TOOLTIP_SERIES_TYPES.has(s?.type)
|
|
2508
|
-
? valueAxisLabelFormatter(seriesNumberFormatFor(s))
|
|
2567
|
+
? valueAxisLabelFormatter(seriesNumberFormatFor(s), locale)
|
|
2509
2568
|
: undefined;
|
|
2510
2569
|
if (seriesTooltipValueFormatter && s?.tooltip?.show !== false) {
|
|
2511
2570
|
next.tooltip = {
|
|
@@ -2518,7 +2577,7 @@ export const BasicChart = ({ width, height, chart, theme, isDarkMode, sheetId, r
|
|
|
2518
2577
|
if (pieNumberFormat && s?.tooltip?.show !== false) {
|
|
2519
2578
|
next.tooltip = {
|
|
2520
2579
|
...(s?.tooltip ?? {}),
|
|
2521
|
-
formatter: circularTooltipFormatter(pieNumberFormat),
|
|
2580
|
+
formatter: circularTooltipFormatter(pieNumberFormat, locale),
|
|
2522
2581
|
};
|
|
2523
2582
|
}
|
|
2524
2583
|
if (explosionOffset > 0 && Array.isArray(next.data)) {
|
|
@@ -2530,10 +2589,15 @@ export const BasicChart = ({ width, height, chart, theme, isDarkMode, sheetId, r
|
|
|
2530
2589
|
}
|
|
2531
2590
|
}
|
|
2532
2591
|
if (isDoughnut && next.type === "pie") {
|
|
2533
|
-
|
|
2534
|
-
|
|
2535
|
-
|
|
2536
|
-
|
|
2592
|
+
// The hole is a fraction of the OUTER radius (Excel's `<c:holeSize>`),
|
|
2593
|
+
// and the doughnut's outer edge sits at 75% of the chart — so every
|
|
2594
|
+
// ring edge is its fraction of 75%, not of the whole chart (#1064:
|
|
2595
|
+
// Excel's default 0.75 used to meet the outer edge, an empty ring).
|
|
2596
|
+
const rank = doughnutSeriesOrder.indexOf(chartSeriesSpecIndex(s?.id));
|
|
2597
|
+
const ring = doughnutRingSet[rank] ??
|
|
2598
|
+
doughnutRings(clampDoughnutHole(doughnutHoleSize), 1)[0];
|
|
2599
|
+
const pct = (fraction) => `${Math.round(fraction * 75 * 100) / 100}%`;
|
|
2600
|
+
next.radius = [pct(ring.inner), pct(ring.outer)];
|
|
2537
2601
|
}
|
|
2538
2602
|
return next;
|
|
2539
2603
|
});
|
|
@@ -2584,7 +2648,7 @@ export const BasicChart = ({ width, height, chart, theme, isDarkMode, sheetId, r
|
|
|
2584
2648
|
applyAxisOverrides({
|
|
2585
2649
|
...valueAxisBase,
|
|
2586
2650
|
name: spec.horizontalAxisTitle ?? "",
|
|
2587
|
-
}, spec.valueAxisOptions, primaryAxisNumberFormat),
|
|
2651
|
+
}, spec.valueAxisOptions, primaryAxisNumberFormat, locale),
|
|
2588
2652
|
];
|
|
2589
2653
|
}
|
|
2590
2654
|
const base = chartDomains.length > 0
|
|
@@ -2671,8 +2735,9 @@ export const BasicChart = ({ width, height, chart, theme, isDarkMode, sheetId, r
|
|
|
2671
2735
|
? s.data.map((d) => d !== null && typeof d === "object" ? d.value : d)
|
|
2672
2736
|
: []),
|
|
2673
2737
|
pattern: primaryAxisNumberFormat,
|
|
2738
|
+
locale,
|
|
2674
2739
|
}),
|
|
2675
|
-
}, spec.valueAxisOptions, primaryAxisNumberFormat),
|
|
2740
|
+
}, spec.valueAxisOptions, primaryAxisNumberFormat, locale),
|
|
2676
2741
|
];
|
|
2677
2742
|
if (hasSecondaryAxis) {
|
|
2678
2743
|
axes.push(applyAxisOverrides({
|
|
@@ -2687,7 +2752,7 @@ export const BasicChart = ({ width, height, chart, theme, isDarkMode, sheetId, r
|
|
|
2687
2752
|
axisLabel: { formatter: "{value}%" },
|
|
2688
2753
|
}
|
|
2689
2754
|
: {}),
|
|
2690
|
-
}, spec.secondaryValueAxisOptions, secondaryAxisNumberFormat));
|
|
2755
|
+
}, spec.secondaryValueAxisOptions, secondaryAxisNumberFormat, locale));
|
|
2691
2756
|
}
|
|
2692
2757
|
return axes;
|
|
2693
2758
|
})(),
|
|
@@ -2835,6 +2900,7 @@ export const BasicChart = ({ width, height, chart, theme, isDarkMode, sheetId, r
|
|
|
2835
2900
|
getDomainValuesFromRange,
|
|
2836
2901
|
getSeriesValuesFromRange,
|
|
2837
2902
|
getFormattingFromRange,
|
|
2903
|
+
locale,
|
|
2838
2904
|
glUpgradeTick,
|
|
2839
2905
|
]);
|
|
2840
2906
|
// Resize chart
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chart-editor.d.ts","sourceRoot":"","sources":["../../../../components/editors/chart-editor.tsx"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAGV,aAAa,EAGd,MAAM,2BAA2B,CAAC;AAuBnC,OAAO,KAAkB,MAAM,OAAO,CAAC;AAMvC,OAAO,EAEL,KAAK,oBAAoB,EAG1B,MAAM,+BAA+B,CAAC;AA4CvC,KAAK,gBAAgB,GAAG;IACtB,KAAK,CAAC,EAAE,aAAa,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,CAAC,KAAK,EAAE,aAAa,GAAG,IAAI,CAAC;IACtC;;;;OAIG;IACH,kBAAkB,CAAC,CAAC,KAAK,EAAE,aAAa,GAAG,IAAI,CAAC;IAChD;;;OAGG;IACH,iBAAiB,CAAC,EAAE,oBAAoB,CAAC;CAC1C,CAAC;AAuBF,eAAO,MAAM,WAAW,GAAI,sEAMzB,gBAAgB,
|
|
1
|
+
{"version":3,"file":"chart-editor.d.ts","sourceRoot":"","sources":["../../../../components/editors/chart-editor.tsx"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAGV,aAAa,EAGd,MAAM,2BAA2B,CAAC;AAuBnC,OAAO,KAAkB,MAAM,OAAO,CAAC;AAMvC,OAAO,EAEL,KAAK,oBAAoB,EAG1B,MAAM,+BAA+B,CAAC;AA4CvC,KAAK,gBAAgB,GAAG;IACtB,KAAK,CAAC,EAAE,aAAa,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,CAAC,KAAK,EAAE,aAAa,GAAG,IAAI,CAAC;IACtC;;;;OAIG;IACH,kBAAkB,CAAC,CAAC,KAAK,EAAE,aAAa,GAAG,IAAI,CAAC;IAChD;;;OAGG;IACH,iBAAiB,CAAC,EAAE,oBAAoB,CAAC;CAC1C,CAAC;AAuBF,eAAO,MAAM,WAAW,GAAI,sEAMzB,gBAAgB,sBAw6DlB,CAAC;AAEF,eAAe,WAAW,CAAC"}
|
|
@@ -622,7 +622,11 @@ export const ChartEditor = ({ chart, sheetId, onSubmit, onRequestMoveChart, getF
|
|
|
622
622
|
React.createElement("option", { value: "outside" }, "Outside"),
|
|
623
623
|
React.createElement("option", { value: "insideEnd" }, "Inside end"),
|
|
624
624
|
React.createElement("option", { value: "outsideEnd" }, "Outside end"),
|
|
625
|
-
React.createElement("option", { value: "bestFit" }, "Best fit")
|
|
625
|
+
React.createElement("option", { value: "bestFit" }, "Best fit"),
|
|
626
|
+
React.createElement("option", { value: "above" }, "Above"),
|
|
627
|
+
React.createElement("option", { value: "below" }, "Below"),
|
|
628
|
+
React.createElement("option", { value: "left" }, "Left"),
|
|
629
|
+
React.createElement("option", { value: "right" }, "Right")),
|
|
626
630
|
React.createElement("label", { className: "font-system text-xs" }, "Number format pattern"),
|
|
627
631
|
React.createElement(Input, { value: values?.spec.dataLabels?.numberFormatPattern ?? "", type: "text", onChange: (e) => setFieldValue("spec.dataLabels.numberFormatPattern", e.target.value || undefined), className: "text-xs w-32", placeholder: "#,##0.00" }))) : null)),
|
|
628
632
|
basicSpec && showChartOptions ? (React.createElement(Section, { title: "Chart options" },
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import type { EChartComponentProps } from "../../types";
|
|
3
3
|
export type BasicChartProps = EChartComponentProps;
|
|
4
|
-
export declare const BasicChart: ({ width, height, chart, theme, isDarkMode, sheetId, readonly, getDomainValuesFromRange, getSeriesValuesFromRange, getFormattingFromRange, onDeleteChart, onUpdateChart, onRequestEdit, onRequestCalculate, isSelected, fieldButtons, }: BasicChartProps) => React.JSX.Element;
|
|
4
|
+
export declare const BasicChart: ({ width, height, chart, theme, isDarkMode, sheetId, readonly, getDomainValuesFromRange, getSeriesValuesFromRange, getFormattingFromRange, onDeleteChart, onUpdateChart, onRequestEdit, onRequestCalculate, isSelected, fieldButtons, locale, }: BasicChartProps) => React.JSX.Element;
|
|
5
5
|
//# sourceMappingURL=basic-chart.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"basic-chart.d.ts","sourceRoot":"","sources":["../../../../plotly/basic-chart/basic-chart.tsx"],"names":[],"mappings":"AAoCA,OAAO,KAAiD,MAAM,OAAO,CAAC;AAEtE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"basic-chart.d.ts","sourceRoot":"","sources":["../../../../plotly/basic-chart/basic-chart.tsx"],"names":[],"mappings":"AAoCA,OAAO,KAAiD,MAAM,OAAO,CAAC;AAEtE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAyZxD,MAAM,MAAM,eAAe,GAAG,oBAAoB,CAAC;AA0FnD,eAAO,MAAM,UAAU,GAAI,gPAkBxB,eAAe,sBAq3EjB,CAAC"}
|