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