ooxml-core 1.17.0 → 1.19.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/{PptxHandler-K7GMS2ST.mjs → PptxHandler-5GBBVJCR.mjs} +2 -2
- package/dist/{PptxHandler-L3JPWOBN.mjs → PptxHandler-H43MAMTO.mjs} +1 -1
- package/dist/{PptxHandler-U6EFO73T.cjs → PptxHandler-ZHPGBSAF.cjs} +2 -2
- package/dist/{PresentationBuilder-XC3F3OPY.mjs → PresentationBuilder-7ZSUKCX5.mjs} +1 -1
- package/dist/{PresentationBuilder-OK526SZ4.mjs → PresentationBuilder-IJW42L3R.mjs} +2 -2
- package/dist/{PresentationBuilder-LUR6LGHU.cjs → PresentationBuilder-O4H4MMWB.cjs} +4 -4
- package/dist/automation/index.cjs +5198 -3235
- package/dist/automation/index.mjs +5198 -3235
- package/dist/chart/axis-range-auto.d.ts +10 -0
- package/dist/chart/axis-range-auto.d.ts.map +1 -0
- package/dist/chart/axis-range-types.d.ts +27 -0
- package/dist/chart/axis-range-types.d.ts.map +1 -0
- package/dist/chart/axis-range.d.ts +37 -0
- package/dist/chart/axis-range.d.ts.map +1 -0
- package/dist/chart/axis-ticks.d.ts +8 -0
- package/dist/chart/axis-ticks.d.ts.map +1 -0
- package/dist/chart/data-label-text.d.ts +70 -0
- package/dist/chart/data-label-text.d.ts.map +1 -0
- package/dist/chart/formatting-nodes.d.ts +6 -0
- package/dist/chart/formatting-nodes.d.ts.map +1 -1
- package/dist/chart/index.cjs +1536 -571
- package/dist/chart/index.d.ts +7 -0
- package/dist/chart/index.d.ts.map +1 -1
- package/dist/chart/index.mjs +1512 -572
- package/dist/chart/line-dash.d.ts +2 -0
- package/dist/chart/line-dash.d.ts.map +1 -0
- package/dist/chart/marker-shape.d.ts +70 -0
- package/dist/chart/marker-shape.d.ts.map +1 -0
- package/dist/chart/read-formatting.d.ts.map +1 -1
- package/dist/chart/render/chart-svg-axes.d.ts +9 -0
- package/dist/chart/render/chart-svg-axes.d.ts.map +1 -0
- package/dist/chart/render/chart-svg-bars.d.ts.map +1 -1
- package/dist/chart/render/chart-svg-cartesian.d.ts.map +1 -1
- package/dist/chart/render/chart-svg-labels.d.ts +42 -0
- package/dist/chart/render/chart-svg-labels.d.ts.map +1 -0
- package/dist/chart/render/chart-svg-markers.d.ts +6 -0
- package/dist/chart/render/chart-svg-markers.d.ts.map +1 -0
- package/dist/chart/render/chart-svg-radial.d.ts.map +1 -1
- package/dist/chart/render/chart-svg-xy.d.ts.map +1 -1
- package/dist/chart/render/chart-view-axes.d.ts +30 -0
- package/dist/chart/render/chart-view-axes.d.ts.map +1 -0
- package/dist/chart/render/chart-view-labels.d.ts +16 -0
- package/dist/chart/render/chart-view-labels.d.ts.map +1 -0
- package/dist/chart/render/chart-view-markers.d.ts +27 -0
- package/dist/chart/render/chart-view-markers.d.ts.map +1 -0
- package/dist/chart/render/chart-view-series.d.ts.map +1 -1
- package/dist/chart/render/chart-view.d.ts +7 -1
- package/dist/chart/render/chart-view.d.ts.map +1 -1
- package/dist/chart/render/index.d.ts +2 -0
- package/dist/chart/render/index.d.ts.map +1 -1
- package/dist/chart/render/summary-from-space.d.ts +2 -2
- package/dist/chart/render/summary-from-space.d.ts.map +1 -1
- package/dist/chart/render/summary-labels.d.ts +9 -0
- package/dist/chart/render/summary-labels.d.ts.map +1 -0
- package/dist/chart/render/summary.d.ts +29 -1
- package/dist/chart/render/summary.d.ts.map +1 -1
- package/dist/{chunk-IM5LFEA2.mjs → chunk-3XFPCZKB.mjs} +1 -1
- package/dist/{chunk-YS43OMM3.mjs → chunk-75GLSRZE.mjs} +4 -4
- package/dist/{chunk-A7S2NYAU.mjs → chunk-BIVNVDAH.mjs} +1 -1
- package/dist/{chunk-UFGJNXRG.mjs → chunk-QBJRB6WW.mjs} +1 -1
- package/dist/{chunk-HLZIALC5.mjs → chunk-RUZEMWDI.mjs} +1 -1
- package/dist/docx/embedded.cjs +15 -0
- package/dist/docx/embedded.mjs +15 -0
- package/dist/docx/index.cjs +1825 -693
- package/dist/docx/index.mjs +1825 -693
- package/dist/docx/layout/index.cjs +1684 -567
- package/dist/docx/layout/index.mjs +1684 -567
- package/dist/docx/load/index.cjs +15 -0
- package/dist/docx/load/index.mjs +15 -0
- package/dist/docx/ui/index.cjs +1696 -579
- package/dist/docx/ui/index.mjs +1696 -579
- package/dist/index.cjs +1623 -658
- package/dist/index.mjs +1623 -658
- package/dist/pptx/automation/index.cjs +61 -0
- package/dist/pptx/automation/index.mjs +5 -5
- package/dist/pptx/cli/index.cjs +61 -0
- package/dist/pptx/cli/index.mjs +4 -4
- package/dist/pptx/converter/index.mjs +2 -2
- package/dist/pptx/editor/render/slide-operations.cjs +1 -1
- package/dist/pptx/editor/render/slide-operations.mjs +1 -1
- package/dist/pptx/index.cjs +61 -0
- package/dist/pptx/index.mjs +5 -5
- package/dist/teams/index.cjs +212 -50
- package/dist/teams/index.mjs +212 -50
- package/dist/visio/edit-chart-object-commands.d.ts +36 -0
- package/dist/visio/edit-chart-object-commands.d.ts.map +1 -0
- package/dist/visio/edit-chart-object.d.ts +7 -0
- package/dist/visio/edit-chart-object.d.ts.map +1 -0
- package/dist/visio/edit-commands.d.ts +2 -1
- package/dist/visio/edit-commands.d.ts.map +1 -1
- package/dist/visio/edit-foreign-frame.d.ts +8 -0
- package/dist/visio/edit-foreign-frame.d.ts.map +1 -0
- package/dist/visio/edit-metadata-commands.d.ts +7 -0
- package/dist/visio/edit-metadata-commands.d.ts.map +1 -1
- package/dist/visio/edit-picture.d.ts +8 -0
- package/dist/visio/edit-picture.d.ts.map +1 -1
- package/dist/visio/edit.d.ts.map +1 -1
- package/dist/visio/emf-bitmap.d.ts +8 -0
- package/dist/visio/emf-bitmap.d.ts.map +1 -0
- package/dist/visio/index.cjs +17505 -6279
- package/dist/visio/index.d.ts +2 -0
- package/dist/visio/index.d.ts.map +1 -1
- package/dist/visio/index.mjs +17503 -6280
- package/dist/visio/model.d.ts +18 -0
- package/dist/visio/model.d.ts.map +1 -1
- package/dist/visio/prepare-embedded.d.ts +10 -0
- package/dist/visio/prepare-embedded.d.ts.map +1 -0
- package/dist/visio/prepare-images.d.ts.map +1 -1
- package/dist/visio/shapes.d.ts.map +1 -1
- package/dist/visio/sheet.d.ts +2 -1
- package/dist/visio/sheet.d.ts.map +1 -1
- package/dist/visio/ui/edit-commands.d.ts.map +1 -1
- package/dist/visio/ui/index.cjs +33580 -22875
- package/dist/visio/ui/index.mjs +33578 -22875
- package/dist/visio/ui/insert.d.ts +11 -0
- package/dist/visio/ui/insert.d.ts.map +1 -1
- package/dist/xlsx/edit/chart-colors.d.ts.map +1 -1
- package/dist/xlsx/index.cjs +1965 -817
- package/dist/xlsx/index.mjs +1965 -817
- package/dist/xlsx/load/index.cjs +190 -51
- package/dist/xlsx/load/index.mjs +190 -51
- package/dist/xlsx/model.d.ts +5 -0
- package/dist/xlsx/model.d.ts.map +1 -1
- package/dist/xlsx/read/chart.d.ts.map +1 -1
- package/dist/xlsx/read/load.d.ts.map +1 -1
- package/dist/xlsx/read/workbook-part.d.ts +2 -0
- package/dist/xlsx/read/workbook-part.d.ts.map +1 -1
- package/dist/xlsx/ui/dialogs/grid-chart.d.ts +22 -1
- package/dist/xlsx/ui/dialogs/grid-chart.d.ts.map +1 -1
- package/dist/xlsx/ui/index.cjs +17482 -4364
- package/dist/xlsx/ui/index.mjs +17472 -4362
- package/dist/xlsx/write/workbook-part.d.ts.map +1 -1
- package/package.json +1 -1
- package/dist/visio/edit-foreign-bitmap.d.ts +0 -7
- package/dist/visio/edit-foreign-bitmap.d.ts.map +0 -1
- /package/dist/{chunk-KU3SMBFU.mjs → chunk-H6TNNXJK.mjs} +0 -0
- /package/dist/{chunk-UWWS6VVJ.cjs → chunk-MHMVD23Y.cjs} +0 -0
package/dist/chart/index.cjs
CHANGED
|
@@ -528,6 +528,52 @@ function formatChartNumber(value, formatCode) {
|
|
|
528
528
|
return formatChartNumberWithColor(value, formatCode)?.text;
|
|
529
529
|
}
|
|
530
530
|
|
|
531
|
+
// chart/data-label-text.ts
|
|
532
|
+
var DATA_LABEL_SEPARATOR = ", ";
|
|
533
|
+
var DATA_LABEL_CATEGORY_PERCENT_SEPARATOR = "\n";
|
|
534
|
+
var FLAG_KEYS = [
|
|
535
|
+
"showValue",
|
|
536
|
+
"showCategory",
|
|
537
|
+
"showSeriesName",
|
|
538
|
+
"showPercent",
|
|
539
|
+
"showBubbleSize"
|
|
540
|
+
];
|
|
541
|
+
function resolveDataLabelFlags(levels) {
|
|
542
|
+
const { point, series, chart } = levels;
|
|
543
|
+
const picked = {};
|
|
544
|
+
for (const key of FLAG_KEYS) picked[key] = point?.[key] ?? series?.[key] ?? chart?.[key];
|
|
545
|
+
const anyDeclared = FLAG_KEYS.some((key) => picked[key] !== void 0);
|
|
546
|
+
return {
|
|
547
|
+
showValue: anyDeclared ? picked.showValue === true : levels.siblingOwnsLabels !== true,
|
|
548
|
+
showCategory: picked.showCategory === true,
|
|
549
|
+
showSeriesName: picked.showSeriesName === true,
|
|
550
|
+
showPercent: picked.showPercent === true,
|
|
551
|
+
showBubbleSize: picked.showBubbleSize === true,
|
|
552
|
+
separator: point?.separator ?? series?.separator ?? chart?.separator ?? (picked.showCategory === true && picked.showPercent === true ? DATA_LABEL_CATEGORY_PERCENT_SEPARATOR : DATA_LABEL_SEPARATOR)
|
|
553
|
+
};
|
|
554
|
+
}
|
|
555
|
+
function composeDataLabelText(input) {
|
|
556
|
+
const { flags, value, numberFormat: numberFormat2 } = input;
|
|
557
|
+
const parts = [];
|
|
558
|
+
let valueColor;
|
|
559
|
+
if (flags.showSeriesName && input.seriesName) parts.push(input.seriesName);
|
|
560
|
+
if (flags.showCategory && input.category) parts.push(input.category);
|
|
561
|
+
if (flags.showValue) {
|
|
562
|
+
const formatted = formatChartNumberWithColor(value, numberFormat2);
|
|
563
|
+
parts.push(formatted?.text ?? (input.formatValue ?? String)(value, numberFormat2));
|
|
564
|
+
valueColor = formatted?.color;
|
|
565
|
+
}
|
|
566
|
+
if (flags.showPercent) {
|
|
567
|
+
const base = input.percentBase;
|
|
568
|
+
parts.push(base > 0 ? `${Math.round(Math.abs(value) / base * 100)}%` : "0%");
|
|
569
|
+
}
|
|
570
|
+
if (flags.showBubbleSize && input.bubbleSize !== void 0)
|
|
571
|
+
parts.push((input.formatBubbleSize ?? String)(input.bubbleSize));
|
|
572
|
+
const text3 = parts.join(flags.separator);
|
|
573
|
+
if (text3.length === 0) return void 0;
|
|
574
|
+
return { text: text3, color: parts.length === 1 && flags.showValue ? valueColor : void 0 };
|
|
575
|
+
}
|
|
576
|
+
|
|
531
577
|
// chart/auto-title.ts
|
|
532
578
|
var CHART_AUTO_TITLE = "Chart Title";
|
|
533
579
|
var CHARTEX_ONLY_TYPES = /* @__PURE__ */ new Set([
|
|
@@ -564,12 +610,12 @@ function formatCompactAxisValue(value, formatCode) {
|
|
|
564
610
|
}
|
|
565
611
|
|
|
566
612
|
// chart/bubble-radius.ts
|
|
567
|
-
function computeBubbleRadius(sizeVal, maxBubble, medianRadius,
|
|
568
|
-
const scale = (
|
|
613
|
+
function computeBubbleRadius(sizeVal, maxBubble, medianRadius, options2) {
|
|
614
|
+
const scale = (options2?.bubbleScale ?? 100) / 100;
|
|
569
615
|
if (sizeVal === void 0) return medianRadius * scale;
|
|
570
616
|
const denom = maxBubble > 0 ? maxBubble : 1;
|
|
571
617
|
const magnitude = Math.abs(sizeVal);
|
|
572
|
-
const ratio = (
|
|
618
|
+
const ratio = (options2?.sizeRepresents ?? "w") === "area" ? Math.sqrt(magnitude) / Math.sqrt(denom) : magnitude / denom;
|
|
573
619
|
return medianRadius * scale * 0.5 + ratio * medianRadius * scale * 1.5;
|
|
574
620
|
}
|
|
575
621
|
function maxBubbleSize(sizes) {
|
|
@@ -675,10 +721,10 @@ function squarify(nodes, box) {
|
|
|
675
721
|
|
|
676
722
|
// chart/hierarchy.ts
|
|
677
723
|
function normalizeLevels(levels, pointCount) {
|
|
678
|
-
return levels.map((
|
|
724
|
+
return levels.map((level2) => {
|
|
679
725
|
let previous = "";
|
|
680
726
|
return Array.from({ length: pointCount }, (_, index) => {
|
|
681
|
-
const label =
|
|
727
|
+
const label = level2[index]?.trim() ?? "";
|
|
682
728
|
if (label) previous = label;
|
|
683
729
|
return label || previous;
|
|
684
730
|
});
|
|
@@ -836,12 +882,12 @@ function computeSunburstArcs(series, cx2, cy, maxR) {
|
|
|
836
882
|
});
|
|
837
883
|
return out;
|
|
838
884
|
}
|
|
839
|
-
function hierarchyKey(levels,
|
|
840
|
-
return levels.slice(
|
|
885
|
+
function hierarchyKey(levels, level2, index) {
|
|
886
|
+
return levels.slice(level2).map((labels) => labels[index] ?? "").join("\0");
|
|
841
887
|
}
|
|
842
888
|
function computeHierarchicalSunburstArcs(categoryLevels2, values, cx2, cy, maxR) {
|
|
843
|
-
const levels = categoryLevels2.filter((
|
|
844
|
-
const leafCount = Math.max(values.length, ...levels.map((
|
|
889
|
+
const levels = categoryLevels2.filter((level2) => level2.length > 0);
|
|
890
|
+
const leafCount = Math.max(values.length, ...levels.map((level2) => level2.length), 0);
|
|
845
891
|
if (levels.length === 0 || leafCount === 0) return [];
|
|
846
892
|
const rawWeights = Array.from({ length: leafCount }, (_, index) => Math.abs(values[index] ?? 0));
|
|
847
893
|
const weights = rawWeights.some((value) => value !== 0) ? rawWeights : rawWeights.map(() => 1);
|
|
@@ -852,15 +898,15 @@ function computeHierarchicalSunburstArcs(categoryLevels2, values, cx2, cy, maxR)
|
|
|
852
898
|
const rootLabels = levels[levels.length - 1] ?? [];
|
|
853
899
|
const rootColors = /* @__PURE__ */ new Map();
|
|
854
900
|
const out = [];
|
|
855
|
-
for (let
|
|
856
|
-
const ringIndex = levels.length - 1 -
|
|
901
|
+
for (let level2 = levels.length - 1; level2 >= 0; level2--) {
|
|
902
|
+
const ringIndex = levels.length - 1 - level2;
|
|
857
903
|
const innerRadius = ringWidth * (ringIndex + 0.5);
|
|
858
904
|
const outerRadius = ringWidth * (ringIndex + 1.5);
|
|
859
905
|
let start = 0;
|
|
860
906
|
while (start < leafCount) {
|
|
861
|
-
const key = hierarchyKey(levels,
|
|
907
|
+
const key = hierarchyKey(levels, level2, start);
|
|
862
908
|
let end = start + 1;
|
|
863
|
-
while (end < leafCount && hierarchyKey(levels,
|
|
909
|
+
while (end < leafCount && hierarchyKey(levels, level2, end) === key) end++;
|
|
864
910
|
const startAngle = -Math.PI / 2 + (prefix[start] ?? 0) / total * Math.PI * 2;
|
|
865
911
|
const endAngle = -Math.PI / 2 + (prefix[end] ?? 0) / total * Math.PI * 2;
|
|
866
912
|
const rootLabel = rootLabels[start] ?? "";
|
|
@@ -870,8 +916,8 @@ function computeHierarchicalSunburstArcs(categoryLevels2, values, cx2, cy, maxR)
|
|
|
870
916
|
colorIndex: rootColors.get(rootLabel) ?? start,
|
|
871
917
|
opacity: Math.max(0.1, 0.9 - ringIndex * 0.1),
|
|
872
918
|
level: ringIndex,
|
|
873
|
-
label: levels[
|
|
874
|
-
...
|
|
919
|
+
label: levels[level2]?.[start] ?? "",
|
|
920
|
+
...level2 === 0 && end === start + 1 ? { pointIndex: start } : {},
|
|
875
921
|
...arcLabelPlacement(cx2, cy, (innerRadius + outerRadius) / 2, startAngle, endAngle)
|
|
876
922
|
});
|
|
877
923
|
start = end;
|
|
@@ -970,14 +1016,14 @@ function scottBinCount(values, min, max) {
|
|
|
970
1016
|
const width = 3.49 * sd * values.length ** (-1 / 3);
|
|
971
1017
|
return Math.max(1, Math.ceil((max - min) / width));
|
|
972
1018
|
}
|
|
973
|
-
function computeHistogramBins(values,
|
|
974
|
-
const closed =
|
|
1019
|
+
function computeHistogramBins(values, options2, format = String) {
|
|
1020
|
+
const closed = options2.intervalClosed ?? "l";
|
|
975
1021
|
const finite = values.map((value, sourceIndex) => ({ value, sourceIndex })).filter((item) => Number.isFinite(item.value));
|
|
976
1022
|
if (finite.length === 0) {
|
|
977
1023
|
return [];
|
|
978
1024
|
}
|
|
979
|
-
const underflow = typeof
|
|
980
|
-
const overflow = typeof
|
|
1025
|
+
const underflow = typeof options2.underflow === "number" ? options2.underflow : void 0;
|
|
1026
|
+
const overflow = typeof options2.overflow === "number" ? options2.overflow : void 0;
|
|
981
1027
|
const under = underflow === void 0 ? [] : finite.filter(
|
|
982
1028
|
(item) => closed === "r" ? item.value <= underflow : item.value < underflow
|
|
983
1029
|
);
|
|
@@ -994,8 +1040,8 @@ function computeHistogramBins(values, options, format = String) {
|
|
|
994
1040
|
if (regular.length > 0) {
|
|
995
1041
|
const min = Math.min(...regular.map((item) => item.value));
|
|
996
1042
|
const max = Math.max(...regular.map((item) => item.value));
|
|
997
|
-
const requestedSize =
|
|
998
|
-
const requestedCount =
|
|
1043
|
+
const requestedSize = options2.binSize && options2.binSize > 0 ? options2.binSize : void 0;
|
|
1044
|
+
const requestedCount = options2.binCount && options2.binCount > 0 ? options2.binCount : void 0;
|
|
999
1045
|
const start = requestedSize ? Math.floor(min / requestedSize) * requestedSize : min;
|
|
1000
1046
|
const count = requestedSize ? Math.max(
|
|
1001
1047
|
closed === "l" ? Math.floor((max - start) / requestedSize) + 1 : Math.ceil((max - start) / requestedSize),
|
|
@@ -1046,9 +1092,9 @@ function aggregateByCategory(values, rawCategories) {
|
|
|
1046
1092
|
}
|
|
1047
1093
|
|
|
1048
1094
|
// chart/waterfall.ts
|
|
1049
|
-
function buildWaterfallSteps(values,
|
|
1095
|
+
function buildWaterfallSteps(values, options2) {
|
|
1050
1096
|
const subtotalIndices = new Set(
|
|
1051
|
-
|
|
1097
|
+
options2?.subtotalIndices ?? (values.length > 0 ? [values.length - 1] : [])
|
|
1052
1098
|
);
|
|
1053
1099
|
const steps = [];
|
|
1054
1100
|
let runningTotal = 0;
|
|
@@ -1124,13 +1170,13 @@ var noFit = () => ({
|
|
|
1124
1170
|
rSquared: 0,
|
|
1125
1171
|
coefficients: []
|
|
1126
1172
|
});
|
|
1127
|
-
function fitModel(
|
|
1173
|
+
function fitModel(options2, xVals, yVals) {
|
|
1128
1174
|
const xs = [...xVals];
|
|
1129
1175
|
const ys = [...yVals];
|
|
1130
|
-
switch (
|
|
1176
|
+
switch (options2.kind) {
|
|
1131
1177
|
case "linear": {
|
|
1132
1178
|
const reg = computeLinearRegression(xs, ys);
|
|
1133
|
-
const fixed =
|
|
1179
|
+
const fixed = options2.intercept;
|
|
1134
1180
|
const slope = fixed !== void 0 ? ys.reduce((s, y, i) => s + (y - fixed) * xs[i], 0) / xs.reduce((s, x) => s + x * x, 0) : reg.slope;
|
|
1135
1181
|
const b = fixed ?? reg.intercept;
|
|
1136
1182
|
return {
|
|
@@ -1180,7 +1226,7 @@ function fitModel(options, xVals, yVals) {
|
|
|
1180
1226
|
};
|
|
1181
1227
|
}
|
|
1182
1228
|
case "polynomial": {
|
|
1183
|
-
const order = Math.min(
|
|
1229
|
+
const order = Math.min(options2.order ?? 2, 6);
|
|
1184
1230
|
const coeffs = fitPolynomial(xs, ys, order);
|
|
1185
1231
|
const evaluate = (x) => coeffs.reduce((s, c2, i) => s + c2 * x ** i, 0);
|
|
1186
1232
|
return {
|
|
@@ -1194,11 +1240,11 @@ function fitModel(options, xVals, yVals) {
|
|
|
1194
1240
|
return void 0;
|
|
1195
1241
|
}
|
|
1196
1242
|
}
|
|
1197
|
-
function fitChartTrendline(
|
|
1243
|
+
function fitChartTrendline(options2, xVals, yVals) {
|
|
1198
1244
|
const count = yVals.length;
|
|
1199
1245
|
if (count < 2) return noFit();
|
|
1200
|
-
if (
|
|
1201
|
-
const period =
|
|
1246
|
+
if (options2.kind === "movingAvg") {
|
|
1247
|
+
const period = options2.period ?? 2;
|
|
1202
1248
|
const points2 = [];
|
|
1203
1249
|
for (let i = period - 1; i < count; i++) {
|
|
1204
1250
|
let sum = 0;
|
|
@@ -1207,10 +1253,10 @@ function fitChartTrendline(options, xVals, yVals) {
|
|
|
1207
1253
|
}
|
|
1208
1254
|
return { points: points2, equation: `${period}-period moving average`, rSquared: 0, coefficients: [] };
|
|
1209
1255
|
}
|
|
1210
|
-
const model = fitModel(
|
|
1256
|
+
const model = fitModel(options2, xVals, yVals);
|
|
1211
1257
|
if (!model) return noFit();
|
|
1212
|
-
const startX = Math.min(...xVals) - (
|
|
1213
|
-
const endX = Math.max(...xVals) + (
|
|
1258
|
+
const startX = Math.min(...xVals) - (options2.backward ?? 0);
|
|
1259
|
+
const endX = Math.max(...xVals) + (options2.forward ?? 0);
|
|
1214
1260
|
const steps = Math.max(Math.ceil((endX - startX) * 4), 20);
|
|
1215
1261
|
const points = [];
|
|
1216
1262
|
for (let step = 0; step <= steps; step++) {
|
|
@@ -1233,18 +1279,18 @@ function chartSampleVariance(values) {
|
|
|
1233
1279
|
const mean = values.reduce((sum, value) => sum + value, 0) / count;
|
|
1234
1280
|
return values.reduce((sum, value) => sum + (value - mean) ** 2, 0) / Math.max(count - 1, 1);
|
|
1235
1281
|
}
|
|
1236
|
-
function chartErrorBarAmount(
|
|
1237
|
-
switch (
|
|
1282
|
+
function chartErrorBarAmount(options2, values, displayIndex, sourceIndex, side) {
|
|
1283
|
+
switch (options2.valueType) {
|
|
1238
1284
|
case "fixedVal":
|
|
1239
|
-
return
|
|
1285
|
+
return options2.value ?? 0;
|
|
1240
1286
|
case "percentage":
|
|
1241
|
-
return Math.abs(values[displayIndex] ?? 0) * ((
|
|
1287
|
+
return Math.abs(values[displayIndex] ?? 0) * ((options2.value ?? 0) / 100);
|
|
1242
1288
|
case "stdDev":
|
|
1243
|
-
return Math.sqrt(chartSampleVariance(values)) * (
|
|
1289
|
+
return Math.sqrt(chartSampleVariance(values)) * (options2.value ?? 1);
|
|
1244
1290
|
case "stdErr":
|
|
1245
1291
|
return Math.sqrt(chartSampleVariance(values) / Math.max(values.length, 1));
|
|
1246
1292
|
case "cust":
|
|
1247
|
-
return side === "plus" ?
|
|
1293
|
+
return side === "plus" ? options2.customPlus?.[sourceIndex] ?? 0 : options2.customMinus?.[sourceIndex] ?? 0;
|
|
1248
1294
|
}
|
|
1249
1295
|
}
|
|
1250
1296
|
|
|
@@ -1449,8 +1495,8 @@ function rgbToHsl(r, g, b) {
|
|
|
1449
1495
|
}
|
|
1450
1496
|
return { h, s: clampUnitInterval(s), l: clampUnitInterval(l) };
|
|
1451
1497
|
}
|
|
1452
|
-
function hslToRgb(h, s, l, roundChannel = Math.round,
|
|
1453
|
-
const sC =
|
|
1498
|
+
function hslToRgb(h, s, l, roundChannel = Math.round, options2) {
|
|
1499
|
+
const sC = options2?.clampSaturation === false ? s : clampUnitInterval(s);
|
|
1454
1500
|
const lC = clampUnitInterval(l);
|
|
1455
1501
|
const hN = (h % 360 + 360) % 360;
|
|
1456
1502
|
const c2 = (1 - Math.abs(2 * lC - 1)) * sC;
|
|
@@ -1855,17 +1901,17 @@ function checkXmlLimits(xml, label, limits = {}) {
|
|
|
1855
1901
|
throw new Error(`${label} XML exceeds the nesting depth limit of ${maxDepth}`);
|
|
1856
1902
|
}
|
|
1857
1903
|
}
|
|
1858
|
-
function parseXml(xml,
|
|
1859
|
-
const label =
|
|
1904
|
+
function parseXml(xml, options2 = {}) {
|
|
1905
|
+
const label = options2.label ?? "OOXML";
|
|
1860
1906
|
if (/<!DOCTYPE|<!ENTITY/i.test(xml))
|
|
1861
1907
|
throw new Error(`${label} XML with DTD or entity declarations is not supported`);
|
|
1862
|
-
checkXmlLimits(xml, label,
|
|
1908
|
+
checkXmlLimits(xml, label, options2.limits);
|
|
1863
1909
|
let parseError = "";
|
|
1864
1910
|
let parsed;
|
|
1865
1911
|
try {
|
|
1866
1912
|
parsed = new xmldom.DOMParser({
|
|
1867
|
-
onError: (
|
|
1868
|
-
if (
|
|
1913
|
+
onError: (level2, message) => {
|
|
1914
|
+
if (level2 !== "warning") parseError = message;
|
|
1869
1915
|
}
|
|
1870
1916
|
}).parseFromString(xml, "application/xml");
|
|
1871
1917
|
} catch (error) {
|
|
@@ -2055,13 +2101,13 @@ var APPLIED = /* @__PURE__ */ new Set([
|
|
|
2055
2101
|
"lumMod",
|
|
2056
2102
|
"lumOff"
|
|
2057
2103
|
]);
|
|
2058
|
-
function resolveDrawingColor(color, theme,
|
|
2104
|
+
function resolveDrawingColor(color, theme, options2) {
|
|
2059
2105
|
const base = baseHex(color, theme);
|
|
2060
2106
|
const rgb = base ? hexToRgbChannels(base) : null;
|
|
2061
2107
|
if (!rgb) return void 0;
|
|
2062
|
-
if (
|
|
2108
|
+
if (options2?.transformOrder === "document") {
|
|
2063
2109
|
const value = orderedColorTransforms(rgb, color.transforms);
|
|
2064
|
-
const round =
|
|
2110
|
+
const round = options2.hslRounding === "halfDown" ? (channel) => Math.ceil(channel - 0.5) : Math.round;
|
|
2065
2111
|
return {
|
|
2066
2112
|
hex: `#${toHex(round(value.r))}${toHex(round(value.g))}${toHex(round(value.b))}`,
|
|
2067
2113
|
alpha: value.alpha,
|
|
@@ -2112,7 +2158,7 @@ function resolveDrawingColor(color, theme, options) {
|
|
|
2112
2158
|
if (lumMod !== void 0) hsl.l = clampUnitInterval(hsl.l * lumMod);
|
|
2113
2159
|
const lumOff = parseDrawingFraction(find("lumOff"));
|
|
2114
2160
|
if (lumOff !== void 0) hsl.l = clampUnitInterval(hsl.l + lumOff);
|
|
2115
|
-
const round =
|
|
2161
|
+
const round = options2?.hslRounding === "halfDown" ? (value) => Math.ceil(value - 0.5) : Math.round;
|
|
2116
2162
|
({ r, g, b } = hslToRgb(hsl.h, hsl.s, hsl.l, round));
|
|
2117
2163
|
}
|
|
2118
2164
|
let alpha = parseDrawingPercent(find("alpha")) ?? 1;
|
|
@@ -2501,6 +2547,19 @@ function readChartStyle(xml) {
|
|
|
2501
2547
|
}
|
|
2502
2548
|
|
|
2503
2549
|
// chart/formatting-nodes.ts
|
|
2550
|
+
function chartDataLabelNode(root) {
|
|
2551
|
+
const plot = first(first(root, "chart", NS.c), "plotArea", NS.c);
|
|
2552
|
+
const groups = plot ? elements(plot).filter((node) => node.localName.endsWith("Chart")) : [];
|
|
2553
|
+
const candidates = groups.flatMap((group2) => [
|
|
2554
|
+
...children(group2, "ser", NS.c).map((ser) => first(ser, "dLbls", NS.c)),
|
|
2555
|
+
first(group2, "dLbls", NS.c)
|
|
2556
|
+
]);
|
|
2557
|
+
return candidates.find(
|
|
2558
|
+
(node) => node !== void 0 && (first(node, "txPr", NS.c) !== void 0 || elements(node).some(
|
|
2559
|
+
(child2) => child2.localName.startsWith("show") && child2.getAttribute("val") === "1"
|
|
2560
|
+
))
|
|
2561
|
+
);
|
|
2562
|
+
}
|
|
2504
2563
|
function chartFormattingNodes(root) {
|
|
2505
2564
|
const chart = first(root, "chart", NS.c);
|
|
2506
2565
|
const plot = first(chart, "plotArea", NS.c);
|
|
@@ -2675,6 +2734,8 @@ function readChartFormatting(root) {
|
|
|
2675
2734
|
const entries = Object.fromEntries(
|
|
2676
2735
|
Object.entries(nodes).flatMap(([name, node]) => node ? [[name, entry2(node)]] : [])
|
|
2677
2736
|
);
|
|
2737
|
+
const labels = chartDataLabelNode(root);
|
|
2738
|
+
if (labels) entries["dataLabel"] = entry2(labels);
|
|
2678
2739
|
const builtInStyle = readBuiltInChartStyle(root);
|
|
2679
2740
|
const textBody = c(root, "txPr");
|
|
2680
2741
|
const textDefaults = textBody ? {
|
|
@@ -3043,7 +3104,7 @@ function resolveInnerRect(fillToRect, focalPoint) {
|
|
|
3043
3104
|
function lerpEdge(inner, outer, t) {
|
|
3044
3105
|
return inner + (outer - inner) * t;
|
|
3045
3106
|
}
|
|
3046
|
-
function buildRectPathGradientSvg(stops, focalPoint, fillToRect,
|
|
3107
|
+
function buildRectPathGradientSvg(stops, focalPoint, fillToRect, options2) {
|
|
3047
3108
|
if (stops.length === 0) {
|
|
3048
3109
|
return '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100"/>';
|
|
3049
3110
|
}
|
|
@@ -3052,7 +3113,7 @@ function buildRectPathGradientSvg(stops, focalPoint, fillToRect, options) {
|
|
|
3052
3113
|
const rects = [];
|
|
3053
3114
|
const alphaRects = [];
|
|
3054
3115
|
const masked = sorted.some((stop) => (stop.opacity ?? 1) < 1);
|
|
3055
|
-
const bands =
|
|
3116
|
+
const bands = options2?.bands;
|
|
3056
3117
|
if (!Number.isInteger(bands) || bands < 1) throw new RangeError("Invalid gradient band count");
|
|
3057
3118
|
for (let i = bands; i >= 0; i -= 1) {
|
|
3058
3119
|
const t = i / bands;
|
|
@@ -3175,12 +3236,12 @@ function chartGradientMarkup(def) {
|
|
|
3175
3236
|
|
|
3176
3237
|
// chart/bar-cluster-geometry.ts
|
|
3177
3238
|
var DEFAULT_BAR_GAP_WIDTH = 150;
|
|
3178
|
-
function assertBarClusterOptions(
|
|
3239
|
+
function assertBarClusterOptions(options2) {
|
|
3179
3240
|
for (const [field, min, max] of [
|
|
3180
3241
|
["barGapWidth", 0, 500],
|
|
3181
3242
|
["barOverlap", -100, 100]
|
|
3182
3243
|
]) {
|
|
3183
|
-
const value =
|
|
3244
|
+
const value = options2[field];
|
|
3184
3245
|
if (value !== void 0 && (!Number.isInteger(value) || value < min || value > max))
|
|
3185
3246
|
throw new RangeError(`${field} must be an integer from ${min} to ${max}`);
|
|
3186
3247
|
}
|
|
@@ -4433,7 +4494,7 @@ function dataSourceInner(source) {
|
|
|
4433
4494
|
case "multiLvlStrRef": {
|
|
4434
4495
|
const levels = source.levels ? elementXml(
|
|
4435
4496
|
"multiLvlStrCache",
|
|
4436
|
-
valXml("ptCount", source.levelPointCount) + source.levels.map((
|
|
4497
|
+
valXml("ptCount", source.levelPointCount) + source.levels.map((level2) => elementXml("lvl", cachePoints(level2))).join("")
|
|
4437
4498
|
) : "";
|
|
4438
4499
|
return `<c:multiLvlStrRef>${formula}${levels}</c:multiLvlStrRef>`;
|
|
4439
4500
|
}
|
|
@@ -4466,8 +4527,8 @@ function titleXml(context, title) {
|
|
|
4466
4527
|
chartTextXml(context, tx, false) + layoutXml(context, title.layout) + valXml("overlay", title.overlay) + shapePropertiesXml(context, title.spPr) + textBodyXml(context, title.txPr) + raw(context, title.extLst)
|
|
4467
4528
|
);
|
|
4468
4529
|
}
|
|
4469
|
-
function labelOptionsXml(context,
|
|
4470
|
-
return numberFormatXml(
|
|
4530
|
+
function labelOptionsXml(context, options2) {
|
|
4531
|
+
return numberFormatXml(options2.numberFormat) + shapePropertiesXml(context, options2.spPr) + textBodyXml(context, options2.txPr) + valXml("dLblPos", options2.position) + valXml("showLegendKey", options2.showLegendKey) + valXml("showVal", options2.showValue) + valXml("showCatName", options2.showCategoryName) + valXml("showSerName", options2.showSeriesName) + valXml("showPercent", options2.showPercent) + valXml("showBubbleSize", options2.showBubbleSize) + (options2.separator === void 0 ? "" : textElement("separator", options2.separator));
|
|
4471
4532
|
}
|
|
4472
4533
|
function labelXml(context, label) {
|
|
4473
4534
|
return elementXml(
|
|
@@ -4637,7 +4698,7 @@ function styleXml(context, space) {
|
|
|
4637
4698
|
);
|
|
4638
4699
|
}
|
|
4639
4700
|
var relationship = (local, id, content = "") => id === void 0 ? "" : elementXml(local, content, ` r:id="${escapeAttribute(id)}"`);
|
|
4640
|
-
function writeChartSpace(space,
|
|
4701
|
+
function writeChartSpace(space, options2 = {}) {
|
|
4641
4702
|
const bindings = new Map(CHART_ROOT_BINDINGS);
|
|
4642
4703
|
for (const { prefix, uri } of space.namespaceDeclarations ?? [])
|
|
4643
4704
|
if (!bindings.has(prefix) && /^[A-Za-z_][\w.-]*$/.test(prefix)) bindings.set(prefix, uri);
|
|
@@ -4652,10 +4713,204 @@ function writeChartSpace(space, options = {}) {
|
|
|
4652
4713
|
space.externalDataRelId,
|
|
4653
4714
|
valXml("autoUpdate", space.externalDataAutoUpdate)
|
|
4654
4715
|
) + raw(context, space.printSettings) + relationship("userShapes", space.userShapesRelId) + raw(context, space.extLst);
|
|
4655
|
-
const breakAfter =
|
|
4716
|
+
const breakAfter = options2.declarationBreak ?? "\r\n";
|
|
4656
4717
|
return `${DECLARATION2}${breakAfter}<c:chartSpace${declarations}>${body}</c:chartSpace>`;
|
|
4657
4718
|
}
|
|
4658
4719
|
|
|
4720
|
+
// chart/marker-shape.ts
|
|
4721
|
+
var CHART_PX_PER_PT = 4 / 3;
|
|
4722
|
+
var DEFAULT_MARKER_OUTLINE_PT = 0.75;
|
|
4723
|
+
function markerOutline(marker) {
|
|
4724
|
+
if (!marker.stroke) {
|
|
4725
|
+
return {};
|
|
4726
|
+
}
|
|
4727
|
+
return {
|
|
4728
|
+
stroke: marker.stroke,
|
|
4729
|
+
strokeWidth: (marker.strokeWidth ?? DEFAULT_MARKER_OUTLINE_PT) * CHART_PX_PER_PT
|
|
4730
|
+
};
|
|
4731
|
+
}
|
|
4732
|
+
var AUTOMATIC_MARKER_CYCLE = [
|
|
4733
|
+
"diamond",
|
|
4734
|
+
"square",
|
|
4735
|
+
"triangle",
|
|
4736
|
+
"x",
|
|
4737
|
+
"star",
|
|
4738
|
+
"circle",
|
|
4739
|
+
"plus",
|
|
4740
|
+
"dot",
|
|
4741
|
+
"dash"
|
|
4742
|
+
];
|
|
4743
|
+
function automaticMarkerSymbol(seriesIdx) {
|
|
4744
|
+
const length = AUTOMATIC_MARKER_CYCLE.length;
|
|
4745
|
+
const normalized = (Math.trunc(seriesIdx) % length + length) % length;
|
|
4746
|
+
return AUTOMATIC_MARKER_CYCLE[Number.isFinite(normalized) ? normalized : 0];
|
|
4747
|
+
}
|
|
4748
|
+
function markerRadius(size, defaultRadius) {
|
|
4749
|
+
if (size === void 0 || !Number.isFinite(size) || size <= 0) {
|
|
4750
|
+
return defaultRadius;
|
|
4751
|
+
}
|
|
4752
|
+
return size / 2;
|
|
4753
|
+
}
|
|
4754
|
+
function polygonPoints(vertices) {
|
|
4755
|
+
return vertices.map(([x, y]) => `${x.toFixed(2)},${y.toFixed(2)}`).join(" ");
|
|
4756
|
+
}
|
|
4757
|
+
function starVertices(cx2, cy, r) {
|
|
4758
|
+
const inner = r * 0.5;
|
|
4759
|
+
const out = [];
|
|
4760
|
+
for (let i = 0; i < 10; i++) {
|
|
4761
|
+
const radius = i % 2 === 0 ? r : inner;
|
|
4762
|
+
const angle = -Math.PI / 2 + Math.PI * i / 5;
|
|
4763
|
+
out.push([cx2 + radius * Math.cos(angle), cy + radius * Math.sin(angle)]);
|
|
4764
|
+
}
|
|
4765
|
+
return out;
|
|
4766
|
+
}
|
|
4767
|
+
function rectPolygon(x, y, w, h) {
|
|
4768
|
+
return polygonPoints([
|
|
4769
|
+
[x, y],
|
|
4770
|
+
[x + w, y],
|
|
4771
|
+
[x + w, y + h],
|
|
4772
|
+
[x, y + h]
|
|
4773
|
+
]);
|
|
4774
|
+
}
|
|
4775
|
+
function buildMarkerPrimitive(input) {
|
|
4776
|
+
const { symbol, cx: cx2, cy, fill } = input;
|
|
4777
|
+
const part = input.part === void 0 ? {} : { part: input.part };
|
|
4778
|
+
if (symbol === "none") {
|
|
4779
|
+
return null;
|
|
4780
|
+
}
|
|
4781
|
+
const r = markerRadius(input.size, input.defaultRadius);
|
|
4782
|
+
const outline = input.stroke ? {
|
|
4783
|
+
stroke: input.stroke,
|
|
4784
|
+
strokeWidth: input.strokeWidth ?? DEFAULT_MARKER_OUTLINE_PT * CHART_PX_PER_PT
|
|
4785
|
+
} : void 0;
|
|
4786
|
+
const polygonStroke = outline ?? { stroke: fill, strokeWidth: 0 };
|
|
4787
|
+
const lineStroke = input.stroke ?? fill;
|
|
4788
|
+
switch (symbol) {
|
|
4789
|
+
case "square":
|
|
4790
|
+
case "dash": {
|
|
4791
|
+
const h = symbol === "dash" ? r * 0.64 : r * 2;
|
|
4792
|
+
const y = cy - h / 2;
|
|
4793
|
+
if (outline) {
|
|
4794
|
+
return {
|
|
4795
|
+
kind: "polygon",
|
|
4796
|
+
points: rectPolygon(cx2 - r, y, r * 2, h),
|
|
4797
|
+
fill,
|
|
4798
|
+
...outline,
|
|
4799
|
+
...part
|
|
4800
|
+
};
|
|
4801
|
+
}
|
|
4802
|
+
return { kind: "rect", x: cx2 - r, y, w: r * 2, h, fill, ...part };
|
|
4803
|
+
}
|
|
4804
|
+
case "diamond":
|
|
4805
|
+
return {
|
|
4806
|
+
kind: "polygon",
|
|
4807
|
+
points: polygonPoints([
|
|
4808
|
+
[cx2, cy - r],
|
|
4809
|
+
[cx2 + r, cy],
|
|
4810
|
+
[cx2, cy + r],
|
|
4811
|
+
[cx2 - r, cy]
|
|
4812
|
+
]),
|
|
4813
|
+
fill,
|
|
4814
|
+
...polygonStroke,
|
|
4815
|
+
...part
|
|
4816
|
+
};
|
|
4817
|
+
case "triangle":
|
|
4818
|
+
return {
|
|
4819
|
+
kind: "polygon",
|
|
4820
|
+
points: polygonPoints([
|
|
4821
|
+
[cx2, cy - r],
|
|
4822
|
+
[cx2 + r * 0.9, cy + r * 0.75],
|
|
4823
|
+
[cx2 - r * 0.9, cy + r * 0.75]
|
|
4824
|
+
]),
|
|
4825
|
+
fill,
|
|
4826
|
+
...polygonStroke,
|
|
4827
|
+
...part
|
|
4828
|
+
};
|
|
4829
|
+
case "star":
|
|
4830
|
+
return {
|
|
4831
|
+
kind: "polygon",
|
|
4832
|
+
points: polygonPoints(starVertices(cx2, cy, r)),
|
|
4833
|
+
fill,
|
|
4834
|
+
...polygonStroke,
|
|
4835
|
+
...part
|
|
4836
|
+
};
|
|
4837
|
+
case "plus":
|
|
4838
|
+
return {
|
|
4839
|
+
kind: "path",
|
|
4840
|
+
d: `M${(cx2 - r).toFixed(2)},${cy.toFixed(2)} L${(cx2 + r).toFixed(2)},${cy.toFixed(2)} M${cx2.toFixed(2)},${(cy - r).toFixed(2)} L${cx2.toFixed(2)},${(cy + r).toFixed(2)}`,
|
|
4841
|
+
fill: "none",
|
|
4842
|
+
stroke: lineStroke,
|
|
4843
|
+
strokeWidth: Math.max(1, r * 0.4),
|
|
4844
|
+
...part
|
|
4845
|
+
};
|
|
4846
|
+
case "x":
|
|
4847
|
+
return {
|
|
4848
|
+
kind: "path",
|
|
4849
|
+
d: `M${(cx2 - r).toFixed(2)},${(cy - r).toFixed(2)} L${(cx2 + r).toFixed(2)},${(cy + r).toFixed(2)} M${(cx2 + r).toFixed(2)},${(cy - r).toFixed(2)} L${(cx2 - r).toFixed(2)},${(cy + r).toFixed(2)}`,
|
|
4850
|
+
fill: "none",
|
|
4851
|
+
stroke: lineStroke,
|
|
4852
|
+
strokeWidth: Math.max(1, r * 0.4),
|
|
4853
|
+
...part
|
|
4854
|
+
};
|
|
4855
|
+
case "dot":
|
|
4856
|
+
return { kind: "circle", cx: cx2, cy, r: Math.max(r * 0.6, 1), fill, ...part, ...outline };
|
|
4857
|
+
default:
|
|
4858
|
+
return { kind: "circle", cx: cx2, cy, r, fill, ...part, ...outline };
|
|
4859
|
+
}
|
|
4860
|
+
}
|
|
4861
|
+
|
|
4862
|
+
// chart/render/chart-view-markers.ts
|
|
4863
|
+
function summaryMarkers(source, group2, seriesPosition) {
|
|
4864
|
+
if (!["line", "scatter", "radar"].includes(group2.kind)) return {};
|
|
4865
|
+
const enabled = group2.kind === "line" ? group2.marker === true : group2.kind === "radar" ? group2.radarStyle === "marker" : !["line", "smooth", "none"].includes(group2.scatterStyle ?? "marker");
|
|
4866
|
+
const symbol = source.marker?.symbol;
|
|
4867
|
+
const marker = {
|
|
4868
|
+
...source.marker,
|
|
4869
|
+
symbol: symbol && symbol !== "auto" ? symbol : source.marker || enabled ? automaticMarkerSymbol(source.index ?? seriesPosition) : "none"
|
|
4870
|
+
};
|
|
4871
|
+
const pointMarkers = {};
|
|
4872
|
+
for (const point of source.dataPoints) {
|
|
4873
|
+
if (point.index === void 0 || !point.marker) continue;
|
|
4874
|
+
const override = point.marker;
|
|
4875
|
+
pointMarkers[point.index] = {
|
|
4876
|
+
...marker,
|
|
4877
|
+
...override,
|
|
4878
|
+
...override.symbol === "auto" || !source.marker && override.symbol === void 0 ? { symbol: automaticMarkerSymbol(source.index ?? seriesPosition) } : {},
|
|
4879
|
+
...marker.spPr || override.spPr ? {
|
|
4880
|
+
spPr: {
|
|
4881
|
+
...marker.spPr,
|
|
4882
|
+
...override.spPr,
|
|
4883
|
+
...marker.spPr?.line || override.spPr?.line ? { line: { ...marker.spPr?.line, ...override.spPr?.line } } : {}
|
|
4884
|
+
}
|
|
4885
|
+
} : {}
|
|
4886
|
+
};
|
|
4887
|
+
}
|
|
4888
|
+
return { marker, ...Object.keys(pointMarkers).length ? { pointMarkers } : {} };
|
|
4889
|
+
}
|
|
4890
|
+
function seriesMarkerViews(source, drawingColor) {
|
|
4891
|
+
const fillColor = (fill) => fill?.kind === "none" ? "none" : fill?.kind === "solid" ? drawingColor(fill.color) : void 0;
|
|
4892
|
+
const resolve = (marker) => {
|
|
4893
|
+
const fill = fillColor(marker.spPr?.fill);
|
|
4894
|
+
const stroke = fillColor(marker.spPr?.line?.fill);
|
|
4895
|
+
const width = marker.spPr?.line?.widthEmu;
|
|
4896
|
+
return {
|
|
4897
|
+
...marker.symbol !== void 0 ? { symbol: marker.symbol } : {},
|
|
4898
|
+
...marker.size !== void 0 ? { size: marker.size } : {},
|
|
4899
|
+
...fill !== void 0 ? { fill } : {},
|
|
4900
|
+
...stroke !== void 0 ? { stroke } : {},
|
|
4901
|
+
...width !== void 0 ? { strokeWidth: width / 9525 } : {}
|
|
4902
|
+
};
|
|
4903
|
+
};
|
|
4904
|
+
return {
|
|
4905
|
+
...source.marker ? { marker: resolve(source.marker) } : {},
|
|
4906
|
+
...source.pointMarkers ? {
|
|
4907
|
+
pointMarkers: Object.fromEntries(
|
|
4908
|
+
Object.entries(source.pointMarkers).map(([i, marker]) => [i, resolve(marker)])
|
|
4909
|
+
)
|
|
4910
|
+
} : {}
|
|
4911
|
+
};
|
|
4912
|
+
}
|
|
4913
|
+
|
|
4659
4914
|
// chart/render/summary-analysis.ts
|
|
4660
4915
|
function summaryTrendline(source) {
|
|
4661
4916
|
const kind = chartTrendlineKind(source.trendlineType);
|
|
@@ -4696,6 +4951,41 @@ function summaryAnalysis(series) {
|
|
|
4696
4951
|
};
|
|
4697
4952
|
}
|
|
4698
4953
|
|
|
4954
|
+
// chart/render/summary-labels.ts
|
|
4955
|
+
function level(options2, custom) {
|
|
4956
|
+
const out = {};
|
|
4957
|
+
if (options2.deleted !== void 0) out.deleted = options2.deleted;
|
|
4958
|
+
if (options2.showValue !== void 0) out.showValue = options2.showValue;
|
|
4959
|
+
if (options2.showCategoryName !== void 0) out.showCategory = options2.showCategoryName;
|
|
4960
|
+
if (options2.showSeriesName !== void 0) out.showSeriesName = options2.showSeriesName;
|
|
4961
|
+
if (options2.showPercent !== void 0) out.showPercent = options2.showPercent;
|
|
4962
|
+
if (options2.showBubbleSize !== void 0) out.showBubbleSize = options2.showBubbleSize;
|
|
4963
|
+
if (options2.separator !== void 0) out.separator = options2.separator;
|
|
4964
|
+
if (options2.position) out.position = options2.position;
|
|
4965
|
+
if (options2.numberFormat?.formatCode) out.numberFormat = options2.numberFormat.formatCode;
|
|
4966
|
+
if (custom?.text !== void 0) out.text = custom.text;
|
|
4967
|
+
return out;
|
|
4968
|
+
}
|
|
4969
|
+
function shows(levels, point) {
|
|
4970
|
+
const flags = resolveDataLabelFlags({ ...levels, ...point ? { point } : {} });
|
|
4971
|
+
return point?.text !== void 0 || Object.values(flags).some((value) => value === true);
|
|
4972
|
+
}
|
|
4973
|
+
function summaryDataLabels(series, group2) {
|
|
4974
|
+
const own = series.dataLabels;
|
|
4975
|
+
if (!own && !group2) return void 0;
|
|
4976
|
+
const out = {};
|
|
4977
|
+
if (group2) out.chart = level(group2);
|
|
4978
|
+
if (own) out.series = level(own);
|
|
4979
|
+
const points = {};
|
|
4980
|
+
for (const labels of [group2, own])
|
|
4981
|
+
for (const label of labels?.labels ?? [])
|
|
4982
|
+
if (label.index !== void 0)
|
|
4983
|
+
points[label.index] = { ...points[label.index], ...level(label, label.tx) };
|
|
4984
|
+
if (Object.keys(points).length) out.points = points;
|
|
4985
|
+
if (!shows(out) && !Object.values(points).some((point) => shows(out, point))) return void 0;
|
|
4986
|
+
return out;
|
|
4987
|
+
}
|
|
4988
|
+
|
|
4699
4989
|
// chart/render/summary-from-space.ts
|
|
4700
4990
|
var solidColor = (fill) => fill?.kind === "solid" ? fill.color : void 0;
|
|
4701
4991
|
var isSolidFill = (fill) => fill?.kind === "solid" || fill?.kind === "unsupported" && fill.element === "solidFill";
|
|
@@ -4713,7 +5003,7 @@ var GROUP_TYPES = {
|
|
|
4713
5003
|
surface: "surface"
|
|
4714
5004
|
};
|
|
4715
5005
|
var GROUPINGS = /* @__PURE__ */ new Set(["clustered", "stacked", "percentStacked", "standard"]);
|
|
4716
|
-
function chartSummarySeries(source, chartType) {
|
|
5006
|
+
function chartSummarySeries(source, chartType, groupLabels) {
|
|
4717
5007
|
const categories = source.categories ?? source.xValues;
|
|
4718
5008
|
const values = source.values ?? source.yValues;
|
|
4719
5009
|
const numeric = (v) => typeof v === "number" ? v : v === "" ? null : Number.isFinite(Number(v)) ? Number(v) : null;
|
|
@@ -4721,6 +5011,7 @@ function chartSummarySeries(source, chartType) {
|
|
|
4721
5011
|
categories: chartSourceValues(categories),
|
|
4722
5012
|
values: chartSourceValues(values).map(numeric)
|
|
4723
5013
|
};
|
|
5014
|
+
if (values?.cache?.formatCode !== void 0) out.numberFormat = values.cache.formatCode;
|
|
4724
5015
|
if (source.bubbleSizes) {
|
|
4725
5016
|
out.bubbleSizes = chartSourceValues(source.bubbleSizes).map(numeric);
|
|
4726
5017
|
if (source.bubbleSizes.formula) out.bubbleSizesRef = source.bubbleSizes.formula;
|
|
@@ -4749,6 +5040,8 @@ function chartSummarySeries(source, chartType) {
|
|
|
4749
5040
|
}
|
|
4750
5041
|
if (Object.keys(points).length) out.pointColors = points;
|
|
4751
5042
|
if (Object.keys(pointFills).length) out.pointFills = pointFills;
|
|
5043
|
+
const dataLabels = summaryDataLabels(source, groupLabels);
|
|
5044
|
+
if (dataLabels) out.dataLabels = dataLabels;
|
|
4752
5045
|
Object.assign(out, summaryAnalysis(source));
|
|
4753
5046
|
return out;
|
|
4754
5047
|
}
|
|
@@ -4776,7 +5069,10 @@ function extraGroups(chartSpace, firstType) {
|
|
|
4776
5069
|
const type = group2.kind === "bar" ? "column" : group2.kind;
|
|
4777
5070
|
const entry3 = {
|
|
4778
5071
|
chartType: type,
|
|
4779
|
-
series: group2.series.map((source) =>
|
|
5072
|
+
series: group2.series.map((source, index) => ({
|
|
5073
|
+
...chartSummarySeries(source, type, group2.dataLabels),
|
|
5074
|
+
...summaryMarkers(source, group2, index)
|
|
5075
|
+
})),
|
|
4780
5076
|
secondary: valueAxisId(chartSpace, group2.axisIds) !== primary
|
|
4781
5077
|
};
|
|
4782
5078
|
if (group2.grouping && GROUPINGS.has(group2.grouping))
|
|
@@ -4794,11 +5090,16 @@ function chartSummaryFromSpace(chartSpace, extras = {}) {
|
|
|
4794
5090
|
const group2 = chartSpace.plotArea.groups[0];
|
|
4795
5091
|
let chartType = group2 ? GROUP_TYPES[group2.kind] : "column";
|
|
4796
5092
|
if (chartType === "bar" && group2?.barDirection !== "bar") chartType = "column";
|
|
4797
|
-
const series = (group2?.series ?? []).map((source) =>
|
|
5093
|
+
const series = (group2?.series ?? []).map((source, index) => ({
|
|
5094
|
+
...chartSummarySeries(source, chartType, group2?.dataLabels),
|
|
5095
|
+
...group2 ? summaryMarkers(source, group2, index) : {}
|
|
5096
|
+
}));
|
|
4798
5097
|
const summary = {
|
|
4799
5098
|
chartType,
|
|
4800
5099
|
series,
|
|
4801
|
-
showLegend: chartSpace.legend !== void 0
|
|
5100
|
+
showLegend: chartSpace.legend !== void 0,
|
|
5101
|
+
axes: chartSpace.plotArea.axes,
|
|
5102
|
+
axisIds: group2?.axisIds ?? []
|
|
4802
5103
|
};
|
|
4803
5104
|
const combined = extraGroups(chartSpace, chartType);
|
|
4804
5105
|
if (combined.length) summary.extraGroups = combined;
|
|
@@ -4860,9 +5161,9 @@ function dimension(data, kind, type) {
|
|
|
4860
5161
|
const out = { points: [] };
|
|
4861
5162
|
const formula = text(cx(element, "f"));
|
|
4862
5163
|
if (formula) out.formula = formula;
|
|
4863
|
-
const
|
|
4864
|
-
const count = Number(
|
|
4865
|
-
for (const point of
|
|
5164
|
+
const level2 = cx(element, "lvl");
|
|
5165
|
+
const count = Number(level2?.getAttribute("ptCount") ?? 0);
|
|
5166
|
+
for (const point of level2 ? children(level2, "pt", NS.cx) : []) {
|
|
4866
5167
|
const index = Number(point.getAttribute("idx") ?? out.points.length);
|
|
4867
5168
|
if (Number.isInteger(index) && index >= 0) out.points[index] = text(point);
|
|
4868
5169
|
}
|
|
@@ -4871,10 +5172,10 @@ function dimension(data, kind, type) {
|
|
|
4871
5172
|
}
|
|
4872
5173
|
function categoryLevels(data) {
|
|
4873
5174
|
const element = data ? children(data, "strDim", NS.cx).find((d) => (d.getAttribute("type") ?? "") === "cat") : void 0;
|
|
4874
|
-
return (element ? children(element, "lvl", NS.cx) : []).map((
|
|
5175
|
+
return (element ? children(element, "lvl", NS.cx) : []).map((level2) => {
|
|
4875
5176
|
const points = [];
|
|
4876
|
-
const count = Number(
|
|
4877
|
-
for (const point of children(
|
|
5177
|
+
const count = Number(level2.getAttribute("ptCount") ?? 0);
|
|
5178
|
+
for (const point of children(level2, "pt", NS.cx)) {
|
|
4878
5179
|
const index = Number(point.getAttribute("idx") ?? points.length);
|
|
4879
5180
|
if (Number.isInteger(index) && index >= 0) points[index] = text(point);
|
|
4880
5181
|
}
|
|
@@ -5045,135 +5346,553 @@ function chartBarSpacing(chart) {
|
|
|
5045
5346
|
};
|
|
5046
5347
|
}
|
|
5047
5348
|
|
|
5048
|
-
//
|
|
5049
|
-
function
|
|
5050
|
-
|
|
5051
|
-
const
|
|
5052
|
-
|
|
5053
|
-
|
|
5054
|
-
return {
|
|
5055
|
-
}
|
|
5056
|
-
function bars(model, frame, out, values) {
|
|
5057
|
-
const stacked = model.grouping === "stacked" || model.grouping === "percentStacked";
|
|
5058
|
-
const { barSize, offset: barOffset } = barLayout(model, frame);
|
|
5059
|
-
const base = frame.value(0);
|
|
5060
|
-
const pos = new Array(model.categories.length).fill(0);
|
|
5061
|
-
const neg = new Array(model.categories.length).fill(0);
|
|
5062
|
-
model.series.forEach((s, si) => {
|
|
5063
|
-
values[si]?.forEach((v, i) => {
|
|
5064
|
-
if (v === null || i >= model.categories.length) return;
|
|
5065
|
-
let from = 0;
|
|
5066
|
-
let to = v;
|
|
5067
|
-
if (stacked) {
|
|
5068
|
-
const acc = v >= 0 ? pos : neg;
|
|
5069
|
-
from = acc[i] ?? 0;
|
|
5070
|
-
to = from + v;
|
|
5071
|
-
acc[i] = to;
|
|
5072
|
-
}
|
|
5073
|
-
const a2 = stacked ? frame.value(from) : base;
|
|
5074
|
-
const b = frame.value(to);
|
|
5075
|
-
const offset = barOffset(si);
|
|
5076
|
-
const center = frame.band(i);
|
|
5077
|
-
const width = model.horizontal ? Math.abs(b - a2) : barSize;
|
|
5078
|
-
const height = model.horizontal ? barSize : Math.abs(b - a2);
|
|
5079
|
-
let color = s.pointColors?.[i] ?? s.color;
|
|
5080
|
-
const gradient = s.pointGradients?.[i] ?? (s.pointColors?.[i] === void 0 ? s.gradient : void 0);
|
|
5081
|
-
if (gradient && (gradient.path === "circle" || gradient.path === "shape")) {
|
|
5082
|
-
const baseId = color.match(/^url\(#(.+)\)$/)?.[1];
|
|
5083
|
-
if (baseId) {
|
|
5084
|
-
const id = baseId.replace(/(-s\d+(?:-p\d+)?)$/, `-mark${i}$1`);
|
|
5085
|
-
const def = buildChartGradientDef(id, gradient, {
|
|
5086
|
-
width: Number(n(width)),
|
|
5087
|
-
height: Number(n(height)),
|
|
5088
|
-
shape: "rect"
|
|
5089
|
-
});
|
|
5090
|
-
out.push(`<defs>${chartGradientMarkup(def)}</defs>`);
|
|
5091
|
-
color = `url(#${id})`;
|
|
5092
|
-
}
|
|
5093
|
-
}
|
|
5094
|
-
out.push(`<g data-chart-series="${si}" data-chart-point="${i}">`);
|
|
5095
|
-
if (model.horizontal)
|
|
5096
|
-
out.push(
|
|
5097
|
-
rect(Math.min(a2, b), center + offset, Math.abs(b - a2), barSize, color, s.shadowFilter)
|
|
5098
|
-
);
|
|
5099
|
-
else
|
|
5100
|
-
out.push(
|
|
5101
|
-
rect(center + offset, Math.min(a2, b), barSize, Math.abs(b - a2), color, s.shadowFilter)
|
|
5102
|
-
);
|
|
5103
|
-
out.push("</g>");
|
|
5104
|
-
});
|
|
5105
|
-
});
|
|
5349
|
+
// drawingml/drawing-color-css.ts
|
|
5350
|
+
function drawingColorCss(value) {
|
|
5351
|
+
if (!value || value.alpha === 1) return value?.hex;
|
|
5352
|
+
const channels = [1, 3, 5].map(
|
|
5353
|
+
(offset) => Number.parseInt(value.hex.slice(offset, offset + 2), 16)
|
|
5354
|
+
);
|
|
5355
|
+
return `rgba(${channels.join(",")},${value.alpha})`;
|
|
5106
5356
|
}
|
|
5107
5357
|
|
|
5108
|
-
//
|
|
5109
|
-
var
|
|
5110
|
-
|
|
5111
|
-
|
|
5112
|
-
|
|
5113
|
-
|
|
5114
|
-
|
|
5115
|
-
|
|
5116
|
-
|
|
5117
|
-
|
|
5118
|
-
|
|
5119
|
-
|
|
5120
|
-
|
|
5121
|
-
|
|
5122
|
-
|
|
5123
|
-
|
|
5124
|
-
|
|
5125
|
-
|
|
5126
|
-
|
|
5127
|
-
var
|
|
5128
|
-
|
|
5129
|
-
|
|
5130
|
-
|
|
5131
|
-
|
|
5132
|
-
|
|
5133
|
-
|
|
5134
|
-
|
|
5135
|
-
|
|
5136
|
-
|
|
5358
|
+
// units/constants.ts
|
|
5359
|
+
var EMU_PER_PIXEL = 9525;
|
|
5360
|
+
var EMU_PER_POINT = 12700;
|
|
5361
|
+
|
|
5362
|
+
// chart/render/theme-palette.ts
|
|
5363
|
+
var THEME_SLOTS = [
|
|
5364
|
+
"lt1",
|
|
5365
|
+
"dk1",
|
|
5366
|
+
"lt2",
|
|
5367
|
+
"dk2",
|
|
5368
|
+
"accent1",
|
|
5369
|
+
"accent2",
|
|
5370
|
+
"accent3",
|
|
5371
|
+
"accent4",
|
|
5372
|
+
"accent5",
|
|
5373
|
+
"accent6",
|
|
5374
|
+
"hlink",
|
|
5375
|
+
"folHlink"
|
|
5376
|
+
];
|
|
5377
|
+
var DEFAULT_THEME_COLORS = [
|
|
5378
|
+
"FFFFFF",
|
|
5379
|
+
"000000",
|
|
5380
|
+
"E7E6E6",
|
|
5381
|
+
"44546A",
|
|
5382
|
+
"4472C4",
|
|
5383
|
+
"ED7D31",
|
|
5384
|
+
"A5A5A5",
|
|
5385
|
+
"FFC000",
|
|
5386
|
+
"5B9BD5",
|
|
5387
|
+
"70AD47",
|
|
5388
|
+
"0563C1",
|
|
5389
|
+
"954F72"
|
|
5390
|
+
];
|
|
5391
|
+
function themeColor(theme, index) {
|
|
5392
|
+
const hex = theme.colors[index] ?? DEFAULT_THEME_COLORS[index];
|
|
5393
|
+
return hex && parseArgbHex(hex) ? hex.replace(/^#/, "") : void 0;
|
|
5137
5394
|
}
|
|
5138
|
-
|
|
5139
|
-
|
|
5140
|
-
|
|
5141
|
-
|
|
5142
|
-
|
|
5143
|
-
|
|
5144
|
-
|
|
5145
|
-
|
|
5146
|
-
|
|
5147
|
-
|
|
5148
|
-
|
|
5149
|
-
|
|
5150
|
-
}
|
|
5395
|
+
|
|
5396
|
+
// chart/render/chart-colors.ts
|
|
5397
|
+
function chartColorScheme(theme) {
|
|
5398
|
+
const slots = Object.fromEntries(
|
|
5399
|
+
THEME_SLOTS.map((slot, index) => [slot, `#${themeColor(theme, index) ?? "000000"}`])
|
|
5400
|
+
);
|
|
5401
|
+
return {
|
|
5402
|
+
...slots,
|
|
5403
|
+
bg1: slots.lt1,
|
|
5404
|
+
tx1: slots.dk1,
|
|
5405
|
+
bg2: slots.lt2,
|
|
5406
|
+
tx2: slots.dk2
|
|
5407
|
+
};
|
|
5151
5408
|
}
|
|
5152
|
-
function
|
|
5153
|
-
|
|
5154
|
-
|
|
5155
|
-
|
|
5156
|
-
|
|
5409
|
+
function modulateLuminance(hex, lumMod, lumOff = 0) {
|
|
5410
|
+
const rgb = parseArgbHex(hex);
|
|
5411
|
+
if (!rgb) return "#000000";
|
|
5412
|
+
if (lumMod === 1 && lumOff === 0) return rgbToUpperHex(rgb);
|
|
5413
|
+
const hsl = rgbToHsl(...rgb);
|
|
5414
|
+
const l = Math.max(0, Math.min(1, hsl.l * lumMod + lumOff));
|
|
5415
|
+
const out = hslToRgb(hsl.h, hsl.s, l);
|
|
5416
|
+
return rgbToUpperHex([out.r, out.g, out.b]);
|
|
5157
5417
|
}
|
|
5158
|
-
function
|
|
5159
|
-
const
|
|
5160
|
-
|
|
5161
|
-
const ys = points.map((p) => p.y);
|
|
5162
|
-
trendlines(series, si, xs, ys, plane, out);
|
|
5163
|
-
for (const bars2 of series.errorBars ?? []) {
|
|
5164
|
-
if (categoryAxis && bars2.direction === "x") continue;
|
|
5165
|
-
const values = bars2.direction === "x" ? xs : ys;
|
|
5166
|
-
points.forEach(
|
|
5167
|
-
(p, displayIndex) => errorBar(bars2, { x: p.x, y: p.y, displayIndex, sourceIndex: p.index }, values, barPlane, out)
|
|
5168
|
-
);
|
|
5169
|
-
}
|
|
5418
|
+
function autoSeriesColor(theme, index) {
|
|
5419
|
+
const i = Math.max(0, Math.floor(index));
|
|
5420
|
+
return chartPaletteSeriesColor(findChartColorPalette(10), i, i + 1, chartColorScheme(theme));
|
|
5170
5421
|
}
|
|
5171
|
-
|
|
5172
|
-
|
|
5173
|
-
|
|
5174
|
-
const
|
|
5175
|
-
|
|
5176
|
-
|
|
5422
|
+
|
|
5423
|
+
// drawingml/drawing-shadow.ts
|
|
5424
|
+
function resolveDrawingShadow(effects, theme) {
|
|
5425
|
+
const node = first(effects, "outerShdw", NS.a);
|
|
5426
|
+
if (!node) return void 0;
|
|
5427
|
+
const value = (key, fallback) => Number(node.getAttribute(key) ?? fallback);
|
|
5428
|
+
if (value("sx", 1e5) !== 1e5 || value("sy", 1e5) !== 1e5 || value("kx", 0) !== 0 || value("ky", 0) !== 0)
|
|
5429
|
+
return void 0;
|
|
5430
|
+
const color = parseDrawingColorIn(node);
|
|
5431
|
+
const resolved = color && resolveDrawingColor(color, theme, { transformOrder: "document" });
|
|
5432
|
+
const blur = value("blurRad", 0) / EMU_PER_PIXEL;
|
|
5433
|
+
const distance = value("dist", 0) / EMU_PER_PIXEL;
|
|
5434
|
+
const angle = value("dir", 0) / 6e4 * Math.PI / 180;
|
|
5435
|
+
if (!resolved || ![blur, distance, angle].every(Number.isFinite) || blur < 0 || distance < 0)
|
|
5436
|
+
return void 0;
|
|
5437
|
+
return {
|
|
5438
|
+
color: resolved.hex,
|
|
5439
|
+
opacity: resolved.alpha,
|
|
5440
|
+
blur,
|
|
5441
|
+
dx: Math.cos(angle) * distance,
|
|
5442
|
+
dy: Math.sin(angle) * distance
|
|
5443
|
+
};
|
|
5444
|
+
}
|
|
5445
|
+
function resolveDrawingShadowXml(xml, theme) {
|
|
5446
|
+
return xml ? resolveDrawingShadow(parseXml(xml).documentElement, theme) : void 0;
|
|
5447
|
+
}
|
|
5448
|
+
function svgDropShadowElement(s, format) {
|
|
5449
|
+
const num = format.number;
|
|
5450
|
+
return `<feDropShadow dx="${num(s.dx)}" dy="${num(s.dy)}" stdDeviation="${num(s.blur / 2)}" flood-color="${format.color(s.color, "#000000")}" flood-opacity="${num(s.opacity)}" result="shadow"/>`;
|
|
5451
|
+
}
|
|
5452
|
+
|
|
5453
|
+
// chart/text-inheritance.ts
|
|
5454
|
+
var TEXT_KEYS = [
|
|
5455
|
+
"fontSize",
|
|
5456
|
+
"bold",
|
|
5457
|
+
"italic",
|
|
5458
|
+
"underline",
|
|
5459
|
+
"typeface",
|
|
5460
|
+
"textColor",
|
|
5461
|
+
"fontRef"
|
|
5462
|
+
];
|
|
5463
|
+
var TEXT_PARTS = [
|
|
5464
|
+
"title",
|
|
5465
|
+
"axisTitle",
|
|
5466
|
+
"categoryAxis",
|
|
5467
|
+
"valueAxis",
|
|
5468
|
+
"legend",
|
|
5469
|
+
"dataLabel"
|
|
5470
|
+
];
|
|
5471
|
+
function inheritChartText(part, entry3, builtIn, root) {
|
|
5472
|
+
if (!root || !TEXT_PARTS.includes(part)) return entry3;
|
|
5473
|
+
const out = { ...entry3 };
|
|
5474
|
+
for (const key of TEXT_KEYS) {
|
|
5475
|
+
delete out[key];
|
|
5476
|
+
const value = root[key] ?? builtIn?.[key];
|
|
5477
|
+
if (value !== void 0) Object.assign(out, { [key]: value });
|
|
5478
|
+
}
|
|
5479
|
+
if (part === "title" && root.fontSize !== void 0) out.fontSize = root.fontSize * 1.2;
|
|
5480
|
+
if (root.textEffectsXml !== void 0) out.textEffectsXml = root.textEffectsXml;
|
|
5481
|
+
return out;
|
|
5482
|
+
}
|
|
5483
|
+
|
|
5484
|
+
// chart/render/chart-appearance.ts
|
|
5485
|
+
var chartPointsToPixels = (points) => points * EMU_PER_POINT / EMU_PER_PIXEL;
|
|
5486
|
+
function typeface(entry3, theme) {
|
|
5487
|
+
const name = entry3.typeface;
|
|
5488
|
+
if (name?.startsWith("+mj-")) return theme.majorFont;
|
|
5489
|
+
if (name?.startsWith("+mn-")) return theme.minorFont;
|
|
5490
|
+
return name ?? (entry3.fontRef?.index === "major" ? theme.majorFont : entry3.fontRef?.index === "minor" ? theme.minorFont : void 0);
|
|
5491
|
+
}
|
|
5492
|
+
function chartAppearance(chart, theme) {
|
|
5493
|
+
const defaults = builtInChartTextStyle(effectiveBuiltInChartStyle(chart.formatting));
|
|
5494
|
+
const entries = {};
|
|
5495
|
+
for (const part of CHART_STYLE_PARTS) {
|
|
5496
|
+
const base = chart.styleDefinition?.entries[part];
|
|
5497
|
+
const direct = chart.formatting?.entries[part];
|
|
5498
|
+
if (!defaults[part] && !base && !direct) continue;
|
|
5499
|
+
const entry3 = {
|
|
5500
|
+
...inheritChartText(
|
|
5501
|
+
part,
|
|
5502
|
+
{ ...defaults[part], ...base, sourceXml: base?.sourceXml ?? "" },
|
|
5503
|
+
defaults[part],
|
|
5504
|
+
chart.formatting?.textDefaults
|
|
5505
|
+
),
|
|
5506
|
+
...direct,
|
|
5507
|
+
sourceXml: direct?.sourceXml ?? base?.sourceXml ?? ""
|
|
5508
|
+
};
|
|
5509
|
+
if (base?.line || direct?.line) entry3.line = { ...base?.line, ...direct?.line };
|
|
5510
|
+
entries[part] = entry3;
|
|
5511
|
+
}
|
|
5512
|
+
const scheme = chartColorScheme(theme);
|
|
5513
|
+
const resolve = (color) => resolveDrawingColor(
|
|
5514
|
+
color,
|
|
5515
|
+
{ scheme: (name) => scheme[name] },
|
|
5516
|
+
{ hslRounding: "halfDown", transformOrder: "document" }
|
|
5517
|
+
);
|
|
5518
|
+
const out = resolveChartStyleDefinition(
|
|
5519
|
+
{ entries},
|
|
5520
|
+
(color) => drawingColorCss(resolve(color))
|
|
5521
|
+
) ?? {};
|
|
5522
|
+
for (const part of CHART_STYLE_PARTS) {
|
|
5523
|
+
const entry3 = entries[part];
|
|
5524
|
+
if (!entry3) continue;
|
|
5525
|
+
const family = typeface(entry3, theme);
|
|
5526
|
+
const shadow = resolveDrawingShadowXml(entry3.textEffectsXml, {
|
|
5527
|
+
scheme: (name) => scheme[name]
|
|
5528
|
+
});
|
|
5529
|
+
if (shadow) (out[part] ??= {}).textShadow = shadow;
|
|
5530
|
+
if (family) (out[part] ??= {}).typeface = family;
|
|
5531
|
+
if (entry3.axisVisible !== void 0) (out[part] ??= {}).axisVisible = entry3.axisVisible;
|
|
5532
|
+
if (entry3.labelsVisible !== void 0) (out[part] ??= {}).labelsVisible = entry3.labelsVisible;
|
|
5533
|
+
if (entry3.line?.widthEmu === 0) (out[part] ??= {}).lineWidth = 0;
|
|
5534
|
+
if (entry3.fill?.kind === "gradient") {
|
|
5535
|
+
(out[part] ??= {}).gradient = resolveChartGradient(entry3.fill, resolve);
|
|
5536
|
+
}
|
|
5537
|
+
}
|
|
5538
|
+
return out;
|
|
5539
|
+
}
|
|
5540
|
+
|
|
5541
|
+
// text/css-font-family.ts
|
|
5542
|
+
var FALLBACKS = {
|
|
5543
|
+
calibri: '"Calibri", "Carlito", "Segoe UI", Arial, sans-serif',
|
|
5544
|
+
"calibri light": '"Calibri Light", "Calibri", "Carlito", "Segoe UI", Arial, sans-serif',
|
|
5545
|
+
cambria: '"Cambria", "Caladea", Georgia, serif',
|
|
5546
|
+
arial: 'Arial, "Liberation Sans", Helvetica, sans-serif',
|
|
5547
|
+
"times new roman": '"Times New Roman", "Liberation Serif", Times, serif',
|
|
5548
|
+
"courier new": '"Courier New", "Liberation Mono", monospace',
|
|
5549
|
+
aptos: '"Aptos", "Calibri", "Carlito", "Segoe UI", sans-serif'
|
|
5550
|
+
};
|
|
5551
|
+
function cssFontFamily(name) {
|
|
5552
|
+
const known = FALLBACKS[name.toLowerCase()];
|
|
5553
|
+
if (known) return known;
|
|
5554
|
+
const quoted = `"${name.replace(/["\\]/g, "")}"`;
|
|
5555
|
+
return `${quoted}, "Calibri", "Carlito", "Segoe UI", sans-serif`;
|
|
5556
|
+
}
|
|
5557
|
+
|
|
5558
|
+
// chart/render/chart-svg-appearance.ts
|
|
5559
|
+
var nextPaintId = 0;
|
|
5560
|
+
function chartGradientPaint(model, width = 1024, height = 768) {
|
|
5561
|
+
const prefix = `xlsx-chart-${++nextPaintId}`;
|
|
5562
|
+
const appearance = { ...model.appearance };
|
|
5563
|
+
const defs = [];
|
|
5564
|
+
const shadowPaint = (shadow, suffix) => {
|
|
5565
|
+
const id = `${prefix}-${suffix}`;
|
|
5566
|
+
const pad = Math.max(4, shadow.blur * 3 + Math.abs(shadow.dx) + Math.abs(shadow.dy));
|
|
5567
|
+
defs.push(
|
|
5568
|
+
`<filter id="${id}" filterUnits="userSpaceOnUse" x="${n(-pad)}" y="${n(-pad)}" width="${n(width + pad * 2)}" height="${n(height + pad * 2)}" color-interpolation-filters="sRGB">${svgDropShadowElement(shadow, { number: n, color: (value) => esc(value) })}</filter>`
|
|
5569
|
+
);
|
|
5570
|
+
return `url(#${id})`;
|
|
5571
|
+
};
|
|
5572
|
+
for (const [part, entry3] of Object.entries(appearance)) {
|
|
5573
|
+
if (entry3?.textShadow)
|
|
5574
|
+
appearance[part] = {
|
|
5575
|
+
...entry3,
|
|
5576
|
+
textShadowFilter: shadowPaint(entry3.textShadow, `${part}-text-shadow`)
|
|
5577
|
+
};
|
|
5578
|
+
}
|
|
5579
|
+
const paint2 = (gradient, suffix, bounds) => {
|
|
5580
|
+
const def = buildChartGradientDef(`${prefix}-${suffix}`, gradient, bounds);
|
|
5581
|
+
defs.push(chartGradientMarkup(def));
|
|
5582
|
+
return `url(#${def.id})`;
|
|
5583
|
+
};
|
|
5584
|
+
for (const part of ["chartArea", "plotArea"]) {
|
|
5585
|
+
const entry3 = appearance[part];
|
|
5586
|
+
if (!entry3?.gradient) continue;
|
|
5587
|
+
if (part === "plotArea" && ["circle", "shape"].includes(entry3.gradient.path ?? "")) continue;
|
|
5588
|
+
appearance[part] = {
|
|
5589
|
+
...entry3,
|
|
5590
|
+
fillColor: paint2(entry3.gradient, part, { width, height, shape: "rect" })
|
|
5591
|
+
};
|
|
5592
|
+
}
|
|
5593
|
+
const series = model.series.map((source, index) => {
|
|
5594
|
+
const view = { ...source };
|
|
5595
|
+
if (source.shadow) view.shadowFilter = shadowPaint(source.shadow, `s${index}-shadow`);
|
|
5596
|
+
const bounds = model.type === "bar" || model.type === "column" ? { width: 1, height: 1, shape: "rect" } : void 0;
|
|
5597
|
+
if (source.gradient) view.color = paint2(source.gradient, `s${index}`, bounds);
|
|
5598
|
+
if (source.pointGradients) {
|
|
5599
|
+
view.pointColors = [...source.pointColors ?? []];
|
|
5600
|
+
for (const [key, gradient] of Object.entries(source.pointGradients))
|
|
5601
|
+
view.pointColors[Number(key)] = paint2(gradient, `s${index}-p${key}`, bounds);
|
|
5602
|
+
}
|
|
5603
|
+
return view;
|
|
5604
|
+
});
|
|
5605
|
+
return defs.length ? { model: { ...model, appearance, series }, defs: `<defs>${defs.join("")}</defs>` } : { model, defs: "" };
|
|
5606
|
+
}
|
|
5607
|
+
function chartTextAttributes(model, part, fallbackSize = FONT_SIZE) {
|
|
5608
|
+
const entry3 = model.appearance?.[part];
|
|
5609
|
+
return {
|
|
5610
|
+
size: entry3?.fontSize === void 0 ? fallbackSize : chartPointsToPixels(entry3.fontSize),
|
|
5611
|
+
...entry3?.color === void 0 ? {} : { fill: entry3.color },
|
|
5612
|
+
...entry3?.bold === void 0 ? {} : { weight: entry3.bold ? "bold" : "normal" },
|
|
5613
|
+
...entry3?.italic === void 0 ? {} : { italic: entry3.italic },
|
|
5614
|
+
...entry3?.underline === void 0 ? {} : { underline: entry3.underline },
|
|
5615
|
+
...entry3?.typeface === void 0 ? {} : { family: cssFontFamily(entry3.typeface) },
|
|
5616
|
+
...entry3?.textShadowFilter === void 0 ? {} : { filter: entry3.textShadowFilter }
|
|
5617
|
+
};
|
|
5618
|
+
}
|
|
5619
|
+
function chartStroke(model, part) {
|
|
5620
|
+
const entry3 = model.appearance?.[part];
|
|
5621
|
+
return {
|
|
5622
|
+
color: entry3?.axisVisible === false ? "none" : entry3?.lineColor ?? (part.startsWith("gridline") ? GRID_COLOR : AXIS_COLOR),
|
|
5623
|
+
width: entry3?.lineWidth === void 0 ? 1 : chartPointsToPixels(entry3.lineWidth)
|
|
5624
|
+
};
|
|
5625
|
+
}
|
|
5626
|
+
function chartAreaRect(model, part, area) {
|
|
5627
|
+
if (area.w <= 0 || area.h <= 0) return "";
|
|
5628
|
+
const entry3 = model.appearance?.[part];
|
|
5629
|
+
let fill = entry3?.fillColor ?? (part === "chartArea" ? "#FFFFFF" : "none");
|
|
5630
|
+
let defs = "";
|
|
5631
|
+
if (part !== "chartArea" && entry3?.gradient && (part !== "plotArea" || ["circle", "shape"].includes(entry3.gradient.path ?? ""))) {
|
|
5632
|
+
const def = buildChartGradientDef(`xlsx-chart-${++nextPaintId}-${part}`, entry3.gradient, {
|
|
5633
|
+
width: area.w,
|
|
5634
|
+
height: area.h,
|
|
5635
|
+
shape: "rect"
|
|
5636
|
+
});
|
|
5637
|
+
defs = `<defs>${chartGradientMarkup(def)}</defs>`;
|
|
5638
|
+
fill = `url(#${def.id})`;
|
|
5639
|
+
}
|
|
5640
|
+
const stroke = entry3?.lineColor ?? "none";
|
|
5641
|
+
if (fill === "none" && stroke === "none") return "";
|
|
5642
|
+
const width = entry3?.lineWidth === void 0 ? 1 : chartPointsToPixels(entry3.lineWidth);
|
|
5643
|
+
return `${defs}<rect x="${n(area.x)}" y="${n(area.y)}" width="${n(area.w)}" height="${n(area.h)}" fill="${esc(fill)}" stroke="${esc(stroke)}" stroke-width="${n(width)}" data-chart-part="${part}"/>`;
|
|
5644
|
+
}
|
|
5645
|
+
|
|
5646
|
+
// chart/render/chart-svg-labels.ts
|
|
5647
|
+
var GAP = 3;
|
|
5648
|
+
var LINE = 1.2;
|
|
5649
|
+
var NAMED_COLORS = /^(black|blue|cyan|green|magenta|red|white|yellow)$/iu;
|
|
5650
|
+
function measure(model, label) {
|
|
5651
|
+
const attrs = chartTextAttributes(model, "dataLabel", 10);
|
|
5652
|
+
const size = attrs.size ?? 10;
|
|
5653
|
+
const lines = label.text.split("\n");
|
|
5654
|
+
return {
|
|
5655
|
+
lines,
|
|
5656
|
+
size,
|
|
5657
|
+
w: Math.max(...lines.map((l) => textWidth(l, size))),
|
|
5658
|
+
h: lines.length * size * LINE,
|
|
5659
|
+
attrs
|
|
5660
|
+
};
|
|
5661
|
+
}
|
|
5662
|
+
function draw(m, label, x, y, anchor, out) {
|
|
5663
|
+
const fill = label.color && NAMED_COLORS.test(label.color) ? label.color.toLowerCase() : void 0;
|
|
5664
|
+
m.lines.forEach((line2, k) => {
|
|
5665
|
+
const lineY = y - m.h / 2 + (k + 0.5) * m.size * LINE + m.size * 0.35;
|
|
5666
|
+
out.push(text2(x, lineY, line2, { ...m.attrs, ...fill ? { fill } : {}, anchor }));
|
|
5667
|
+
});
|
|
5668
|
+
}
|
|
5669
|
+
function barLabels(model, marks, out) {
|
|
5670
|
+
const stacked = model.grouping === "stacked" || model.grouping === "percentStacked";
|
|
5671
|
+
for (const mark of marks) {
|
|
5672
|
+
const label = mark.series.labels?.[mark.index];
|
|
5673
|
+
if (!label) continue;
|
|
5674
|
+
const m = measure(model, label);
|
|
5675
|
+
let position = label.position ?? (stacked ? "ctr" : "outEnd");
|
|
5676
|
+
if (stacked && position === "outEnd") position = "ctr";
|
|
5677
|
+
const cx2 = mark.x + mark.w / 2;
|
|
5678
|
+
const cy = mark.y + mark.h / 2;
|
|
5679
|
+
if (model.horizontal) {
|
|
5680
|
+
const end = mark.negative ? mark.x : mark.x + mark.w;
|
|
5681
|
+
const base = mark.negative ? mark.x + mark.w : mark.x;
|
|
5682
|
+
const dir2 = mark.negative ? -1 : 1;
|
|
5683
|
+
const side = (at, outward) => [
|
|
5684
|
+
at + (outward ? dir2 : -dir2) * GAP,
|
|
5685
|
+
(outward ? dir2 : -dir2) > 0 ? "start" : "end"
|
|
5686
|
+
];
|
|
5687
|
+
const [x, anchor] = position === "ctr" ? [cx2, "middle"] : position === "inEnd" ? side(end, false) : position === "inBase" ? side(base, true) : side(end, true);
|
|
5688
|
+
draw(m, label, x, cy, anchor, out);
|
|
5689
|
+
continue;
|
|
5690
|
+
}
|
|
5691
|
+
const top = mark.negative ? mark.y + mark.h : mark.y;
|
|
5692
|
+
const bottom = mark.negative ? mark.y : mark.y + mark.h;
|
|
5693
|
+
const dir = mark.negative ? 1 : -1;
|
|
5694
|
+
const y = position === "ctr" ? cy : position === "inEnd" ? top - dir * (GAP + m.h / 2) : position === "inBase" ? bottom + dir * (GAP + m.h / 2) : top + dir * (GAP + m.h / 2);
|
|
5695
|
+
draw(m, label, cx2, y, "middle", out);
|
|
5696
|
+
}
|
|
5697
|
+
}
|
|
5698
|
+
function pointLabels(model, marks, out) {
|
|
5699
|
+
for (const mark of marks) {
|
|
5700
|
+
const label = mark.series.labels?.[mark.index];
|
|
5701
|
+
if (!label) continue;
|
|
5702
|
+
const m = measure(model, label);
|
|
5703
|
+
const reach = mark.radius + GAP;
|
|
5704
|
+
switch (model.type === "area" ? "ctr" : label.position ?? "r") {
|
|
5705
|
+
case "ctr":
|
|
5706
|
+
draw(m, label, mark.x, mark.y, "middle", out);
|
|
5707
|
+
break;
|
|
5708
|
+
case "t":
|
|
5709
|
+
draw(m, label, mark.x, mark.y - reach - m.h / 2, "middle", out);
|
|
5710
|
+
break;
|
|
5711
|
+
case "b":
|
|
5712
|
+
draw(m, label, mark.x, mark.y + reach + m.h / 2, "middle", out);
|
|
5713
|
+
break;
|
|
5714
|
+
case "l":
|
|
5715
|
+
draw(m, label, mark.x - reach, mark.y, "end", out);
|
|
5716
|
+
break;
|
|
5717
|
+
default:
|
|
5718
|
+
draw(m, label, mark.x + reach, mark.y, "start", out);
|
|
5719
|
+
}
|
|
5720
|
+
}
|
|
5721
|
+
}
|
|
5722
|
+
function sliceLabels(model, marks, out) {
|
|
5723
|
+
for (const mark of marks) {
|
|
5724
|
+
const label = mark.series.labels?.[mark.index];
|
|
5725
|
+
if (!label) continue;
|
|
5726
|
+
const m = measure(model, label);
|
|
5727
|
+
const mid = (mark.start + mark.end) / 2;
|
|
5728
|
+
const ux = Math.sin(mid);
|
|
5729
|
+
const uy = -Math.cos(mid);
|
|
5730
|
+
const place = (radius) => [
|
|
5731
|
+
mark.cx + radius * ux,
|
|
5732
|
+
mark.cy + radius * uy
|
|
5733
|
+
];
|
|
5734
|
+
const position = model.type === "doughnut" ? "ctr" : label.position ?? "bestFit";
|
|
5735
|
+
let x;
|
|
5736
|
+
let y;
|
|
5737
|
+
if (position === "ctr") [x, y] = place(mark.inner + (mark.outer - mark.inner) / 2);
|
|
5738
|
+
else if (position === "inEnd") {
|
|
5739
|
+
const extent = Math.abs(ux) * m.w / 2 + Math.abs(uy) * m.h / 2;
|
|
5740
|
+
[x, y] = place(Math.max(0, mark.outer - GAP - extent));
|
|
5741
|
+
} else if (position === "outEnd") {
|
|
5742
|
+
const extent = Math.abs(ux) * m.w / 2 + Math.abs(uy) * m.h / 2;
|
|
5743
|
+
[x, y] = place(mark.outer + GAP + extent);
|
|
5744
|
+
} else {
|
|
5745
|
+
const placed = placeBestFitLabel(
|
|
5746
|
+
{
|
|
5747
|
+
cx: mark.cx,
|
|
5748
|
+
cy: mark.cy,
|
|
5749
|
+
outerR: mark.outer,
|
|
5750
|
+
startAngle: mark.start - Math.PI / 2,
|
|
5751
|
+
endAngle: mark.end - Math.PI / 2
|
|
5752
|
+
},
|
|
5753
|
+
m.w,
|
|
5754
|
+
m.h
|
|
5755
|
+
);
|
|
5756
|
+
x = placed.x;
|
|
5757
|
+
y = placed.y;
|
|
5758
|
+
}
|
|
5759
|
+
draw(m, label, x, y, "middle", out);
|
|
5760
|
+
}
|
|
5761
|
+
}
|
|
5762
|
+
function hasOutsideLabels(model) {
|
|
5763
|
+
return model.series.some(
|
|
5764
|
+
(s) => s.labels?.some(
|
|
5765
|
+
(l) => l !== void 0 && ["bestFit", "outEnd"].includes(l.position ?? "bestFit")
|
|
5766
|
+
)
|
|
5767
|
+
);
|
|
5768
|
+
}
|
|
5769
|
+
|
|
5770
|
+
// chart/render/chart-svg-bars.ts
|
|
5771
|
+
function barLayout(model, frame) {
|
|
5772
|
+
const count = Math.max(1, model.series.length);
|
|
5773
|
+
const geometry = clusteredBarGeometry(frame.bandSize, count, chartBarSpacing(model));
|
|
5774
|
+
const barSize = geometry.singleBarWidth;
|
|
5775
|
+
const offset = (si) => model.horizontal ? geometry.clusterWidth / 2 - barSize - si * geometry.step : -geometry.clusterWidth / 2 + si * geometry.step;
|
|
5776
|
+
return { barSize, offset };
|
|
5777
|
+
}
|
|
5778
|
+
function bars(model, frame, out, values) {
|
|
5779
|
+
const stacked = model.grouping === "stacked" || model.grouping === "percentStacked";
|
|
5780
|
+
const { barSize, offset: barOffset } = barLayout(model, frame);
|
|
5781
|
+
const base = frame.value(0);
|
|
5782
|
+
const pos = new Array(model.categories.length).fill(0);
|
|
5783
|
+
const neg = new Array(model.categories.length).fill(0);
|
|
5784
|
+
const marks = [];
|
|
5785
|
+
model.series.forEach((s, si) => {
|
|
5786
|
+
values[si]?.forEach((v, i) => {
|
|
5787
|
+
if (v === null || i >= model.categories.length) return;
|
|
5788
|
+
let from = 0;
|
|
5789
|
+
let to = v;
|
|
5790
|
+
if (stacked) {
|
|
5791
|
+
const acc = v >= 0 ? pos : neg;
|
|
5792
|
+
from = acc[i] ?? 0;
|
|
5793
|
+
to = from + v;
|
|
5794
|
+
acc[i] = to;
|
|
5795
|
+
}
|
|
5796
|
+
const a2 = stacked ? frame.value(from) : base;
|
|
5797
|
+
const b = frame.value(to);
|
|
5798
|
+
const offset = barOffset(si);
|
|
5799
|
+
const center = frame.band(i);
|
|
5800
|
+
const width = model.horizontal ? Math.abs(b - a2) : barSize;
|
|
5801
|
+
const height = model.horizontal ? barSize : Math.abs(b - a2);
|
|
5802
|
+
let color = s.pointColors?.[i] ?? s.color;
|
|
5803
|
+
const gradient = s.pointGradients?.[i] ?? (s.pointColors?.[i] === void 0 ? s.gradient : void 0);
|
|
5804
|
+
if (gradient && (gradient.path === "circle" || gradient.path === "shape")) {
|
|
5805
|
+
const baseId = color.match(/^url\(#(.+)\)$/)?.[1];
|
|
5806
|
+
if (baseId) {
|
|
5807
|
+
const id = baseId.replace(/(-s\d+(?:-p\d+)?)$/, `-mark${i}$1`);
|
|
5808
|
+
const def = buildChartGradientDef(id, gradient, {
|
|
5809
|
+
width: Number(n(width)),
|
|
5810
|
+
height: Number(n(height)),
|
|
5811
|
+
shape: "rect"
|
|
5812
|
+
});
|
|
5813
|
+
out.push(`<defs>${chartGradientMarkup(def)}</defs>`);
|
|
5814
|
+
color = `url(#${id})`;
|
|
5815
|
+
}
|
|
5816
|
+
}
|
|
5817
|
+
out.push(`<g data-chart-series="${si}" data-chart-point="${i}">`);
|
|
5818
|
+
const box = model.horizontal ? { x: Math.min(a2, b), y: center + offset, w: Math.abs(b - a2), h: barSize } : { x: center + offset, y: Math.min(a2, b), w: barSize, h: Math.abs(b - a2) };
|
|
5819
|
+
out.push(rect(box.x, box.y, box.w, box.h, color, s.shadowFilter));
|
|
5820
|
+
out.push("</g>");
|
|
5821
|
+
marks.push({ series: s, index: i, ...box, negative: v < 0 });
|
|
5822
|
+
});
|
|
5823
|
+
});
|
|
5824
|
+
barLabels(model, marks, out);
|
|
5825
|
+
}
|
|
5826
|
+
|
|
5827
|
+
// chart/render/chart-svg-analysis.ts
|
|
5828
|
+
var DASHES = {
|
|
5829
|
+
dot: [1, 3],
|
|
5830
|
+
dash: [4, 3],
|
|
5831
|
+
lgDash: [8, 3],
|
|
5832
|
+
dashDot: [4, 3, 1, 3],
|
|
5833
|
+
lgDashDot: [8, 3, 1, 3],
|
|
5834
|
+
lgDashDotDot: [8, 3, 1, 3, 1, 3],
|
|
5835
|
+
sysDash: [3, 1],
|
|
5836
|
+
sysDot: [1, 1],
|
|
5837
|
+
sysDashDot: [3, 1, 1, 1],
|
|
5838
|
+
sysDashDotDot: [3, 1, 1, 1, 1, 1]
|
|
5839
|
+
};
|
|
5840
|
+
var CAP = 4;
|
|
5841
|
+
function strokeAttributes(stroke) {
|
|
5842
|
+
const pattern = stroke.dash ? DASHES[stroke.dash] : void 0;
|
|
5843
|
+
const dash = pattern ? ` stroke-dasharray="${pattern.map((step) => n(step * stroke.width)).join(" ")}"` : "";
|
|
5844
|
+
return `stroke="${esc(stroke.color)}" stroke-width="${n(stroke.width)}"${dash}`;
|
|
5845
|
+
}
|
|
5846
|
+
var segment = (x1, y1, x2, y2, stroke) => `<line x1="${n(x1)}" y1="${n(y1)}" x2="${n(x2)}" y2="${n(y2)}" ${stroke}/>`;
|
|
5847
|
+
function trendlines(series, si, xs, ys, plane, out) {
|
|
5848
|
+
for (const trendline of series.trendlines ?? []) {
|
|
5849
|
+
const fit2 = fitChartTrendline(trendline.fit, xs, ys);
|
|
5850
|
+
if (fit2.points.length < 2) continue;
|
|
5851
|
+
const points = fit2.points.map(({ x, y }) => plane(x, y).map(n).join(",")).join(" ");
|
|
5852
|
+
out.push(
|
|
5853
|
+
`<polyline points="${points}" fill="none" ${strokeAttributes(trendline.stroke)} data-chart-part="trendline" data-chart-series="${si}"/>`
|
|
5854
|
+
);
|
|
5855
|
+
}
|
|
5856
|
+
}
|
|
5857
|
+
function errorBar(bars2, at, values, plane, out) {
|
|
5858
|
+
const stroke = strokeAttributes(bars2.stroke);
|
|
5859
|
+
for (const side of ["plus", "minus"]) {
|
|
5860
|
+
if (bars2.barType !== side && bars2.barType !== "both") continue;
|
|
5861
|
+
const amount = chartErrorBarAmount(bars2.amount, values, at.displayIndex, at.sourceIndex, side);
|
|
5862
|
+
const sign = side === "plus" ? 1 : -1;
|
|
5863
|
+
const [x1, y1] = plane(at.x, at.y);
|
|
5864
|
+
const [x2, y2] = bars2.direction === "x" ? plane(at.x + sign * amount, at.y) : plane(at.x, at.y + sign * amount);
|
|
5865
|
+
out.push(segment(x1, y1, x2, y2, stroke));
|
|
5866
|
+
if (!bars2.endCap) continue;
|
|
5867
|
+
if (x1 === x2) out.push(segment(x2 - CAP, y2, x2 + CAP, y2, stroke));
|
|
5868
|
+
else out.push(segment(x2, y2 - CAP, x2, y2 + CAP, stroke));
|
|
5869
|
+
}
|
|
5870
|
+
}
|
|
5871
|
+
function plottedPoints(series, xOf) {
|
|
5872
|
+
return series.values.flatMap((y, index) => {
|
|
5873
|
+
const x = xOf(index);
|
|
5874
|
+
return y === null || x === null ? [] : [{ x, y, index }];
|
|
5875
|
+
});
|
|
5876
|
+
}
|
|
5877
|
+
function seriesAnalysis(series, si, xOf, plane, barPlane, categoryAxis, out) {
|
|
5878
|
+
const points = plottedPoints(series, xOf);
|
|
5879
|
+
const xs = points.map((p) => p.x);
|
|
5880
|
+
const ys = points.map((p) => p.y);
|
|
5881
|
+
trendlines(series, si, xs, ys, plane, out);
|
|
5882
|
+
for (const bars2 of series.errorBars ?? []) {
|
|
5883
|
+
if (categoryAxis && bars2.direction === "x") continue;
|
|
5884
|
+
const values = bars2.direction === "x" ? xs : ys;
|
|
5885
|
+
points.forEach(
|
|
5886
|
+
(p, displayIndex) => errorBar(bars2, { x: p.x, y: p.y, displayIndex, sourceIndex: p.index }, values, barPlane, out)
|
|
5887
|
+
);
|
|
5888
|
+
}
|
|
5889
|
+
}
|
|
5890
|
+
function categoryAnalysis(model, frame, out) {
|
|
5891
|
+
if (model.grouping === "stacked" || model.grouping === "percentStacked") return;
|
|
5892
|
+
const plane = (x, y) => model.horizontal ? [frame.value(y), frame.band(x - 1)] : [frame.band(x - 1), frame.value(y)];
|
|
5893
|
+
const barred = model.type === "bar" || model.type === "column";
|
|
5894
|
+
const layout = barred ? barLayout(model, frame) : void 0;
|
|
5895
|
+
model.series.forEach((series, si) => {
|
|
5177
5896
|
if (!series.trendlines && !series.errorBars) return;
|
|
5178
5897
|
const shift = layout ? layout.offset(si) + layout.barSize / 2 : 0;
|
|
5179
5898
|
const barPlane = (x, y) => {
|
|
@@ -5191,6 +5910,60 @@ function scatterAnalysis(model, px, py, out) {
|
|
|
5191
5910
|
});
|
|
5192
5911
|
}
|
|
5193
5912
|
|
|
5913
|
+
// chart/render/chart-svg-markers.ts
|
|
5914
|
+
function chartMarkerRadius(series, index, defaultRadius = 3) {
|
|
5915
|
+
const marker = { ...series.marker, ...series.pointMarkers?.[index] };
|
|
5916
|
+
if (marker.symbol === "none") return 0;
|
|
5917
|
+
const radius = markerRadius(marker.size, defaultRadius);
|
|
5918
|
+
return marker.symbol === "dot" ? Math.max(radius * 0.6, 1) : radius;
|
|
5919
|
+
}
|
|
5920
|
+
function chartSeriesMarkerSvg(series, index, cx2, cy, defaultRadius = 3) {
|
|
5921
|
+
const marker = { ...series.marker, ...series.pointMarkers?.[index] };
|
|
5922
|
+
const primitive = buildMarkerPrimitive({
|
|
5923
|
+
...marker,
|
|
5924
|
+
symbol: marker.symbol,
|
|
5925
|
+
size: marker.size,
|
|
5926
|
+
cx: cx2,
|
|
5927
|
+
cy,
|
|
5928
|
+
fill: marker.fill ?? series.pointColors?.[index] ?? series.color,
|
|
5929
|
+
defaultRadius
|
|
5930
|
+
});
|
|
5931
|
+
if (!primitive) return "";
|
|
5932
|
+
let geometry;
|
|
5933
|
+
switch (primitive.kind) {
|
|
5934
|
+
case "circle":
|
|
5935
|
+
geometry = `cx="${n(primitive.cx)}" cy="${n(primitive.cy)}" r="${n(primitive.r)}"`;
|
|
5936
|
+
break;
|
|
5937
|
+
case "rect":
|
|
5938
|
+
geometry = `x="${n(primitive.x)}" y="${n(primitive.y)}" width="${n(primitive.w)}" height="${n(primitive.h)}"`;
|
|
5939
|
+
break;
|
|
5940
|
+
case "path":
|
|
5941
|
+
geometry = `d="${esc(primitive.d)}"`;
|
|
5942
|
+
break;
|
|
5943
|
+
case "polygon":
|
|
5944
|
+
geometry = `points="${esc(primitive.points)}"`;
|
|
5945
|
+
break;
|
|
5946
|
+
}
|
|
5947
|
+
const outline = primitive.stroke ? ` stroke="${esc(primitive.stroke)}" stroke-width="${n(primitive.strokeWidth ?? 1)}"` : "";
|
|
5948
|
+
const filter = series.shadowFilter ? ` filter="${esc(series.shadowFilter)}"` : "";
|
|
5949
|
+
return `<${primitive.kind} ${geometry} fill="${esc(primitive.fill)}"${outline}${filter}/>`;
|
|
5950
|
+
}
|
|
5951
|
+
|
|
5952
|
+
// chart/line-dash.ts
|
|
5953
|
+
function chartLineDashArray(style, width) {
|
|
5954
|
+
if (!style || style === "solid") {
|
|
5955
|
+
return void 0;
|
|
5956
|
+
}
|
|
5957
|
+
const unit = Math.max(width, 1);
|
|
5958
|
+
if (style === "dot" || style === "sysDot") {
|
|
5959
|
+
return `${unit} ${unit * 2}`;
|
|
5960
|
+
}
|
|
5961
|
+
if (style === "lgDash") {
|
|
5962
|
+
return `${unit * 6} ${unit * 3}`;
|
|
5963
|
+
}
|
|
5964
|
+
return `${unit * 3} ${unit * 2}`;
|
|
5965
|
+
}
|
|
5966
|
+
|
|
5194
5967
|
// chart/render/chart-scale.ts
|
|
5195
5968
|
var clean = (n2) => Number(n2.toPrecision(12));
|
|
5196
5969
|
function* units(raw2) {
|
|
@@ -5201,14 +5974,14 @@ function* units(raw2) {
|
|
|
5201
5974
|
exp++;
|
|
5202
5975
|
}
|
|
5203
5976
|
}
|
|
5204
|
-
function niceScale(dataMin, dataMax,
|
|
5205
|
-
const maxIntervals = Math.max(1,
|
|
5977
|
+
function niceScale(dataMin, dataMax, options2 = {}) {
|
|
5978
|
+
const maxIntervals = Math.max(1, options2.maxIntervals ?? 10);
|
|
5206
5979
|
let lo = Number.isFinite(dataMin) ? dataMin : 0;
|
|
5207
5980
|
let hi = Number.isFinite(dataMax) ? dataMax : 0;
|
|
5208
5981
|
if (lo > hi) [lo, hi] = [hi, lo];
|
|
5209
5982
|
if (lo === hi) {
|
|
5210
5983
|
if (lo === 0) hi = 1;
|
|
5211
|
-
else if (
|
|
5984
|
+
else if (options2.noZero) {
|
|
5212
5985
|
const pad = Math.abs(lo) * 0.1 || 1;
|
|
5213
5986
|
lo -= pad;
|
|
5214
5987
|
hi += pad;
|
|
@@ -5217,7 +5990,7 @@ function niceScale(dataMin, dataMax, options = {}) {
|
|
|
5217
5990
|
}
|
|
5218
5991
|
let fixedLo = false;
|
|
5219
5992
|
let fixedHi = false;
|
|
5220
|
-
if (!
|
|
5993
|
+
if (!options2.noZero) {
|
|
5221
5994
|
if (lo >= 0 && hi - lo >= hi / 6) {
|
|
5222
5995
|
lo = 0;
|
|
5223
5996
|
fixedLo = true;
|
|
@@ -5257,196 +6030,327 @@ function formatAxisValue(value, percent = false) {
|
|
|
5257
6030
|
return `${v < 0 ? "-" : ""}${grouped}${frac ? `.${frac}` : ""}`;
|
|
5258
6031
|
}
|
|
5259
6032
|
|
|
5260
|
-
//
|
|
5261
|
-
function
|
|
5262
|
-
|
|
5263
|
-
|
|
5264
|
-
|
|
6033
|
+
// chart/render/chart-svg-axes.ts
|
|
6034
|
+
function axisTickText(value, axis, percent = false) {
|
|
6035
|
+
return formatChartNumber(value, axis?.source.numberFormat?.formatCode) ?? formatAxisValue(value, percent);
|
|
6036
|
+
}
|
|
6037
|
+
function axisLine(model, axis, part, x1, y1, x2, y2) {
|
|
6038
|
+
if (axis?.source.deleted) return "";
|
|
6039
|
+
return styledAxisLine(x1, y1, x2, y2, axis?.line, chartStroke(model, part));
|
|
6040
|
+
}
|
|
6041
|
+
function styledAxisLine(x1, y1, x2, y2, paint2, fallback) {
|
|
6042
|
+
const color = paint2?.color ?? fallback.color;
|
|
6043
|
+
const width = paint2?.width ?? fallback.width;
|
|
6044
|
+
if (color === "none" || width === 0) return "";
|
|
6045
|
+
const dash = chartLineDashArray(paint2?.dash, width);
|
|
6046
|
+
return line(x1, y1, x2, y2, esc(color), width).replace(
|
|
6047
|
+
"/>",
|
|
6048
|
+
dash ? ` stroke-dasharray="${dash}"/>` : "/>"
|
|
5265
6049
|
);
|
|
5266
|
-
|
|
6050
|
+
}
|
|
6051
|
+
function axisGridlines(model, axis, ticks, position, plot, vertical) {
|
|
6052
|
+
const draw2 = (values, paint2, minor2) => {
|
|
6053
|
+
const fallback = chartStroke(model, minor2 ? "gridlineMinor" : "gridlineMajor");
|
|
6054
|
+
return values.map((value) => {
|
|
6055
|
+
const p = position(value);
|
|
6056
|
+
return vertical ? styledAxisLine(p, plot.y, p, plot.y + plot.h, paint2, fallback) : styledAxisLine(plot.x, p, plot.x + plot.w, p, paint2, fallback);
|
|
6057
|
+
}).join("");
|
|
6058
|
+
};
|
|
6059
|
+
const major = !axis || axis.source.majorGridlines ? draw2(ticks, axis?.majorGrid, false) : "";
|
|
6060
|
+
const minor = axis?.source.minorGridlines ? draw2(axis.minorTicks, axis.minorGrid, true) : "";
|
|
6061
|
+
return major + minor;
|
|
5267
6062
|
}
|
|
5268
6063
|
|
|
5269
|
-
//
|
|
5270
|
-
|
|
5271
|
-
|
|
6064
|
+
// chart/axis-range-auto.ts
|
|
6065
|
+
function computeAxisValueRange(series, plotHeightPx) {
|
|
6066
|
+
let dataMin = Number.POSITIVE_INFINITY, dataMax = Number.NEGATIVE_INFINITY;
|
|
6067
|
+
for (const item of series) {
|
|
6068
|
+
for (const value of item.values) {
|
|
6069
|
+
if (value !== null && Number.isFinite(value) && value < dataMin) {
|
|
6070
|
+
dataMin = value;
|
|
6071
|
+
}
|
|
6072
|
+
if (value !== null && Number.isFinite(value) && value > dataMax) {
|
|
6073
|
+
dataMax = value;
|
|
6074
|
+
}
|
|
6075
|
+
}
|
|
6076
|
+
}
|
|
6077
|
+
if (dataMin === Number.POSITIVE_INFINITY) {
|
|
6078
|
+
return { min: 0, max: 1, span: 1 };
|
|
6079
|
+
}
|
|
6080
|
+
const { min, max, majorUnit } = niceValueAxisBounds(
|
|
6081
|
+
dataMin,
|
|
6082
|
+
dataMax,
|
|
6083
|
+
plotHeightPx !== void 0 ? axisTargetIntervals(plotHeightPx) : void 0
|
|
6084
|
+
);
|
|
6085
|
+
return { min, max, span: Math.max(max - min, Number.EPSILON), majorUnit };
|
|
6086
|
+
}
|
|
6087
|
+
function computeAxisStackedValueRange(series, catCount, plotHeightPx) {
|
|
6088
|
+
let maxSum = 0, minSum = 0;
|
|
6089
|
+
for (let ci = 0; ci < catCount; ci++) {
|
|
6090
|
+
let pos = 0, neg = 0;
|
|
6091
|
+
for (const s of series) {
|
|
6092
|
+
const v = s.values[ci] ?? 0;
|
|
6093
|
+
if (v >= 0) {
|
|
6094
|
+
pos += v;
|
|
6095
|
+
} else {
|
|
6096
|
+
neg += v;
|
|
6097
|
+
}
|
|
6098
|
+
}
|
|
6099
|
+
maxSum = Math.max(maxSum, pos);
|
|
6100
|
+
minSum = Math.min(minSum, neg);
|
|
6101
|
+
}
|
|
6102
|
+
const { min, max, majorUnit } = niceValueAxisBounds(
|
|
6103
|
+
Math.min(minSum, 0),
|
|
6104
|
+
Math.max(maxSum, 0),
|
|
6105
|
+
plotHeightPx !== void 0 ? axisTargetIntervals(plotHeightPx) : void 0
|
|
6106
|
+
);
|
|
6107
|
+
return { min, max, span: Math.max(max - min, Number.EPSILON), majorUnit };
|
|
6108
|
+
}
|
|
5272
6109
|
|
|
5273
|
-
//
|
|
5274
|
-
function
|
|
5275
|
-
const
|
|
5276
|
-
if (
|
|
5277
|
-
|
|
5278
|
-
|
|
5279
|
-
|
|
5280
|
-
const
|
|
5281
|
-
const
|
|
5282
|
-
const
|
|
5283
|
-
const
|
|
5284
|
-
const
|
|
5285
|
-
if (!resolved || ![blur, distance, angle].every(Number.isFinite) || blur < 0 || distance < 0)
|
|
5286
|
-
return void 0;
|
|
6110
|
+
// chart/axis-range.ts
|
|
6111
|
+
function computeLogValueRange(series, logBase) {
|
|
6112
|
+
const allValues = series.flatMap((item) => item.values).filter((value) => value !== null && Number.isFinite(value) && value > 0);
|
|
6113
|
+
if (allValues.length === 0) {
|
|
6114
|
+
return { min: 1, max: logBase, span: 1, logScale: true, logBase };
|
|
6115
|
+
}
|
|
6116
|
+
const dataMin = Math.min(...allValues);
|
|
6117
|
+
const dataMax = Math.max(...allValues);
|
|
6118
|
+
const logMin = Math.floor(Math.log(dataMin) / Math.log(logBase));
|
|
6119
|
+
const logMax = Math.ceil(Math.log(dataMax) / Math.log(logBase));
|
|
6120
|
+
const min = logBase ** logMin;
|
|
6121
|
+
const max = logBase ** Math.max(logMax, logMin + 1);
|
|
5287
6122
|
return {
|
|
5288
|
-
|
|
5289
|
-
|
|
5290
|
-
|
|
5291
|
-
|
|
5292
|
-
|
|
6123
|
+
min,
|
|
6124
|
+
max,
|
|
6125
|
+
span: Math.max(Math.log(max) / Math.log(logBase) - Math.log(min) / Math.log(logBase), 1),
|
|
6126
|
+
logScale: true,
|
|
6127
|
+
logBase
|
|
5293
6128
|
};
|
|
5294
6129
|
}
|
|
5295
|
-
function
|
|
5296
|
-
|
|
6130
|
+
function computeValueRangeForAxis(series, axis, plotHeightPx) {
|
|
6131
|
+
const requestedLogBase = axis?.logBase ?? 10;
|
|
6132
|
+
const logBase = axis?.logScale && Number.isFinite(requestedLogBase) && requestedLogBase > 1 ? requestedLogBase : axis?.logScale ? 10 : void 0;
|
|
6133
|
+
const automatic = logBase ? computeLogValueRange(series, logBase) : computeAxisValueRange(series, plotHeightPx);
|
|
6134
|
+
return withAxisBounds(automatic, axis, logBase);
|
|
5297
6135
|
}
|
|
5298
|
-
function
|
|
5299
|
-
|
|
5300
|
-
|
|
6136
|
+
function computeStackedValueRangeForAxis(series, catCount, axis, isPercent, plotSizePx) {
|
|
6137
|
+
if (isPercent) {
|
|
6138
|
+
return {
|
|
6139
|
+
...percentStackedRange(series, catCount, plotSizePx),
|
|
6140
|
+
...axis?.orientation === "maxMin" ? { reverseOrder: true } : {}
|
|
6141
|
+
};
|
|
6142
|
+
}
|
|
6143
|
+
return withAxisBounds(computeAxisStackedValueRange(series, catCount, plotSizePx), axis);
|
|
5301
6144
|
}
|
|
5302
|
-
|
|
5303
|
-
|
|
5304
|
-
|
|
5305
|
-
|
|
5306
|
-
|
|
5307
|
-
|
|
5308
|
-
|
|
5309
|
-
|
|
5310
|
-
|
|
5311
|
-
|
|
5312
|
-
|
|
5313
|
-
|
|
5314
|
-
|
|
5315
|
-
|
|
5316
|
-
|
|
5317
|
-
|
|
5318
|
-
|
|
5319
|
-
|
|
5320
|
-
|
|
5321
|
-
|
|
5322
|
-
"44546A",
|
|
5323
|
-
"4472C4",
|
|
5324
|
-
"ED7D31",
|
|
5325
|
-
"A5A5A5",
|
|
5326
|
-
"FFC000",
|
|
5327
|
-
"5B9BD5",
|
|
5328
|
-
"70AD47",
|
|
5329
|
-
"0563C1",
|
|
5330
|
-
"954F72"
|
|
5331
|
-
];
|
|
5332
|
-
function themeColor(theme, index) {
|
|
5333
|
-
const hex = theme.colors[index] ?? DEFAULT_THEME_COLORS[index];
|
|
5334
|
-
return hex && parseArgbHex(hex) ? hex.replace(/^#/, "") : void 0;
|
|
6145
|
+
function percentStackedRange(series, catCount, plotSizePx) {
|
|
6146
|
+
const shares = series.map((entry3) => ({
|
|
6147
|
+
...entry3,
|
|
6148
|
+
values: Array.from({ length: catCount }, (_, ci) => {
|
|
6149
|
+
const total = series.reduce((sum, s) => sum + Math.abs(s.values[ci] ?? 0), 0);
|
|
6150
|
+
return total > 0 ? (entry3.values[ci] ?? 0) / total * 100 : 0;
|
|
6151
|
+
})
|
|
6152
|
+
}));
|
|
6153
|
+
const automatic = computeAxisStackedValueRange(shares, catCount, plotSizePx);
|
|
6154
|
+
if (automatic.min >= 0) {
|
|
6155
|
+
return { min: 0, max: 100, span: 100 };
|
|
6156
|
+
}
|
|
6157
|
+
const min = Math.max(automatic.min, -100);
|
|
6158
|
+
const unit = automatic.majorUnit;
|
|
6159
|
+
return {
|
|
6160
|
+
min,
|
|
6161
|
+
max: 100,
|
|
6162
|
+
span: 100 - min,
|
|
6163
|
+
...unit !== void 0 && 100 % unit === 0 && min % unit === 0 ? { majorUnit: unit } : {}
|
|
6164
|
+
};
|
|
5335
6165
|
}
|
|
5336
|
-
|
|
5337
|
-
|
|
5338
|
-
|
|
5339
|
-
const
|
|
5340
|
-
|
|
5341
|
-
|
|
6166
|
+
function withAxisBounds(automatic, axis, logBase) {
|
|
6167
|
+
const validMin = typeof axis?.min === "number" && Number.isFinite(axis.min) && (!logBase || axis.min > 0) ? axis.min : void 0;
|
|
6168
|
+
const validMax = typeof axis?.max === "number" && Number.isFinite(axis.max) && (!logBase || axis.max > 0) ? axis.max : void 0;
|
|
6169
|
+
const min = validMin ?? automatic.min;
|
|
6170
|
+
let max = validMax ?? automatic.max;
|
|
6171
|
+
const majorUnit = validMin === void 0 && validMax === void 0 ? automatic.majorUnit : void 0;
|
|
6172
|
+
if (max <= min) {
|
|
6173
|
+
max = logBase ? min * logBase : min + 1;
|
|
6174
|
+
}
|
|
6175
|
+
const span = logBase ? Math.log(max) / Math.log(logBase) - Math.log(min) / Math.log(logBase) : max - min;
|
|
5342
6176
|
return {
|
|
5343
|
-
|
|
5344
|
-
|
|
5345
|
-
|
|
5346
|
-
|
|
5347
|
-
|
|
6177
|
+
min,
|
|
6178
|
+
max,
|
|
6179
|
+
span: Math.max(span, Number.EPSILON),
|
|
6180
|
+
...majorUnit !== void 0 ? { majorUnit } : {},
|
|
6181
|
+
...logBase ? { logScale: true, logBase } : {},
|
|
6182
|
+
...axis?.orientation === "maxMin" ? { reverseOrder: true } : {}
|
|
5348
6183
|
};
|
|
5349
6184
|
}
|
|
5350
|
-
function
|
|
5351
|
-
const
|
|
5352
|
-
|
|
5353
|
-
|
|
5354
|
-
const
|
|
5355
|
-
|
|
5356
|
-
|
|
5357
|
-
|
|
6185
|
+
function valueToYLog(val, range, topY, bottomY) {
|
|
6186
|
+
const base = range.logBase ?? 10;
|
|
6187
|
+
const logValue = Math.log(Math.max(val, range.min)) / Math.log(base);
|
|
6188
|
+
const logMin = Math.log(range.min) / Math.log(base);
|
|
6189
|
+
const ratio = (logValue - logMin) / range.span;
|
|
6190
|
+
return range.reverseOrder ? topY + ratio * (bottomY - topY) : bottomY - ratio * (bottomY - topY);
|
|
6191
|
+
}
|
|
6192
|
+
function findLogAxis(axes) {
|
|
6193
|
+
return axes?.find((axis) => axis.axisType === "valAx" && axis.logScale);
|
|
6194
|
+
}
|
|
6195
|
+
function computeValueRangeForChart(series, axes, plotHeightPx) {
|
|
6196
|
+
const primaryAxis = axes?.find((axis) => axis.axisType === "valAx" && axis.axPos === "l") ?? axes?.find((axis) => axis.axisType === "valAx" && axis.axPos !== "r");
|
|
6197
|
+
return computeValueRangeForAxis(series, primaryAxis, plotHeightPx);
|
|
6198
|
+
}
|
|
6199
|
+
|
|
6200
|
+
// chart/axis-ticks.ts
|
|
6201
|
+
var LOG_EXPONENT_TOLERANCE = 1e-12;
|
|
6202
|
+
function generateLogTicks(range) {
|
|
6203
|
+
if (!range.logScale || !range.logBase) {
|
|
6204
|
+
return [];
|
|
6205
|
+
}
|
|
6206
|
+
const base = range.logBase;
|
|
6207
|
+
const logMin = Math.log(range.min) / Math.log(base);
|
|
6208
|
+
const logMax = Math.log(range.max) / Math.log(base);
|
|
6209
|
+
const firstExponent = Math.ceil(logMin - LOG_EXPONENT_TOLERANCE);
|
|
6210
|
+
const lastExponent = Math.floor(logMax + LOG_EXPONENT_TOLERANCE);
|
|
6211
|
+
if (lastExponent < firstExponent) {
|
|
6212
|
+
return range.min === range.max ? [range.min] : [range.min, range.max];
|
|
6213
|
+
}
|
|
6214
|
+
return Array.from(
|
|
6215
|
+
{ length: lastExponent - firstExponent + 1 },
|
|
6216
|
+
(_unused, index) => base ** (firstExponent + index)
|
|
6217
|
+
);
|
|
6218
|
+
}
|
|
6219
|
+
function generateIntervalTicks(range, unit) {
|
|
6220
|
+
if (!Number.isFinite(unit) || unit <= 0 || range.logScale) {
|
|
6221
|
+
return [];
|
|
6222
|
+
}
|
|
6223
|
+
const tolerance = Math.max(1, Math.abs(range.min), Math.abs(range.max)) * 1e-12;
|
|
6224
|
+
const first2 = Math.ceil((range.min - tolerance) / unit);
|
|
6225
|
+
const last = Math.floor((range.max + tolerance) / unit);
|
|
6226
|
+
const count = Math.min(Math.max(last - first2 + 1, 0), 2e3);
|
|
6227
|
+
return Array.from({ length: count }, (_, index) => (first2 + index) * unit);
|
|
5358
6228
|
}
|
|
5359
|
-
function
|
|
5360
|
-
|
|
5361
|
-
|
|
6229
|
+
function generateAxisTicks(range, axis, defaultIntervals) {
|
|
6230
|
+
if (range.logScale && range.logBase) {
|
|
6231
|
+
return generateLogTicks(range);
|
|
6232
|
+
}
|
|
6233
|
+
const explicit = generateIntervalTicks(range, axis?.majorUnit ?? 0);
|
|
6234
|
+
if (explicit.length > 0) {
|
|
6235
|
+
return explicit;
|
|
6236
|
+
}
|
|
6237
|
+
const automatic = generateIntervalTicks(range, range.majorUnit ?? 0);
|
|
6238
|
+
if (automatic.length > 0) {
|
|
6239
|
+
return automatic;
|
|
6240
|
+
}
|
|
6241
|
+
return Array.from(
|
|
6242
|
+
{ length: defaultIntervals + 1 },
|
|
6243
|
+
(_, index) => range.min + range.span / defaultIntervals * index
|
|
6244
|
+
);
|
|
5362
6245
|
}
|
|
5363
|
-
|
|
5364
|
-
|
|
5365
|
-
|
|
5366
|
-
|
|
5367
|
-
"bold",
|
|
5368
|
-
"italic",
|
|
5369
|
-
"underline",
|
|
5370
|
-
"typeface",
|
|
5371
|
-
"textColor",
|
|
5372
|
-
"fontRef"
|
|
5373
|
-
];
|
|
5374
|
-
var TEXT_PARTS = [
|
|
5375
|
-
"title",
|
|
5376
|
-
"axisTitle",
|
|
5377
|
-
"categoryAxis",
|
|
5378
|
-
"valueAxis",
|
|
5379
|
-
"legend",
|
|
5380
|
-
"dataLabel"
|
|
5381
|
-
];
|
|
5382
|
-
function inheritChartText(part, entry3, builtIn, root) {
|
|
5383
|
-
if (!root || !TEXT_PARTS.includes(part)) return entry3;
|
|
5384
|
-
const out = { ...entry3 };
|
|
5385
|
-
for (const key of TEXT_KEYS) {
|
|
5386
|
-
delete out[key];
|
|
5387
|
-
const value = root[key] ?? builtIn?.[key];
|
|
5388
|
-
if (value !== void 0) Object.assign(out, { [key]: value });
|
|
6246
|
+
function generateMinorAxisTicks(range, axis) {
|
|
6247
|
+
const minor = generateIntervalTicks(range, axis?.minorUnit ?? 0);
|
|
6248
|
+
if (minor.length === 0) {
|
|
6249
|
+
return [];
|
|
5389
6250
|
}
|
|
5390
|
-
|
|
5391
|
-
if (
|
|
5392
|
-
|
|
6251
|
+
const majorUnit = axis?.majorUnit;
|
|
6252
|
+
if (!majorUnit || !Number.isFinite(majorUnit) || majorUnit <= 0) {
|
|
6253
|
+
return minor;
|
|
6254
|
+
}
|
|
6255
|
+
const tolerance = Math.max(1, Math.abs(range.min), Math.abs(range.max)) * 1e-10;
|
|
6256
|
+
return minor.filter(
|
|
6257
|
+
(value) => Math.abs(value / majorUnit - Math.round(value / majorUnit)) > tolerance
|
|
6258
|
+
);
|
|
5393
6259
|
}
|
|
5394
6260
|
|
|
5395
|
-
// chart/render/chart-
|
|
5396
|
-
|
|
5397
|
-
|
|
5398
|
-
const
|
|
5399
|
-
|
|
5400
|
-
if (name?.startsWith("+mn-")) return theme.minorFont;
|
|
5401
|
-
return name ?? (entry3.fontRef?.index === "major" ? theme.majorFont : entry3.fontRef?.index === "minor" ? theme.minorFont : void 0);
|
|
6261
|
+
// chart/render/chart-view-axes.ts
|
|
6262
|
+
function chartAxisRatio(value, scale, axis) {
|
|
6263
|
+
const range = axis?.range;
|
|
6264
|
+
const ratio = range?.logScale ? Math.log(Math.max(value, range.min) / range.min) / Math.log(range.max / range.min) : (value - scale.min) / (scale.max - scale.min || 1);
|
|
6265
|
+
return range?.reverseOrder ? 1 - ratio : ratio;
|
|
5402
6266
|
}
|
|
5403
|
-
function
|
|
5404
|
-
|
|
5405
|
-
|
|
5406
|
-
|
|
5407
|
-
|
|
5408
|
-
|
|
5409
|
-
|
|
5410
|
-
|
|
5411
|
-
|
|
5412
|
-
|
|
5413
|
-
|
|
5414
|
-
|
|
5415
|
-
|
|
5416
|
-
|
|
5417
|
-
|
|
5418
|
-
|
|
5419
|
-
|
|
5420
|
-
|
|
5421
|
-
|
|
5422
|
-
|
|
5423
|
-
const scheme = chartColorScheme(theme);
|
|
5424
|
-
const resolve = (color) => resolveDrawingColor(
|
|
5425
|
-
color,
|
|
5426
|
-
{ scheme: (name) => scheme[name] },
|
|
5427
|
-
{ hslRounding: "halfDown", transformOrder: "document" }
|
|
6267
|
+
function chartAxisLabels(axis) {
|
|
6268
|
+
return axis?.source.deleted !== true && axis?.source.tickLabelPosition !== "none";
|
|
6269
|
+
}
|
|
6270
|
+
function options(axis) {
|
|
6271
|
+
return {
|
|
6272
|
+
...axis.scaling,
|
|
6273
|
+
...axis.scaling.logBase === void 0 ? {} : { logScale: true },
|
|
6274
|
+
...axis.majorUnit === void 0 ? {} : { majorUnit: axis.majorUnit },
|
|
6275
|
+
...axis.minorUnit === void 0 ? {} : { minorUnit: axis.minorUnit }
|
|
6276
|
+
};
|
|
6277
|
+
}
|
|
6278
|
+
function applyChartAxes(model, chart, color) {
|
|
6279
|
+
if (!chart.axes?.length) return;
|
|
6280
|
+
const axes = chart.axes;
|
|
6281
|
+
const linked = axes.filter((axis) => axis.id !== void 0 && chart.axisIds?.includes(axis.id));
|
|
6282
|
+
const candidates = linked.length ? linked : axes;
|
|
6283
|
+
const xy = model.type === "scatter" || model.type === "bubble";
|
|
6284
|
+
const value = candidates.find((axis) => axis.kind === "val" && !["b", "t"].includes(axis.position ?? "")) ?? candidates.find((axis) => axis.kind === "val");
|
|
6285
|
+
const category = candidates.find(
|
|
6286
|
+
(axis) => xy ? axis.kind === "val" && axis !== value : axis.kind === "cat" || axis.kind === "date"
|
|
5428
6287
|
);
|
|
5429
|
-
const
|
|
5430
|
-
|
|
5431
|
-
|
|
5432
|
-
|
|
5433
|
-
|
|
5434
|
-
|
|
5435
|
-
|
|
5436
|
-
|
|
5437
|
-
|
|
5438
|
-
|
|
5439
|
-
|
|
5440
|
-
|
|
5441
|
-
|
|
5442
|
-
|
|
5443
|
-
|
|
5444
|
-
|
|
5445
|
-
|
|
5446
|
-
|
|
6288
|
+
const secondary = axes.find((axis) => axis.kind === "val" && axis !== value && axis !== category);
|
|
6289
|
+
const paint2 = (shape) => {
|
|
6290
|
+
const ln = shape?.line;
|
|
6291
|
+
const fill = ln?.fill;
|
|
6292
|
+
const resolved = fill?.kind === "none" ? "none" : color(fill?.kind === "solid" ? fill.color : void 0);
|
|
6293
|
+
return {
|
|
6294
|
+
...resolved === void 0 ? {} : { color: resolved },
|
|
6295
|
+
...ln?.widthEmu === void 0 ? {} : { width: ln.widthEmu / EMU_PER_PIXEL },
|
|
6296
|
+
...ln?.dash === void 0 ? {} : { dash: ln.dash }
|
|
6297
|
+
};
|
|
6298
|
+
};
|
|
6299
|
+
const bind = (axis, scale, values) => {
|
|
6300
|
+
const opts = options(axis);
|
|
6301
|
+
const automatic = opts.logScale ? computeLogValueRange(
|
|
6302
|
+
[{ values: values ?? [] }],
|
|
6303
|
+
opts.logBase && Number.isFinite(opts.logBase) && opts.logBase > 1 ? opts.logBase : 10
|
|
6304
|
+
) : {
|
|
6305
|
+
min: scale?.min ?? 0,
|
|
6306
|
+
max: scale?.max ?? 1,
|
|
6307
|
+
span: (scale?.max ?? 1) - (scale?.min ?? 0),
|
|
6308
|
+
...scale ? { majorUnit: scale.majorUnit } : {}
|
|
6309
|
+
};
|
|
6310
|
+
const logBase = automatic.logBase;
|
|
6311
|
+
const range = withAxisBounds(automatic, opts, logBase);
|
|
6312
|
+
if (scale) {
|
|
6313
|
+
scale.min = range.min;
|
|
6314
|
+
scale.max = range.max;
|
|
6315
|
+
scale.ticks = generateAxisTicks(range, opts, 5);
|
|
5447
6316
|
}
|
|
5448
|
-
|
|
5449
|
-
|
|
6317
|
+
return {
|
|
6318
|
+
source: axis,
|
|
6319
|
+
range,
|
|
6320
|
+
minorTicks: generateMinorAxisTicks(range, opts),
|
|
6321
|
+
line: paint2(axis.spPr),
|
|
6322
|
+
majorGrid: paint2(axis.majorGridlinesSpPr),
|
|
6323
|
+
minorGrid: paint2(axis.minorGridlinesSpPr)
|
|
6324
|
+
};
|
|
6325
|
+
};
|
|
6326
|
+
const out = {};
|
|
6327
|
+
if (value)
|
|
6328
|
+
out.value = bind(
|
|
6329
|
+
value,
|
|
6330
|
+
model.valueAxis,
|
|
6331
|
+
[
|
|
6332
|
+
...model.series,
|
|
6333
|
+
...model.extraGroups?.filter((g) => !g.secondary).flatMap((g) => g.series) ?? []
|
|
6334
|
+
].flatMap((s) => s.values)
|
|
6335
|
+
);
|
|
6336
|
+
if (category)
|
|
6337
|
+
out.category = bind(
|
|
6338
|
+
category,
|
|
6339
|
+
model.xAxis ?? {
|
|
6340
|
+
min: 0,
|
|
6341
|
+
max: Math.max(1, model.categories.length - 1),
|
|
6342
|
+
majorUnit: 1,
|
|
6343
|
+
ticks: []
|
|
6344
|
+
},
|
|
6345
|
+
model.series.flatMap((s) => s.xValues ?? [])
|
|
6346
|
+
);
|
|
6347
|
+
if (secondary)
|
|
6348
|
+
out.secondary = bind(
|
|
6349
|
+
secondary,
|
|
6350
|
+
model.secondaryAxis,
|
|
6351
|
+
model.extraGroups?.filter((g) => g.secondary).flatMap((g) => g.series.flatMap((s) => s.values))
|
|
6352
|
+
);
|
|
6353
|
+
model.axes = out;
|
|
5450
6354
|
}
|
|
5451
6355
|
|
|
5452
6356
|
// chart/render/chart-view-analysis.ts
|
|
@@ -5498,15 +6402,15 @@ function seriesName(series, index, evaluateRef) {
|
|
|
5498
6402
|
const fromRef = resolveRef(series.nameRef, evaluateRef)?.map(toText).filter((t) => t !== "").join(" ");
|
|
5499
6403
|
return fromRef || series.name || `Series${index + 1}`;
|
|
5500
6404
|
}
|
|
5501
|
-
function seriesContext(chart, theme,
|
|
6405
|
+
function seriesContext(chart, theme, options2) {
|
|
5502
6406
|
const scheme = chartColorScheme(theme);
|
|
5503
6407
|
const resolver = { scheme: (name) => scheme[name] };
|
|
5504
6408
|
return {
|
|
5505
6409
|
theme,
|
|
5506
6410
|
scheme,
|
|
5507
6411
|
palette: chart.colorPalette === void 0 ? void 0 : findChartColorPalette(chart.colorPalette),
|
|
5508
|
-
evaluateRef:
|
|
5509
|
-
seriesColor:
|
|
6412
|
+
evaluateRef: options2.evaluateRef ?? (() => []),
|
|
6413
|
+
seriesColor: options2.seriesColor,
|
|
5510
6414
|
drawingColor: (color) => color && drawingColorCss(resolveDrawingColor(color, resolver, { transformOrder: "document" })),
|
|
5511
6415
|
gradient: (fill) => fill?.kind === "gradient" ? resolveChartGradient(
|
|
5512
6416
|
fill,
|
|
@@ -5532,7 +6436,11 @@ function seriesView(ctx, s, index, total, categoriesOf) {
|
|
|
5532
6436
|
})
|
|
5533
6437
|
);
|
|
5534
6438
|
if (Object.keys(points).length) view.pointGradients = points;
|
|
5535
|
-
Object.assign(
|
|
6439
|
+
Object.assign(
|
|
6440
|
+
view,
|
|
6441
|
+
analysisView(s, color, ctx.drawingColor),
|
|
6442
|
+
seriesMarkerViews(s, ctx.drawingColor)
|
|
6443
|
+
);
|
|
5536
6444
|
return view;
|
|
5537
6445
|
}
|
|
5538
6446
|
|
|
@@ -5705,6 +6613,64 @@ function chartTitleText(chart, theme) {
|
|
|
5705
6613
|
};
|
|
5706
6614
|
}
|
|
5707
6615
|
|
|
6616
|
+
// chart/render/chart-view-labels.ts
|
|
6617
|
+
function labelsOf(source, view, categories, numberFormat2) {
|
|
6618
|
+
const { chart, series, points } = source;
|
|
6619
|
+
if ((series?.deleted ?? chart?.deleted) === true) return void 0;
|
|
6620
|
+
const percentBase = view.values.reduce(
|
|
6621
|
+
(sum, v) => sum + (v === null ? 0 : Math.abs(v)),
|
|
6622
|
+
0
|
|
6623
|
+
);
|
|
6624
|
+
const out = [];
|
|
6625
|
+
let any = false;
|
|
6626
|
+
view.values.forEach((value, i) => {
|
|
6627
|
+
const point = points?.[i];
|
|
6628
|
+
if (value === null || point?.deleted === true) return;
|
|
6629
|
+
const position = point?.position ?? series?.position ?? chart?.position;
|
|
6630
|
+
const x = view.xValues?.[i];
|
|
6631
|
+
const category = x === void 0 || x === null ? categories[i] : formatAxisValue(x);
|
|
6632
|
+
let built;
|
|
6633
|
+
if (point?.text !== void 0) built = { text: point.text };
|
|
6634
|
+
else {
|
|
6635
|
+
const flags = resolveDataLabelFlags({
|
|
6636
|
+
...point ? { point } : {},
|
|
6637
|
+
...series ? { series } : {},
|
|
6638
|
+
...chart ? { chart } : {}
|
|
6639
|
+
});
|
|
6640
|
+
built = composeDataLabelText({
|
|
6641
|
+
flags,
|
|
6642
|
+
seriesName: view.name,
|
|
6643
|
+
category,
|
|
6644
|
+
value,
|
|
6645
|
+
numberFormat: point?.numberFormat ?? series?.numberFormat ?? chart?.numberFormat ?? numberFormat2,
|
|
6646
|
+
percentBase,
|
|
6647
|
+
bubbleSize: view.sizes?.[i] ?? void 0,
|
|
6648
|
+
formatValue: (v) => formatAxisValue(v),
|
|
6649
|
+
formatBubbleSize: (size) => formatAxisValue(size)
|
|
6650
|
+
});
|
|
6651
|
+
}
|
|
6652
|
+
if (!built) return;
|
|
6653
|
+
any = true;
|
|
6654
|
+
out[i] = {
|
|
6655
|
+
text: built.text,
|
|
6656
|
+
...position ? { position } : {},
|
|
6657
|
+
...built.color ? { color: built.color } : {}
|
|
6658
|
+
};
|
|
6659
|
+
});
|
|
6660
|
+
return any ? out : void 0;
|
|
6661
|
+
}
|
|
6662
|
+
function applyDataLabels(model, sources, extra) {
|
|
6663
|
+
const apply = (source, view) => {
|
|
6664
|
+
if (!source?.dataLabels) return;
|
|
6665
|
+
const labels = labelsOf(source.dataLabels, view, model.categories, source.numberFormat);
|
|
6666
|
+
if (labels) view.labels = labels;
|
|
6667
|
+
};
|
|
6668
|
+
model.series.forEach((view, i) => apply(sources[i], view));
|
|
6669
|
+
model.extraGroups?.forEach(
|
|
6670
|
+
(group2, g) => group2.series.forEach((view, i) => apply(extra[g]?.series[i], view))
|
|
6671
|
+
);
|
|
6672
|
+
}
|
|
6673
|
+
|
|
5708
6674
|
// chart/render/chart-view-ex.ts
|
|
5709
6675
|
function groupsAxis(groups, categories) {
|
|
5710
6676
|
let min = Infinity;
|
|
@@ -5774,11 +6740,11 @@ function histogramView(chart, model) {
|
|
|
5774
6740
|
const first2 = model.series[0];
|
|
5775
6741
|
if (!first2) return;
|
|
5776
6742
|
const raw2 = first2.values.map((v) => v ?? Number.NaN);
|
|
5777
|
-
const
|
|
5778
|
-
const bins =
|
|
6743
|
+
const options2 = chart.histogram ?? {};
|
|
6744
|
+
const bins = options2.aggregateByCategory ? aggregateByCategory(
|
|
5779
6745
|
first2.values.map((v) => v ?? 0),
|
|
5780
6746
|
model.categories
|
|
5781
|
-
) : computeHistogramBins(raw2,
|
|
6747
|
+
) : computeHistogramBins(raw2, options2, formatAxisValue);
|
|
5782
6748
|
model.categories = bins.map((bin) => bin.label);
|
|
5783
6749
|
first2.values = bins.map((bin) => bin.value);
|
|
5784
6750
|
model.barGapWidth = 0;
|
|
@@ -5802,11 +6768,11 @@ var SUPPORTED = /* @__PURE__ */ new Set([
|
|
|
5802
6768
|
"treemap",
|
|
5803
6769
|
"sunburst"
|
|
5804
6770
|
]);
|
|
5805
|
-
function chartSummaryView(chart, theme,
|
|
6771
|
+
function chartSummaryView(chart, theme, options2 = {}) {
|
|
5806
6772
|
const type = chart.chartType;
|
|
5807
6773
|
const radial = type === "pie" || type === "doughnut";
|
|
5808
6774
|
const byPoint = radial || type === "treemap" || type === "sunburst";
|
|
5809
|
-
const ctx = seriesContext(chart, theme,
|
|
6775
|
+
const ctx = seriesContext(chart, theme, options2);
|
|
5810
6776
|
const { palette, scheme, drawingColor } = ctx;
|
|
5811
6777
|
const grouping = chart.grouping ?? (type === "bar" || type === "column" ? "clustered" : "standard");
|
|
5812
6778
|
const rawCategories = [];
|
|
@@ -5890,128 +6856,23 @@ function chartSummaryView(chart, theme, options = {}) {
|
|
|
5890
6856
|
chartExtraView(chart, model, ctx, total, collect);
|
|
5891
6857
|
if (type === "waterfall") waterfallView(chart, model, ctx);
|
|
5892
6858
|
else if (!byPoint) model.valueAxis = valueAxis(model);
|
|
6859
|
+
applyDataLabels(model, chart.series, extra);
|
|
5893
6860
|
chartExtraAxes(model);
|
|
6861
|
+
applyChartAxes(model, chart, ctx.drawingColor);
|
|
5894
6862
|
return model;
|
|
5895
6863
|
}
|
|
5896
6864
|
|
|
5897
|
-
// text/css-font-family.ts
|
|
5898
|
-
var FALLBACKS = {
|
|
5899
|
-
calibri: '"Calibri", "Carlito", "Segoe UI", Arial, sans-serif',
|
|
5900
|
-
"calibri light": '"Calibri Light", "Calibri", "Carlito", "Segoe UI", Arial, sans-serif',
|
|
5901
|
-
cambria: '"Cambria", "Caladea", Georgia, serif',
|
|
5902
|
-
arial: 'Arial, "Liberation Sans", Helvetica, sans-serif',
|
|
5903
|
-
"times new roman": '"Times New Roman", "Liberation Serif", Times, serif',
|
|
5904
|
-
"courier new": '"Courier New", "Liberation Mono", monospace',
|
|
5905
|
-
aptos: '"Aptos", "Calibri", "Carlito", "Segoe UI", sans-serif'
|
|
5906
|
-
};
|
|
5907
|
-
function cssFontFamily(name) {
|
|
5908
|
-
const known = FALLBACKS[name.toLowerCase()];
|
|
5909
|
-
if (known) return known;
|
|
5910
|
-
const quoted = `"${name.replace(/["\\]/g, "")}"`;
|
|
5911
|
-
return `${quoted}, "Calibri", "Carlito", "Segoe UI", sans-serif`;
|
|
5912
|
-
}
|
|
5913
|
-
|
|
5914
|
-
// chart/render/chart-svg-appearance.ts
|
|
5915
|
-
var nextPaintId = 0;
|
|
5916
|
-
function chartGradientPaint(model, width = 1024, height = 768) {
|
|
5917
|
-
const prefix = `xlsx-chart-${++nextPaintId}`;
|
|
5918
|
-
const appearance = { ...model.appearance };
|
|
5919
|
-
const defs = [];
|
|
5920
|
-
const shadowPaint = (shadow, suffix) => {
|
|
5921
|
-
const id = `${prefix}-${suffix}`;
|
|
5922
|
-
const pad = Math.max(4, shadow.blur * 3 + Math.abs(shadow.dx) + Math.abs(shadow.dy));
|
|
5923
|
-
defs.push(
|
|
5924
|
-
`<filter id="${id}" filterUnits="userSpaceOnUse" x="${n(-pad)}" y="${n(-pad)}" width="${n(width + pad * 2)}" height="${n(height + pad * 2)}" color-interpolation-filters="sRGB">${svgDropShadowElement(shadow, { number: n, color: (value) => esc(value) })}</filter>`
|
|
5925
|
-
);
|
|
5926
|
-
return `url(#${id})`;
|
|
5927
|
-
};
|
|
5928
|
-
for (const [part, entry3] of Object.entries(appearance)) {
|
|
5929
|
-
if (entry3?.textShadow)
|
|
5930
|
-
appearance[part] = {
|
|
5931
|
-
...entry3,
|
|
5932
|
-
textShadowFilter: shadowPaint(entry3.textShadow, `${part}-text-shadow`)
|
|
5933
|
-
};
|
|
5934
|
-
}
|
|
5935
|
-
const paint2 = (gradient, suffix, bounds) => {
|
|
5936
|
-
const def = buildChartGradientDef(`${prefix}-${suffix}`, gradient, bounds);
|
|
5937
|
-
defs.push(chartGradientMarkup(def));
|
|
5938
|
-
return `url(#${def.id})`;
|
|
5939
|
-
};
|
|
5940
|
-
for (const part of ["chartArea", "plotArea"]) {
|
|
5941
|
-
const entry3 = appearance[part];
|
|
5942
|
-
if (!entry3?.gradient) continue;
|
|
5943
|
-
if (part === "plotArea" && ["circle", "shape"].includes(entry3.gradient.path ?? "")) continue;
|
|
5944
|
-
appearance[part] = {
|
|
5945
|
-
...entry3,
|
|
5946
|
-
fillColor: paint2(entry3.gradient, part, { width, height, shape: "rect" })
|
|
5947
|
-
};
|
|
5948
|
-
}
|
|
5949
|
-
const series = model.series.map((source, index) => {
|
|
5950
|
-
const view = { ...source };
|
|
5951
|
-
if (source.shadow) view.shadowFilter = shadowPaint(source.shadow, `s${index}-shadow`);
|
|
5952
|
-
const bounds = model.type === "bar" || model.type === "column" ? { width: 1, height: 1, shape: "rect" } : void 0;
|
|
5953
|
-
if (source.gradient) view.color = paint2(source.gradient, `s${index}`, bounds);
|
|
5954
|
-
if (source.pointGradients) {
|
|
5955
|
-
view.pointColors = [...source.pointColors ?? []];
|
|
5956
|
-
for (const [key, gradient] of Object.entries(source.pointGradients))
|
|
5957
|
-
view.pointColors[Number(key)] = paint2(gradient, `s${index}-p${key}`, bounds);
|
|
5958
|
-
}
|
|
5959
|
-
return view;
|
|
5960
|
-
});
|
|
5961
|
-
return defs.length ? { model: { ...model, appearance, series }, defs: `<defs>${defs.join("")}</defs>` } : { model, defs: "" };
|
|
5962
|
-
}
|
|
5963
|
-
function chartTextAttributes(model, part, fallbackSize = FONT_SIZE) {
|
|
5964
|
-
const entry3 = model.appearance?.[part];
|
|
5965
|
-
return {
|
|
5966
|
-
size: entry3?.fontSize === void 0 ? fallbackSize : chartPointsToPixels(entry3.fontSize),
|
|
5967
|
-
...entry3?.color === void 0 ? {} : { fill: entry3.color },
|
|
5968
|
-
...entry3?.bold === void 0 ? {} : { weight: entry3.bold ? "bold" : "normal" },
|
|
5969
|
-
...entry3?.italic === void 0 ? {} : { italic: entry3.italic },
|
|
5970
|
-
...entry3?.underline === void 0 ? {} : { underline: entry3.underline },
|
|
5971
|
-
...entry3?.typeface === void 0 ? {} : { family: cssFontFamily(entry3.typeface) },
|
|
5972
|
-
...entry3?.textShadowFilter === void 0 ? {} : { filter: entry3.textShadowFilter }
|
|
5973
|
-
};
|
|
5974
|
-
}
|
|
5975
|
-
function chartStroke(model, part) {
|
|
5976
|
-
const entry3 = model.appearance?.[part];
|
|
5977
|
-
return {
|
|
5978
|
-
color: entry3?.axisVisible === false ? "none" : entry3?.lineColor ?? (part === "gridlineMajor" ? GRID_COLOR : AXIS_COLOR),
|
|
5979
|
-
width: entry3?.lineWidth === void 0 ? 1 : chartPointsToPixels(entry3.lineWidth)
|
|
5980
|
-
};
|
|
5981
|
-
}
|
|
5982
|
-
function chartAreaRect(model, part, area) {
|
|
5983
|
-
if (area.w <= 0 || area.h <= 0) return "";
|
|
5984
|
-
const entry3 = model.appearance?.[part];
|
|
5985
|
-
let fill = entry3?.fillColor ?? (part === "chartArea" ? "#FFFFFF" : "none");
|
|
5986
|
-
let defs = "";
|
|
5987
|
-
if (part !== "chartArea" && entry3?.gradient && (part !== "plotArea" || ["circle", "shape"].includes(entry3.gradient.path ?? ""))) {
|
|
5988
|
-
const def = buildChartGradientDef(`xlsx-chart-${++nextPaintId}-${part}`, entry3.gradient, {
|
|
5989
|
-
width: area.w,
|
|
5990
|
-
height: area.h,
|
|
5991
|
-
shape: "rect"
|
|
5992
|
-
});
|
|
5993
|
-
defs = `<defs>${chartGradientMarkup(def)}</defs>`;
|
|
5994
|
-
fill = `url(#${def.id})`;
|
|
5995
|
-
}
|
|
5996
|
-
const stroke = entry3?.lineColor ?? "none";
|
|
5997
|
-
if (fill === "none" && stroke === "none") return "";
|
|
5998
|
-
const width = entry3?.lineWidth === void 0 ? 1 : chartPointsToPixels(entry3.lineWidth);
|
|
5999
|
-
return `${defs}<rect x="${n(area.x)}" y="${n(area.y)}" width="${n(area.w)}" height="${n(area.h)}" fill="${esc(fill)}" stroke="${esc(stroke)}" stroke-width="${n(width)}" data-chart-part="${part}"/>`;
|
|
6000
|
-
}
|
|
6001
|
-
|
|
6002
6865
|
// chart/render/chart-svg-cartesian.ts
|
|
6003
6866
|
function cartesianAxes(model, area, out) {
|
|
6004
6867
|
const scale = model.valueAxis;
|
|
6005
6868
|
if (!scale) return void 0;
|
|
6006
|
-
const labels = scale.ticks.map((t) =>
|
|
6869
|
+
const labels = scale.ticks.map((t) => axisTickText(t, model.axes?.value, scale.percent));
|
|
6007
6870
|
const valueAttrs = chartTextAttributes(model, "valueAxis");
|
|
6008
6871
|
const categoryAttrs = chartTextAttributes(model, "categoryAxis");
|
|
6009
6872
|
const valueSize = valueAttrs.size ?? 10;
|
|
6010
6873
|
const categorySize = categoryAttrs.size ?? 10;
|
|
6011
|
-
const
|
|
6012
|
-
const
|
|
6013
|
-
const valueLabels = model.appearance?.valueAxis?.labelsVisible !== false;
|
|
6014
|
-
const categoryLabels = model.appearance?.categoryAxis?.labelsVisible !== false;
|
|
6874
|
+
const valueLabels = chartAxisLabels(model.axes?.value) && model.appearance?.valueAxis?.labelsVisible !== false;
|
|
6875
|
+
const categoryLabels = chartAxisLabels(model.axes?.category) && model.appearance?.categoryAxis?.labelsVisible !== false;
|
|
6015
6876
|
const labelW = valueLabels ? Math.max(...labels.map((l) => textWidth(l, valueSize)), 8) + 6 : 4;
|
|
6016
6877
|
const horizontal = model.horizontal;
|
|
6017
6878
|
const cats = Math.max(1, model.categories.length);
|
|
@@ -6020,7 +6881,7 @@ function cartesianAxes(model, area, out) {
|
|
|
6020
6881
|
Math.max(...model.categories.map((c2) => textWidth(c2, categorySize)), 8) + 6
|
|
6021
6882
|
);
|
|
6022
6883
|
const second = horizontal ? void 0 : model.secondaryAxis;
|
|
6023
|
-
const secondLabels = second?.ticks.map((t) =>
|
|
6884
|
+
const secondLabels = second?.ticks.map((t) => axisTickText(t, model.axes?.secondary, second.percent)) ?? [];
|
|
6024
6885
|
const secondW = second ? valueLabels ? Math.max(...secondLabels.map((l) => textWidth(l, valueSize)), 8) + 8 : 4 : 0;
|
|
6025
6886
|
const plot = horizontal ? {
|
|
6026
6887
|
x: area.x + catW,
|
|
@@ -6033,29 +6894,47 @@ function cartesianAxes(model, area, out) {
|
|
|
6033
6894
|
w: Math.max(1, area.w - labelW - 4 - secondW),
|
|
6034
6895
|
h: Math.max(1, area.h - Math.max(20, categorySize * 1.5))
|
|
6035
6896
|
};
|
|
6036
|
-
const
|
|
6037
|
-
const value = horizontal ? (v) => plot.x + (v - scale.min) / span * plot.w : (v) => plot.y + plot.h - (v - scale.min) / span * plot.h;
|
|
6897
|
+
const value = horizontal ? (v) => plot.x + chartAxisRatio(v, scale, model.axes?.value) * plot.w : (v) => plot.y + plot.h - chartAxisRatio(v, scale, model.axes?.value) * plot.h;
|
|
6038
6898
|
const bandSize = (horizontal ? plot.h : plot.w) / cats;
|
|
6039
|
-
const
|
|
6899
|
+
const index = (i) => model.axes?.category?.range.reverseOrder ? cats - 1 - i : i;
|
|
6900
|
+
const band = horizontal ? (i) => plot.y + plot.h - bandSize * (index(i) + 0.5) : (i) => plot.x + bandSize * (index(i) + 0.5);
|
|
6040
6901
|
out.push(chartAreaRect(model, "plotArea", plot));
|
|
6902
|
+
out.push(axisGridlines(model, model.axes?.value, scale.ticks, value, plot, horizontal));
|
|
6903
|
+
if (model.axes?.category?.source.majorGridlines || model.axes?.category?.source.minorGridlines)
|
|
6904
|
+
out.push(
|
|
6905
|
+
axisGridlines(
|
|
6906
|
+
model,
|
|
6907
|
+
model.axes.category,
|
|
6908
|
+
model.categories.map((_, i) => i),
|
|
6909
|
+
band,
|
|
6910
|
+
plot,
|
|
6911
|
+
!horizontal
|
|
6912
|
+
)
|
|
6913
|
+
);
|
|
6041
6914
|
scale.ticks.forEach((t, i) => {
|
|
6042
6915
|
const p = value(t);
|
|
6043
6916
|
const label = labels[i] ?? "";
|
|
6044
6917
|
if (horizontal) {
|
|
6045
|
-
out.push(line(p, plot.y, p, plot.y + plot.h, grid.color, grid.width));
|
|
6046
6918
|
if (valueLabels)
|
|
6047
6919
|
out.push(
|
|
6048
6920
|
text2(p, plot.y + plot.h + valueSize + 2, label, { anchor: "middle", ...valueAttrs })
|
|
6049
6921
|
);
|
|
6050
6922
|
} else {
|
|
6051
|
-
out.push(line(plot.x, p, plot.x + plot.w, p, grid.color, grid.width));
|
|
6052
6923
|
if (valueLabels)
|
|
6053
6924
|
out.push(text2(plot.x - 4, p + valueSize * 0.3, label, { anchor: "end", ...valueAttrs }));
|
|
6054
6925
|
}
|
|
6055
6926
|
});
|
|
6056
|
-
const
|
|
6057
|
-
|
|
6058
|
-
|
|
6927
|
+
const source = model.axes?.value?.source;
|
|
6928
|
+
const crossing = source?.crosses === "max" ? scale.max : source?.crosses === "min" ? scale.min : source?.crossesAt ?? 0;
|
|
6929
|
+
const zero = value(Math.min(Math.max(crossing, scale.min), scale.max));
|
|
6930
|
+
if (horizontal)
|
|
6931
|
+
out.push(
|
|
6932
|
+
axisLine(model, model.axes?.category, "categoryAxis", zero, plot.y, zero, plot.y + plot.h)
|
|
6933
|
+
);
|
|
6934
|
+
else
|
|
6935
|
+
out.push(
|
|
6936
|
+
axisLine(model, model.axes?.category, "categoryAxis", plot.x, zero, plot.x + plot.w, zero)
|
|
6937
|
+
);
|
|
6059
6938
|
const step = Math.max(
|
|
6060
6939
|
1,
|
|
6061
6940
|
Math.ceil(cats / Math.max(1, Math.floor((horizontal ? plot.h : plot.w) / 14)))
|
|
@@ -6080,20 +6959,23 @@ function cartesianAxes(model, area, out) {
|
|
|
6080
6959
|
});
|
|
6081
6960
|
const frame = { plot, value, band, bandSize };
|
|
6082
6961
|
if (second) {
|
|
6083
|
-
|
|
6084
|
-
frame.secondary = (v) => plot.y + plot.h - (v - second.min) / secondSpan * plot.h;
|
|
6085
|
-
const secondAxis = chartStroke(model, "valueAxis");
|
|
6962
|
+
frame.secondary = (v) => plot.y + plot.h - chartAxisRatio(v, second, model.axes?.secondary) * plot.h;
|
|
6086
6963
|
out.push(
|
|
6087
|
-
|
|
6964
|
+
axisLine(
|
|
6965
|
+
model,
|
|
6966
|
+
model.axes?.secondary,
|
|
6967
|
+
"valueAxis",
|
|
6088
6968
|
plot.x + plot.w,
|
|
6089
6969
|
plot.y,
|
|
6090
6970
|
plot.x + plot.w,
|
|
6091
|
-
plot.y + plot.h
|
|
6092
|
-
secondAxis.color,
|
|
6093
|
-
secondAxis.width
|
|
6971
|
+
plot.y + plot.h
|
|
6094
6972
|
)
|
|
6095
6973
|
);
|
|
6096
|
-
if (
|
|
6974
|
+
if (model.axes?.secondary?.source.majorGridlines || model.axes?.secondary?.source.minorGridlines)
|
|
6975
|
+
out.push(
|
|
6976
|
+
axisGridlines(model, model.axes.secondary, second.ticks, frame.secondary, plot, false)
|
|
6977
|
+
);
|
|
6978
|
+
if (chartAxisLabels(model.axes?.secondary))
|
|
6097
6979
|
second.ticks.forEach(
|
|
6098
6980
|
(t, i) => out.push(
|
|
6099
6981
|
text2(plot.x + plot.w + 4, frame.secondary(t) + valueSize * 0.3, secondLabels[i] ?? "", {
|
|
@@ -6117,6 +6999,7 @@ function linesAndAreas(model, frame, out) {
|
|
|
6117
6999
|
const stacked = model.grouping === "stacked" || model.grouping === "percentStacked";
|
|
6118
7000
|
const acc = new Array(model.categories.length).fill(0);
|
|
6119
7001
|
const area = model.type === "area";
|
|
7002
|
+
const marks = [];
|
|
6120
7003
|
const layers = [];
|
|
6121
7004
|
model.series.forEach((s, si) => {
|
|
6122
7005
|
const points = [];
|
|
@@ -6131,16 +7014,24 @@ function linesAndAreas(model, frame, out) {
|
|
|
6131
7014
|
const top = below + (v ?? 0);
|
|
6132
7015
|
if (stacked) acc[i] = top;
|
|
6133
7016
|
points.push([frame.band(i), frame.value(top)]);
|
|
7017
|
+
marks.push({
|
|
7018
|
+
series: s,
|
|
7019
|
+
index: i,
|
|
7020
|
+
x: frame.band(i),
|
|
7021
|
+
y: frame.value(top),
|
|
7022
|
+
radius: area ? 0 : chartMarkerRadius(s, i, 2.5)
|
|
7023
|
+
});
|
|
6134
7024
|
lower.push([frame.band(i), frame.value(below)]);
|
|
6135
7025
|
});
|
|
6136
7026
|
layers.push({
|
|
7027
|
+
series: s,
|
|
6137
7028
|
points,
|
|
6138
7029
|
lower,
|
|
6139
7030
|
color: s.color,
|
|
6140
7031
|
filter: s.shadowFilter ? ` filter="${s.shadowFilter}"` : ""
|
|
6141
7032
|
});
|
|
6142
7033
|
});
|
|
6143
|
-
for (const { points, lower, color, filter } of area ? [...layers].reverse() : layers) {
|
|
7034
|
+
for (const { points, lower, color, filter, series } of area ? [...layers].reverse() : layers) {
|
|
6144
7035
|
if (area) {
|
|
6145
7036
|
const poly = [...points, ...[...lower].reverse()].map(([x, y]) => `${n(x)},${n(y)}`).join(" ");
|
|
6146
7037
|
out.push(`<polygon points="${poly}" fill="${color}" fill-opacity="0.85"${filter}/>`);
|
|
@@ -6159,10 +7050,11 @@ function linesAndAreas(model, frame, out) {
|
|
|
6159
7050
|
else segment2.push(`${n(x)},${n(y)}`);
|
|
6160
7051
|
}
|
|
6161
7052
|
flush();
|
|
6162
|
-
|
|
6163
|
-
if (!Number.isNaN(x))
|
|
6164
|
-
|
|
7053
|
+
points.forEach(([x, y], index) => {
|
|
7054
|
+
if (!Number.isNaN(x)) out.push(chartSeriesMarkerSvg(series, index, x, y, 2.5));
|
|
7055
|
+
});
|
|
6165
7056
|
}
|
|
7057
|
+
pointLabels(model, marks, out);
|
|
6166
7058
|
}
|
|
6167
7059
|
|
|
6168
7060
|
// chart/render/chart-svg-xy.ts
|
|
@@ -6170,16 +7062,14 @@ function scatter(model, area, out) {
|
|
|
6170
7062
|
const ys = model.valueAxis;
|
|
6171
7063
|
const xs = model.xAxis;
|
|
6172
7064
|
if (!ys || !xs) return;
|
|
6173
|
-
const yLabels = ys.ticks.map((t) =>
|
|
7065
|
+
const yLabels = ys.ticks.map((t) => axisTickText(t, model.axes?.value));
|
|
6174
7066
|
const valueAttrs = chartTextAttributes(model, "valueAxis");
|
|
6175
7067
|
const categoryAttrs = chartTextAttributes(model, "categoryAxis");
|
|
6176
7068
|
const valueSize = valueAttrs.size ?? 10;
|
|
6177
7069
|
const categorySize = categoryAttrs.size ?? 10;
|
|
6178
|
-
const grid = chartStroke(model, "gridlineMajor");
|
|
6179
7070
|
const xAxis = chartStroke(model, "categoryAxis");
|
|
6180
|
-
const
|
|
6181
|
-
const
|
|
6182
|
-
const categoryLabels = model.appearance?.categoryAxis?.labelsVisible !== false;
|
|
7071
|
+
const valueLabels = chartAxisLabels(model.axes?.value) && model.appearance?.valueAxis?.labelsVisible !== false;
|
|
7072
|
+
const categoryLabels = chartAxisLabels(model.axes?.category) && model.appearance?.categoryAxis?.labelsVisible !== false;
|
|
6183
7073
|
const labelW = valueLabels ? Math.max(...yLabels.map((l) => textWidth(l, valueSize)), 8) + 6 : 4;
|
|
6184
7074
|
const plot = {
|
|
6185
7075
|
x: area.x + labelW,
|
|
@@ -6199,17 +7089,24 @@ function scatter(model, area, out) {
|
|
|
6199
7089
|
s.values.forEach((_, i) => {
|
|
6200
7090
|
reach = Math.max(reach, radiusOf(s.sizes?.[i] ?? void 0) ?? 0);
|
|
6201
7091
|
});
|
|
6202
|
-
const widen = (s, length) => {
|
|
7092
|
+
const widen = (s, length, axis) => {
|
|
7093
|
+
if (axis?.range.logScale) return s;
|
|
6203
7094
|
const pad = reach * (s.max - s.min || 1) / Math.max(1, length - 2 * reach);
|
|
6204
|
-
return {
|
|
7095
|
+
return {
|
|
7096
|
+
...s,
|
|
7097
|
+
min: axis?.source.scaling.min === void 0 ? s.min - pad : s.min,
|
|
7098
|
+
max: axis?.source.scaling.max === void 0 ? s.max + pad : s.max
|
|
7099
|
+
};
|
|
6205
7100
|
};
|
|
6206
|
-
const xView = widen(xs, plot.w);
|
|
6207
|
-
const yView = widen(ys, plot.h);
|
|
6208
|
-
const px = (v) => plot.x + (v
|
|
6209
|
-
const py = (v) => plot.y + plot.h - (v
|
|
7101
|
+
const xView = widen(xs, plot.w, model.axes?.category);
|
|
7102
|
+
const yView = widen(ys, plot.h, model.axes?.value);
|
|
7103
|
+
const px = (v) => plot.x + chartAxisRatio(v, xView, model.axes?.category) * plot.w;
|
|
7104
|
+
const py = (v) => plot.y + plot.h - chartAxisRatio(v, yView, model.axes?.value) * plot.h;
|
|
6210
7105
|
out.push(chartAreaRect(model, "plotArea", plot));
|
|
7106
|
+
out.push(axisGridlines(model, model.axes?.value, ys.ticks, py, plot, false));
|
|
7107
|
+
if (model.axes?.category)
|
|
7108
|
+
out.push(axisGridlines(model, model.axes.category, xs.ticks, px, plot, true));
|
|
6211
7109
|
ys.ticks.forEach((t, i) => {
|
|
6212
|
-
out.push(line(plot.x, py(t), plot.x + plot.w, py(t), grid.color, grid.width));
|
|
6213
7110
|
if (valueLabels)
|
|
6214
7111
|
out.push(
|
|
6215
7112
|
text2(plot.x - 4, py(t) + valueSize * 0.3, yLabels[i] ?? "", {
|
|
@@ -6219,19 +7116,31 @@ function scatter(model, area, out) {
|
|
|
6219
7116
|
);
|
|
6220
7117
|
});
|
|
6221
7118
|
for (const t of xs.ticks) {
|
|
6222
|
-
|
|
7119
|
+
if (!model.axes?.category?.source.deleted)
|
|
7120
|
+
out.push(line(px(t), plot.y + plot.h, px(t), plot.y + plot.h + 3, xAxis.color, xAxis.width));
|
|
6223
7121
|
if (categoryLabels)
|
|
6224
7122
|
out.push(
|
|
6225
|
-
text2(px(t), plot.y + plot.h + categorySize + 3,
|
|
7123
|
+
text2(px(t), plot.y + plot.h + categorySize + 3, axisTickText(t, model.axes?.category), {
|
|
6226
7124
|
anchor: "middle",
|
|
6227
7125
|
...categoryAttrs
|
|
6228
7126
|
})
|
|
6229
7127
|
);
|
|
6230
7128
|
}
|
|
6231
7129
|
out.push(
|
|
6232
|
-
|
|
7130
|
+
axisLine(
|
|
7131
|
+
model,
|
|
7132
|
+
model.axes?.category,
|
|
7133
|
+
"categoryAxis",
|
|
7134
|
+
plot.x,
|
|
7135
|
+
plot.y + plot.h,
|
|
7136
|
+
plot.x + plot.w,
|
|
7137
|
+
plot.y + plot.h
|
|
7138
|
+
)
|
|
7139
|
+
);
|
|
7140
|
+
out.push(
|
|
7141
|
+
axisLine(model, model.axes?.value, "valueAxis", plot.x, plot.y, plot.x, plot.y + plot.h)
|
|
6233
7142
|
);
|
|
6234
|
-
|
|
7143
|
+
const marks = [];
|
|
6235
7144
|
for (const [si, s] of model.series.entries())
|
|
6236
7145
|
s.values.forEach((v, i) => {
|
|
6237
7146
|
const x = s.xValues?.[i] ?? null;
|
|
@@ -6239,15 +7148,18 @@ function scatter(model, area, out) {
|
|
|
6239
7148
|
const filter = s.shadowFilter ? ` filter="${s.shadowFilter}"` : "";
|
|
6240
7149
|
const fill = s.pointColors?.[i] ?? s.color;
|
|
6241
7150
|
if (!bubble) {
|
|
6242
|
-
out.push(
|
|
7151
|
+
out.push(chartSeriesMarkerSvg(s, i, px(x), py(v)));
|
|
7152
|
+
marks.push({ series: s, index: i, x: px(x), y: py(v), radius: chartMarkerRadius(s, i) });
|
|
6243
7153
|
return;
|
|
6244
7154
|
}
|
|
6245
7155
|
const r = radiusOf(s.sizes?.[i] ?? void 0);
|
|
6246
7156
|
if (r === void 0) return;
|
|
7157
|
+
marks.push({ series: s, index: i, x: px(x), y: py(v), radius: r });
|
|
6247
7158
|
out.push(
|
|
6248
7159
|
`<circle cx="${n(px(x))}" cy="${n(py(v))}" r="${n(r)}" fill="${fill}" fill-opacity="0.6" data-chart-series="${si}" data-chart-point="${i}"${filter}/>`
|
|
6249
7160
|
);
|
|
6250
7161
|
});
|
|
7162
|
+
pointLabels(model, marks, out);
|
|
6251
7163
|
scatterAnalysis(model, px, py, out);
|
|
6252
7164
|
}
|
|
6253
7165
|
|
|
@@ -6412,7 +7324,9 @@ function pieSvg(model, area) {
|
|
|
6412
7324
|
const out = [chartAreaRect(model, "plotArea", area)];
|
|
6413
7325
|
const cx2 = area.x + area.w / 2;
|
|
6414
7326
|
const cy = area.y + area.h / 2;
|
|
6415
|
-
const
|
|
7327
|
+
const margin = hasOutsideLabels(model) ? Math.min(area.w, area.h) * 0.12 : 0;
|
|
7328
|
+
const radius = Math.max(1, Math.min(area.w, area.h) / 2 - 4 - margin);
|
|
7329
|
+
const slices = [];
|
|
6416
7330
|
const rings = model.type === "doughnut" ? model.series : model.series.slice(0, 1);
|
|
6417
7331
|
const hole = model.type === "doughnut" ? radius * 0.5 : 0;
|
|
6418
7332
|
const ringSize = (radius - hole) / Math.max(1, rings.length);
|
|
@@ -6429,9 +7343,20 @@ function pieSvg(model, area) {
|
|
|
6429
7343
|
out.push(
|
|
6430
7344
|
`<path d="${slicePath(cx2, cy, outer, inner, angle, angle + sweep)}" fill="${color}" stroke="#FFFFFF" stroke-width="1"${s.shadowFilter ? ` filter="${s.shadowFilter}"` : ""}/>`
|
|
6431
7345
|
);
|
|
7346
|
+
slices.push({
|
|
7347
|
+
series: s,
|
|
7348
|
+
index: i,
|
|
7349
|
+
cx: cx2,
|
|
7350
|
+
cy,
|
|
7351
|
+
outer,
|
|
7352
|
+
inner,
|
|
7353
|
+
start: angle,
|
|
7354
|
+
end: angle + sweep
|
|
7355
|
+
});
|
|
6432
7356
|
angle += sweep;
|
|
6433
7357
|
});
|
|
6434
7358
|
});
|
|
7359
|
+
sliceLabels(model, slices, out);
|
|
6435
7360
|
return out.join("");
|
|
6436
7361
|
}
|
|
6437
7362
|
function radarSvg(model, area) {
|
|
@@ -6444,32 +7369,37 @@ function radarSvg(model, area) {
|
|
|
6444
7369
|
const valueSize = valueAttrs.size ?? 9;
|
|
6445
7370
|
const categorySize = categoryAttrs.size ?? 10;
|
|
6446
7371
|
const grid = chartStroke(model, "gridlineMajor");
|
|
6447
|
-
const axis = chartStroke(model, "categoryAxis");
|
|
6448
7372
|
const cx2 = area.x + area.w / 2;
|
|
6449
7373
|
const cy = area.y + area.h / 2 + 4;
|
|
6450
7374
|
const radius = Math.max(1, Math.min(area.w, area.h) / 2 - Math.max(18, categorySize * 1.8));
|
|
6451
7375
|
const angle = (i) => i / count * Math.PI * 2;
|
|
6452
|
-
const r = (v) => (v
|
|
7376
|
+
const r = (v) => chartAxisRatio(v, scale, model.axes?.value) * radius;
|
|
6453
7377
|
const labelEvery = Math.max(
|
|
6454
7378
|
1,
|
|
6455
7379
|
Math.ceil(12 / Math.max(1, radius / Math.max(1, scale.ticks.length - 1)))
|
|
6456
7380
|
);
|
|
6457
7381
|
for (const [k, t] of scale.ticks.entries()) {
|
|
6458
7382
|
const ring = Array.from({ length: count }, (_, i) => polar(cx2, cy, r(t), angle(i))).map(([x, y]) => `${n(x)},${n(y)}`).join(" ");
|
|
6459
|
-
|
|
6460
|
-
|
|
6461
|
-
|
|
6462
|
-
|
|
7383
|
+
if (!model.axes?.value || model.axes.value.source.majorGridlines)
|
|
7384
|
+
out.push(
|
|
7385
|
+
`<polygon points="${ring}" fill="none" stroke="${grid.color}" stroke-width="${n(grid.width)}"/>`
|
|
7386
|
+
);
|
|
7387
|
+
if (chartAxisLabels(model.axes?.value) && model.appearance?.valueAxis?.labelsVisible !== false && k % labelEvery === 0)
|
|
6463
7388
|
out.push(
|
|
6464
|
-
text2(
|
|
7389
|
+
text2(
|
|
7390
|
+
cx2 + 3,
|
|
7391
|
+
cy - r(t) + valueSize * 0.3,
|
|
7392
|
+
axisTickText(t, model.axes?.value, scale.percent),
|
|
7393
|
+
valueAttrs
|
|
7394
|
+
)
|
|
6465
7395
|
);
|
|
6466
7396
|
}
|
|
6467
7397
|
model.categories.forEach((c2, i) => {
|
|
6468
7398
|
const [x, y] = polar(cx2, cy, radius, angle(i));
|
|
6469
|
-
out.push(
|
|
7399
|
+
out.push(axisLine(model, model.axes?.category, "categoryAxis", cx2, cy, x, y));
|
|
6470
7400
|
const [lx, ly] = polar(cx2, cy, radius + 10, angle(i));
|
|
6471
7401
|
const anchor = Math.abs(lx - cx2) < 2 ? "middle" : lx > cx2 ? "start" : "end";
|
|
6472
|
-
if (model.appearance?.categoryAxis?.labelsVisible !== false)
|
|
7402
|
+
if (chartAxisLabels(model.axes?.category) && model.appearance?.categoryAxis?.labelsVisible !== false)
|
|
6473
7403
|
out.push(
|
|
6474
7404
|
text2(lx, ly + categorySize * 0.3, fit(c2, area.w / 4, categorySize), {
|
|
6475
7405
|
anchor,
|
|
@@ -6477,12 +7407,22 @@ function radarSvg(model, area) {
|
|
|
6477
7407
|
})
|
|
6478
7408
|
);
|
|
6479
7409
|
});
|
|
7410
|
+
const marks = [];
|
|
6480
7411
|
for (const s of model.series) {
|
|
6481
|
-
const
|
|
7412
|
+
const vertices = s.values.slice(0, count).map((v, i) => polar(cx2, cy, r(v ?? scale.min), angle(i)));
|
|
7413
|
+
vertices.forEach(([x, y], i) => {
|
|
7414
|
+
if (s.values[i] === null) return;
|
|
7415
|
+
const markerSeries = s;
|
|
7416
|
+
if (markerSeries.marker || markerSeries.pointMarkers)
|
|
7417
|
+
out.push(chartSeriesMarkerSvg(s, i, x, y));
|
|
7418
|
+
marks.push({ series: s, index: i, x, y, radius: chartMarkerRadius(s, i) });
|
|
7419
|
+
});
|
|
7420
|
+
const points = vertices.map(([x, y]) => `${n(x)},${n(y)}`).join(" ");
|
|
6482
7421
|
out.push(
|
|
6483
7422
|
`<polygon points="${points}" fill="none" stroke="${s.color}" stroke-width="2"${s.shadowFilter ? ` filter="${s.shadowFilter}"` : ""}/>`
|
|
6484
7423
|
);
|
|
6485
7424
|
}
|
|
7425
|
+
pointLabels(model, marks, out);
|
|
6486
7426
|
return out.join("");
|
|
6487
7427
|
}
|
|
6488
7428
|
|
|
@@ -6573,33 +7513,33 @@ var CHART_FONT_FAMILY = "Calibri, Carlito, Arial, sans-serif";
|
|
|
6573
7513
|
function cssFont(attrs) {
|
|
6574
7514
|
return `${attrs.italic ? "italic" : "normal"} ${attrs.weight ?? "normal"} ${attrs.size ?? 10}px ${attrs.family ?? CHART_FONT_FAMILY}`;
|
|
6575
7515
|
}
|
|
6576
|
-
function chartFontMetrics(attrs,
|
|
6577
|
-
const metrics =
|
|
7516
|
+
function chartFontMetrics(attrs, options2) {
|
|
7517
|
+
const metrics = options2.measureFont?.(cssFont(attrs));
|
|
6578
7518
|
return metrics && Number.isFinite(metrics.ascent) && Number.isFinite(metrics.descent) && metrics.ascent >= 0 && metrics.descent >= 0 && metrics.ascent + metrics.descent > 0 ? metrics : void 0;
|
|
6579
7519
|
}
|
|
6580
|
-
function chartTextWidth(content, attrs,
|
|
6581
|
-
const width =
|
|
7520
|
+
function chartTextWidth(content, attrs, options2) {
|
|
7521
|
+
const width = options2.measureText?.(content, cssFont(attrs));
|
|
6582
7522
|
return width !== void 0 && Number.isFinite(width) && width >= 0 ? width : textWidth(content, attrs.size);
|
|
6583
7523
|
}
|
|
6584
|
-
function fitChartText(content, maxWidth, attrs,
|
|
6585
|
-
if (!
|
|
6586
|
-
if (chartTextWidth(content, attrs,
|
|
7524
|
+
function fitChartText(content, maxWidth, attrs, options2) {
|
|
7525
|
+
if (!options2.measureText) return fit(content, maxWidth, attrs.size);
|
|
7526
|
+
if (chartTextWidth(content, attrs, options2) <= maxWidth) return content;
|
|
6587
7527
|
const points = [...content];
|
|
6588
7528
|
let low = 0;
|
|
6589
7529
|
let high = points.length;
|
|
6590
7530
|
while (low < high) {
|
|
6591
7531
|
const mid = Math.ceil((low + high) / 2);
|
|
6592
|
-
if (chartTextWidth(`${points.slice(0, mid).join("")}\u2026`, attrs,
|
|
7532
|
+
if (chartTextWidth(`${points.slice(0, mid).join("")}\u2026`, attrs, options2) <= maxWidth) low = mid;
|
|
6593
7533
|
else high = mid - 1;
|
|
6594
7534
|
}
|
|
6595
7535
|
return `${points.slice(0, low).join("")}\u2026`;
|
|
6596
7536
|
}
|
|
6597
7537
|
|
|
6598
7538
|
// chart/render/chart-svg-legend.ts
|
|
6599
|
-
function chartLegendSvg(model, area, frame,
|
|
7539
|
+
function chartLegendSvg(model, area, frame, options2) {
|
|
6600
7540
|
const automatic = [];
|
|
6601
7541
|
const bounds = {};
|
|
6602
|
-
const reserved = automaticLegend(model, area, automatic,
|
|
7542
|
+
const reserved = automaticLegend(model, area, automatic, options2, bounds);
|
|
6603
7543
|
const plot = model.legendOverlay ? area : reserved;
|
|
6604
7544
|
const box = bounds.box;
|
|
6605
7545
|
if (!box) return { plot, markup: "", foreground: false };
|
|
@@ -6613,11 +7553,11 @@ function chartLegendSvg(model, area, frame, options) {
|
|
|
6613
7553
|
const entries = legendEntries(model);
|
|
6614
7554
|
const attrs = chartTextAttributes(model, "legend");
|
|
6615
7555
|
const size = attrs.size ?? 10;
|
|
6616
|
-
const font = chartFontMetrics(attrs,
|
|
7556
|
+
const font = chartFontMetrics(attrs, options2);
|
|
6617
7557
|
const keySize = size / 2;
|
|
6618
7558
|
const keyGap = size / 4;
|
|
6619
7559
|
const widths = entries.map(
|
|
6620
|
-
(entry3) => chartTextWidth(entry3.label, attrs,
|
|
7560
|
+
(entry3) => chartTextWidth(entry3.label, attrs, options2) + keySize + keyGap
|
|
6621
7561
|
);
|
|
6622
7562
|
const horizontal = manual.width > manual.height && widths.reduce((sum, width) => sum + width, 0) + size <= manual.width;
|
|
6623
7563
|
const rowWidth = horizontal ? manual.width / entries.length : manual.width;
|
|
@@ -6632,8 +7572,8 @@ function chartLegendSvg(model, area, frame, options) {
|
|
|
6632
7572
|
];
|
|
6633
7573
|
const baselineOffset = font ? (font.ascent - font.descent) / 2 : size * 0.35;
|
|
6634
7574
|
entries.forEach((entry3, i) => {
|
|
6635
|
-
const available = horizontal ? chartTextWidth(entry3.label, attrs,
|
|
6636
|
-
const label = fitChartText(entry3.label, available, attrs,
|
|
7575
|
+
const available = horizontal ? chartTextWidth(entry3.label, attrs, options2) : Math.max(0, rowWidth - size / 2 - keySize - keyGap);
|
|
7576
|
+
const label = fitChartText(entry3.label, available, attrs, options2);
|
|
6637
7577
|
const contentWidth = Math.min(
|
|
6638
7578
|
horizontal ? widths[i] ?? 0 : Math.max(...widths),
|
|
6639
7579
|
rowWidth - size / 2
|
|
@@ -6676,7 +7616,7 @@ function legendEntries(model) {
|
|
|
6676
7616
|
color: s.color
|
|
6677
7617
|
}));
|
|
6678
7618
|
}
|
|
6679
|
-
function automaticLegend(model, area, out,
|
|
7619
|
+
function automaticLegend(model, area, out, options2, bounds) {
|
|
6680
7620
|
const entries = legendEntries(model);
|
|
6681
7621
|
if (!model.showLegend || entries.length === 0) return area;
|
|
6682
7622
|
const pos = model.legendPosition;
|
|
@@ -6685,7 +7625,7 @@ function automaticLegend(model, area, out, options, bounds) {
|
|
|
6685
7625
|
const rowH = Math.max(16, size * 1.4);
|
|
6686
7626
|
if (pos === "t" || pos === "b") {
|
|
6687
7627
|
const widths = entries.map(
|
|
6688
|
-
(e) => Math.min(chartTextWidth(e.label, attrs,
|
|
7628
|
+
(e) => Math.min(chartTextWidth(e.label, attrs, options2) + 20, area.w / 2)
|
|
6689
7629
|
);
|
|
6690
7630
|
const total = widths.reduce((a2, b) => a2 + b, 0);
|
|
6691
7631
|
let x2 = area.x + Math.max(0, (area.w - total) / 2);
|
|
@@ -6702,14 +7642,14 @@ function automaticLegend(model, area, out, options, bounds) {
|
|
|
6702
7642
|
entries.forEach((e, i) => {
|
|
6703
7643
|
const w = widths[i] ?? 0;
|
|
6704
7644
|
out.push(rect(x2, y, 8, 8, e.color));
|
|
6705
|
-
out.push(text2(x2 + 12, y + 8, fitChartText(e.label, w - 16, attrs,
|
|
7645
|
+
out.push(text2(x2 + 12, y + 8, fitChartText(e.label, w - 16, attrs, options2), attrs));
|
|
6706
7646
|
x2 += w;
|
|
6707
7647
|
});
|
|
6708
7648
|
return pos === "t" ? { x: area.x, y: area.y + rowH + 4, w: area.w, h: area.h - rowH - 4 } : { x: area.x, y: area.y, w: area.w, h: area.h - rowH - 4 };
|
|
6709
7649
|
}
|
|
6710
7650
|
const width = Math.min(
|
|
6711
7651
|
area.w * 0.35,
|
|
6712
|
-
Math.max(...entries.map((e) => chartTextWidth(e.label, attrs,
|
|
7652
|
+
Math.max(...entries.map((e) => chartTextWidth(e.label, attrs, options2))) + 22
|
|
6713
7653
|
);
|
|
6714
7654
|
const height = entries.length * rowH;
|
|
6715
7655
|
const x = pos === "l" ? area.x + 4 : area.x + area.w - width;
|
|
@@ -6727,14 +7667,14 @@ function automaticLegend(model, area, out, options, bounds) {
|
|
|
6727
7667
|
const y = y0 + i * rowH;
|
|
6728
7668
|
if (y + rowH > area.y + area.h + 2) return;
|
|
6729
7669
|
out.push(rect(x, y + 3, 8, 8, e.color));
|
|
6730
|
-
out.push(text2(x + 12, y + 11, fitChartText(e.label, width - 16, attrs,
|
|
7670
|
+
out.push(text2(x + 12, y + 11, fitChartText(e.label, width - 16, attrs, options2), attrs));
|
|
6731
7671
|
});
|
|
6732
7672
|
return pos === "l" ? { x: area.x + width + 8, y: area.y, w: area.w - width - 8, h: area.h } : { x: area.x, y: area.y, w: area.w - width - 8, h: area.h };
|
|
6733
7673
|
}
|
|
6734
7674
|
|
|
6735
7675
|
// text/wrap-styled-runs.ts
|
|
6736
7676
|
var graphemes = new Intl.Segmenter(void 0, { granularity: "grapheme" });
|
|
6737
|
-
function wrapStyledRuns(runs, maxWidth,
|
|
7677
|
+
function wrapStyledRuns(runs, maxWidth, measure2, options2 = {}) {
|
|
6738
7678
|
const groups = [];
|
|
6739
7679
|
for (const [source, run2] of runs.entries()) {
|
|
6740
7680
|
for (const token of run2.text.split(/(\r\n|[\r\n]|[ \t]+)/u).filter(Boolean)) {
|
|
@@ -6757,7 +7697,7 @@ function wrapStyledRuns(runs, maxWidth, measure, options = {}) {
|
|
|
6757
7697
|
return result2;
|
|
6758
7698
|
};
|
|
6759
7699
|
const width = (pieces) => pieces.reduce((sum, piece) => {
|
|
6760
|
-
const advance =
|
|
7700
|
+
const advance = measure2(piece.text, piece.run);
|
|
6761
7701
|
return sum + (Number.isFinite(advance) && advance >= 0 ? advance : 0);
|
|
6762
7702
|
}, 0);
|
|
6763
7703
|
const result = [];
|
|
@@ -6782,7 +7722,7 @@ function wrapStyledRuns(runs, maxWidth, measure, options = {}) {
|
|
|
6782
7722
|
if (line2.length && width(merged(line2, [...separator, ...group2.pieces])) > maxWidth) flush();
|
|
6783
7723
|
else line2 = merged(line2, separator);
|
|
6784
7724
|
spaces = [];
|
|
6785
|
-
if (
|
|
7725
|
+
if (options2.breakWords && wordWidth > maxWidth) {
|
|
6786
7726
|
for (const piece of group2.pieces) {
|
|
6787
7727
|
for (const { segment: segment2 } of graphemes.segment(piece.text)) {
|
|
6788
7728
|
const next = { ...piece, text: segment2 };
|
|
@@ -6800,11 +7740,11 @@ function wrapStyledRuns(runs, maxWidth, measure, options = {}) {
|
|
|
6800
7740
|
function spacing2(value, naturalHeight, fallback) {
|
|
6801
7741
|
return value ? value.unit === "points" ? chartPointsToPixels(value.value) : naturalHeight * value.value : fallback;
|
|
6802
7742
|
}
|
|
6803
|
-
function chartRichTitleSvg(model, width,
|
|
7743
|
+
function chartRichTitleSvg(model, width, options2 = {}, frameHeight = 400) {
|
|
6804
7744
|
if (!model.title) return void 0;
|
|
6805
7745
|
const base = chartTextAttributes(model, "title", 14);
|
|
6806
7746
|
const capacity = Math.max(1, width * 0.8 - 8);
|
|
6807
|
-
if (!model.titleText && !hasManualLayoutFields(model.titleLayout) && !model.titleOverlay && !model.title.includes("\n") && chartTextWidth(model.title, base,
|
|
7747
|
+
if (!model.titleText && !hasManualLayoutFields(model.titleLayout) && !model.titleOverlay && !model.title.includes("\n") && chartTextWidth(model.title, base, options2) <= capacity)
|
|
6808
7748
|
return void 0;
|
|
6809
7749
|
const paragraphs = model.titleText?.paragraphs ?? [
|
|
6810
7750
|
{
|
|
@@ -6840,7 +7780,7 @@ function chartRichTitleSvg(model, width, options = {}, frameHeight = 400) {
|
|
|
6840
7780
|
"title",
|
|
6841
7781
|
base.size
|
|
6842
7782
|
),
|
|
6843
|
-
|
|
7783
|
+
options2
|
|
6844
7784
|
),
|
|
6845
7785
|
{ breakWords: true }
|
|
6846
7786
|
);
|
|
@@ -6864,10 +7804,10 @@ function chartRichTitleSvg(model, width, options = {}, frameHeight = 400) {
|
|
|
6864
7804
|
return {
|
|
6865
7805
|
...line2,
|
|
6866
7806
|
runs,
|
|
6867
|
-
width: runs.reduce((sum, run2) => sum + chartTextWidth(run2.text, run2.attrs,
|
|
7807
|
+
width: runs.reduce((sum, run2) => sum + chartTextWidth(run2.text, run2.attrs, options2), 0),
|
|
6868
7808
|
size: runs.length ? Math.max(...runs.map((run2) => run2.attrs.size ?? 14)) : base.size ?? 14,
|
|
6869
7809
|
fontMetrics: (runs.length ? runs.map((run2) => run2.attrs) : [base]).map(
|
|
6870
|
-
(attrs) => chartFontMetrics(attrs,
|
|
7810
|
+
(attrs) => chartFontMetrics(attrs, options2)
|
|
6871
7811
|
)
|
|
6872
7812
|
};
|
|
6873
7813
|
});
|
|
@@ -6905,7 +7845,7 @@ function chartRichTitleSvg(model, width, options = {}, frameHeight = 400) {
|
|
|
6905
7845
|
anchor: "start"
|
|
6906
7846
|
}).replace("<text ", '<tspan data-chart-title-run="true" ').replace("</text>", "</tspan>")
|
|
6907
7847
|
);
|
|
6908
|
-
x += chartTextWidth(run2.text, run2.attrs,
|
|
7848
|
+
x += chartTextWidth(run2.text, run2.attrs, options2);
|
|
6909
7849
|
}
|
|
6910
7850
|
}
|
|
6911
7851
|
const parent = text2(0, 0, "", { ...base, underline: false }).replace(
|
|
@@ -6931,7 +7871,7 @@ function chartRichTitleSvg(model, width, options = {}, frameHeight = 400) {
|
|
|
6931
7871
|
}
|
|
6932
7872
|
|
|
6933
7873
|
// chart/render/chart-svg.ts
|
|
6934
|
-
function renderChartSvg(model, width, height,
|
|
7874
|
+
function renderChartSvg(model, width, height, options2 = {}) {
|
|
6935
7875
|
const paint2 = chartGradientPaint(model, Math.max(1, width), Math.max(1, height));
|
|
6936
7876
|
model = paint2.model;
|
|
6937
7877
|
const w = Math.max(1, width);
|
|
@@ -6945,7 +7885,7 @@ function renderChartSvg(model, width, height, options = {}) {
|
|
|
6945
7885
|
if (paint2.defs) out.push(paint2.defs);
|
|
6946
7886
|
out.push(chartAreaRect(model, "chartArea", { x: 0, y: 0, w, h }));
|
|
6947
7887
|
let area = { x: 8, y: 8, w: w - 16, h: h - 16 };
|
|
6948
|
-
const richTitle = chartRichTitleSvg(model, w,
|
|
7888
|
+
const richTitle = chartRichTitleSvg(model, w, options2, h);
|
|
6949
7889
|
if (richTitle) {
|
|
6950
7890
|
if (model.titleLayout || model.titleOverlay) foregroundTitle = richTitle.markup;
|
|
6951
7891
|
else out.push(richTitle.markup);
|
|
@@ -6954,9 +7894,9 @@ function renderChartSvg(model, width, height, options = {}) {
|
|
|
6954
7894
|
} else if (model.title) {
|
|
6955
7895
|
const attrs = chartTextAttributes(model, "title", 14);
|
|
6956
7896
|
const size = attrs.size ?? 14;
|
|
6957
|
-
const label = fitChartText(model.title, w - 16, attrs,
|
|
6958
|
-
const titleWidth = Math.min(w - 16, chartTextWidth(label, attrs,
|
|
6959
|
-
const font = chartFontMetrics(attrs,
|
|
7897
|
+
const label = fitChartText(model.title, w - 16, attrs, options2);
|
|
7898
|
+
const titleWidth = Math.min(w - 16, chartTextWidth(label, attrs, options2) + 8);
|
|
7899
|
+
const font = chartFontMetrics(attrs, options2);
|
|
6960
7900
|
const titleHeight = Math.max(24, font ? font.ascent + font.descent + 4 : size * 1.4 + 4);
|
|
6961
7901
|
out.push(
|
|
6962
7902
|
chartAreaRect(model, "title", {
|
|
@@ -6984,7 +7924,7 @@ function renderChartSvg(model, width, height, options = {}) {
|
|
|
6984
7924
|
out.push("</svg>");
|
|
6985
7925
|
return out.join("");
|
|
6986
7926
|
}
|
|
6987
|
-
const legend = chartLegendSvg(model, area, { width: w, height: h },
|
|
7927
|
+
const legend = chartLegendSvg(model, area, { width: w, height: h }, options2);
|
|
6988
7928
|
area = legend.plot;
|
|
6989
7929
|
if (!legend.foreground) out.push(legend.markup);
|
|
6990
7930
|
if (area.w > 4 && area.h > 4) {
|
|
@@ -7031,8 +7971,8 @@ function chartSpaceKind(space) {
|
|
|
7031
7971
|
const type = chartSummaryFromSpace(space).chartType;
|
|
7032
7972
|
return { type, drawn: DRAWN_CHART_TYPES.has(type) };
|
|
7033
7973
|
}
|
|
7034
|
-
function renderChartSpaceSvg(space,
|
|
7035
|
-
const { width, height, theme, fonts, formatting, colorPalette, styleDefinition, ...svg } =
|
|
7974
|
+
function renderChartSpaceSvg(space, options2) {
|
|
7975
|
+
const { width, height, theme, fonts, formatting, colorPalette, styleDefinition, ...svg } = options2;
|
|
7036
7976
|
const summary = chartSummaryFromSpace(space, {
|
|
7037
7977
|
...formatting ? { formatting } : {},
|
|
7038
7978
|
...colorPalette !== void 0 ? { colorPalette } : {},
|
|
@@ -7041,8 +7981,8 @@ function renderChartSpaceSvg(space, options) {
|
|
|
7041
7981
|
const view = chartSummaryView(summary, chartThemePalette(theme, fonts));
|
|
7042
7982
|
return renderChartSvg(view, width, height, svg);
|
|
7043
7983
|
}
|
|
7044
|
-
function renderChartSummarySvg(summary,
|
|
7045
|
-
const { width, height, theme, fonts, ...svg } =
|
|
7984
|
+
function renderChartSummarySvg(summary, options2) {
|
|
7985
|
+
const { width, height, theme, fonts, ...svg } = options2;
|
|
7046
7986
|
const view = chartSummaryView(summary, chartThemePalette(theme, fonts));
|
|
7047
7987
|
return renderChartSvg(view, width, height, svg);
|
|
7048
7988
|
}
|
|
@@ -7060,6 +8000,8 @@ exports.CHART_ERROR_BAR_TYPES = CHART_ERROR_BAR_TYPES;
|
|
|
7060
8000
|
exports.CHART_ERROR_VALUE_TYPES = CHART_ERROR_VALUE_TYPES;
|
|
7061
8001
|
exports.CHART_GROUP_ELEMENTS = CHART_GROUP_ELEMENTS;
|
|
7062
8002
|
exports.CHART_STYLE_PARTS = CHART_STYLE_PARTS;
|
|
8003
|
+
exports.DATA_LABEL_CATEGORY_PERCENT_SEPARATOR = DATA_LABEL_CATEGORY_PERCENT_SEPARATOR;
|
|
8004
|
+
exports.DATA_LABEL_SEPARATOR = DATA_LABEL_SEPARATOR;
|
|
7063
8005
|
exports.DEFAULT_BAR_GAP_WIDTH = DEFAULT_BAR_GAP_WIDTH;
|
|
7064
8006
|
exports.DEFAULT_CHART_PALETTE = DEFAULT_CHART_PALETTE;
|
|
7065
8007
|
exports.DEFAULT_THEME_COLORS = DEFAULT_THEME_COLORS;
|
|
@@ -7074,9 +8016,11 @@ exports.aggregate = aggregate;
|
|
|
7074
8016
|
exports.aggregateByCategory = aggregateByCategory;
|
|
7075
8017
|
exports.assertBarClusterOptions = assertBarClusterOptions;
|
|
7076
8018
|
exports.autoSeriesColor = autoSeriesColor;
|
|
8019
|
+
exports.automaticMarkerSymbol = automaticMarkerSymbol;
|
|
7077
8020
|
exports.axisTargetIntervals = axisTargetIntervals;
|
|
7078
8021
|
exports.buildChartGradientDef = buildChartGradientDef;
|
|
7079
8022
|
exports.buildHierarchyRoots = buildHierarchyRoots;
|
|
8023
|
+
exports.buildMarkerPrimitive = buildMarkerPrimitive;
|
|
7080
8024
|
exports.buildWaterfallSteps = buildWaterfallSteps;
|
|
7081
8025
|
exports.builtInChartStyleXml = builtInChartStyleXml;
|
|
7082
8026
|
exports.builtInChartTextStyle = builtInChartTextStyle;
|
|
@@ -7088,10 +8032,13 @@ exports.chartColorStyleXml = chartColorStyleXml;
|
|
|
7088
8032
|
exports.chartErrorBarAmount = chartErrorBarAmount;
|
|
7089
8033
|
exports.chartExSummary = chartExSummary;
|
|
7090
8034
|
exports.chartGradientMarkup = chartGradientMarkup;
|
|
8035
|
+
exports.chartLineDashArray = chartLineDashArray;
|
|
8036
|
+
exports.chartMarkerRadius = chartMarkerRadius;
|
|
7091
8037
|
exports.chartPaletteColors = chartPaletteColors;
|
|
7092
8038
|
exports.chartPaletteSeriesColor = chartPaletteSeriesColor;
|
|
7093
8039
|
exports.chartPaletteSeriesColorChoice = chartPaletteSeriesColorChoice;
|
|
7094
8040
|
exports.chartSampleVariance = chartSampleVariance;
|
|
8041
|
+
exports.chartSeriesMarkerSvg = chartSeriesMarkerSvg;
|
|
7095
8042
|
exports.chartSourceValues = chartSourceValues;
|
|
7096
8043
|
exports.chartSpaceKind = chartSpaceKind;
|
|
7097
8044
|
exports.chartSummaryFromSpace = chartSummaryFromSpace;
|
|
@@ -7101,18 +8048,26 @@ exports.chartThemePalette = chartThemePalette;
|
|
|
7101
8048
|
exports.chartTrendlineKind = chartTrendlineKind;
|
|
7102
8049
|
exports.chartTrendlineType = chartTrendlineType;
|
|
7103
8050
|
exports.clusteredBarGeometry = clusteredBarGeometry;
|
|
8051
|
+
exports.composeDataLabelText = composeDataLabelText;
|
|
8052
|
+
exports.computeAxisStackedValueRange = computeAxisStackedValueRange;
|
|
8053
|
+
exports.computeAxisValueRange = computeAxisValueRange;
|
|
7104
8054
|
exports.computeBoxStats = computeBoxStats;
|
|
7105
8055
|
exports.computeBubbleRadius = computeBubbleRadius;
|
|
7106
8056
|
exports.computeHierarchicalSunburstArcs = computeHierarchicalSunburstArcs;
|
|
7107
8057
|
exports.computeHistogramBins = computeHistogramBins;
|
|
7108
8058
|
exports.computeLinearRegression = computeLinearRegression;
|
|
8059
|
+
exports.computeLogValueRange = computeLogValueRange;
|
|
7109
8060
|
exports.computeRSquared = computeRSquared;
|
|
7110
8061
|
exports.computeRadarPoints = computeRadarPoints;
|
|
7111
8062
|
exports.computeStackedSeriesPlots = computeStackedSeriesPlots;
|
|
8063
|
+
exports.computeStackedValueRangeForAxis = computeStackedValueRangeForAxis;
|
|
7112
8064
|
exports.computeSunburstArcs = computeSunburstArcs;
|
|
8065
|
+
exports.computeValueRangeForAxis = computeValueRangeForAxis;
|
|
8066
|
+
exports.computeValueRangeForChart = computeValueRangeForChart;
|
|
7113
8067
|
exports.computeWaterfallRange = computeWaterfallRange;
|
|
7114
8068
|
exports.effectiveBuiltInChartStyle = effectiveBuiltInChartStyle;
|
|
7115
8069
|
exports.findChartColorPalette = findChartColorPalette;
|
|
8070
|
+
exports.findLogAxis = findLogAxis;
|
|
7116
8071
|
exports.fitChartTrendline = fitChartTrendline;
|
|
7117
8072
|
exports.fitPolynomial = fitPolynomial;
|
|
7118
8073
|
exports.formatChartNumber = formatChartNumber;
|
|
@@ -7124,6 +8079,9 @@ exports.formatLogarithmicEquation = formatLogarithmicEquation;
|
|
|
7124
8079
|
exports.formatPolynomialEquation = formatPolynomialEquation;
|
|
7125
8080
|
exports.formatPowerEquation = formatPowerEquation;
|
|
7126
8081
|
exports.formatTrendlineCoefficient = formatTrendlineCoefficient;
|
|
8082
|
+
exports.generateAxisTicks = generateAxisTicks;
|
|
8083
|
+
exports.generateLogTicks = generateLogTicks;
|
|
8084
|
+
exports.generateMinorAxisTicks = generateMinorAxisTicks;
|
|
7127
8085
|
exports.getChartStylePalette = getChartStylePalette;
|
|
7128
8086
|
exports.groupRowsByCategory = groupRowsByCategory;
|
|
7129
8087
|
exports.hasManualLayoutFields = hasManualLayoutFields;
|
|
@@ -7131,6 +8089,8 @@ exports.hierarchyBranchLabels = hierarchyBranchLabels;
|
|
|
7131
8089
|
exports.impliesAutoTitle = impliesAutoTitle;
|
|
7132
8090
|
exports.isChartexOnlyType = isChartexOnlyType;
|
|
7133
8091
|
exports.layoutTreemap = layoutTreemap;
|
|
8092
|
+
exports.markerOutline = markerOutline;
|
|
8093
|
+
exports.markerRadius = markerRadius;
|
|
7134
8094
|
exports.maxBubbleSize = maxBubbleSize;
|
|
7135
8095
|
exports.medianBubbleRadius = medianBubbleRadius;
|
|
7136
8096
|
exports.modulateLuminance = modulateLuminance;
|
|
@@ -7155,18 +8115,23 @@ exports.resolveAutoTitleText = resolveAutoTitleText;
|
|
|
7155
8115
|
exports.resolveBlankDisplay = resolveBlankDisplay;
|
|
7156
8116
|
exports.resolveChartGradient = resolveChartGradient;
|
|
7157
8117
|
exports.resolveChartStyleDefinition = resolveChartStyleDefinition;
|
|
8118
|
+
exports.resolveDataLabelFlags = resolveDataLabelFlags;
|
|
7158
8119
|
exports.resolveManualLayoutRect = resolveManualLayoutRect;
|
|
7159
8120
|
exports.scottBinCount = scottBinCount;
|
|
8121
|
+
exports.seriesMarkerViews = seriesMarkerViews;
|
|
7160
8122
|
exports.shade = shade;
|
|
7161
8123
|
exports.sortGradientStops = sortGradientStops;
|
|
7162
8124
|
exports.squarify = squarify;
|
|
7163
8125
|
exports.stockCandle = stockCandle;
|
|
7164
8126
|
exports.stockSlots = stockSlots;
|
|
8127
|
+
exports.summaryMarkers = summaryMarkers;
|
|
7165
8128
|
exports.sunburstArcPath = sunburstArcPath;
|
|
7166
8129
|
exports.themeColor = themeColor;
|
|
7167
8130
|
exports.tint = tint;
|
|
7168
8131
|
exports.updateGradientStop = updateGradientStop;
|
|
8132
|
+
exports.valueToYLog = valueToYLog;
|
|
7169
8133
|
exports.visibleRuns = visibleRuns;
|
|
8134
|
+
exports.withAxisBounds = withAxisBounds;
|
|
7170
8135
|
exports.withChartGradientDirection = withChartGradientDirection;
|
|
7171
8136
|
exports.withinLinearTransform = withinLinearTransform;
|
|
7172
8137
|
exports.writeChartAxisFormatting = writeChartAxisFormatting;
|