@extend-ai/react-xlsx 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +23154 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +776 -0
- package/dist/index.d.ts +776 -0
- package/dist/index.js +23125 -0
- package/dist/index.js.map +1 -0
- package/dist/xlsx-worker.js +4688 -0
- package/dist/xlsx-worker.js.map +1 -0
- package/package.json +60 -0
|
@@ -0,0 +1,4688 @@
|
|
|
1
|
+
// src/charts.ts
|
|
2
|
+
import { strFromU8, strToU8 } from "fflate";
|
|
3
|
+
var CHART_REL_TYPE = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/chart";
|
|
4
|
+
var CHART_EX_REL_TYPE = "http://schemas.microsoft.com/office/2014/relationships/chartEx";
|
|
5
|
+
var CHART_STYLE_REL_TYPE = "http://schemas.microsoft.com/office/2011/relationships/chartStyle";
|
|
6
|
+
var CHART_COLOR_STYLE_REL_TYPE = "http://schemas.microsoft.com/office/2011/relationships/chartColorStyle";
|
|
7
|
+
var SERIES_COLORS = [
|
|
8
|
+
"#4472c4",
|
|
9
|
+
"#ed7d31",
|
|
10
|
+
"#a5a5a5",
|
|
11
|
+
"#ffc000",
|
|
12
|
+
"#5b9bd5",
|
|
13
|
+
"#70ad47",
|
|
14
|
+
"#264478",
|
|
15
|
+
"#9e480e",
|
|
16
|
+
"#636363",
|
|
17
|
+
"#997300"
|
|
18
|
+
];
|
|
19
|
+
var EMU_PER_PIXEL = 9525;
|
|
20
|
+
var THEME_COLOR_INDEX_BY_NAME = {
|
|
21
|
+
accent1: 4,
|
|
22
|
+
accent2: 5,
|
|
23
|
+
accent3: 6,
|
|
24
|
+
accent4: 7,
|
|
25
|
+
accent5: 8,
|
|
26
|
+
accent6: 9,
|
|
27
|
+
dk1: 1,
|
|
28
|
+
dk2: 3,
|
|
29
|
+
folHlink: 11,
|
|
30
|
+
hlink: 10,
|
|
31
|
+
lt1: 0,
|
|
32
|
+
lt2: 2,
|
|
33
|
+
tx1: 1,
|
|
34
|
+
tx2: 3,
|
|
35
|
+
bg1: 0,
|
|
36
|
+
bg2: 2
|
|
37
|
+
};
|
|
38
|
+
var PRIMARY_CHART_TYPE_LOCAL_NAMES = [
|
|
39
|
+
"barChart",
|
|
40
|
+
"lineChart",
|
|
41
|
+
"line3DChart",
|
|
42
|
+
"stockChart",
|
|
43
|
+
"radarChart",
|
|
44
|
+
"scatterChart",
|
|
45
|
+
"pieChart",
|
|
46
|
+
"pie3DChart",
|
|
47
|
+
"doughnutChart",
|
|
48
|
+
"areaChart",
|
|
49
|
+
"area3DChart",
|
|
50
|
+
"bar3DChart",
|
|
51
|
+
"ofPieChart",
|
|
52
|
+
"bubbleChart",
|
|
53
|
+
"surfaceChart",
|
|
54
|
+
"surface3DChart"
|
|
55
|
+
];
|
|
56
|
+
function clampUnitInterval(value) {
|
|
57
|
+
return Math.max(0, Math.min(1, value));
|
|
58
|
+
}
|
|
59
|
+
function isElementNode(node) {
|
|
60
|
+
return node != null && node.nodeType === 1;
|
|
61
|
+
}
|
|
62
|
+
function normalizeHexColor(value) {
|
|
63
|
+
const hex = value.replace(/^#/, "");
|
|
64
|
+
if (hex.length === 8) {
|
|
65
|
+
return `#${hex.slice(2).toLowerCase()}`;
|
|
66
|
+
}
|
|
67
|
+
if (hex.length === 6) {
|
|
68
|
+
return `#${hex.toLowerCase()}`;
|
|
69
|
+
}
|
|
70
|
+
return null;
|
|
71
|
+
}
|
|
72
|
+
function resolveColorFromXmlFragment(fragment, themePalette) {
|
|
73
|
+
if (!fragment) {
|
|
74
|
+
return void 0;
|
|
75
|
+
}
|
|
76
|
+
const srgbMatch = fragment.match(/<a:srgbClr\b[^>]*\bval="([0-9a-fA-F]{6,8})"/i);
|
|
77
|
+
if (srgbMatch?.[1]) {
|
|
78
|
+
return normalizeHexColor(srgbMatch[1]) ?? void 0;
|
|
79
|
+
}
|
|
80
|
+
const schemeMatch = fragment.match(/<a:schemeClr\b[^>]*\bval="([^"]+)"[^>]*>([\s\S]*?)<\/a:schemeClr>/i) ?? fragment.match(/<a:schemeClr\b[^>]*\bval="([^"]+)"[^>]*/i);
|
|
81
|
+
if (!schemeMatch?.[1]) {
|
|
82
|
+
return void 0;
|
|
83
|
+
}
|
|
84
|
+
const baseColor = resolveThemeColor(schemeMatch[1], themePalette);
|
|
85
|
+
if (!baseColor) {
|
|
86
|
+
return void 0;
|
|
87
|
+
}
|
|
88
|
+
const transforms = schemeMatch[2] ?? "";
|
|
89
|
+
let lightnessModifier = 1;
|
|
90
|
+
let lightnessOffset = 0;
|
|
91
|
+
for (const match of transforms.matchAll(/<a:(lumMod|lumOff|tint|shade)\b[^>]*\bval="(-?\d+(?:\.\d+)?)"/gi)) {
|
|
92
|
+
const transform = match[1]?.toLowerCase();
|
|
93
|
+
const rawValue = Number(match[2] ?? Number.NaN);
|
|
94
|
+
if (!transform || !Number.isFinite(rawValue)) {
|
|
95
|
+
continue;
|
|
96
|
+
}
|
|
97
|
+
if (transform === "lummod") {
|
|
98
|
+
lightnessModifier *= rawValue / 1e5;
|
|
99
|
+
} else if (transform === "lumoff") {
|
|
100
|
+
lightnessOffset += rawValue / 1e5;
|
|
101
|
+
} else if (transform === "tint") {
|
|
102
|
+
lightnessOffset += (1 - lightnessOffset) * (rawValue / 1e5);
|
|
103
|
+
} else if (transform === "shade") {
|
|
104
|
+
lightnessModifier *= rawValue / 1e5;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return applyLightnessTransform(baseColor, lightnessModifier, lightnessOffset) ?? void 0;
|
|
108
|
+
}
|
|
109
|
+
function readHexColorFromXmlFragment(fragment, preferLine = false, themePalette) {
|
|
110
|
+
const source = preferLine ? fragment.match(/<a:ln\b[\s\S]*?<\/a:ln>/i)?.[0] ?? "" : fragment.match(/<a:solidFill\b[\s\S]*?<\/a:solidFill>/i)?.[0] ?? "";
|
|
111
|
+
return resolveColorFromXmlFragment(source, themePalette);
|
|
112
|
+
}
|
|
113
|
+
function parseFallbackSeriesStylesFromChartXml(chartXml, themePalette) {
|
|
114
|
+
const seriesBlocks = chartXml.match(/<c:ser\b[\s\S]*?<\/c:ser>/gi) ?? [];
|
|
115
|
+
if (seriesBlocks.length === 0) {
|
|
116
|
+
return [];
|
|
117
|
+
}
|
|
118
|
+
return seriesBlocks.map((seriesBlock) => {
|
|
119
|
+
const shapeBlock = seriesBlock.match(/<c:spPr\b[\s\S]*?<\/c:spPr>/i)?.[0] ?? "";
|
|
120
|
+
return {
|
|
121
|
+
color: readHexColorFromXmlFragment(shapeBlock, false, themePalette),
|
|
122
|
+
lineColor: readHexColorFromXmlFragment(shapeBlock, true, themePalette)
|
|
123
|
+
};
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
function parseFallbackPointStylesFromChartXml(chartXml, themePalette) {
|
|
127
|
+
const chartDocument = parseXml(chartXml);
|
|
128
|
+
if (chartDocument) {
|
|
129
|
+
const parsedSeriesStyles = getLocalDescendants(chartDocument, "ser").map((seriesNode) => {
|
|
130
|
+
const styles = [];
|
|
131
|
+
for (const dataPointNode of getLocalChildren(seriesNode, "dPt")) {
|
|
132
|
+
const indexValue = readChartNumericAttribute(dataPointNode, "idx");
|
|
133
|
+
if (indexValue === void 0) {
|
|
134
|
+
continue;
|
|
135
|
+
}
|
|
136
|
+
const shapeProperties = getFirstLocalChild(dataPointNode, "spPr");
|
|
137
|
+
const lineStyle = resolveChartLineStyle(shapeProperties, themePalette);
|
|
138
|
+
styles.push({
|
|
139
|
+
color: resolveChartFillColor(shapeProperties, themePalette) ?? void 0,
|
|
140
|
+
explosion: readChartNumericAttribute(dataPointNode, "explosion"),
|
|
141
|
+
index: indexValue,
|
|
142
|
+
lineColor: lineStyle.color ?? void 0
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
return styles;
|
|
146
|
+
});
|
|
147
|
+
if (parsedSeriesStyles.some((styles) => styles.length > 0)) {
|
|
148
|
+
return parsedSeriesStyles;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
const seriesBlocks = chartXml.match(/<c:ser\b[\s\S]*?<\/c:ser>/gi) ?? [];
|
|
152
|
+
if (seriesBlocks.length === 0) {
|
|
153
|
+
return [];
|
|
154
|
+
}
|
|
155
|
+
return seriesBlocks.map((seriesBlock) => {
|
|
156
|
+
const pointBlocks = seriesBlock.match(/<c:dPt\b[\s\S]*?<\/c:dPt>/gi) ?? [];
|
|
157
|
+
if (pointBlocks.length === 0) {
|
|
158
|
+
return [];
|
|
159
|
+
}
|
|
160
|
+
const styles = [];
|
|
161
|
+
for (const pointBlock of pointBlocks) {
|
|
162
|
+
const indexMatch = pointBlock.match(/<c:idx\b[^>]*\bval="(-?\d+)"/i);
|
|
163
|
+
const index = indexMatch?.[1] ? Number(indexMatch[1]) : Number.NaN;
|
|
164
|
+
if (!Number.isFinite(index)) {
|
|
165
|
+
continue;
|
|
166
|
+
}
|
|
167
|
+
const explosionMatch = pointBlock.match(/<c:explosion\b[^>]*\bval="(-?\d+(?:\.\d+)?)"/i);
|
|
168
|
+
const explosionValue = explosionMatch?.[1] ? Number(explosionMatch[1]) : Number.NaN;
|
|
169
|
+
styles.push({
|
|
170
|
+
color: readHexColorFromXmlFragment(pointBlock, false, themePalette),
|
|
171
|
+
explosion: Number.isFinite(explosionValue) ? explosionValue : void 0,
|
|
172
|
+
index,
|
|
173
|
+
lineColor: readHexColorFromXmlFragment(pointBlock, true, themePalette)
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
return styles;
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
function parseNumericPointCacheFromXmlFragment(fragment) {
|
|
180
|
+
const pointMatches = Array.from(fragment.matchAll(/<c:pt\b[^>]*\bidx="(-?\d+)"[^>]*>[\s\S]*?<c:v>([^<]*)<\/c:v>[\s\S]*?<\/c:pt>/gi));
|
|
181
|
+
if (pointMatches.length === 0) {
|
|
182
|
+
return [];
|
|
183
|
+
}
|
|
184
|
+
const explicitPointCountMatch = fragment.match(/<c:ptCount\b[^>]*\bval="(\d+)"/i);
|
|
185
|
+
const explicitPointCount = explicitPointCountMatch?.[1] ? Number(explicitPointCountMatch[1]) : Number.NaN;
|
|
186
|
+
const maxIndex = pointMatches.reduce((max, match) => {
|
|
187
|
+
const current = Number(match[1] ?? Number.NaN);
|
|
188
|
+
return Number.isFinite(current) ? Math.max(max, current) : max;
|
|
189
|
+
}, -1);
|
|
190
|
+
const pointCount = Math.max(
|
|
191
|
+
pointMatches.length,
|
|
192
|
+
Number.isFinite(explicitPointCount) ? explicitPointCount : 0,
|
|
193
|
+
maxIndex + 1
|
|
194
|
+
);
|
|
195
|
+
const values = Array.from({ length: pointCount }, () => null);
|
|
196
|
+
for (const match of pointMatches) {
|
|
197
|
+
const index = Number(match[1] ?? Number.NaN);
|
|
198
|
+
const rawValue = (match[2] ?? "").trim();
|
|
199
|
+
const numericValue = Number(rawValue);
|
|
200
|
+
if (!Number.isFinite(index) || index < 0 || !Number.isFinite(numericValue)) {
|
|
201
|
+
continue;
|
|
202
|
+
}
|
|
203
|
+
values[index] = numericValue;
|
|
204
|
+
}
|
|
205
|
+
return values;
|
|
206
|
+
}
|
|
207
|
+
function parseFallbackBubbleSizesFromChartXml(chartXml) {
|
|
208
|
+
const seriesBlocks = chartXml.match(/<c:ser\b[\s\S]*?<\/c:ser>/gi) ?? [];
|
|
209
|
+
if (seriesBlocks.length === 0) {
|
|
210
|
+
return [];
|
|
211
|
+
}
|
|
212
|
+
return seriesBlocks.map((seriesBlock) => {
|
|
213
|
+
const bubbleSizeBlock = seriesBlock.match(/<c:bubbleSize\b[\s\S]*?<\/c:bubbleSize>/i)?.[0] ?? "";
|
|
214
|
+
if (!bubbleSizeBlock) {
|
|
215
|
+
return [];
|
|
216
|
+
}
|
|
217
|
+
return parseNumericPointCacheFromXmlFragment(bubbleSizeBlock);
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
function decodeChartXmlText(value) {
|
|
221
|
+
return value.replace(/</g, "<").replace(/>/g, ">").replace(/&/g, "&").replace(/"/g, '"').replace(/'/g, "'");
|
|
222
|
+
}
|
|
223
|
+
function normalizeChartTitleForMatch(value) {
|
|
224
|
+
return (value ?? "").trim().replace(/\s+/g, " ").toLowerCase();
|
|
225
|
+
}
|
|
226
|
+
function extractChartTitleFromXml(chartXml) {
|
|
227
|
+
const match = chartXml.match(/<c:title\b[\s\S]*?<a:t>([\s\S]*?)<\/a:t>/i);
|
|
228
|
+
if (!match?.[1]) {
|
|
229
|
+
return null;
|
|
230
|
+
}
|
|
231
|
+
const decoded = decodeChartXmlText(match[1]).trim();
|
|
232
|
+
return decoded.length > 0 ? decoded : null;
|
|
233
|
+
}
|
|
234
|
+
function resolveArchiveFallbackBubbleSizes(archive, preferredTitle) {
|
|
235
|
+
const preferred = normalizeChartTitleForMatch(preferredTitle);
|
|
236
|
+
let bestScore = Number.NEGATIVE_INFINITY;
|
|
237
|
+
let bestCandidate = [];
|
|
238
|
+
for (const [path, bytes] of Object.entries(archive)) {
|
|
239
|
+
if (!/\/charts\/chart\d+\.xml$/i.test(path)) {
|
|
240
|
+
continue;
|
|
241
|
+
}
|
|
242
|
+
const chartXml = strFromU8(bytes);
|
|
243
|
+
if (!/<c:bubbleChart\b/i.test(chartXml)) {
|
|
244
|
+
continue;
|
|
245
|
+
}
|
|
246
|
+
const candidateBubbleSizes = parseFallbackBubbleSizesFromChartXml(chartXml);
|
|
247
|
+
const hasCandidateValues = candidateBubbleSizes.some((seriesValues) => seriesValues.some((value) => value != null));
|
|
248
|
+
if (!hasCandidateValues) {
|
|
249
|
+
continue;
|
|
250
|
+
}
|
|
251
|
+
let score = 0;
|
|
252
|
+
const candidateTitle = normalizeChartTitleForMatch(extractChartTitleFromXml(chartXml));
|
|
253
|
+
if (preferred.length > 0 && candidateTitle.length > 0 && preferred === candidateTitle) {
|
|
254
|
+
score += 100;
|
|
255
|
+
}
|
|
256
|
+
if (bestCandidate.length === 0) {
|
|
257
|
+
score += 1;
|
|
258
|
+
}
|
|
259
|
+
if (score > bestScore) {
|
|
260
|
+
bestScore = score;
|
|
261
|
+
bestCandidate = candidateBubbleSizes;
|
|
262
|
+
if (score >= 100) {
|
|
263
|
+
break;
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
return bestCandidate;
|
|
268
|
+
}
|
|
269
|
+
function parseChartTypeFromXml(chartXml) {
|
|
270
|
+
for (const chartType of PRIMARY_CHART_TYPE_LOCAL_NAMES) {
|
|
271
|
+
if (new RegExp(`<c:${chartType}\\b`, "i").test(chartXml)) {
|
|
272
|
+
return chartType;
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
return "";
|
|
276
|
+
}
|
|
277
|
+
function findPrimaryChartTypeNode(plotAreaNode) {
|
|
278
|
+
if (!plotAreaNode) {
|
|
279
|
+
return null;
|
|
280
|
+
}
|
|
281
|
+
for (const localName of PRIMARY_CHART_TYPE_LOCAL_NAMES) {
|
|
282
|
+
const node = getLocalChildren(plotAreaNode, localName)[0];
|
|
283
|
+
if (node) {
|
|
284
|
+
return node;
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
return null;
|
|
288
|
+
}
|
|
289
|
+
function resolveScatterChartType(scatterStyle) {
|
|
290
|
+
switch (scatterStyle) {
|
|
291
|
+
case "line":
|
|
292
|
+
case "lineMarker":
|
|
293
|
+
return "ScatterLines";
|
|
294
|
+
case "smooth":
|
|
295
|
+
case "smoothMarker":
|
|
296
|
+
return "ScatterSmooth";
|
|
297
|
+
default:
|
|
298
|
+
return "Scatter";
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
function resolveArchiveFallbackPointStyles(archive, preferredTitle, preferredChartXmlType, themePalette) {
|
|
302
|
+
const preferred = normalizeChartTitleForMatch(preferredTitle);
|
|
303
|
+
const preferredType = (preferredChartXmlType ?? "").trim();
|
|
304
|
+
let bestScore = Number.NEGATIVE_INFINITY;
|
|
305
|
+
let bestCandidate = [];
|
|
306
|
+
for (const [path, bytes] of Object.entries(archive)) {
|
|
307
|
+
if (!/\/charts\/chart\d+\.xml$/i.test(path)) {
|
|
308
|
+
continue;
|
|
309
|
+
}
|
|
310
|
+
const chartXml = strFromU8(bytes);
|
|
311
|
+
const candidateType = parseChartTypeFromXml(chartXml);
|
|
312
|
+
if (!candidateType) {
|
|
313
|
+
continue;
|
|
314
|
+
}
|
|
315
|
+
const candidatePointStyles = parseFallbackPointStylesFromChartXml(chartXml, themePalette);
|
|
316
|
+
const hasCandidateValues = candidatePointStyles.some((seriesStyles) => seriesStyles.some((style) => typeof style.color === "string" && style.color.length > 0 || typeof style.explosion === "number"));
|
|
317
|
+
if (!hasCandidateValues) {
|
|
318
|
+
continue;
|
|
319
|
+
}
|
|
320
|
+
let score = 0;
|
|
321
|
+
const candidateTitle = normalizeChartTitleForMatch(extractChartTitleFromXml(chartXml));
|
|
322
|
+
if (preferred.length > 0 && candidateTitle.length > 0 && preferred === candidateTitle) {
|
|
323
|
+
score += 100;
|
|
324
|
+
}
|
|
325
|
+
if (preferredType && candidateType === preferredType) {
|
|
326
|
+
score += 20;
|
|
327
|
+
}
|
|
328
|
+
if (bestCandidate.length === 0) {
|
|
329
|
+
score += 1;
|
|
330
|
+
}
|
|
331
|
+
if (score > bestScore) {
|
|
332
|
+
bestScore = score;
|
|
333
|
+
bestCandidate = candidatePointStyles;
|
|
334
|
+
if (score >= 120) {
|
|
335
|
+
break;
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
return bestCandidate;
|
|
340
|
+
}
|
|
341
|
+
function parseHexColor(color) {
|
|
342
|
+
const normalized = normalizeHexColor(color);
|
|
343
|
+
if (!normalized) {
|
|
344
|
+
return null;
|
|
345
|
+
}
|
|
346
|
+
const match = /^#([0-9a-f]{6})$/.exec(normalized);
|
|
347
|
+
if (!match) {
|
|
348
|
+
return null;
|
|
349
|
+
}
|
|
350
|
+
return [
|
|
351
|
+
Number.parseInt(match[1].slice(0, 2), 16),
|
|
352
|
+
Number.parseInt(match[1].slice(2, 4), 16),
|
|
353
|
+
Number.parseInt(match[1].slice(4, 6), 16)
|
|
354
|
+
];
|
|
355
|
+
}
|
|
356
|
+
function rgbToHsl(red, green, blue) {
|
|
357
|
+
const normalizedRed = red / 255;
|
|
358
|
+
const normalizedGreen = green / 255;
|
|
359
|
+
const normalizedBlue = blue / 255;
|
|
360
|
+
const max = Math.max(normalizedRed, normalizedGreen, normalizedBlue);
|
|
361
|
+
const min = Math.min(normalizedRed, normalizedGreen, normalizedBlue);
|
|
362
|
+
const lightness = (max + min) / 2;
|
|
363
|
+
if (max === min) {
|
|
364
|
+
return [0, 0, lightness];
|
|
365
|
+
}
|
|
366
|
+
const delta = max - min;
|
|
367
|
+
const saturation = lightness > 0.5 ? delta / (2 - max - min) : delta / (max + min);
|
|
368
|
+
let hue = 0;
|
|
369
|
+
switch (max) {
|
|
370
|
+
case normalizedRed:
|
|
371
|
+
hue = (normalizedGreen - normalizedBlue) / delta + (normalizedGreen < normalizedBlue ? 6 : 0);
|
|
372
|
+
break;
|
|
373
|
+
case normalizedGreen:
|
|
374
|
+
hue = (normalizedBlue - normalizedRed) / delta + 2;
|
|
375
|
+
break;
|
|
376
|
+
default:
|
|
377
|
+
hue = (normalizedRed - normalizedGreen) / delta + 4;
|
|
378
|
+
break;
|
|
379
|
+
}
|
|
380
|
+
return [hue / 6, saturation, lightness];
|
|
381
|
+
}
|
|
382
|
+
function hueToRgb(p, q, t) {
|
|
383
|
+
let nextT = t;
|
|
384
|
+
if (nextT < 0) {
|
|
385
|
+
nextT += 1;
|
|
386
|
+
}
|
|
387
|
+
if (nextT > 1) {
|
|
388
|
+
nextT -= 1;
|
|
389
|
+
}
|
|
390
|
+
if (nextT < 1 / 6) {
|
|
391
|
+
return p + (q - p) * 6 * nextT;
|
|
392
|
+
}
|
|
393
|
+
if (nextT < 1 / 2) {
|
|
394
|
+
return q;
|
|
395
|
+
}
|
|
396
|
+
if (nextT < 2 / 3) {
|
|
397
|
+
return p + (q - p) * (2 / 3 - nextT) * 6;
|
|
398
|
+
}
|
|
399
|
+
return p;
|
|
400
|
+
}
|
|
401
|
+
function hslToRgb(hue, saturation, lightness) {
|
|
402
|
+
if (saturation === 0) {
|
|
403
|
+
const gray = Math.round(lightness * 255);
|
|
404
|
+
return [gray, gray, gray];
|
|
405
|
+
}
|
|
406
|
+
const q = lightness < 0.5 ? lightness * (1 + saturation) : lightness + saturation - lightness * saturation;
|
|
407
|
+
const p = 2 * lightness - q;
|
|
408
|
+
return [
|
|
409
|
+
Math.round(hueToRgb(p, q, hue + 1 / 3) * 255),
|
|
410
|
+
Math.round(hueToRgb(p, q, hue) * 255),
|
|
411
|
+
Math.round(hueToRgb(p, q, hue - 1 / 3) * 255)
|
|
412
|
+
];
|
|
413
|
+
}
|
|
414
|
+
function rgbToHex(red, green, blue) {
|
|
415
|
+
return `#${[red, green, blue].map((channel) => Math.max(0, Math.min(255, Math.round(channel))).toString(16).padStart(2, "0")).join("")}`;
|
|
416
|
+
}
|
|
417
|
+
function applyLightnessTransform(baseColor, modifier = 1, offset = 0) {
|
|
418
|
+
const rgb = parseHexColor(baseColor);
|
|
419
|
+
if (!rgb) {
|
|
420
|
+
return normalizeHexColor(baseColor);
|
|
421
|
+
}
|
|
422
|
+
const [hue, saturation, lightness] = rgbToHsl(rgb[0], rgb[1], rgb[2]);
|
|
423
|
+
const nextLightness = clampUnitInterval(lightness * modifier + offset);
|
|
424
|
+
const [nextRed, nextGreen, nextBlue] = hslToRgb(hue, saturation, nextLightness);
|
|
425
|
+
return rgbToHex(nextRed, nextGreen, nextBlue);
|
|
426
|
+
}
|
|
427
|
+
function resolveThemeColor(name, themePalette) {
|
|
428
|
+
if (!name) {
|
|
429
|
+
return null;
|
|
430
|
+
}
|
|
431
|
+
const index = THEME_COLOR_INDEX_BY_NAME[name];
|
|
432
|
+
return index === void 0 ? null : themePalette?.colorsByIndex[index] ?? null;
|
|
433
|
+
}
|
|
434
|
+
function resolveThemeTypeface(typeface, themePalette) {
|
|
435
|
+
if (!typeface) {
|
|
436
|
+
return null;
|
|
437
|
+
}
|
|
438
|
+
if (typeface === "+mn-lt" || typeface === "+mn-ea" || typeface === "+mn-cs") {
|
|
439
|
+
return themePalette?.minorLatinFont ?? null;
|
|
440
|
+
}
|
|
441
|
+
if (typeface === "+mj-lt" || typeface === "+mj-ea" || typeface === "+mj-cs") {
|
|
442
|
+
return themePalette?.majorLatinFont ?? null;
|
|
443
|
+
}
|
|
444
|
+
return typeface;
|
|
445
|
+
}
|
|
446
|
+
function readChartTextTypeface(textPropertiesNode, themePalette) {
|
|
447
|
+
if (!textPropertiesNode) {
|
|
448
|
+
return null;
|
|
449
|
+
}
|
|
450
|
+
const defaultRunProperties = getFirstLocalDescendant(textPropertiesNode, "defRPr") ?? getFirstLocalDescendant(textPropertiesNode, "rPr");
|
|
451
|
+
if (!defaultRunProperties) {
|
|
452
|
+
return null;
|
|
453
|
+
}
|
|
454
|
+
const typeface = getFirstLocalChild(defaultRunProperties, "latin")?.getAttribute("typeface") ?? getFirstLocalChild(defaultRunProperties, "ea")?.getAttribute("typeface") ?? getFirstLocalChild(defaultRunProperties, "cs")?.getAttribute("typeface") ?? null;
|
|
455
|
+
const resolved = resolveThemeTypeface(typeface, themePalette)?.trim() ?? "";
|
|
456
|
+
return resolved.length > 0 ? resolved : null;
|
|
457
|
+
}
|
|
458
|
+
function resolveChartColorNode(node, themePalette) {
|
|
459
|
+
if (!node) {
|
|
460
|
+
return null;
|
|
461
|
+
}
|
|
462
|
+
let baseColor = null;
|
|
463
|
+
if (node.localName === "srgbClr") {
|
|
464
|
+
baseColor = normalizeHexColor(`#${node.getAttribute("val") ?? ""}`);
|
|
465
|
+
} else if (node.localName === "schemeClr") {
|
|
466
|
+
baseColor = resolveThemeColor(node.getAttribute("val"), themePalette);
|
|
467
|
+
} else if (node.localName === "sysClr") {
|
|
468
|
+
baseColor = normalizeHexColor(`#${node.getAttribute("lastClr") ?? ""}`);
|
|
469
|
+
}
|
|
470
|
+
if (!baseColor) {
|
|
471
|
+
return null;
|
|
472
|
+
}
|
|
473
|
+
let lightnessModifier = 1;
|
|
474
|
+
let lightnessOffset = 0;
|
|
475
|
+
for (const transformNode of Array.from(node.childNodes).filter(isElementNode)) {
|
|
476
|
+
const rawValue = Number(transformNode.getAttribute("val") ?? Number.NaN);
|
|
477
|
+
if (!Number.isFinite(rawValue)) {
|
|
478
|
+
continue;
|
|
479
|
+
}
|
|
480
|
+
if (transformNode.localName === "lumMod") {
|
|
481
|
+
lightnessModifier *= rawValue / 1e5;
|
|
482
|
+
} else if (transformNode.localName === "lumOff") {
|
|
483
|
+
lightnessOffset += rawValue / 1e5;
|
|
484
|
+
} else if (transformNode.localName === "tint") {
|
|
485
|
+
lightnessOffset += (1 - lightnessOffset) * (rawValue / 1e5);
|
|
486
|
+
} else if (transformNode.localName === "shade") {
|
|
487
|
+
lightnessModifier *= rawValue / 1e5;
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
return applyLightnessTransform(baseColor, lightnessModifier, lightnessOffset);
|
|
491
|
+
}
|
|
492
|
+
function isChartColorElement(node) {
|
|
493
|
+
return Boolean(node && (node.localName === "schemeClr" || node.localName === "srgbClr" || node.localName === "sysClr"));
|
|
494
|
+
}
|
|
495
|
+
function findFirstChartColorElement(node) {
|
|
496
|
+
if (!node) {
|
|
497
|
+
return null;
|
|
498
|
+
}
|
|
499
|
+
if (isChartColorElement(node)) {
|
|
500
|
+
return node;
|
|
501
|
+
}
|
|
502
|
+
for (const localName of ["srgbClr", "schemeClr", "sysClr"]) {
|
|
503
|
+
for (const candidate of getLocalDescendants(node, localName)) {
|
|
504
|
+
if (isChartColorElement(candidate)) {
|
|
505
|
+
return candidate;
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
return null;
|
|
510
|
+
}
|
|
511
|
+
function resolveChartFillColor(shapeNode, themePalette) {
|
|
512
|
+
if (!shapeNode || getFirstLocalChild(shapeNode, "noFill")) {
|
|
513
|
+
return null;
|
|
514
|
+
}
|
|
515
|
+
const solidFill = getFirstLocalChild(shapeNode, "solidFill");
|
|
516
|
+
if (solidFill) {
|
|
517
|
+
const colorNode = findFirstChartColorElement(Array.from(solidFill.childNodes).find(isElementNode) ?? null);
|
|
518
|
+
return resolveChartColorNode(colorNode, themePalette);
|
|
519
|
+
}
|
|
520
|
+
const gradientFill = getFirstLocalChild(shapeNode, "gradFill");
|
|
521
|
+
const gradientStops = gradientFill ? getLocalDescendants(gradientFill, "gs").map((stopNode) => ({
|
|
522
|
+
colorNode: Array.from(stopNode.childNodes).find(isElementNode) ?? null,
|
|
523
|
+
position: Number(stopNode.getAttribute("pos") ?? Number.NaN)
|
|
524
|
+
})).filter((stop) => Boolean(stop.colorNode)) : [];
|
|
525
|
+
if (gradientStops.length === 0) {
|
|
526
|
+
return null;
|
|
527
|
+
}
|
|
528
|
+
gradientStops.sort((left, right) => {
|
|
529
|
+
const leftPos = Number.isFinite(left.position) ? left.position : 0;
|
|
530
|
+
const rightPos = Number.isFinite(right.position) ? right.position : 0;
|
|
531
|
+
return leftPos - rightPos;
|
|
532
|
+
});
|
|
533
|
+
const midpointStop = gradientStops.find((stop) => Number.isFinite(stop.position) && stop.position >= 5e4) ?? gradientStops[Math.floor(gradientStops.length / 2)] ?? gradientStops[0];
|
|
534
|
+
return resolveChartColorNode(midpointStop.colorNode, themePalette);
|
|
535
|
+
}
|
|
536
|
+
function resolveChartLineStyle(shapeNode, themePalette) {
|
|
537
|
+
const lineNode = shapeNode?.localName === "ln" ? shapeNode : shapeNode ? getFirstLocalChild(shapeNode, "ln") : null;
|
|
538
|
+
if (!lineNode) {
|
|
539
|
+
return { color: null, hidden: false, widthPx: void 0 };
|
|
540
|
+
}
|
|
541
|
+
if (getFirstLocalChild(lineNode, "noFill")) {
|
|
542
|
+
return { color: null, hidden: true, widthPx: void 0 };
|
|
543
|
+
}
|
|
544
|
+
const solidFill = getFirstLocalChild(lineNode, "solidFill");
|
|
545
|
+
const colorNode = solidFill ? findFirstChartColorElement(Array.from(solidFill.childNodes).find(isElementNode) ?? null) : null;
|
|
546
|
+
const widthValue = Number(lineNode.getAttribute("w") ?? Number.NaN);
|
|
547
|
+
return {
|
|
548
|
+
color: resolveChartColorNode(colorNode, themePalette),
|
|
549
|
+
hidden: false,
|
|
550
|
+
widthPx: Number.isFinite(widthValue) ? Math.max(1, widthValue / EMU_PER_PIXEL) : void 0
|
|
551
|
+
};
|
|
552
|
+
}
|
|
553
|
+
function normalizeLegend(raw) {
|
|
554
|
+
if (!raw || typeof raw !== "object") {
|
|
555
|
+
return null;
|
|
556
|
+
}
|
|
557
|
+
const legend = raw;
|
|
558
|
+
return {
|
|
559
|
+
overlay: typeof legend.overlay === "boolean" ? legend.overlay : void 0,
|
|
560
|
+
position: typeof legend.position === "string" ? legend.position : void 0,
|
|
561
|
+
raw: legend
|
|
562
|
+
};
|
|
563
|
+
}
|
|
564
|
+
function normalizeLegendPosition(position) {
|
|
565
|
+
if (!position) {
|
|
566
|
+
return void 0;
|
|
567
|
+
}
|
|
568
|
+
switch (position) {
|
|
569
|
+
case "bottom":
|
|
570
|
+
return "b";
|
|
571
|
+
case "left":
|
|
572
|
+
return "l";
|
|
573
|
+
case "right":
|
|
574
|
+
return "r";
|
|
575
|
+
case "top":
|
|
576
|
+
return "t";
|
|
577
|
+
default:
|
|
578
|
+
return position;
|
|
579
|
+
}
|
|
580
|
+
}
|
|
581
|
+
function readChartNumericAttribute(parent, localName) {
|
|
582
|
+
const node = parent ? getFirstLocalChild(parent, localName) : null;
|
|
583
|
+
const value = Number(node?.getAttribute("val") ?? Number.NaN);
|
|
584
|
+
return Number.isFinite(value) ? value : void 0;
|
|
585
|
+
}
|
|
586
|
+
function readChartBooleanAttribute(parent, localName) {
|
|
587
|
+
const node = parent ? getFirstLocalChild(parent, localName) : null;
|
|
588
|
+
if (!node) {
|
|
589
|
+
return void 0;
|
|
590
|
+
}
|
|
591
|
+
const rawValue = node.getAttribute("val");
|
|
592
|
+
if (rawValue == null) {
|
|
593
|
+
return true;
|
|
594
|
+
}
|
|
595
|
+
if (rawValue === "1" || rawValue === "true") {
|
|
596
|
+
return true;
|
|
597
|
+
}
|
|
598
|
+
if (rawValue === "0" || rawValue === "false") {
|
|
599
|
+
return false;
|
|
600
|
+
}
|
|
601
|
+
return void 0;
|
|
602
|
+
}
|
|
603
|
+
function readChartLabelFontSizePt(textPropertiesNode) {
|
|
604
|
+
if (!textPropertiesNode) {
|
|
605
|
+
return void 0;
|
|
606
|
+
}
|
|
607
|
+
const runPropertiesNode = getFirstLocalDescendant(textPropertiesNode, "defRPr") ?? getFirstLocalDescendant(textPropertiesNode, "rPr");
|
|
608
|
+
const rawSize = Number(runPropertiesNode?.getAttribute("sz") ?? Number.NaN);
|
|
609
|
+
if (!Number.isFinite(rawSize) || rawSize <= 0) {
|
|
610
|
+
return void 0;
|
|
611
|
+
}
|
|
612
|
+
return rawSize / 100;
|
|
613
|
+
}
|
|
614
|
+
function parseChartPointDataLabelsFromXml(labelsNode) {
|
|
615
|
+
const fallbackFontSizePt = readChartLabelFontSizePt(getFirstLocalChild(labelsNode, "txPr"));
|
|
616
|
+
const labels = [];
|
|
617
|
+
for (const pointLabelNode of getLocalChildren(labelsNode, "dLbl")) {
|
|
618
|
+
const index = readChartNumericAttribute(pointLabelNode, "idx");
|
|
619
|
+
if (typeof index !== "number" || !Number.isFinite(index)) {
|
|
620
|
+
continue;
|
|
621
|
+
}
|
|
622
|
+
const layoutNode = getFirstLocalChild(pointLabelNode, "layout");
|
|
623
|
+
const manualLayoutNode = getFirstLocalChild(layoutNode, "manualLayout");
|
|
624
|
+
labels.push({
|
|
625
|
+
deleted: readChartBooleanAttribute(pointLabelNode, "delete"),
|
|
626
|
+
fontSizePt: readChartLabelFontSizePt(getFirstLocalChild(pointLabelNode, "txPr")) ?? fallbackFontSizePt,
|
|
627
|
+
index,
|
|
628
|
+
showBubbleSize: readChartBooleanAttribute(pointLabelNode, "showBubbleSize"),
|
|
629
|
+
showCategoryName: readChartBooleanAttribute(pointLabelNode, "showCatName"),
|
|
630
|
+
showPercent: readChartBooleanAttribute(pointLabelNode, "showPercent"),
|
|
631
|
+
showSeriesName: readChartBooleanAttribute(pointLabelNode, "showSerName"),
|
|
632
|
+
showValue: readChartBooleanAttribute(pointLabelNode, "showVal"),
|
|
633
|
+
x: readChartNumericAttribute(manualLayoutNode, "x"),
|
|
634
|
+
y: readChartNumericAttribute(manualLayoutNode, "y")
|
|
635
|
+
});
|
|
636
|
+
}
|
|
637
|
+
return labels;
|
|
638
|
+
}
|
|
639
|
+
function parseChartDataLabelsFromXml(labelsNode) {
|
|
640
|
+
if (!labelsNode) {
|
|
641
|
+
return null;
|
|
642
|
+
}
|
|
643
|
+
const pointLabels = parseChartPointDataLabelsFromXml(labelsNode);
|
|
644
|
+
const labels = {
|
|
645
|
+
pointLabels: pointLabels.length > 0 ? pointLabels : void 0,
|
|
646
|
+
raw: {},
|
|
647
|
+
showBubbleSize: readChartBooleanAttribute(labelsNode, "showBubbleSize"),
|
|
648
|
+
showCategoryName: readChartBooleanAttribute(labelsNode, "showCatName"),
|
|
649
|
+
showLegendKey: readChartBooleanAttribute(labelsNode, "showLegendKey"),
|
|
650
|
+
showPercent: readChartBooleanAttribute(labelsNode, "showPercent"),
|
|
651
|
+
showSeriesName: readChartBooleanAttribute(labelsNode, "showSerName"),
|
|
652
|
+
showValue: readChartBooleanAttribute(labelsNode, "showVal")
|
|
653
|
+
};
|
|
654
|
+
const hasValue = labels.showBubbleSize !== void 0 || labels.showCategoryName !== void 0 || labels.showLegendKey !== void 0 || labels.showPercent !== void 0 || (labels.pointLabels?.length ?? 0) > 0 || labels.showSeriesName !== void 0 || labels.showValue !== void 0;
|
|
655
|
+
return hasValue ? labels : null;
|
|
656
|
+
}
|
|
657
|
+
function readChartRelationships(archive, chartPath) {
|
|
658
|
+
const relsPath = normalizeArchivePath(`${dirname(chartPath)}/_rels/${chartPath.split("/").pop()}.rels`);
|
|
659
|
+
const relsXml = readArchiveText(archive, relsPath);
|
|
660
|
+
if (!relsXml) {
|
|
661
|
+
return /* @__PURE__ */ new Map();
|
|
662
|
+
}
|
|
663
|
+
const relsDocument = parseXml(relsXml);
|
|
664
|
+
if (!relsDocument) {
|
|
665
|
+
return /* @__PURE__ */ new Map();
|
|
666
|
+
}
|
|
667
|
+
const relationships = /* @__PURE__ */ new Map();
|
|
668
|
+
for (const relationshipNode of getLocalDescendants(relsDocument, "Relationship")) {
|
|
669
|
+
const type = relationshipNode.getAttribute("Type");
|
|
670
|
+
const target = relationshipNode.getAttribute("Target");
|
|
671
|
+
if (!type || !target) {
|
|
672
|
+
continue;
|
|
673
|
+
}
|
|
674
|
+
relationships.set(type, resolveRelationshipPath(relsPath, target));
|
|
675
|
+
}
|
|
676
|
+
return relationships;
|
|
677
|
+
}
|
|
678
|
+
function readChartColorPalette(archive, colorStylePath, themePalette) {
|
|
679
|
+
const colorStyleXml = readArchiveText(archive, colorStylePath);
|
|
680
|
+
if (!colorStyleXml) {
|
|
681
|
+
return [];
|
|
682
|
+
}
|
|
683
|
+
const colorStyleDocument = parseXml(colorStyleXml);
|
|
684
|
+
if (!colorStyleDocument?.documentElement) {
|
|
685
|
+
return [];
|
|
686
|
+
}
|
|
687
|
+
return Array.from(colorStyleDocument.documentElement.childNodes).filter((child) => isElementNode(child) && child.localName !== "variation").map((child) => resolveChartColorNode(child, themePalette) ?? resolveChartColorNode(findFirstChartColorElement(child), themePalette)).filter((color) => typeof color === "string");
|
|
688
|
+
}
|
|
689
|
+
function readChartStyleAppearance(archive, stylePath, themePalette) {
|
|
690
|
+
const styleXml = readArchiveText(archive, stylePath);
|
|
691
|
+
if (!styleXml) {
|
|
692
|
+
return {};
|
|
693
|
+
}
|
|
694
|
+
const styleDocument = parseXml(styleXml);
|
|
695
|
+
if (!styleDocument) {
|
|
696
|
+
return {};
|
|
697
|
+
}
|
|
698
|
+
const dataPointNode = getFirstLocalDescendant(styleDocument, "dataPoint");
|
|
699
|
+
const fillRefNode = dataPointNode ? getFirstLocalChild(dataPointNode, "fillRef") : null;
|
|
700
|
+
const index = Number(fillRefNode?.getAttribute("idx") ?? Number.NaN);
|
|
701
|
+
const chartAreaNode = getFirstLocalDescendant(styleDocument, "chartArea");
|
|
702
|
+
const chartAreaShapeProperties = chartAreaNode ? getFirstLocalChild(chartAreaNode, "spPr") : null;
|
|
703
|
+
const chartAreaFontRef = chartAreaNode ? getFirstLocalChild(chartAreaNode, "fontRef") : null;
|
|
704
|
+
const chartAreaFontColor = chartAreaFontRef ? resolveChartColorNode(Array.from(chartAreaFontRef.childNodes).find(isElementNode) ?? null, themePalette) : null;
|
|
705
|
+
const titleNode = getFirstLocalDescendant(styleDocument, "title");
|
|
706
|
+
const titleFontRef = titleNode ? getFirstLocalChild(titleNode, "fontRef") : null;
|
|
707
|
+
const titleColor = titleFontRef ? resolveChartColorNode(Array.from(titleFontRef.childNodes).find(isElementNode) ?? null, themePalette) : null;
|
|
708
|
+
const axisStyleNode = getFirstLocalDescendant(styleDocument, "categoryAxis") ?? getFirstLocalDescendant(styleDocument, "valueAxis");
|
|
709
|
+
const axisShapeProperties = axisStyleNode ? getFirstLocalChild(axisStyleNode, "spPr") : null;
|
|
710
|
+
const axisFontRef = axisStyleNode ? getFirstLocalChild(axisStyleNode, "fontRef") : null;
|
|
711
|
+
const chartAreaNoFill = chartAreaShapeProperties ? getFirstLocalChild(chartAreaShapeProperties, "noFill") != null : false;
|
|
712
|
+
return {
|
|
713
|
+
axisLabelColor: axisFontRef ? resolveChartColorNode(Array.from(axisFontRef.childNodes).find(isElementNode) ?? null, themePalette) ?? void 0 : void 0,
|
|
714
|
+
axisLineColor: resolveChartLineStyle(axisShapeProperties, themePalette).color ?? void 0,
|
|
715
|
+
chartAreaBorderColor: resolveChartLineStyle(chartAreaShapeProperties, themePalette).color ?? void 0,
|
|
716
|
+
chartAreaFillColor: resolveChartFillColor(chartAreaShapeProperties, themePalette) ?? void 0,
|
|
717
|
+
chartAreaNoFill,
|
|
718
|
+
paletteOffset: Number.isFinite(index) ? index : void 0,
|
|
719
|
+
textColor: chartAreaFontColor ?? void 0,
|
|
720
|
+
titleColor: titleColor ?? chartAreaFontColor ?? void 0
|
|
721
|
+
};
|
|
722
|
+
}
|
|
723
|
+
function buildThemeSeriesPalette(themePalette) {
|
|
724
|
+
const themeColors = [4, 5, 6, 7, 8, 9].map((index) => themePalette?.colorsByIndex[index] ?? null).filter((color) => Boolean(color));
|
|
725
|
+
return themeColors.length > 0 ? themeColors : SERIES_COLORS;
|
|
726
|
+
}
|
|
727
|
+
function normalizeBuiltinSurfaceStyleId(styleId) {
|
|
728
|
+
if (typeof styleId !== "number" || !Number.isFinite(styleId)) {
|
|
729
|
+
return null;
|
|
730
|
+
}
|
|
731
|
+
return styleId >= 100 ? styleId - 100 : styleId;
|
|
732
|
+
}
|
|
733
|
+
function getBuiltinSurfacePalette(styleId, wireframe) {
|
|
734
|
+
const normalized = normalizeBuiltinSurfaceStyleId(styleId);
|
|
735
|
+
if (normalized === 34 || wireframe === true && normalized == null) {
|
|
736
|
+
return ["#5b9bd5", "#ed7d31", "#a5a5a5"];
|
|
737
|
+
}
|
|
738
|
+
if (normalized === 35 || normalized === 36 || wireframe !== true && normalized == null) {
|
|
739
|
+
return ["#2f5597", "#4472c4", "#5b9bd5", "#8faadc", "#d9e2f3"];
|
|
740
|
+
}
|
|
741
|
+
return null;
|
|
742
|
+
}
|
|
743
|
+
function applyBuiltinSurfaceDefaults(chart) {
|
|
744
|
+
if (chart.chartType !== "Surface") {
|
|
745
|
+
return;
|
|
746
|
+
}
|
|
747
|
+
const builtinPalette = getBuiltinSurfacePalette(chart.chartStyleId, chart.wireframe);
|
|
748
|
+
if ((!chart.chartColorPalette || chart.chartColorPalette.length === 0) && builtinPalette) {
|
|
749
|
+
chart.chartColorPalette = builtinPalette;
|
|
750
|
+
}
|
|
751
|
+
const wallFill = chart.wireframe ? "#d0d0d0" : "#d9d9df";
|
|
752
|
+
const wallLine = chart.wireframe ? "#a6a6a6" : "#a8adb7";
|
|
753
|
+
chart.floor = {
|
|
754
|
+
...chart.floor ?? {},
|
|
755
|
+
fillColor: chart.floor?.fillColor ?? wallFill,
|
|
756
|
+
lineColor: chart.floor?.lineColor ?? wallLine
|
|
757
|
+
};
|
|
758
|
+
chart.sideWall = {
|
|
759
|
+
...chart.sideWall ?? {},
|
|
760
|
+
fillColor: chart.sideWall?.fillColor ?? wallFill,
|
|
761
|
+
lineColor: chart.sideWall?.lineColor ?? wallLine
|
|
762
|
+
};
|
|
763
|
+
chart.backWall = {
|
|
764
|
+
...chart.backWall ?? {},
|
|
765
|
+
fillColor: chart.backWall?.fillColor ?? wallFill,
|
|
766
|
+
lineColor: chart.backWall?.lineColor ?? wallLine
|
|
767
|
+
};
|
|
768
|
+
if (!chart.surfaceMaterial && chart.wireframe !== true) {
|
|
769
|
+
chart.surfaceMaterial = "flat";
|
|
770
|
+
}
|
|
771
|
+
}
|
|
772
|
+
function applyBuiltinChartDefaults(chart, themePalette) {
|
|
773
|
+
const darkBuiltInStyle = typeof chart.chartStyleId === "number" && chart.chartStyleId >= 140 && chart.chartStyleId < 150;
|
|
774
|
+
const textColor = themePalette?.colorsByIndex[1] ?? themePalette?.colorsByIndex[3] ?? null;
|
|
775
|
+
const minorTypeface = themePalette?.minorLatinFont?.trim() || void 0;
|
|
776
|
+
const derivedAxisColor = textColor ? applyLightnessTransform(textColor, 0.35, 0.55) : null;
|
|
777
|
+
const derivedBorderColor = textColor ? applyLightnessTransform(textColor, chart.is3d ? 0.28 : 0.22, chart.is3d ? 0.6 : 0.7) : null;
|
|
778
|
+
if (darkBuiltInStyle) {
|
|
779
|
+
chart.chartAreaFillColor = chart.chartAreaFillColor ?? "#1f1f1f";
|
|
780
|
+
chart.chartAreaBorderColor = chart.chartAreaBorderColor ?? "#1f1f1f";
|
|
781
|
+
chart.textColor = chart.textColor ?? "#f5f5f5";
|
|
782
|
+
chart.titleColor = chart.titleColor ?? "#f5f5f5";
|
|
783
|
+
chart.axisLabelColor = chart.axisLabelColor ?? "#d9d9d9";
|
|
784
|
+
chart.axisLineColor = chart.axisLineColor ?? "#8c8c8c";
|
|
785
|
+
}
|
|
786
|
+
chart.chartAreaBorderColor = chart.chartAreaBorderColor ?? derivedBorderColor ?? void 0;
|
|
787
|
+
chart.textColor = chart.textColor ?? textColor ?? void 0;
|
|
788
|
+
chart.titleColor = chart.titleColor ?? textColor ?? void 0;
|
|
789
|
+
chart.axisLabelColor = chart.axisLabelColor ?? derivedAxisColor ?? textColor ?? void 0;
|
|
790
|
+
chart.axisLineColor = chart.axisLineColor ?? derivedAxisColor ?? textColor ?? void 0;
|
|
791
|
+
chart.fontFamily = chart.fontFamily ?? minorTypeface;
|
|
792
|
+
chart.titleFontFamily = chart.titleFontFamily ?? chart.fontFamily ?? minorTypeface;
|
|
793
|
+
const seriesPalette = chart.chartColorPalette && chart.chartColorPalette.length > 0 ? chart.chartColorPalette : buildThemeSeriesPalette(themePalette);
|
|
794
|
+
if (!chart.chartColorPalette || chart.chartColorPalette.length === 0) {
|
|
795
|
+
chart.chartColorPalette = seriesPalette;
|
|
796
|
+
}
|
|
797
|
+
chart.series = chart.series.map((series, index) => {
|
|
798
|
+
const fallbackColor = seriesPalette[index % seriesPalette.length];
|
|
799
|
+
return {
|
|
800
|
+
...series,
|
|
801
|
+
color: series.color ?? series.lineColor ?? fallbackColor,
|
|
802
|
+
lineColor: series.lineColor ?? series.color ?? fallbackColor,
|
|
803
|
+
markerColor: series.markerColor ?? series.color ?? series.lineColor ?? fallbackColor,
|
|
804
|
+
markerLineColor: series.markerLineColor ?? series.lineColor ?? series.color ?? fallbackColor
|
|
805
|
+
};
|
|
806
|
+
});
|
|
807
|
+
chart.typeGroups = chart.typeGroups?.map((group, groupIndex) => ({
|
|
808
|
+
...group,
|
|
809
|
+
series: group.series.map((series, seriesIndex) => {
|
|
810
|
+
const fallbackColor = seriesPalette[(groupIndex + seriesIndex) % seriesPalette.length];
|
|
811
|
+
return {
|
|
812
|
+
...series,
|
|
813
|
+
color: series.color ?? series.lineColor ?? fallbackColor,
|
|
814
|
+
lineColor: series.lineColor ?? series.color ?? fallbackColor,
|
|
815
|
+
markerColor: series.markerColor ?? series.color ?? series.lineColor ?? fallbackColor,
|
|
816
|
+
markerLineColor: series.markerLineColor ?? series.lineColor ?? series.color ?? fallbackColor
|
|
817
|
+
};
|
|
818
|
+
})
|
|
819
|
+
}));
|
|
820
|
+
applyBuiltinSurfaceDefaults(chart);
|
|
821
|
+
}
|
|
822
|
+
function parseChartPointStyles(seriesNode, themePalette) {
|
|
823
|
+
const pointStyles = [];
|
|
824
|
+
for (const dataPointNode of getLocalChildren(seriesNode, "dPt")) {
|
|
825
|
+
const indexValue = readChartNumericAttribute(dataPointNode, "idx");
|
|
826
|
+
if (indexValue === void 0) {
|
|
827
|
+
continue;
|
|
828
|
+
}
|
|
829
|
+
const shapeProperties = getFirstLocalChild(dataPointNode, "spPr");
|
|
830
|
+
const lineStyle = resolveChartLineStyle(shapeProperties, themePalette);
|
|
831
|
+
pointStyles.push({
|
|
832
|
+
color: resolveChartFillColor(shapeProperties, themePalette) ?? void 0,
|
|
833
|
+
explosion: readChartNumericAttribute(dataPointNode, "explosion"),
|
|
834
|
+
index: indexValue,
|
|
835
|
+
lineColor: lineStyle.color ?? void 0
|
|
836
|
+
});
|
|
837
|
+
}
|
|
838
|
+
return pointStyles;
|
|
839
|
+
}
|
|
840
|
+
function parseInvertNegativeStyle(seriesNode, themePalette) {
|
|
841
|
+
const invertNode = getFirstLocalDescendant(seriesNode, "invertSolidFillFmt");
|
|
842
|
+
const shapeProperties = invertNode ? getFirstLocalChild(invertNode, "spPr") : null;
|
|
843
|
+
if (!shapeProperties) {
|
|
844
|
+
return {
|
|
845
|
+
color: void 0,
|
|
846
|
+
lineColor: void 0
|
|
847
|
+
};
|
|
848
|
+
}
|
|
849
|
+
const lineStyle = resolveChartLineStyle(shapeProperties, themePalette);
|
|
850
|
+
return {
|
|
851
|
+
color: resolveChartFillColor(shapeProperties, themePalette) ?? void 0,
|
|
852
|
+
lineColor: lineStyle.color ?? void 0
|
|
853
|
+
};
|
|
854
|
+
}
|
|
855
|
+
function parseChartCacheValues(parentNode, cacheName, mode) {
|
|
856
|
+
if (!parentNode) {
|
|
857
|
+
return null;
|
|
858
|
+
}
|
|
859
|
+
const referenceNode = getFirstLocalChild(parentNode, "numRef") ?? getFirstLocalChild(parentNode, "strRef") ?? parentNode;
|
|
860
|
+
const cacheNode = getFirstLocalChild(referenceNode, cacheName);
|
|
861
|
+
if (!cacheNode) {
|
|
862
|
+
return null;
|
|
863
|
+
}
|
|
864
|
+
const pointCount = readChartNumericAttribute(cacheNode, "ptCount");
|
|
865
|
+
const pointNodes = getLocalChildren(cacheNode, "pt").map((pointNode) => {
|
|
866
|
+
const rawIndex = Number(pointNode.getAttribute("idx") ?? Number.NaN);
|
|
867
|
+
return {
|
|
868
|
+
index: Number.isFinite(rawIndex) ? rawIndex : 0,
|
|
869
|
+
value: getFirstLocalChild(pointNode, "v")?.textContent ?? ""
|
|
870
|
+
};
|
|
871
|
+
}).sort((left, right) => left.index - right.index);
|
|
872
|
+
if (pointNodes.length === 0) {
|
|
873
|
+
return null;
|
|
874
|
+
}
|
|
875
|
+
const maxIndex = pointNodes.reduce((max, point) => Math.max(max, point.index), 0);
|
|
876
|
+
const targetLength = Math.max(
|
|
877
|
+
pointNodes.length,
|
|
878
|
+
Number.isFinite(pointCount ?? Number.NaN) ? Number(pointCount) : 0,
|
|
879
|
+
maxIndex + 1
|
|
880
|
+
);
|
|
881
|
+
const values = Array.from({ length: targetLength }, () => null);
|
|
882
|
+
for (const point of pointNodes) {
|
|
883
|
+
if (mode === "value") {
|
|
884
|
+
values[point.index] = cellValueToNumber(point.value);
|
|
885
|
+
} else {
|
|
886
|
+
values[point.index] = point.value.length > 0 ? point.value : null;
|
|
887
|
+
}
|
|
888
|
+
}
|
|
889
|
+
return values;
|
|
890
|
+
}
|
|
891
|
+
function parseChartMultiLevelCacheValues(parentNode, mode) {
|
|
892
|
+
if (!parentNode) {
|
|
893
|
+
return null;
|
|
894
|
+
}
|
|
895
|
+
const referenceNode = getFirstLocalChild(parentNode, "multiLvlStrRef") ?? parentNode;
|
|
896
|
+
const cacheNode = getFirstLocalChild(referenceNode, "multiLvlStrCache");
|
|
897
|
+
if (!cacheNode) {
|
|
898
|
+
return null;
|
|
899
|
+
}
|
|
900
|
+
const levelNodes = getLocalChildren(cacheNode, "lvl");
|
|
901
|
+
if (levelNodes.length === 0) {
|
|
902
|
+
return null;
|
|
903
|
+
}
|
|
904
|
+
const pointCount = readChartNumericAttribute(cacheNode, "ptCount");
|
|
905
|
+
const primaryLevelNode = mode === "category" ? levelNodes[levelNodes.length - 1] ?? levelNodes[0] : levelNodes[0];
|
|
906
|
+
const pointNodes = getLocalChildren(primaryLevelNode, "pt").map((pointNode) => {
|
|
907
|
+
const rawIndex = Number(pointNode.getAttribute("idx") ?? Number.NaN);
|
|
908
|
+
return {
|
|
909
|
+
index: Number.isFinite(rawIndex) ? rawIndex : 0,
|
|
910
|
+
value: getFirstLocalChild(pointNode, "v")?.textContent ?? ""
|
|
911
|
+
};
|
|
912
|
+
}).sort((left, right) => left.index - right.index);
|
|
913
|
+
if (pointNodes.length === 0) {
|
|
914
|
+
return null;
|
|
915
|
+
}
|
|
916
|
+
const maxIndex = pointNodes.reduce((max, point) => Math.max(max, point.index), 0);
|
|
917
|
+
const targetLength = Math.max(
|
|
918
|
+
pointNodes.length,
|
|
919
|
+
Number.isFinite(pointCount ?? Number.NaN) ? Number(pointCount) : 0,
|
|
920
|
+
maxIndex + 1
|
|
921
|
+
);
|
|
922
|
+
const values = Array.from({ length: targetLength }, () => null);
|
|
923
|
+
for (const point of pointNodes) {
|
|
924
|
+
if (mode === "value") {
|
|
925
|
+
values[point.index] = cellValueToNumber(point.value);
|
|
926
|
+
continue;
|
|
927
|
+
}
|
|
928
|
+
values[point.index] = point.value.length > 0 ? point.value : null;
|
|
929
|
+
}
|
|
930
|
+
return values;
|
|
931
|
+
}
|
|
932
|
+
function applyChartSeriesStyleFromXml(chart, chartTypeNode, themePalette) {
|
|
933
|
+
const seriesNodes = getLocalChildren(chartTypeNode, "ser");
|
|
934
|
+
chart.series = chart.series.map((series, index) => {
|
|
935
|
+
const seriesNode = seriesNodes[index];
|
|
936
|
+
if (!seriesNode) {
|
|
937
|
+
return series;
|
|
938
|
+
}
|
|
939
|
+
const shapeProperties = getFirstLocalChild(seriesNode, "spPr");
|
|
940
|
+
const markerNode = getFirstLocalChild(seriesNode, "marker");
|
|
941
|
+
const markerShapeProperties = getFirstLocalChild(markerNode ?? chartTypeNode, "spPr");
|
|
942
|
+
const lineStyle = resolveChartLineStyle(shapeProperties, themePalette);
|
|
943
|
+
const markerLineStyle = resolveChartLineStyle(markerShapeProperties, themePalette);
|
|
944
|
+
const fillColor = resolveChartFillColor(shapeProperties, themePalette);
|
|
945
|
+
const markerSize = readChartNumericAttribute(markerNode, "size");
|
|
946
|
+
const markerSymbolNode = markerNode ? getFirstLocalChild(markerNode, "symbol") : null;
|
|
947
|
+
const markerSymbol = markerSymbolNode?.getAttribute("val") ?? void 0;
|
|
948
|
+
const pointStyles = parseChartPointStyles(seriesNode, themePalette);
|
|
949
|
+
const seriesExplosion = readChartNumericAttribute(seriesNode, "explosion");
|
|
950
|
+
const invertNegativeStyle = parseInvertNegativeStyle(seriesNode, themePalette);
|
|
951
|
+
const invertIfNegative = readChartBooleanAttribute(seriesNode, "invertIfNegative");
|
|
952
|
+
const isScatterChart = chart.chartType === "Scatter" || chart.chartType === "ScatterLines" || chart.chartType === "ScatterSmooth" || chart.chartType === "Bubble";
|
|
953
|
+
const cachedCategories = isScatterChart ? parseChartCacheValues(getFirstLocalChild(seriesNode, "xVal"), "numCache", "value") ?? parseChartMultiLevelCacheValues(getFirstLocalChild(seriesNode, "xVal"), "category") : parseChartCacheValues(getFirstLocalChild(seriesNode, "cat"), "strCache", "category");
|
|
954
|
+
const cachedValues = isScatterChart ? parseChartCacheValues(getFirstLocalChild(seriesNode, "yVal"), "numCache", "value") : parseChartCacheValues(getFirstLocalChild(seriesNode, "val"), "numCache", "value");
|
|
955
|
+
const cachedBubbleSizes = chart.chartType === "Bubble" ? parseChartCacheValues(getFirstLocalChild(seriesNode, "bubbleSize"), "numCache", "value") : null;
|
|
956
|
+
const existingShapeProperties = series.shapeProperties && typeof series.shapeProperties === "object" ? series.shapeProperties : null;
|
|
957
|
+
const rawFillColor = typeof existingShapeProperties?.solidFillHex === "string" ? normalizeHexColor(existingShapeProperties.solidFillHex) : null;
|
|
958
|
+
const rawLineColor = typeof existingShapeProperties?.lineColorHex === "string" ? normalizeHexColor(existingShapeProperties.lineColorHex) : null;
|
|
959
|
+
const resolvedLineColor = lineStyle.hidden ? void 0 : rawLineColor ?? lineStyle.color ?? rawFillColor ?? fillColor ?? series.lineColor ?? series.color;
|
|
960
|
+
const hasCategoryReference = typeof series.categoriesRef?.formula === "string" && series.categoriesRef.formula.length > 0;
|
|
961
|
+
const hasValueReference = typeof series.valuesRef?.formula === "string" && series.valuesRef.formula.length > 0;
|
|
962
|
+
const hasBubbleSizeReference = typeof series.bubbleSizeRef?.formula === "string" && series.bubbleSizeRef.formula.length > 0;
|
|
963
|
+
return {
|
|
964
|
+
...series,
|
|
965
|
+
bubbleSizes: !hasBubbleSizeReference && cachedBubbleSizes ? cachedBubbleSizes.map((value) => typeof value === "number" && Number.isFinite(value) ? value : null) : series.bubbleSizes,
|
|
966
|
+
categories: !hasCategoryReference && cachedCategories ? cachedCategories : series.categories,
|
|
967
|
+
color: rawFillColor ?? rawLineColor ?? fillColor ?? lineStyle.color ?? series.color,
|
|
968
|
+
dataPointStyles: pointStyles.length > 0 ? pointStyles : series.dataPointStyles,
|
|
969
|
+
lineColor: resolvedLineColor,
|
|
970
|
+
lineWidthPx: lineStyle.hidden ? void 0 : lineStyle.widthPx ?? series.lineWidthPx,
|
|
971
|
+
markerColor: rawFillColor ?? rawLineColor ?? resolveChartFillColor(markerShapeProperties, themePalette) ?? fillColor ?? lineStyle.color ?? void 0,
|
|
972
|
+
markerLineColor: rawLineColor ?? rawFillColor ?? markerLineStyle.color ?? lineStyle.color ?? fillColor ?? void 0,
|
|
973
|
+
markerSize: markerSize ?? series.markerSize,
|
|
974
|
+
markerSymbol,
|
|
975
|
+
smooth: readChartBooleanAttribute(seriesNode, "smooth") ?? series.smooth,
|
|
976
|
+
invertIfNegative: invertIfNegative ?? series.invertIfNegative,
|
|
977
|
+
shapeProperties: {
|
|
978
|
+
...series.shapeProperties,
|
|
979
|
+
xmlExplosion: seriesExplosion ?? void 0,
|
|
980
|
+
xmlFillColor: fillColor ?? void 0,
|
|
981
|
+
xmlLineHidden: lineStyle.hidden ? true : void 0,
|
|
982
|
+
xmlLineColor: lineStyle.color ?? void 0,
|
|
983
|
+
xmlLineWidthPx: lineStyle.widthPx ?? void 0,
|
|
984
|
+
xmlNegativeFillColor: invertNegativeStyle.color ?? void 0,
|
|
985
|
+
xmlNegativeLineColor: invertNegativeStyle.lineColor ?? void 0
|
|
986
|
+
},
|
|
987
|
+
negativeColor: invertNegativeStyle.color ?? series.negativeColor,
|
|
988
|
+
negativeLineColor: invertNegativeStyle.lineColor ?? series.negativeLineColor,
|
|
989
|
+
values: !hasValueReference && cachedValues ? cachedValues.map((value) => typeof value === "number" && Number.isFinite(value) ? value : null) : series.values
|
|
990
|
+
};
|
|
991
|
+
});
|
|
992
|
+
}
|
|
993
|
+
function applyChartStyleFromXml(chart, chartPath, archive, themePalette) {
|
|
994
|
+
const chartXml = readArchiveText(archive, chartPath);
|
|
995
|
+
if (!chartXml) {
|
|
996
|
+
return;
|
|
997
|
+
}
|
|
998
|
+
const relationships = chartPath ? readChartRelationships(archive, chartPath) : /* @__PURE__ */ new Map();
|
|
999
|
+
const fallbackPointStylesBySeries = parseFallbackPointStylesFromChartXml(chartXml, themePalette);
|
|
1000
|
+
const fallbackSeriesStyles = parseFallbackSeriesStylesFromChartXml(chartXml, themePalette);
|
|
1001
|
+
const fallbackBubbleSizesBySeries = parseFallbackBubbleSizesFromChartXml(chartXml);
|
|
1002
|
+
const applyFallbackSeriesStyles = () => {
|
|
1003
|
+
if (fallbackBubbleSizesBySeries.length > 0) {
|
|
1004
|
+
chart.series = chart.series.map((series, seriesIndex) => {
|
|
1005
|
+
const fallbackBubbleSizes = fallbackBubbleSizesBySeries[seriesIndex] ?? [];
|
|
1006
|
+
if (fallbackBubbleSizes.length === 0) {
|
|
1007
|
+
return series;
|
|
1008
|
+
}
|
|
1009
|
+
const currentNumericPointCount = (series.bubbleSizes ?? []).filter(
|
|
1010
|
+
(value) => typeof value === "number" && Number.isFinite(value)
|
|
1011
|
+
).length;
|
|
1012
|
+
const fallbackNumericPointCount = fallbackBubbleSizes.filter(
|
|
1013
|
+
(value) => typeof value === "number" && Number.isFinite(value)
|
|
1014
|
+
).length;
|
|
1015
|
+
if (currentNumericPointCount >= fallbackNumericPointCount) {
|
|
1016
|
+
return series;
|
|
1017
|
+
}
|
|
1018
|
+
return {
|
|
1019
|
+
...series,
|
|
1020
|
+
bubbleSizes: fallbackBubbleSizes
|
|
1021
|
+
};
|
|
1022
|
+
});
|
|
1023
|
+
}
|
|
1024
|
+
if (fallbackPointStylesBySeries.length > 0) {
|
|
1025
|
+
chart.series = chart.series.map((series, seriesIndex) => {
|
|
1026
|
+
const fallbackPointStyles = fallbackPointStylesBySeries[seriesIndex] ?? [];
|
|
1027
|
+
if (fallbackPointStyles.length === 0) {
|
|
1028
|
+
return series;
|
|
1029
|
+
}
|
|
1030
|
+
const existingByIndex = new Map((series.dataPointStyles ?? []).map((entry) => [entry.index, entry]));
|
|
1031
|
+
for (const fallbackStyle of fallbackPointStyles) {
|
|
1032
|
+
const existing = existingByIndex.get(fallbackStyle.index);
|
|
1033
|
+
existingByIndex.set(fallbackStyle.index, {
|
|
1034
|
+
color: existing?.color ?? fallbackStyle.color,
|
|
1035
|
+
explosion: existing?.explosion ?? fallbackStyle.explosion,
|
|
1036
|
+
index: fallbackStyle.index,
|
|
1037
|
+
lineColor: existing?.lineColor ?? fallbackStyle.lineColor
|
|
1038
|
+
});
|
|
1039
|
+
}
|
|
1040
|
+
return {
|
|
1041
|
+
...series,
|
|
1042
|
+
dataPointStyles: Array.from(existingByIndex.values()).sort((left, right) => left.index - right.index)
|
|
1043
|
+
};
|
|
1044
|
+
});
|
|
1045
|
+
}
|
|
1046
|
+
if (fallbackSeriesStyles.length > 0) {
|
|
1047
|
+
chart.series = chart.series.map((series, seriesIndex) => {
|
|
1048
|
+
const fallbackStyle = fallbackSeriesStyles[seriesIndex];
|
|
1049
|
+
if (!fallbackStyle) {
|
|
1050
|
+
return series;
|
|
1051
|
+
}
|
|
1052
|
+
const fallbackColor = fallbackStyle.color ?? fallbackStyle.lineColor;
|
|
1053
|
+
return {
|
|
1054
|
+
...series,
|
|
1055
|
+
color: series.color ?? fallbackColor,
|
|
1056
|
+
lineColor: series.lineColor ?? fallbackStyle.lineColor ?? fallbackColor,
|
|
1057
|
+
markerColor: series.markerColor ?? fallbackColor ?? series.color,
|
|
1058
|
+
markerLineColor: series.markerLineColor ?? fallbackStyle.lineColor ?? fallbackColor ?? series.lineColor
|
|
1059
|
+
};
|
|
1060
|
+
});
|
|
1061
|
+
}
|
|
1062
|
+
};
|
|
1063
|
+
const applyRelationshipStyles = () => {
|
|
1064
|
+
chart.chartColorPalette = readChartColorPalette(archive, relationships.get(CHART_COLOR_STYLE_REL_TYPE), themePalette);
|
|
1065
|
+
const styleAppearance2 = readChartStyleAppearance(
|
|
1066
|
+
archive,
|
|
1067
|
+
relationships.get(CHART_STYLE_REL_TYPE),
|
|
1068
|
+
themePalette
|
|
1069
|
+
);
|
|
1070
|
+
chart.axisLabelColor = styleAppearance2.axisLabelColor ?? chart.axisLabelColor;
|
|
1071
|
+
chart.axisLineColor = styleAppearance2.axisLineColor ?? chart.axisLineColor;
|
|
1072
|
+
chart.chartAreaBorderColor = styleAppearance2.chartAreaBorderColor ?? chart.chartAreaBorderColor;
|
|
1073
|
+
chart.chartAreaFillColor = styleAppearance2.chartAreaFillColor ?? chart.chartAreaFillColor;
|
|
1074
|
+
chart.chartColorPaletteOffset = styleAppearance2.paletteOffset ?? chart.chartColorPaletteOffset;
|
|
1075
|
+
chart.textColor = styleAppearance2.textColor ?? chart.textColor;
|
|
1076
|
+
chart.titleColor = styleAppearance2.titleColor ?? chart.titleColor;
|
|
1077
|
+
return styleAppearance2;
|
|
1078
|
+
};
|
|
1079
|
+
const applyModernChartExStyles = () => {
|
|
1080
|
+
const modernPlotAreaNode = chartDocument?.documentElement ? getFirstLocalDescendant(chartDocument.documentElement, "plotArea") : null;
|
|
1081
|
+
if (!modernPlotAreaNode) {
|
|
1082
|
+
return;
|
|
1083
|
+
}
|
|
1084
|
+
const parseModernBinning = (seriesNode) => {
|
|
1085
|
+
const layoutPrNode = getFirstLocalChild(seriesNode, "layoutPr");
|
|
1086
|
+
const binningNode = layoutPrNode ? getFirstLocalChild(layoutPrNode, "binning") : null;
|
|
1087
|
+
if (!binningNode) {
|
|
1088
|
+
return null;
|
|
1089
|
+
}
|
|
1090
|
+
const binning = {};
|
|
1091
|
+
for (const attribute of Array.from(binningNode.attributes)) {
|
|
1092
|
+
const rawValue = attribute.value;
|
|
1093
|
+
const numeric = Number(rawValue);
|
|
1094
|
+
binning[attribute.localName || attribute.name] = Number.isFinite(numeric) && rawValue.trim() !== "" ? numeric : rawValue;
|
|
1095
|
+
}
|
|
1096
|
+
return Object.keys(binning).length > 0 ? binning : {};
|
|
1097
|
+
};
|
|
1098
|
+
const plotAreaShapeProperties2 = getFirstLocalChild(modernPlotAreaNode, "spPr");
|
|
1099
|
+
if (plotAreaShapeProperties2) {
|
|
1100
|
+
const plotAreaFillColor = resolveChartFillColor(plotAreaShapeProperties2, themePalette);
|
|
1101
|
+
const plotAreaLineStyle = resolveChartLineStyle(plotAreaShapeProperties2, themePalette);
|
|
1102
|
+
if (plotAreaFillColor) {
|
|
1103
|
+
chart.chartAreaFillColor = chart.chartAreaFillColor ?? plotAreaFillColor;
|
|
1104
|
+
}
|
|
1105
|
+
if (plotAreaLineStyle.color) {
|
|
1106
|
+
chart.chartAreaBorderColor = chart.chartAreaBorderColor ?? plotAreaLineStyle.color;
|
|
1107
|
+
}
|
|
1108
|
+
}
|
|
1109
|
+
const modernSeriesNodes = getLocalDescendants(modernPlotAreaNode, "series");
|
|
1110
|
+
if (modernSeriesNodes.length === 0) {
|
|
1111
|
+
return;
|
|
1112
|
+
}
|
|
1113
|
+
chart.series = chart.series.map((series, seriesIndex) => {
|
|
1114
|
+
const modernSeriesNode = modernSeriesNodes[seriesIndex] ?? null;
|
|
1115
|
+
if (!modernSeriesNode) {
|
|
1116
|
+
return series;
|
|
1117
|
+
}
|
|
1118
|
+
const valueColorsNode = getFirstLocalChild(modernSeriesNode, "valueColors");
|
|
1119
|
+
const valueColors = valueColorsNode ? Array.from(valueColorsNode.childNodes).filter((node) => node.nodeType === Node.ELEMENT_NODE).map((node) => resolveChartColorNode(findFirstChartColorElement(node) ?? node, themePalette)).filter((value) => typeof value === "string" && value.length > 0) : [];
|
|
1120
|
+
const nextRaw = valueColors.length > 0 ? {
|
|
1121
|
+
...series.raw && typeof series.raw === "object" ? series.raw : {},
|
|
1122
|
+
valueColors
|
|
1123
|
+
} : series.raw;
|
|
1124
|
+
const seriesShapeProperties = getFirstLocalChild(modernSeriesNode, "spPr");
|
|
1125
|
+
if (!seriesShapeProperties) {
|
|
1126
|
+
return nextRaw === series.raw ? series : {
|
|
1127
|
+
...series,
|
|
1128
|
+
raw: nextRaw
|
|
1129
|
+
};
|
|
1130
|
+
}
|
|
1131
|
+
const fillColor = resolveChartFillColor(seriesShapeProperties, themePalette);
|
|
1132
|
+
const lineStyle = resolveChartLineStyle(seriesShapeProperties, themePalette);
|
|
1133
|
+
const fallbackColor = fillColor ?? lineStyle.color ?? void 0;
|
|
1134
|
+
return {
|
|
1135
|
+
...series,
|
|
1136
|
+
color: series.color ?? fallbackColor,
|
|
1137
|
+
lineColor: series.lineColor ?? lineStyle.color ?? fillColor ?? fallbackColor,
|
|
1138
|
+
lineWidthPx: series.lineWidthPx ?? (typeof lineStyle.widthPx === "number" ? lineStyle.widthPx : void 0),
|
|
1139
|
+
markerColor: series.markerColor ?? fallbackColor ?? series.color,
|
|
1140
|
+
markerLineColor: series.markerLineColor ?? lineStyle.color ?? fallbackColor ?? series.lineColor,
|
|
1141
|
+
raw: nextRaw
|
|
1142
|
+
};
|
|
1143
|
+
});
|
|
1144
|
+
const seriesLayouts = modernSeriesNodes.map((node) => node.getAttribute("layoutId") ?? node.getAttribute("layout"));
|
|
1145
|
+
const clusteredColumnIndex = seriesLayouts.findIndex((layout) => layout === "clusteredColumn");
|
|
1146
|
+
if (clusteredColumnIndex >= 0) {
|
|
1147
|
+
const clusteredNode = modernSeriesNodes[clusteredColumnIndex] ?? null;
|
|
1148
|
+
const parsedBinning = clusteredNode ? parseModernBinning(clusteredNode) : null;
|
|
1149
|
+
if (parsedBinning) {
|
|
1150
|
+
const syntheticRawSeries = {
|
|
1151
|
+
layoutId: "clusteredColumn",
|
|
1152
|
+
layoutPr: {
|
|
1153
|
+
binning: parsedBinning
|
|
1154
|
+
}
|
|
1155
|
+
};
|
|
1156
|
+
const hasParetoLine = seriesLayouts.includes("paretoLine");
|
|
1157
|
+
const replaceColumnSeries = (series) => series ? buildChartExHistogramSeries(series, syntheticRawSeries, hasParetoLine) : null;
|
|
1158
|
+
if (chart.typeGroups && chart.typeGroups.length > 0) {
|
|
1159
|
+
const nextTypeGroups = chart.typeGroups.map((group) => ({ ...group, series: [...group.series] }));
|
|
1160
|
+
const columnGroupIndex = nextTypeGroups.findIndex((group) => group.chartType === "ColumnClustered");
|
|
1161
|
+
if (columnGroupIndex >= 0) {
|
|
1162
|
+
const originalColumnSeries = nextTypeGroups[columnGroupIndex]?.series[0] ?? null;
|
|
1163
|
+
const binnedColumnSeries = replaceColumnSeries(originalColumnSeries);
|
|
1164
|
+
if (binnedColumnSeries) {
|
|
1165
|
+
nextTypeGroups[columnGroupIndex].series = [binnedColumnSeries];
|
|
1166
|
+
const lineGroupIndex = nextTypeGroups.findIndex((group) => group.chartType === "Line");
|
|
1167
|
+
if (lineGroupIndex >= 0 && nextTypeGroups[lineGroupIndex]?.series[0]) {
|
|
1168
|
+
const originalLineSeries = nextTypeGroups[lineGroupIndex].series[0];
|
|
1169
|
+
const recomputedLine = buildChartExParetoLineSeries(
|
|
1170
|
+
binnedColumnSeries,
|
|
1171
|
+
{
|
|
1172
|
+
text: originalLineSeries.name,
|
|
1173
|
+
...originalLineSeries.raw && typeof originalLineSeries.raw === "object" ? originalLineSeries.raw : {}
|
|
1174
|
+
},
|
|
1175
|
+
0
|
|
1176
|
+
);
|
|
1177
|
+
nextTypeGroups[lineGroupIndex].series = [
|
|
1178
|
+
{
|
|
1179
|
+
...originalLineSeries,
|
|
1180
|
+
categories: recomputedLine.categories,
|
|
1181
|
+
categoriesRef: recomputedLine.categoriesRef,
|
|
1182
|
+
raw: recomputedLine.raw,
|
|
1183
|
+
values: recomputedLine.values
|
|
1184
|
+
}
|
|
1185
|
+
];
|
|
1186
|
+
chart.series = [binnedColumnSeries, nextTypeGroups[lineGroupIndex].series[0]];
|
|
1187
|
+
} else {
|
|
1188
|
+
chart.series = [binnedColumnSeries];
|
|
1189
|
+
}
|
|
1190
|
+
chart.typeGroups = nextTypeGroups;
|
|
1191
|
+
}
|
|
1192
|
+
} else if (chart.series[0]) {
|
|
1193
|
+
const binnedSeries = replaceColumnSeries(chart.series[0]);
|
|
1194
|
+
if (binnedSeries) {
|
|
1195
|
+
chart.series = [binnedSeries];
|
|
1196
|
+
}
|
|
1197
|
+
}
|
|
1198
|
+
} else if (chart.series[0]) {
|
|
1199
|
+
const binnedSeries = replaceColumnSeries(chart.series[0]);
|
|
1200
|
+
if (binnedSeries) {
|
|
1201
|
+
chart.series = [binnedSeries];
|
|
1202
|
+
}
|
|
1203
|
+
}
|
|
1204
|
+
}
|
|
1205
|
+
}
|
|
1206
|
+
};
|
|
1207
|
+
const chartDocument = parseXml(chartXml);
|
|
1208
|
+
const chartNode = chartDocument ? getFirstLocalDescendant(chartDocument, "chart") : null;
|
|
1209
|
+
const plotAreaNode = chartNode ? getFirstLocalChild(chartNode, "plotArea") : null;
|
|
1210
|
+
const styleIdNode = chartDocument?.documentElement ? getFirstLocalDescendant(chartDocument.documentElement, "style") : null;
|
|
1211
|
+
const chartTypeNode = findPrimaryChartTypeNode(plotAreaNode);
|
|
1212
|
+
if (!chartNode || !chartTypeNode) {
|
|
1213
|
+
applyRelationshipStyles();
|
|
1214
|
+
const fallbackStyleId = readChartNumericAttribute(styleIdNode, "style");
|
|
1215
|
+
if (typeof fallbackStyleId === "number" && Number.isFinite(fallbackStyleId)) {
|
|
1216
|
+
chart.chartStyleId = fallbackStyleId;
|
|
1217
|
+
}
|
|
1218
|
+
applyModernChartExStyles();
|
|
1219
|
+
applyFallbackSeriesStyles();
|
|
1220
|
+
applyBuiltinChartDefaults(chart, themePalette);
|
|
1221
|
+
return;
|
|
1222
|
+
}
|
|
1223
|
+
const plotArea = plotAreaNode;
|
|
1224
|
+
if (!plotArea) {
|
|
1225
|
+
applyRelationshipStyles();
|
|
1226
|
+
applyFallbackSeriesStyles();
|
|
1227
|
+
applyBuiltinChartDefaults(chart, themePalette);
|
|
1228
|
+
return;
|
|
1229
|
+
}
|
|
1230
|
+
switch (chartTypeNode.localName) {
|
|
1231
|
+
case "barChart":
|
|
1232
|
+
case "bar3DChart": {
|
|
1233
|
+
const grouping = getFirstLocalChild(chartTypeNode, "grouping")?.getAttribute("val");
|
|
1234
|
+
const barDir = getFirstLocalChild(chartTypeNode, "barDir")?.getAttribute("val");
|
|
1235
|
+
const isHorizontalBar = barDir === "bar";
|
|
1236
|
+
chart.is3d = chartTypeNode.localName === "bar3DChart" ? true : chart.is3d;
|
|
1237
|
+
if (grouping === "percentStacked") {
|
|
1238
|
+
chart.chartType = isHorizontalBar ? "BarPercentStacked" : "ColumnPercentStacked";
|
|
1239
|
+
} else if (grouping === "stacked") {
|
|
1240
|
+
chart.chartType = isHorizontalBar ? "BarStacked" : "ColumnStacked";
|
|
1241
|
+
} else {
|
|
1242
|
+
chart.chartType = isHorizontalBar ? "BarClustered" : "ColumnClustered";
|
|
1243
|
+
}
|
|
1244
|
+
break;
|
|
1245
|
+
}
|
|
1246
|
+
case "areaChart":
|
|
1247
|
+
case "area3DChart": {
|
|
1248
|
+
const grouping = getFirstLocalChild(chartTypeNode, "grouping")?.getAttribute("val");
|
|
1249
|
+
chart.is3d = chartTypeNode.localName === "area3DChart" ? true : chart.is3d;
|
|
1250
|
+
if (grouping === "stacked") {
|
|
1251
|
+
chart.chartType = "AreaStacked";
|
|
1252
|
+
} else if (grouping === "percentStacked") {
|
|
1253
|
+
chart.chartType = "AreaPercentStacked";
|
|
1254
|
+
} else {
|
|
1255
|
+
chart.chartType = "Area";
|
|
1256
|
+
}
|
|
1257
|
+
break;
|
|
1258
|
+
}
|
|
1259
|
+
case "lineChart":
|
|
1260
|
+
case "line3DChart": {
|
|
1261
|
+
const grouping = getFirstLocalChild(chartTypeNode, "grouping")?.getAttribute("val");
|
|
1262
|
+
chart.is3d = chartTypeNode.localName === "line3DChart" ? true : chart.is3d;
|
|
1263
|
+
if (grouping === "stacked") {
|
|
1264
|
+
chart.chartType = "LineStacked";
|
|
1265
|
+
} else if (grouping === "percentStacked") {
|
|
1266
|
+
chart.chartType = "LinePercentStacked";
|
|
1267
|
+
} else {
|
|
1268
|
+
chart.chartType = "Line";
|
|
1269
|
+
}
|
|
1270
|
+
break;
|
|
1271
|
+
}
|
|
1272
|
+
case "pieChart":
|
|
1273
|
+
chart.chartType = "Pie";
|
|
1274
|
+
break;
|
|
1275
|
+
case "pie3DChart":
|
|
1276
|
+
chart.chartType = "Pie3D";
|
|
1277
|
+
chart.is3d = true;
|
|
1278
|
+
break;
|
|
1279
|
+
case "doughnutChart":
|
|
1280
|
+
chart.chartType = "Doughnut";
|
|
1281
|
+
break;
|
|
1282
|
+
case "ofPieChart":
|
|
1283
|
+
chart.chartType = "BarOfPie";
|
|
1284
|
+
break;
|
|
1285
|
+
case "scatterChart":
|
|
1286
|
+
chart.chartType = resolveScatterChartType(getFirstLocalChild(chartTypeNode, "scatterStyle")?.getAttribute("val"));
|
|
1287
|
+
break;
|
|
1288
|
+
case "radarChart":
|
|
1289
|
+
chart.chartType = "Radar";
|
|
1290
|
+
break;
|
|
1291
|
+
case "surfaceChart":
|
|
1292
|
+
chart.chartType = "Surface";
|
|
1293
|
+
chart.is3d = false;
|
|
1294
|
+
break;
|
|
1295
|
+
case "surface3DChart":
|
|
1296
|
+
chart.chartType = "Surface";
|
|
1297
|
+
chart.is3d = true;
|
|
1298
|
+
break;
|
|
1299
|
+
case "stockChart":
|
|
1300
|
+
chart.chartType = "Stock";
|
|
1301
|
+
break;
|
|
1302
|
+
case "bubbleChart":
|
|
1303
|
+
chart.chartType = "Bubble";
|
|
1304
|
+
break;
|
|
1305
|
+
default:
|
|
1306
|
+
break;
|
|
1307
|
+
}
|
|
1308
|
+
const legendNode = getFirstLocalChild(chartNode, "legend");
|
|
1309
|
+
const legendPosition = legendNode ? getFirstLocalChild(legendNode, "legendPos")?.getAttribute("val") ?? void 0 : void 0;
|
|
1310
|
+
const legendOverlay = legendNode ? getFirstLocalChild(legendNode, "overlay")?.getAttribute("val") : void 0;
|
|
1311
|
+
chart.legend = legendNode ? {
|
|
1312
|
+
overlay: legendOverlay === "1",
|
|
1313
|
+
position: normalizeLegendPosition(legendPosition),
|
|
1314
|
+
raw: chart.legend?.raw
|
|
1315
|
+
} : chart.legend;
|
|
1316
|
+
const plotVisibleOnly = readChartBooleanAttribute(chartNode, "plotVisOnly");
|
|
1317
|
+
if (plotVisibleOnly !== void 0) {
|
|
1318
|
+
chart.plotVisibleOnly = plotVisibleOnly;
|
|
1319
|
+
}
|
|
1320
|
+
chart.displayBlanksAs = getFirstLocalChild(chartNode, "dispBlanksAs")?.getAttribute("val") ?? chart.displayBlanksAs;
|
|
1321
|
+
const styleId = Number(styleIdNode?.getAttribute("val") ?? Number.NaN);
|
|
1322
|
+
chart.chartStyleId = Number.isFinite(styleId) ? styleId : chart.chartStyleId;
|
|
1323
|
+
chart.firstSliceAngle = readChartNumericAttribute(chartTypeNode, "firstSliceAng") ?? chart.firstSliceAngle;
|
|
1324
|
+
chart.gapWidth = readChartNumericAttribute(chartTypeNode, "gapWidth") ?? chart.gapWidth;
|
|
1325
|
+
chart.overlap = readChartNumericAttribute(chartTypeNode, "overlap") ?? chart.overlap;
|
|
1326
|
+
chart.bubbleScale = readChartNumericAttribute(chartTypeNode, "bubbleScale") ?? chart.bubbleScale;
|
|
1327
|
+
chart.varyColors = readChartBooleanAttribute(chartTypeNode, "varyColors") ?? chart.varyColors;
|
|
1328
|
+
const bubble3dNode = getFirstLocalChild(chartTypeNode, "bubble3D");
|
|
1329
|
+
chart.bubble3d = bubble3dNode ? bubble3dNode.getAttribute("val") !== "0" : chart.bubble3d;
|
|
1330
|
+
chart.holeSize = readChartNumericAttribute(chartTypeNode, "holeSize") ?? chart.holeSize;
|
|
1331
|
+
chart.radarStyle = getFirstLocalChild(chartTypeNode, "radarStyle")?.getAttribute("val") ?? chart.radarStyle;
|
|
1332
|
+
chart.scatterStyle = getFirstLocalChild(chartTypeNode, "scatterStyle")?.getAttribute("val") ?? chart.scatterStyle;
|
|
1333
|
+
chart.shape3d = getFirstLocalChild(chartTypeNode, "shape")?.getAttribute("val") ?? chart.shape3d;
|
|
1334
|
+
const wireframeNode = getFirstLocalChild(chartTypeNode, "wireframe");
|
|
1335
|
+
chart.wireframe = wireframeNode ? wireframeNode.getAttribute("val") !== "0" : chart.wireframe;
|
|
1336
|
+
const chartTypeDataLabels = parseChartDataLabelsFromXml(getFirstLocalChild(chartTypeNode, "dLbls"));
|
|
1337
|
+
const firstSeriesNode = getLocalChildren(chartTypeNode, "ser")[0] ?? null;
|
|
1338
|
+
const seriesDataLabels = parseChartDataLabelsFromXml(getFirstLocalChild(firstSeriesNode, "dLbls"));
|
|
1339
|
+
chart.dataLabels = chartTypeDataLabels ?? seriesDataLabels ?? chart.dataLabels;
|
|
1340
|
+
const seriesSp3dNode = firstSeriesNode ? getFirstLocalDescendant(firstSeriesNode, "sp3d") : null;
|
|
1341
|
+
chart.surfaceMaterial = seriesSp3dNode?.getAttribute("prstMaterial") ?? chart.surfaceMaterial;
|
|
1342
|
+
const bandFormatsNode = getLocalChildren(chartTypeNode, "bandFmts")[0] ?? null;
|
|
1343
|
+
const bandFormatNodes = bandFormatsNode ? getLocalChildren(bandFormatsNode, "bandFmt") : [];
|
|
1344
|
+
const bandFormatColors = bandFormatNodes.map((bandFormatNode) => {
|
|
1345
|
+
const shapeProperties = getFirstLocalChild(bandFormatNode, "spPr");
|
|
1346
|
+
return resolveChartFillColor(shapeProperties, themePalette) ?? void 0;
|
|
1347
|
+
}).filter((color) => typeof color === "string" && color.length > 0);
|
|
1348
|
+
const bandFormatLineColors = bandFormatNodes.map((bandFormatNode) => {
|
|
1349
|
+
const shapeProperties = getFirstLocalChild(bandFormatNode, "spPr");
|
|
1350
|
+
return resolveChartLineStyle(shapeProperties, themePalette).color ?? void 0;
|
|
1351
|
+
}).filter((color) => typeof color === "string" && color.length > 0);
|
|
1352
|
+
chart.raw = {
|
|
1353
|
+
...chart.raw ?? {},
|
|
1354
|
+
bandFormatCount: bandFormatNodes.length > 0 ? bandFormatNodes.length : void 0,
|
|
1355
|
+
bandFormatColors: bandFormatColors.length > 0 ? bandFormatColors : void 0,
|
|
1356
|
+
bandFormatLineColors: bandFormatLineColors.length > 0 ? bandFormatLineColors : void 0,
|
|
1357
|
+
date1904: readChartBooleanAttribute(chartDocument?.documentElement ?? null, "date1904"),
|
|
1358
|
+
bubble3d: chart.bubble3d,
|
|
1359
|
+
grouping: getFirstLocalChild(chartTypeNode, "grouping")?.getAttribute("val") ?? void 0,
|
|
1360
|
+
ofPieType: getFirstLocalChild(chartTypeNode, "ofPieType")?.getAttribute("val") ?? void 0,
|
|
1361
|
+
shape: getFirstLocalChild(chartTypeNode, "shape")?.getAttribute("val") ?? void 0,
|
|
1362
|
+
secondPieSize: readChartNumericAttribute(chartTypeNode, "secondPieSize"),
|
|
1363
|
+
scatterStyle: chart.scatterStyle,
|
|
1364
|
+
splitPos: readChartNumericAttribute(chartTypeNode, "splitPos"),
|
|
1365
|
+
splitType: getFirstLocalChild(chartTypeNode, "splitType")?.getAttribute("val") ?? void 0,
|
|
1366
|
+
xmlChartType: chartTypeNode.localName
|
|
1367
|
+
};
|
|
1368
|
+
const view3dNode = getFirstLocalDescendant(chartNode, "view3D");
|
|
1369
|
+
if (view3dNode) {
|
|
1370
|
+
chart.view3d = {
|
|
1371
|
+
depthPercent: readChartNumericAttribute(view3dNode, "depthPercent"),
|
|
1372
|
+
perspective: readChartNumericAttribute(view3dNode, "perspective"),
|
|
1373
|
+
rAngAx: getFirstLocalChild(view3dNode, "rAngAx")?.getAttribute("val") === "1",
|
|
1374
|
+
rotX: readChartNumericAttribute(view3dNode, "rotX"),
|
|
1375
|
+
rotY: readChartNumericAttribute(view3dNode, "rotY")
|
|
1376
|
+
};
|
|
1377
|
+
}
|
|
1378
|
+
chart.floor = readChartWallFromXml(getFirstLocalChild(chartNode, "floor"), themePalette) ?? chart.floor;
|
|
1379
|
+
chart.sideWall = readChartWallFromXml(getFirstLocalChild(chartNode, "sideWall"), themePalette) ?? chart.sideWall;
|
|
1380
|
+
chart.backWall = readChartWallFromXml(getFirstLocalChild(chartNode, "backWall"), themePalette) ?? chart.backWall;
|
|
1381
|
+
const styleAppearance = applyRelationshipStyles();
|
|
1382
|
+
const chartTextTypeface = readChartTextTypeface(getFirstLocalChild(chartNode, "txPr"), themePalette);
|
|
1383
|
+
const titleTypeface = readChartTextTypeface(getFirstLocalDescendant(chartNode, "title"), themePalette);
|
|
1384
|
+
chart.fontFamily = chartTextTypeface ?? chart.fontFamily;
|
|
1385
|
+
chart.titleFontFamily = titleTypeface ?? chart.titleFontFamily ?? chart.fontFamily;
|
|
1386
|
+
const chartAreaShapeProperties = chartDocument?.documentElement ? getFirstLocalChild(chartDocument.documentElement, "spPr") : null;
|
|
1387
|
+
const plotAreaShapeProperties = getFirstLocalChild(plotArea, "spPr");
|
|
1388
|
+
const chartAreaNoFill = chartAreaShapeProperties ? getFirstLocalChild(chartAreaShapeProperties, "noFill") != null : false;
|
|
1389
|
+
const plotAreaNoFill = plotAreaShapeProperties ? getFirstLocalChild(plotAreaShapeProperties, "noFill") != null : false;
|
|
1390
|
+
chart.raw = {
|
|
1391
|
+
...chart.raw ?? {},
|
|
1392
|
+
chartAreaNoFill: styleAppearance.chartAreaNoFill === true || chartAreaNoFill,
|
|
1393
|
+
plotAreaNoFill
|
|
1394
|
+
};
|
|
1395
|
+
if (chartAreaShapeProperties) {
|
|
1396
|
+
const chartAreaFillColor = resolveChartFillColor(chartAreaShapeProperties, themePalette);
|
|
1397
|
+
if (chartAreaFillColor) {
|
|
1398
|
+
chart.chartAreaFillColor = chartAreaFillColor;
|
|
1399
|
+
} else if (getFirstLocalChild(chartAreaShapeProperties, "noFill")) {
|
|
1400
|
+
chart.chartAreaFillColor = "transparent";
|
|
1401
|
+
}
|
|
1402
|
+
const chartAreaLineStyle = resolveChartLineStyle(chartAreaShapeProperties, themePalette);
|
|
1403
|
+
if (chartAreaLineStyle.hidden) {
|
|
1404
|
+
chart.chartAreaBorderColor = "transparent";
|
|
1405
|
+
} else if (chartAreaLineStyle.color) {
|
|
1406
|
+
chart.chartAreaBorderColor = chartAreaLineStyle.color;
|
|
1407
|
+
}
|
|
1408
|
+
}
|
|
1409
|
+
if (!chart.chartAreaFillColor && (styleAppearance.chartAreaNoFill === true || plotAreaNoFill)) {
|
|
1410
|
+
chart.chartAreaFillColor = "transparent";
|
|
1411
|
+
}
|
|
1412
|
+
const categoryAxisNodes = [
|
|
1413
|
+
...getLocalChildren(plotArea, "catAx"),
|
|
1414
|
+
...getLocalChildren(plotArea, "dateAx")
|
|
1415
|
+
];
|
|
1416
|
+
const valueAxisNodes = getLocalChildren(plotArea, "valAx");
|
|
1417
|
+
const seriesAxisNode = getLocalChildren(plotArea, "serAx")[0] ?? null;
|
|
1418
|
+
const isScatterLikeChart = chart.chartType === "Scatter" || chart.chartType === "ScatterLines" || chart.chartType === "ScatterSmooth" || chart.chartType === "Bubble";
|
|
1419
|
+
let categoryAxisNode = categoryAxisNodes[0] ?? null;
|
|
1420
|
+
let valueAxisNode = valueAxisNodes[0] ?? null;
|
|
1421
|
+
if (!categoryAxisNode && isScatterLikeChart && valueAxisNodes.length >= 2) {
|
|
1422
|
+
categoryAxisNode = valueAxisNodes.find((axisNode) => {
|
|
1423
|
+
const position = getFirstLocalChild(axisNode, "axPos")?.getAttribute("val");
|
|
1424
|
+
return position === "b" || position === "t";
|
|
1425
|
+
}) ?? valueAxisNodes[0];
|
|
1426
|
+
valueAxisNode = valueAxisNodes.find((axisNode) => {
|
|
1427
|
+
const position = getFirstLocalChild(axisNode, "axPos")?.getAttribute("val");
|
|
1428
|
+
return position === "l" || position === "r";
|
|
1429
|
+
}) ?? valueAxisNodes[1] ?? valueAxisNodes[0];
|
|
1430
|
+
}
|
|
1431
|
+
chart.categoryAxis = mergeChartAxis(chart.categoryAxis, readChartAxisFromXml(categoryAxisNode));
|
|
1432
|
+
chart.valueAxis = mergeChartAxis(chart.valueAxis, readChartAxisFromXml(valueAxisNode));
|
|
1433
|
+
chart.seriesAxis = mergeChartAxis(chart.seriesAxis, readChartAxisFromXml(seriesAxisNode));
|
|
1434
|
+
chart.axes = chart.axes.length > 0 ? chart.axes.map((axis, index) => index === 0 && categoryAxisNode ? { ...axis, ...readChartAxisFromXml(categoryAxisNode) } : index === 1 && valueAxisNode ? { ...axis, ...readChartAxisFromXml(valueAxisNode) } : axis) : chart.axes;
|
|
1435
|
+
if (seriesAxisNode) {
|
|
1436
|
+
const seriesAxis = readChartAxisFromXml(seriesAxisNode);
|
|
1437
|
+
if (seriesAxis && !chart.axes.some((axis) => axis.id != null && axis.id === seriesAxis.id)) {
|
|
1438
|
+
chart.axes = [...chart.axes, seriesAxis];
|
|
1439
|
+
}
|
|
1440
|
+
}
|
|
1441
|
+
applyChartSeriesStyleFromXml(chart, chartTypeNode, themePalette);
|
|
1442
|
+
applyFallbackSeriesStyles();
|
|
1443
|
+
if (chart.chartType === "Bubble") {
|
|
1444
|
+
const archiveFallbackBubbleSizes = resolveArchiveFallbackBubbleSizes(archive, chart.title);
|
|
1445
|
+
if (archiveFallbackBubbleSizes.length > 0) {
|
|
1446
|
+
chart.series = chart.series.map((series, seriesIndex) => {
|
|
1447
|
+
const pointCount = Math.max(series.values.length, series.categories.length);
|
|
1448
|
+
if (pointCount <= 1) {
|
|
1449
|
+
return series;
|
|
1450
|
+
}
|
|
1451
|
+
const numericBubbleCount = (series.bubbleSizes ?? []).filter(
|
|
1452
|
+
(value) => typeof value === "number" && Number.isFinite(value)
|
|
1453
|
+
).length;
|
|
1454
|
+
if (numericBubbleCount >= pointCount) {
|
|
1455
|
+
return series;
|
|
1456
|
+
}
|
|
1457
|
+
const fallbackCandidate = archiveFallbackBubbleSizes[seriesIndex] ?? archiveFallbackBubbleSizes[0] ?? [];
|
|
1458
|
+
const fallbackNumericCount = fallbackCandidate.filter(
|
|
1459
|
+
(value) => typeof value === "number" && Number.isFinite(value)
|
|
1460
|
+
).length;
|
|
1461
|
+
if (fallbackNumericCount < pointCount) {
|
|
1462
|
+
return series;
|
|
1463
|
+
}
|
|
1464
|
+
return {
|
|
1465
|
+
...series,
|
|
1466
|
+
bubbleSizes: fallbackCandidate
|
|
1467
|
+
};
|
|
1468
|
+
});
|
|
1469
|
+
}
|
|
1470
|
+
}
|
|
1471
|
+
if (chart.chartType === "Pie" || chart.chartType === "Pie3D" || chart.chartType === "PieExploded" || chart.chartType === "Doughnut" || chart.chartType === "BarOfPie") {
|
|
1472
|
+
const needsPointColorFallback = chart.series.some((series) => {
|
|
1473
|
+
const pointCount = Math.max(series.values.length, series.categories.length);
|
|
1474
|
+
if (pointCount <= 0) {
|
|
1475
|
+
return false;
|
|
1476
|
+
}
|
|
1477
|
+
const coloredPointCount = (series.dataPointStyles ?? []).filter(
|
|
1478
|
+
(style) => typeof style.color === "string" && style.color.length > 0
|
|
1479
|
+
).length;
|
|
1480
|
+
return coloredPointCount === 0;
|
|
1481
|
+
});
|
|
1482
|
+
if (needsPointColorFallback) {
|
|
1483
|
+
const archiveFallbackPointStyles = resolveArchiveFallbackPointStyles(
|
|
1484
|
+
archive,
|
|
1485
|
+
chart.title,
|
|
1486
|
+
chartTypeNode.localName,
|
|
1487
|
+
themePalette
|
|
1488
|
+
);
|
|
1489
|
+
if (archiveFallbackPointStyles.length > 0) {
|
|
1490
|
+
chart.series = chart.series.map((series, seriesIndex) => {
|
|
1491
|
+
const fallbackStyles = archiveFallbackPointStyles[seriesIndex] ?? archiveFallbackPointStyles[0] ?? [];
|
|
1492
|
+
if (fallbackStyles.length === 0) {
|
|
1493
|
+
return series;
|
|
1494
|
+
}
|
|
1495
|
+
const existingByIndex = new Map((series.dataPointStyles ?? []).map((entry) => [entry.index, entry]));
|
|
1496
|
+
for (const fallbackStyle of fallbackStyles) {
|
|
1497
|
+
const existing = existingByIndex.get(fallbackStyle.index);
|
|
1498
|
+
existingByIndex.set(fallbackStyle.index, {
|
|
1499
|
+
color: existing?.color ?? fallbackStyle.color,
|
|
1500
|
+
explosion: existing?.explosion ?? fallbackStyle.explosion,
|
|
1501
|
+
index: fallbackStyle.index,
|
|
1502
|
+
lineColor: existing?.lineColor ?? fallbackStyle.lineColor
|
|
1503
|
+
});
|
|
1504
|
+
}
|
|
1505
|
+
return {
|
|
1506
|
+
...series,
|
|
1507
|
+
dataPointStyles: Array.from(existingByIndex.values()).sort((left, right) => left.index - right.index)
|
|
1508
|
+
};
|
|
1509
|
+
});
|
|
1510
|
+
}
|
|
1511
|
+
}
|
|
1512
|
+
}
|
|
1513
|
+
applyBuiltinChartDefaults(chart, themePalette);
|
|
1514
|
+
}
|
|
1515
|
+
function normalizeArchivePath(path) {
|
|
1516
|
+
return path.replace(/^\/+/, "").replace(/\\/g, "/");
|
|
1517
|
+
}
|
|
1518
|
+
function dirname(path) {
|
|
1519
|
+
const normalized = normalizeArchivePath(path);
|
|
1520
|
+
const index = normalized.lastIndexOf("/");
|
|
1521
|
+
return index >= 0 ? normalized.slice(0, index) : "";
|
|
1522
|
+
}
|
|
1523
|
+
function resolveRelationshipPath(basePath, target) {
|
|
1524
|
+
if (!target) {
|
|
1525
|
+
return "";
|
|
1526
|
+
}
|
|
1527
|
+
const normalizedTarget = target.replace(/\\/g, "/");
|
|
1528
|
+
if (normalizedTarget.startsWith("/")) {
|
|
1529
|
+
return normalizeArchivePath(normalizedTarget);
|
|
1530
|
+
}
|
|
1531
|
+
const normalizedBasePath = normalizeArchivePath(basePath);
|
|
1532
|
+
let baseDirectory = dirname(normalizedBasePath);
|
|
1533
|
+
if (normalizedBasePath.endsWith(".rels")) {
|
|
1534
|
+
const relsMarker = "/_rels/";
|
|
1535
|
+
const relsMarkerIndex = normalizedBasePath.lastIndexOf(relsMarker);
|
|
1536
|
+
if (relsMarkerIndex >= 0) {
|
|
1537
|
+
const ownerPrefix = normalizedBasePath.slice(0, relsMarkerIndex);
|
|
1538
|
+
const relFileName = normalizedBasePath.slice(relsMarkerIndex + relsMarker.length);
|
|
1539
|
+
const ownerFileName = relFileName.endsWith(".rels") ? relFileName.slice(0, -".rels".length) : relFileName;
|
|
1540
|
+
baseDirectory = dirname(`${ownerPrefix}/${ownerFileName}`);
|
|
1541
|
+
}
|
|
1542
|
+
}
|
|
1543
|
+
const segments = [...baseDirectory.split("/").filter(Boolean), ...normalizedTarget.split("/").filter(Boolean)];
|
|
1544
|
+
const resolved = [];
|
|
1545
|
+
for (const segment of segments) {
|
|
1546
|
+
if (segment === ".") {
|
|
1547
|
+
continue;
|
|
1548
|
+
}
|
|
1549
|
+
if (segment === "..") {
|
|
1550
|
+
resolved.pop();
|
|
1551
|
+
continue;
|
|
1552
|
+
}
|
|
1553
|
+
resolved.push(segment);
|
|
1554
|
+
}
|
|
1555
|
+
return resolved.join("/");
|
|
1556
|
+
}
|
|
1557
|
+
function readArchiveText(archive, path) {
|
|
1558
|
+
if (!path) {
|
|
1559
|
+
return null;
|
|
1560
|
+
}
|
|
1561
|
+
const entry = archive[normalizeArchivePath(path)];
|
|
1562
|
+
return entry ? strFromU8(entry) : null;
|
|
1563
|
+
}
|
|
1564
|
+
function parseXml(xml) {
|
|
1565
|
+
if (typeof DOMParser === "undefined") {
|
|
1566
|
+
return null;
|
|
1567
|
+
}
|
|
1568
|
+
try {
|
|
1569
|
+
return new DOMParser().parseFromString(xml, "application/xml");
|
|
1570
|
+
} catch {
|
|
1571
|
+
return null;
|
|
1572
|
+
}
|
|
1573
|
+
}
|
|
1574
|
+
function getLocalChildren(parent, localName) {
|
|
1575
|
+
return Array.from(parent.childNodes).filter(
|
|
1576
|
+
(node) => node.nodeType === Node.ELEMENT_NODE && node.localName === localName
|
|
1577
|
+
);
|
|
1578
|
+
}
|
|
1579
|
+
function getLocalDescendants(parent, localName) {
|
|
1580
|
+
return Array.from(parent.getElementsByTagName("*")).filter(
|
|
1581
|
+
(node) => node.localName === localName
|
|
1582
|
+
);
|
|
1583
|
+
}
|
|
1584
|
+
function getFirstLocalChild(parent, localName) {
|
|
1585
|
+
return getLocalChildren(parent, localName)[0] ?? null;
|
|
1586
|
+
}
|
|
1587
|
+
function getFirstLocalDescendant(parent, localName) {
|
|
1588
|
+
return getLocalDescendants(parent, localName)[0] ?? null;
|
|
1589
|
+
}
|
|
1590
|
+
function unquoteSheetName(value) {
|
|
1591
|
+
const trimmed = value.trim();
|
|
1592
|
+
if (trimmed.startsWith("'") && trimmed.endsWith("'")) {
|
|
1593
|
+
return trimmed.slice(1, -1).replace(/''/g, "'");
|
|
1594
|
+
}
|
|
1595
|
+
return trimmed;
|
|
1596
|
+
}
|
|
1597
|
+
function splitSheetReference(reference) {
|
|
1598
|
+
let bangIndex = -1;
|
|
1599
|
+
let quoted = false;
|
|
1600
|
+
for (let index = 0; index < reference.length; index += 1) {
|
|
1601
|
+
const char = reference[index];
|
|
1602
|
+
if (char === "'") {
|
|
1603
|
+
quoted = !quoted;
|
|
1604
|
+
} else if (char === "!" && !quoted) {
|
|
1605
|
+
bangIndex = index;
|
|
1606
|
+
break;
|
|
1607
|
+
}
|
|
1608
|
+
}
|
|
1609
|
+
if (bangIndex < 0) {
|
|
1610
|
+
return null;
|
|
1611
|
+
}
|
|
1612
|
+
return {
|
|
1613
|
+
range: reference.slice(bangIndex + 1),
|
|
1614
|
+
sheetName: unquoteSheetName(reference.slice(0, bangIndex))
|
|
1615
|
+
};
|
|
1616
|
+
}
|
|
1617
|
+
function parseA1Cell(reference) {
|
|
1618
|
+
const match = /^\$?([A-Z]+)\$?(\d+)$/i.exec(reference.trim());
|
|
1619
|
+
if (!match) {
|
|
1620
|
+
return null;
|
|
1621
|
+
}
|
|
1622
|
+
let col = 0;
|
|
1623
|
+
for (const char of match[1].toUpperCase()) {
|
|
1624
|
+
col = col * 26 + (char.charCodeAt(0) - 64);
|
|
1625
|
+
}
|
|
1626
|
+
return {
|
|
1627
|
+
col: col - 1,
|
|
1628
|
+
row: Number(match[2]) - 1
|
|
1629
|
+
};
|
|
1630
|
+
}
|
|
1631
|
+
function parseA1Range(reference) {
|
|
1632
|
+
const [startRef, endRef = startRef] = reference.split(":");
|
|
1633
|
+
const start = parseA1Cell(startRef ?? "");
|
|
1634
|
+
const end = parseA1Cell(endRef ?? "");
|
|
1635
|
+
if (!start || !end) {
|
|
1636
|
+
return null;
|
|
1637
|
+
}
|
|
1638
|
+
return {
|
|
1639
|
+
end: {
|
|
1640
|
+
col: Math.max(start.col, end.col),
|
|
1641
|
+
row: Math.max(start.row, end.row)
|
|
1642
|
+
},
|
|
1643
|
+
start: {
|
|
1644
|
+
col: Math.min(start.col, end.col),
|
|
1645
|
+
row: Math.min(start.row, end.row)
|
|
1646
|
+
}
|
|
1647
|
+
};
|
|
1648
|
+
}
|
|
1649
|
+
function formatA1Column(col) {
|
|
1650
|
+
let current = col + 1;
|
|
1651
|
+
let label = "";
|
|
1652
|
+
while (current > 0) {
|
|
1653
|
+
const remainder = (current - 1) % 26;
|
|
1654
|
+
label = String.fromCharCode(65 + remainder) + label;
|
|
1655
|
+
current = Math.floor((current - 1) / 26);
|
|
1656
|
+
}
|
|
1657
|
+
return label;
|
|
1658
|
+
}
|
|
1659
|
+
function buildA1RangeFormula(sheetName, start, end) {
|
|
1660
|
+
const escapedSheetName = sheetName.replace(/'/g, "''");
|
|
1661
|
+
return `'${escapedSheetName}'!$${formatA1Column(start.col)}$${start.row + 1}:$${formatA1Column(end.col)}$${end.row + 1}`;
|
|
1662
|
+
}
|
|
1663
|
+
function resolveReferenceSheet(workbook2, fallbackSheetIndex, formula) {
|
|
1664
|
+
if (!formula) {
|
|
1665
|
+
return {
|
|
1666
|
+
range: null,
|
|
1667
|
+
sheet: workbook2.getSheet(fallbackSheetIndex),
|
|
1668
|
+
sheetName: workbook2.getSheet(fallbackSheetIndex)?.name ?? ""
|
|
1669
|
+
};
|
|
1670
|
+
}
|
|
1671
|
+
const trimmedFormula = formula.trim();
|
|
1672
|
+
if (trimmedFormula.length > 0 && !trimmedFormula.includes("!")) {
|
|
1673
|
+
try {
|
|
1674
|
+
const namedRange = workbook2.getNamedRange(trimmedFormula);
|
|
1675
|
+
if (typeof namedRange === "string" && namedRange.length > 0 && namedRange !== trimmedFormula) {
|
|
1676
|
+
return resolveReferenceSheet(workbook2, fallbackSheetIndex, namedRange);
|
|
1677
|
+
}
|
|
1678
|
+
} catch {
|
|
1679
|
+
}
|
|
1680
|
+
}
|
|
1681
|
+
const split = splitSheetReference(trimmedFormula);
|
|
1682
|
+
if (!split) {
|
|
1683
|
+
return {
|
|
1684
|
+
range: parseA1Range(trimmedFormula),
|
|
1685
|
+
sheet: workbook2.getSheet(fallbackSheetIndex),
|
|
1686
|
+
sheetName: workbook2.getSheet(fallbackSheetIndex)?.name ?? ""
|
|
1687
|
+
};
|
|
1688
|
+
}
|
|
1689
|
+
try {
|
|
1690
|
+
return {
|
|
1691
|
+
range: parseA1Range(split.range),
|
|
1692
|
+
sheet: workbook2.getSheetByName(split.sheetName),
|
|
1693
|
+
sheetName: split.sheetName
|
|
1694
|
+
};
|
|
1695
|
+
} catch {
|
|
1696
|
+
return {
|
|
1697
|
+
range: parseA1Range(split.range),
|
|
1698
|
+
sheet: workbook2.getSheet(fallbackSheetIndex),
|
|
1699
|
+
sheetName: workbook2.getSheet(fallbackSheetIndex)?.name ?? ""
|
|
1700
|
+
};
|
|
1701
|
+
}
|
|
1702
|
+
}
|
|
1703
|
+
function resolveChartReferenceLabel(workbook2, fallbackSheetIndex, reference, fallbackLabel) {
|
|
1704
|
+
if (!reference?.formula) {
|
|
1705
|
+
return fallbackLabel;
|
|
1706
|
+
}
|
|
1707
|
+
const resolved = resolveReferenceSheet(workbook2, fallbackSheetIndex, reference.formula);
|
|
1708
|
+
if (!resolved.sheet || !resolved.range) {
|
|
1709
|
+
return fallbackLabel;
|
|
1710
|
+
}
|
|
1711
|
+
const { start } = resolved.range;
|
|
1712
|
+
if (start.row > 0) {
|
|
1713
|
+
const headerDisplay = cellValueToDisplay(
|
|
1714
|
+
typeof resolved.sheet.getFormattedValueAt === "function" ? resolved.sheet.getFormattedValueAt(start.row - 1, start.col) : null
|
|
1715
|
+
);
|
|
1716
|
+
if (headerDisplay.length > 0) {
|
|
1717
|
+
return headerDisplay;
|
|
1718
|
+
}
|
|
1719
|
+
}
|
|
1720
|
+
const firstDisplay = cellValueToDisplay(
|
|
1721
|
+
typeof resolved.sheet.getFormattedValueAt === "function" ? resolved.sheet.getFormattedValueAt(start.row, start.col) : null
|
|
1722
|
+
);
|
|
1723
|
+
return firstDisplay.length > 0 ? firstDisplay : fallbackLabel;
|
|
1724
|
+
}
|
|
1725
|
+
function resolveReferenceRowPaths(workbook2, fallbackSheetIndex, reference) {
|
|
1726
|
+
if (!reference?.formula) {
|
|
1727
|
+
return [];
|
|
1728
|
+
}
|
|
1729
|
+
const resolved = resolveReferenceSheet(workbook2, fallbackSheetIndex, reference.formula);
|
|
1730
|
+
if (!resolved.sheet || !resolved.range) {
|
|
1731
|
+
return [];
|
|
1732
|
+
}
|
|
1733
|
+
const rows = [];
|
|
1734
|
+
for (let row = resolved.range.start.row; row <= resolved.range.end.row; row += 1) {
|
|
1735
|
+
const parts = [];
|
|
1736
|
+
for (let col = resolved.range.start.col; col <= resolved.range.end.col; col += 1) {
|
|
1737
|
+
const calculated = typeof resolved.sheet.getCalculatedValueAt === "function" ? resolved.sheet.getCalculatedValueAt(row, col) : null;
|
|
1738
|
+
const formatted = typeof resolved.sheet.getFormattedValueAt === "function" ? resolved.sheet.getFormattedValueAt(row, col) : calculated;
|
|
1739
|
+
const display = cellValueToDisplay(formatted ?? calculated);
|
|
1740
|
+
const numeric = cellValueToNumber(calculated ?? formatted);
|
|
1741
|
+
const label = display.length > 0 ? display : numeric != null ? String(numeric) : "";
|
|
1742
|
+
if (label.length > 0) {
|
|
1743
|
+
parts.push(label);
|
|
1744
|
+
}
|
|
1745
|
+
}
|
|
1746
|
+
rows.push(parts);
|
|
1747
|
+
}
|
|
1748
|
+
return rows;
|
|
1749
|
+
}
|
|
1750
|
+
function normalizeChartExLegend(raw) {
|
|
1751
|
+
if (!raw || typeof raw !== "object") {
|
|
1752
|
+
return null;
|
|
1753
|
+
}
|
|
1754
|
+
const legend = raw;
|
|
1755
|
+
const position = typeof legend.pos === "string" ? normalizeLegendPosition(String(legend.pos)) : void 0;
|
|
1756
|
+
return {
|
|
1757
|
+
overlay: typeof legend.overlay === "boolean" ? legend.overlay : void 0,
|
|
1758
|
+
position,
|
|
1759
|
+
raw: legend
|
|
1760
|
+
};
|
|
1761
|
+
}
|
|
1762
|
+
function humanizeChartExLayoutLabel(layout) {
|
|
1763
|
+
if (!layout) {
|
|
1764
|
+
return void 0;
|
|
1765
|
+
}
|
|
1766
|
+
return layout.replace(/([a-z0-9])([A-Z])/g, "$1 $2").replace(/[-_]+/g, " ").trim().replace(/\b\w/g, (match) => match.toUpperCase());
|
|
1767
|
+
}
|
|
1768
|
+
function normalizeChartExAxis(raw) {
|
|
1769
|
+
if (!raw || typeof raw !== "object") {
|
|
1770
|
+
return null;
|
|
1771
|
+
}
|
|
1772
|
+
const axis = raw;
|
|
1773
|
+
const scaling = axis.scaling && typeof axis.scaling === "object" ? axis.scaling : null;
|
|
1774
|
+
const numberFormat = axis.numberFormat && typeof axis.numberFormat === "object" ? axis.numberFormat : null;
|
|
1775
|
+
return {
|
|
1776
|
+
delete: typeof axis.hidden === "boolean" ? axis.hidden : void 0,
|
|
1777
|
+
id: typeof axis.id === "number" && Number.isFinite(axis.id) ? axis.id : void 0,
|
|
1778
|
+
crossId: typeof axis.crossId === "number" && Number.isFinite(axis.crossId) ? axis.crossId : void 0,
|
|
1779
|
+
majorGridlines: axis.majorGridlines != null ? true : void 0,
|
|
1780
|
+
majorUnit: typeof scaling?.majorUnit === "number" ? scaling.majorUnit : void 0,
|
|
1781
|
+
max: typeof scaling?.max === "number" ? scaling.max : void 0,
|
|
1782
|
+
min: typeof scaling?.min === "number" ? scaling.min : void 0,
|
|
1783
|
+
minorGridlines: axis.minorGridlines != null ? true : void 0,
|
|
1784
|
+
minorUnit: typeof scaling?.minorUnit === "number" ? scaling.minorUnit : void 0,
|
|
1785
|
+
numberFormat: numberFormat ? {
|
|
1786
|
+
formatCode: typeof numberFormat.formatCode === "string" ? numberFormat.formatCode : void 0,
|
|
1787
|
+
sourceLinked: typeof numberFormat.sourceLinked === "boolean" ? numberFormat.sourceLinked : void 0
|
|
1788
|
+
} : void 0,
|
|
1789
|
+
raw: axis,
|
|
1790
|
+
position: typeof axis.position === "string" ? axis.position : void 0,
|
|
1791
|
+
tickLabelSkip: typeof axis.tickLabelSkip === "number" ? axis.tickLabelSkip : void 0,
|
|
1792
|
+
tickMarkSkip: typeof axis.tickMarkSkip === "number" ? axis.tickMarkSkip : void 0
|
|
1793
|
+
};
|
|
1794
|
+
}
|
|
1795
|
+
function resolveChartExLayoutChartType(layout) {
|
|
1796
|
+
switch (layout) {
|
|
1797
|
+
case "boxWhisker":
|
|
1798
|
+
return "BoxWhisker";
|
|
1799
|
+
case "clusteredColumn":
|
|
1800
|
+
return "ColumnClustered";
|
|
1801
|
+
case "funnel":
|
|
1802
|
+
return "Funnel";
|
|
1803
|
+
case "paretoLine":
|
|
1804
|
+
return "Line";
|
|
1805
|
+
case "regionMap":
|
|
1806
|
+
return "RegionMap";
|
|
1807
|
+
case "sunburst":
|
|
1808
|
+
return "Sunburst";
|
|
1809
|
+
case "treemap":
|
|
1810
|
+
return "Treemap";
|
|
1811
|
+
case "waterfall":
|
|
1812
|
+
return "Waterfall";
|
|
1813
|
+
default:
|
|
1814
|
+
return layout ? `Unsupported(cx:${layout})` : "ColumnClustered";
|
|
1815
|
+
}
|
|
1816
|
+
}
|
|
1817
|
+
function resolveChartExSeriesLayout(raw) {
|
|
1818
|
+
if (!raw || typeof raw !== "object") {
|
|
1819
|
+
return void 0;
|
|
1820
|
+
}
|
|
1821
|
+
const record = raw;
|
|
1822
|
+
return typeof record.layout === "string" ? record.layout : typeof record.layoutId === "string" ? record.layoutId : void 0;
|
|
1823
|
+
}
|
|
1824
|
+
function resolveChartExSeriesAxisIds(raw) {
|
|
1825
|
+
if (!raw || typeof raw !== "object") {
|
|
1826
|
+
return [];
|
|
1827
|
+
}
|
|
1828
|
+
const record = raw;
|
|
1829
|
+
if (Array.isArray(record.axisIds)) {
|
|
1830
|
+
return record.axisIds.filter((value) => typeof value === "number" && Number.isFinite(value));
|
|
1831
|
+
}
|
|
1832
|
+
if (Array.isArray(record.axisId)) {
|
|
1833
|
+
return record.axisId.flatMap((value) => {
|
|
1834
|
+
if (typeof value === "number" && Number.isFinite(value)) {
|
|
1835
|
+
return [value];
|
|
1836
|
+
}
|
|
1837
|
+
if (value && typeof value === "object" && typeof value.val === "number") {
|
|
1838
|
+
return [value.val];
|
|
1839
|
+
}
|
|
1840
|
+
return [];
|
|
1841
|
+
});
|
|
1842
|
+
}
|
|
1843
|
+
if (typeof record.axisId === "number" && Number.isFinite(record.axisId)) {
|
|
1844
|
+
return [record.axisId];
|
|
1845
|
+
}
|
|
1846
|
+
return [];
|
|
1847
|
+
}
|
|
1848
|
+
function niceHistogramStep(value) {
|
|
1849
|
+
if (!Number.isFinite(value) || value <= 0) {
|
|
1850
|
+
return 1;
|
|
1851
|
+
}
|
|
1852
|
+
const exponent = Math.floor(Math.log10(value));
|
|
1853
|
+
const scale = 10 ** exponent;
|
|
1854
|
+
const normalized = value / scale;
|
|
1855
|
+
if (normalized <= 1) {
|
|
1856
|
+
return scale;
|
|
1857
|
+
}
|
|
1858
|
+
if (normalized <= 2) {
|
|
1859
|
+
return scale * 2;
|
|
1860
|
+
}
|
|
1861
|
+
if (normalized <= 5) {
|
|
1862
|
+
return scale * 5;
|
|
1863
|
+
}
|
|
1864
|
+
return scale * 10;
|
|
1865
|
+
}
|
|
1866
|
+
function formatHistogramBinLabel(lower, upper, index, closedRight) {
|
|
1867
|
+
const leftBracket = closedRight ? index === 0 ? "[" : "(" : "[";
|
|
1868
|
+
const rightBracket = closedRight ? "]" : ")";
|
|
1869
|
+
return `${leftBracket}${Number(lower.toFixed(6))},${Number(upper.toFixed(6))}${rightBracket}`;
|
|
1870
|
+
}
|
|
1871
|
+
function buildChartExHistogramBins(values, rawSeries, sortByFrequency) {
|
|
1872
|
+
if (values.length === 0) {
|
|
1873
|
+
return [];
|
|
1874
|
+
}
|
|
1875
|
+
const rawRecord = rawSeries && typeof rawSeries === "object" ? rawSeries : null;
|
|
1876
|
+
const layoutProperties = rawRecord?.layoutPr && typeof rawRecord.layoutPr === "object" ? rawRecord.layoutPr : null;
|
|
1877
|
+
const rawBinning = layoutProperties?.binning && typeof layoutProperties.binning === "object" ? layoutProperties.binning : null;
|
|
1878
|
+
const minValue = Math.min(...values);
|
|
1879
|
+
const maxValue = Math.max(...values);
|
|
1880
|
+
const explicitWidth = typeof rawBinning?.binWidth === "number" && Number.isFinite(rawBinning.binWidth) && rawBinning.binWidth > 0 ? rawBinning.binWidth : typeof rawBinning?.width === "number" && Number.isFinite(rawBinning.width) && rawBinning.width > 0 ? rawBinning.width : void 0;
|
|
1881
|
+
const explicitCount = typeof rawBinning?.binCount === "number" && Number.isFinite(rawBinning.binCount) && rawBinning.binCount > 0 ? rawBinning.binCount : typeof rawBinning?.count === "number" && Number.isFinite(rawBinning.count) && rawBinning.count > 0 ? rawBinning.count : void 0;
|
|
1882
|
+
const closedRight = rawBinning?.intervalClosed === "r" || rawBinning?.intervalClosed === "right";
|
|
1883
|
+
const mean = values.reduce((sum, value) => sum + value, 0) / values.length;
|
|
1884
|
+
const variance = values.reduce((sum, value) => sum + (value - mean) ** 2, 0) / Math.max(1, values.length);
|
|
1885
|
+
const standardDeviation = Math.sqrt(Math.max(0, variance));
|
|
1886
|
+
const allIntegers = values.every((value) => Math.abs(value - Math.round(value)) < 1e-9);
|
|
1887
|
+
const scottWidth = standardDeviation > 0 ? 3.49 * standardDeviation / Math.cbrt(values.length) : void 0;
|
|
1888
|
+
const fallbackWidth = explicitCount != null ? (maxValue - minValue) / Math.max(1, explicitCount) : scottWidth ?? (maxValue - minValue) / Math.max(1, Math.ceil(Math.log2(values.length) + 1));
|
|
1889
|
+
const roughWidth = explicitWidth ?? (allIntegers ? Math.max(1, Math.ceil(Math.max(fallbackWidth, 1e-6))) : niceHistogramStep(Math.max(fallbackWidth, 1e-6)));
|
|
1890
|
+
const binWidth = Math.max(roughWidth, 1e-6);
|
|
1891
|
+
const start = explicitWidth != null || explicitCount != null ? Math.floor(minValue / binWidth) * binWidth : minValue;
|
|
1892
|
+
const end = Math.max(start + binWidth, start + Math.ceil((maxValue - start) / binWidth) * binWidth);
|
|
1893
|
+
const binCount = Math.max(1, Math.ceil((end - start) / binWidth));
|
|
1894
|
+
const bins = Array.from({ length: binCount }, (_, index) => {
|
|
1895
|
+
const lower = start + binWidth * index;
|
|
1896
|
+
const upper = lower + binWidth;
|
|
1897
|
+
return {
|
|
1898
|
+
count: 0,
|
|
1899
|
+
label: formatHistogramBinLabel(lower, upper, index, closedRight),
|
|
1900
|
+
lower,
|
|
1901
|
+
upper
|
|
1902
|
+
};
|
|
1903
|
+
});
|
|
1904
|
+
values.forEach((value) => {
|
|
1905
|
+
if (!Number.isFinite(value)) {
|
|
1906
|
+
return;
|
|
1907
|
+
}
|
|
1908
|
+
const offset = (value - start) / binWidth;
|
|
1909
|
+
let binIndex = Math.floor(offset);
|
|
1910
|
+
if (closedRight && Math.abs(offset - Math.round(offset)) < 1e-9 && value > start) {
|
|
1911
|
+
binIndex -= 1;
|
|
1912
|
+
}
|
|
1913
|
+
if (value >= end) {
|
|
1914
|
+
binIndex = bins.length - 1;
|
|
1915
|
+
}
|
|
1916
|
+
if (value <= start) {
|
|
1917
|
+
binIndex = 0;
|
|
1918
|
+
}
|
|
1919
|
+
const target = bins[Math.max(0, Math.min(bins.length - 1, binIndex))];
|
|
1920
|
+
if (target) {
|
|
1921
|
+
target.count += 1;
|
|
1922
|
+
}
|
|
1923
|
+
});
|
|
1924
|
+
if (sortByFrequency) {
|
|
1925
|
+
bins.sort((left, right) => right.count - left.count || left.lower - right.lower);
|
|
1926
|
+
}
|
|
1927
|
+
return bins;
|
|
1928
|
+
}
|
|
1929
|
+
function buildChartExHistogramSeries(series, rawSeries, sortByFrequency) {
|
|
1930
|
+
const layout = resolveChartExSeriesLayout(rawSeries);
|
|
1931
|
+
const rawRecord = rawSeries && typeof rawSeries === "object" ? rawSeries : null;
|
|
1932
|
+
const hasBinning = Boolean(
|
|
1933
|
+
layout === "clusteredColumn" && rawRecord?.layoutPr && typeof rawRecord.layoutPr === "object" && rawRecord.layoutPr.binning != null
|
|
1934
|
+
);
|
|
1935
|
+
if (!hasBinning) {
|
|
1936
|
+
return series;
|
|
1937
|
+
}
|
|
1938
|
+
const numericValues = series.values.filter((value) => typeof value === "number" && Number.isFinite(value));
|
|
1939
|
+
if (numericValues.length === 0) {
|
|
1940
|
+
return series;
|
|
1941
|
+
}
|
|
1942
|
+
const bins = buildChartExHistogramBins(numericValues, rawSeries, sortByFrequency);
|
|
1943
|
+
if (bins.length === 0) {
|
|
1944
|
+
return series;
|
|
1945
|
+
}
|
|
1946
|
+
return {
|
|
1947
|
+
...series,
|
|
1948
|
+
categories: bins.map((bin) => bin.label),
|
|
1949
|
+
categoriesRef: null,
|
|
1950
|
+
raw: {
|
|
1951
|
+
...series.raw,
|
|
1952
|
+
chartExHistogramBins: bins,
|
|
1953
|
+
chartExSourceValues: numericValues
|
|
1954
|
+
},
|
|
1955
|
+
values: bins.map((bin) => bin.count)
|
|
1956
|
+
};
|
|
1957
|
+
}
|
|
1958
|
+
function buildChartExParetoLineSeries(series, sourceRaw, index) {
|
|
1959
|
+
const counts = series.values.map((value) => typeof value === "number" && Number.isFinite(value) ? value : 0);
|
|
1960
|
+
const total = counts.reduce((sum, value) => sum + value, 0);
|
|
1961
|
+
let running = 0;
|
|
1962
|
+
const cumulative = counts.map((value) => {
|
|
1963
|
+
running += value;
|
|
1964
|
+
return total > 0 ? running / total * 100 : 0;
|
|
1965
|
+
});
|
|
1966
|
+
return {
|
|
1967
|
+
...series,
|
|
1968
|
+
color: void 0,
|
|
1969
|
+
lineColor: void 0,
|
|
1970
|
+
markerColor: void 0,
|
|
1971
|
+
markerLineColor: void 0,
|
|
1972
|
+
markerSize: 7,
|
|
1973
|
+
markerSymbol: "circle",
|
|
1974
|
+
name: typeof sourceRaw?.text === "string" ? sourceRaw.text : "Pareto",
|
|
1975
|
+
raw: {
|
|
1976
|
+
...series.raw ?? {},
|
|
1977
|
+
chartExLayout: "paretoLine",
|
|
1978
|
+
source: sourceRaw && typeof sourceRaw === "object" ? sourceRaw : void 0
|
|
1979
|
+
},
|
|
1980
|
+
values: cumulative
|
|
1981
|
+
};
|
|
1982
|
+
}
|
|
1983
|
+
function resolveChartExTextFormula(raw) {
|
|
1984
|
+
if (typeof raw === "string" && raw.length > 0) {
|
|
1985
|
+
return raw;
|
|
1986
|
+
}
|
|
1987
|
+
if (!raw || typeof raw !== "object") {
|
|
1988
|
+
return void 0;
|
|
1989
|
+
}
|
|
1990
|
+
const record = raw;
|
|
1991
|
+
if (typeof record.formula === "string" && record.formula.length > 0) {
|
|
1992
|
+
return record.formula;
|
|
1993
|
+
}
|
|
1994
|
+
if (typeof record.text === "string" && record.text.length > 0) {
|
|
1995
|
+
return record.text;
|
|
1996
|
+
}
|
|
1997
|
+
if (typeof record.value === "string" && record.value.length > 0) {
|
|
1998
|
+
return record.value;
|
|
1999
|
+
}
|
|
2000
|
+
return void 0;
|
|
2001
|
+
}
|
|
2002
|
+
function resolveChartExTitleText(raw) {
|
|
2003
|
+
if (typeof raw === "string" && raw.length > 0) {
|
|
2004
|
+
return raw;
|
|
2005
|
+
}
|
|
2006
|
+
if (!raw || typeof raw !== "object") {
|
|
2007
|
+
return void 0;
|
|
2008
|
+
}
|
|
2009
|
+
const record = raw;
|
|
2010
|
+
if (typeof record.text === "string" && record.text.length > 0) {
|
|
2011
|
+
return record.text;
|
|
2012
|
+
}
|
|
2013
|
+
const nestedText = record.text && typeof record.text === "object" ? resolveChartExTextFormula(record.text) : void 0;
|
|
2014
|
+
if (nestedText) {
|
|
2015
|
+
return nestedText;
|
|
2016
|
+
}
|
|
2017
|
+
return typeof record.value === "string" && record.value.length > 0 ? record.value : void 0;
|
|
2018
|
+
}
|
|
2019
|
+
function resolveChartExFallbackCategoryReference(workbook2, fallbackSheetIndex, valueFormula) {
|
|
2020
|
+
if (!valueFormula) {
|
|
2021
|
+
return null;
|
|
2022
|
+
}
|
|
2023
|
+
const resolved = resolveReferenceSheet(workbook2, fallbackSheetIndex, valueFormula);
|
|
2024
|
+
if (!resolved.sheet || !resolved.range || resolved.range.start.col <= 0) {
|
|
2025
|
+
return null;
|
|
2026
|
+
}
|
|
2027
|
+
return normalizeChartReference({
|
|
2028
|
+
formula: buildA1RangeFormula(
|
|
2029
|
+
resolved.sheetName,
|
|
2030
|
+
{
|
|
2031
|
+
col: resolved.range.start.col - 1,
|
|
2032
|
+
row: resolved.range.start.row
|
|
2033
|
+
},
|
|
2034
|
+
{
|
|
2035
|
+
col: resolved.range.start.col - 1,
|
|
2036
|
+
row: resolved.range.end.row
|
|
2037
|
+
}
|
|
2038
|
+
)
|
|
2039
|
+
});
|
|
2040
|
+
}
|
|
2041
|
+
function normalizeChartExSeries(workbook2, workbookSheetIndex, chartId, raw, dataById, index, chartType) {
|
|
2042
|
+
const series = raw && typeof raw === "object" ? raw : {};
|
|
2043
|
+
const dataId = typeof series.dataId === "number" ? series.dataId : null;
|
|
2044
|
+
const dataEntry = dataId != null ? dataById.get(dataId) ?? null : null;
|
|
2045
|
+
const dimensions = Array.isArray(dataEntry?.dimensions) ? dataEntry.dimensions.filter((value) => Boolean(value && typeof value === "object")) : [];
|
|
2046
|
+
const categoryDimension = dimensions.find((dimension) => dimension.dimType === "cat") ?? dimensions.find((dimension) => dimension.dimType === "name") ?? null;
|
|
2047
|
+
const valueDimension = dimensions.find((dimension) => dimension.dimType === "val" || dimension.dimType === "y" || dimension.dimType === "colorVal" || dimension.dimType === "size") ?? dimensions.find((dimension) => dimension !== categoryDimension) ?? categoryDimension;
|
|
2048
|
+
const categoryDimensionFormula = typeof categoryDimension?.formula === "string" ? categoryDimension.formula : void 0;
|
|
2049
|
+
const valueDimensionFormula = typeof valueDimension?.formula === "string" ? valueDimension.formula : void 0;
|
|
2050
|
+
const fallbackCategoryRef = (chartType === "Sunburst" || chartType === "Treemap") && !categoryDimension && typeof valueDimensionFormula === "string" ? resolveChartExFallbackCategoryReference(workbook2, workbookSheetIndex, valueDimensionFormula) : null;
|
|
2051
|
+
const categoriesRef = categoryDimension ? normalizeChartReference({
|
|
2052
|
+
formula: categoryDimensionFormula
|
|
2053
|
+
}) : fallbackCategoryRef;
|
|
2054
|
+
const valuesRef = valueDimension ? normalizeChartReference({
|
|
2055
|
+
formula: valueDimensionFormula
|
|
2056
|
+
}) : null;
|
|
2057
|
+
const resolvedValueCells = resolveReferenceValues(workbook2, workbookSheetIndex, valuesRef, "value");
|
|
2058
|
+
const values = resolvedValueCells.map((value) => typeof value === "number" && Number.isFinite(value) ? value : null);
|
|
2059
|
+
const colorStrings = chartType === "RegionMap" && valueDimension?.dimType === "colorStr" ? resolvedValueCells.map((value) => {
|
|
2060
|
+
if (typeof value === "string") {
|
|
2061
|
+
const trimmed = value.trim();
|
|
2062
|
+
return trimmed.length > 0 ? trimmed : null;
|
|
2063
|
+
}
|
|
2064
|
+
if (typeof value === "number" && Number.isFinite(value)) {
|
|
2065
|
+
return String(value);
|
|
2066
|
+
}
|
|
2067
|
+
return null;
|
|
2068
|
+
}) : [];
|
|
2069
|
+
const categories = resolveReferenceValues(workbook2, workbookSheetIndex, categoriesRef, "category");
|
|
2070
|
+
const hierarchyCategories = chartType === "Sunburst" || chartType === "Treemap" ? resolveReferenceRowPaths(workbook2, workbookSheetIndex, categoriesRef) : [];
|
|
2071
|
+
const seriesTextFormula = resolveChartExTextFormula(series.text);
|
|
2072
|
+
const shapeProperties = series.shapeProperties && typeof series.shapeProperties === "object" ? series.shapeProperties : void 0;
|
|
2073
|
+
const rawFillColor = typeof shapeProperties?.solidFillHex === "string" ? normalizeHexColor(shapeProperties.solidFillHex) : null;
|
|
2074
|
+
const rawLineColor = typeof shapeProperties?.lineColorHex === "string" ? normalizeHexColor(shapeProperties.lineColorHex) : null;
|
|
2075
|
+
return {
|
|
2076
|
+
bubbleSizeRef: null,
|
|
2077
|
+
bubbleSizes: [],
|
|
2078
|
+
categories,
|
|
2079
|
+
categoriesRef,
|
|
2080
|
+
color: rawFillColor ?? void 0,
|
|
2081
|
+
dataPoints: Array.isArray(series.dataPoints) ? series.dataPoints : [],
|
|
2082
|
+
dataPointStyles: void 0,
|
|
2083
|
+
formatIdx: typeof series.formatIdx === "number" ? series.formatIdx : void 0,
|
|
2084
|
+
hidden: typeof series.hidden === "boolean" ? series.hidden : void 0,
|
|
2085
|
+
id: `${chartId}-series-${index}`,
|
|
2086
|
+
invertIfNegative: void 0,
|
|
2087
|
+
lineColor: rawLineColor ?? rawFillColor ?? void 0,
|
|
2088
|
+
lineWidthPx: typeof shapeProperties?.lineWidth === "number" ? Math.max(1, Number(shapeProperties.lineWidth) / EMU_PER_PIXEL) : void 0,
|
|
2089
|
+
marker: void 0,
|
|
2090
|
+
markerColor: rawFillColor ?? void 0,
|
|
2091
|
+
markerLineColor: rawLineColor ?? rawFillColor ?? void 0,
|
|
2092
|
+
markerSize: void 0,
|
|
2093
|
+
markerSymbol: void 0,
|
|
2094
|
+
name: typeof series.text === "string" ? series.text : seriesTextFormula ? resolveSeriesName(workbook2, workbookSheetIndex, seriesTextFormula) : resolveChartReferenceLabel(workbook2, workbookSheetIndex, valuesRef, `Series ${index + 1}`),
|
|
2095
|
+
negativeColor: void 0,
|
|
2096
|
+
negativeLineColor: void 0,
|
|
2097
|
+
raw: {
|
|
2098
|
+
...series,
|
|
2099
|
+
chartExColorStrings: colorStrings,
|
|
2100
|
+
chartExHierarchyCategories: hierarchyCategories,
|
|
2101
|
+
data: dataEntry,
|
|
2102
|
+
dimType: typeof valueDimension?.dimType === "string" ? valueDimension.dimType : void 0
|
|
2103
|
+
},
|
|
2104
|
+
shapeProperties,
|
|
2105
|
+
smooth: void 0,
|
|
2106
|
+
values,
|
|
2107
|
+
valuesRef
|
|
2108
|
+
};
|
|
2109
|
+
}
|
|
2110
|
+
function collapseChartExPointSeries(chartType, series) {
|
|
2111
|
+
if (chartType !== "Funnel" && chartType !== "Waterfall") {
|
|
2112
|
+
if ((chartType === "Sunburst" || chartType === "Treemap") && series.length > 1 && series.every((entry) => {
|
|
2113
|
+
const raw = entry.raw && typeof entry.raw === "object" ? entry.raw : null;
|
|
2114
|
+
return raw?.dimType === "size";
|
|
2115
|
+
})) {
|
|
2116
|
+
const primarySeries2 = series.find((entry) => entry.hidden !== true) ?? series[0] ?? null;
|
|
2117
|
+
if (!primarySeries2) {
|
|
2118
|
+
return series;
|
|
2119
|
+
}
|
|
2120
|
+
return [
|
|
2121
|
+
{
|
|
2122
|
+
...primarySeries2,
|
|
2123
|
+
dataPoints: [],
|
|
2124
|
+
hidden: false
|
|
2125
|
+
}
|
|
2126
|
+
];
|
|
2127
|
+
}
|
|
2128
|
+
return series;
|
|
2129
|
+
}
|
|
2130
|
+
const primarySeries = series.find((entry) => entry.hidden !== true) ?? series[0] ?? null;
|
|
2131
|
+
if (!primarySeries) {
|
|
2132
|
+
return series;
|
|
2133
|
+
}
|
|
2134
|
+
return [
|
|
2135
|
+
{
|
|
2136
|
+
...primarySeries,
|
|
2137
|
+
categories: [],
|
|
2138
|
+
categoriesRef: null,
|
|
2139
|
+
dataPoints: [],
|
|
2140
|
+
hidden: false
|
|
2141
|
+
}
|
|
2142
|
+
];
|
|
2143
|
+
}
|
|
2144
|
+
function normalizeChartExChart(workbook2, workbookSheetIndex, visibleSheetIndex, raw, index, themePalette) {
|
|
2145
|
+
const chart = raw && typeof raw === "object" ? raw : {};
|
|
2146
|
+
const plotArea = chart.plotArea && typeof chart.plotArea === "object" ? chart.plotArea : {};
|
|
2147
|
+
const rawSeries = Array.isArray(plotArea.series) ? plotArea.series : [];
|
|
2148
|
+
const seriesLayouts = rawSeries.map(resolveChartExSeriesLayout);
|
|
2149
|
+
const dataEntries = Array.isArray(chart.data) ? chart.data : [];
|
|
2150
|
+
const dataById = /* @__PURE__ */ new Map();
|
|
2151
|
+
dataEntries.forEach((entry) => {
|
|
2152
|
+
if (!entry || typeof entry !== "object") {
|
|
2153
|
+
return;
|
|
2154
|
+
}
|
|
2155
|
+
const record = entry;
|
|
2156
|
+
if (typeof record.id === "number") {
|
|
2157
|
+
dataById.set(record.id, record);
|
|
2158
|
+
}
|
|
2159
|
+
});
|
|
2160
|
+
const axes = Array.isArray(plotArea.axes) ? plotArea.axes.map(normalizeChartExAxis).filter((value) => Boolean(value)) : [];
|
|
2161
|
+
const primaryLayout = typeof chart.layout === "string" ? chart.layout : seriesLayouts.find((value) => typeof value === "string" && value.length > 0);
|
|
2162
|
+
const fallbackTitle = humanizeChartExLayoutLabel(primaryLayout);
|
|
2163
|
+
const chartTitle = resolveChartExTitleText(chart.title) ?? (chart.title != null ? "Chart Title" : fallbackTitle);
|
|
2164
|
+
const chartType = resolveChartExLayoutChartType(primaryLayout);
|
|
2165
|
+
const normalizedSeries = rawSeries.map((entry, seriesIndex) => normalizeChartExSeries(workbook2, workbookSheetIndex, `chart-ex-${workbookSheetIndex}-${index}`, entry, dataById, seriesIndex, chartType));
|
|
2166
|
+
const clusteredColumnSeriesIndex = seriesLayouts.findIndex((layout) => layout === "clusteredColumn");
|
|
2167
|
+
const hasParetoLine = seriesLayouts.includes("paretoLine");
|
|
2168
|
+
const clusteredColumnAxisIds = clusteredColumnSeriesIndex >= 0 ? resolveChartExSeriesAxisIds(rawSeries[clusteredColumnSeriesIndex]) : [];
|
|
2169
|
+
const paretoLineSeriesIndex = seriesLayouts.findIndex((layout) => layout === "paretoLine");
|
|
2170
|
+
const paretoLineAxisIds = paretoLineSeriesIndex >= 0 ? resolveChartExSeriesAxisIds(rawSeries[paretoLineSeriesIndex]) : [];
|
|
2171
|
+
const primaryHistogramSeries = clusteredColumnSeriesIndex >= 0 ? buildChartExHistogramSeries(normalizedSeries[clusteredColumnSeriesIndex] ?? normalizedSeries[0], rawSeries[clusteredColumnSeriesIndex], hasParetoLine) : null;
|
|
2172
|
+
const synthesizedParetoSeries = hasParetoLine && primaryHistogramSeries && primaryHistogramSeries.values.length > 0 ? buildChartExParetoLineSeries(primaryHistogramSeries, rawSeries[paretoLineSeriesIndex], paretoLineSeriesIndex) : null;
|
|
2173
|
+
const resolvedSeries = synthesizedParetoSeries ? [primaryHistogramSeries, synthesizedParetoSeries] : primaryHistogramSeries ? [
|
|
2174
|
+
primaryHistogramSeries,
|
|
2175
|
+
...normalizedSeries.filter((_, seriesIndex) => seriesIndex !== clusteredColumnSeriesIndex)
|
|
2176
|
+
] : collapseChartExPointSeries(chartType, normalizedSeries);
|
|
2177
|
+
const resolvedChartType = primaryHistogramSeries ? "ColumnClustered" : chartType;
|
|
2178
|
+
const resolvedGapWidth = primaryHistogramSeries ? 0 : void 0;
|
|
2179
|
+
const typeGroups = synthesizedParetoSeries ? [
|
|
2180
|
+
{
|
|
2181
|
+
axisIds: clusteredColumnAxisIds,
|
|
2182
|
+
chartType: "ColumnClustered",
|
|
2183
|
+
gapWidth: 0,
|
|
2184
|
+
raw: {
|
|
2185
|
+
gapWidth: 0,
|
|
2186
|
+
layout: "clusteredColumn"
|
|
2187
|
+
},
|
|
2188
|
+
series: [primaryHistogramSeries]
|
|
2189
|
+
},
|
|
2190
|
+
{
|
|
2191
|
+
axisIds: paretoLineAxisIds,
|
|
2192
|
+
chartType: "Line",
|
|
2193
|
+
raw: {
|
|
2194
|
+
layout: "paretoLine"
|
|
2195
|
+
},
|
|
2196
|
+
series: [synthesizedParetoSeries]
|
|
2197
|
+
}
|
|
2198
|
+
] : [];
|
|
2199
|
+
const normalizedChart = {
|
|
2200
|
+
anchor: normalizeChartAnchor(chart.anchor),
|
|
2201
|
+
autoTitleDeleted: void 0,
|
|
2202
|
+
axes,
|
|
2203
|
+
axisLabelColor: void 0,
|
|
2204
|
+
axisLineColor: void 0,
|
|
2205
|
+
categoryAxis: axes[0] ?? null,
|
|
2206
|
+
chartAreaBorderColor: void 0,
|
|
2207
|
+
chartAreaFillColor: void 0,
|
|
2208
|
+
chartColorPalette: void 0,
|
|
2209
|
+
chartColorPaletteOffset: void 0,
|
|
2210
|
+
chartExLayout: primaryLayout,
|
|
2211
|
+
chartPath: void 0,
|
|
2212
|
+
chartStyleId: void 0,
|
|
2213
|
+
chartType: resolvedChartType,
|
|
2214
|
+
dataLabels: rawSeries.length > 0 && rawSeries[0] && typeof rawSeries[0] === "object" ? normalizeChartDataLabels(rawSeries[0].dataLabels) : null,
|
|
2215
|
+
displayBlanksAs: void 0,
|
|
2216
|
+
editable: true,
|
|
2217
|
+
firstSliceAngle: void 0,
|
|
2218
|
+
fontFamily: void 0,
|
|
2219
|
+
gapWidth: resolvedGapWidth,
|
|
2220
|
+
holeSize: void 0,
|
|
2221
|
+
id: `chart-ex-${workbookSheetIndex}-${index}`,
|
|
2222
|
+
is3d: void 0,
|
|
2223
|
+
legend: normalizeChartExLegend(chart.legend),
|
|
2224
|
+
name: chartTitle,
|
|
2225
|
+
overlap: void 0,
|
|
2226
|
+
plotVisibleOnly: void 0,
|
|
2227
|
+
raw: chart,
|
|
2228
|
+
radarStyle: void 0,
|
|
2229
|
+
scatterStyle: void 0,
|
|
2230
|
+
roundedCorners: void 0,
|
|
2231
|
+
shape3d: void 0,
|
|
2232
|
+
seriesAxis: null,
|
|
2233
|
+
series: resolvedSeries,
|
|
2234
|
+
sheetIndex: visibleSheetIndex,
|
|
2235
|
+
showDlblsOverMax: void 0,
|
|
2236
|
+
sideWall: null,
|
|
2237
|
+
backWall: null,
|
|
2238
|
+
bubbleScale: void 0,
|
|
2239
|
+
bubble3d: void 0,
|
|
2240
|
+
floor: null,
|
|
2241
|
+
surfaceMaterial: void 0,
|
|
2242
|
+
textColor: void 0,
|
|
2243
|
+
title: chartTitle,
|
|
2244
|
+
titleColor: void 0,
|
|
2245
|
+
titleFontFamily: void 0,
|
|
2246
|
+
typeGroups,
|
|
2247
|
+
valueAxis: axes.find((axis) => axis.numberFormat || axis.majorGridlines) ?? axes[1] ?? null,
|
|
2248
|
+
varyColors: typeof chart.valueColors === "boolean" ? chart.valueColors : void 0,
|
|
2249
|
+
view3d: void 0,
|
|
2250
|
+
wireframe: void 0,
|
|
2251
|
+
workbookSheetIndex,
|
|
2252
|
+
zIndex: index
|
|
2253
|
+
};
|
|
2254
|
+
applyBuiltinChartDefaults(normalizedChart, themePalette);
|
|
2255
|
+
return normalizedChart;
|
|
2256
|
+
}
|
|
2257
|
+
function cellValueToNumber(value) {
|
|
2258
|
+
if (typeof value === "number" && Number.isFinite(value)) {
|
|
2259
|
+
return value;
|
|
2260
|
+
}
|
|
2261
|
+
if (value && typeof value === "object") {
|
|
2262
|
+
if (value.is_empty) {
|
|
2263
|
+
return null;
|
|
2264
|
+
}
|
|
2265
|
+
const candidates = [];
|
|
2266
|
+
if (typeof value.asNumber === "function") {
|
|
2267
|
+
candidates.push(value.asNumber());
|
|
2268
|
+
}
|
|
2269
|
+
if (typeof value.toJs === "function") {
|
|
2270
|
+
candidates.push(value.toJs());
|
|
2271
|
+
}
|
|
2272
|
+
if (typeof value.asText === "function") {
|
|
2273
|
+
candidates.push(value.asText());
|
|
2274
|
+
}
|
|
2275
|
+
if (typeof value.toString === "function") {
|
|
2276
|
+
candidates.push(value.toString());
|
|
2277
|
+
}
|
|
2278
|
+
for (const candidate of candidates) {
|
|
2279
|
+
if (typeof candidate === "number" && Number.isFinite(candidate)) {
|
|
2280
|
+
return candidate;
|
|
2281
|
+
}
|
|
2282
|
+
if (typeof candidate === "string") {
|
|
2283
|
+
const parsed = Number(candidate.replace(/,/g, ""));
|
|
2284
|
+
if (Number.isFinite(parsed)) {
|
|
2285
|
+
return parsed;
|
|
2286
|
+
}
|
|
2287
|
+
}
|
|
2288
|
+
}
|
|
2289
|
+
}
|
|
2290
|
+
if (typeof value === "string") {
|
|
2291
|
+
const parsed = Number(value.replace(/,/g, ""));
|
|
2292
|
+
return Number.isFinite(parsed) ? parsed : null;
|
|
2293
|
+
}
|
|
2294
|
+
return null;
|
|
2295
|
+
}
|
|
2296
|
+
function cellValueToDisplay(value) {
|
|
2297
|
+
if (value === null || value === void 0) {
|
|
2298
|
+
return "";
|
|
2299
|
+
}
|
|
2300
|
+
if (typeof value === "string") {
|
|
2301
|
+
return value;
|
|
2302
|
+
}
|
|
2303
|
+
if (typeof value === "number" || typeof value === "boolean") {
|
|
2304
|
+
return String(value);
|
|
2305
|
+
}
|
|
2306
|
+
if (value && typeof value === "object") {
|
|
2307
|
+
if (value.is_empty) {
|
|
2308
|
+
return "";
|
|
2309
|
+
}
|
|
2310
|
+
const candidates = [];
|
|
2311
|
+
if (typeof value.asText === "function") {
|
|
2312
|
+
candidates.push(value.asText());
|
|
2313
|
+
}
|
|
2314
|
+
if (typeof value.toJs === "function") {
|
|
2315
|
+
candidates.push(value.toJs());
|
|
2316
|
+
}
|
|
2317
|
+
if (typeof value.toString === "function") {
|
|
2318
|
+
candidates.push(value.toString());
|
|
2319
|
+
}
|
|
2320
|
+
for (const candidate of candidates) {
|
|
2321
|
+
if (candidate === null || candidate === void 0) {
|
|
2322
|
+
continue;
|
|
2323
|
+
}
|
|
2324
|
+
if (typeof candidate === "string") {
|
|
2325
|
+
return candidate;
|
|
2326
|
+
}
|
|
2327
|
+
return String(candidate);
|
|
2328
|
+
}
|
|
2329
|
+
}
|
|
2330
|
+
return String(value);
|
|
2331
|
+
}
|
|
2332
|
+
function resolveReferenceValues(workbook2, fallbackSheetIndex, reference, mode) {
|
|
2333
|
+
if (!reference?.formula) {
|
|
2334
|
+
return reference?.values ?? [];
|
|
2335
|
+
}
|
|
2336
|
+
const resolved = resolveReferenceSheet(workbook2, fallbackSheetIndex, reference.formula);
|
|
2337
|
+
if (!resolved.sheet || !resolved.range) {
|
|
2338
|
+
return reference.values ?? [];
|
|
2339
|
+
}
|
|
2340
|
+
const values = [];
|
|
2341
|
+
for (let row = resolved.range.start.row; row <= resolved.range.end.row; row += 1) {
|
|
2342
|
+
for (let col = resolved.range.start.col; col <= resolved.range.end.col; col += 1) {
|
|
2343
|
+
const calculated = typeof resolved.sheet.getCalculatedValueAt === "function" ? resolved.sheet.getCalculatedValueAt(row, col) : null;
|
|
2344
|
+
const formatted = typeof resolved.sheet.getFormattedValueAt === "function" ? resolved.sheet.getFormattedValueAt(row, col) : calculated;
|
|
2345
|
+
if (mode === "value") {
|
|
2346
|
+
values.push(cellValueToNumber(calculated ?? formatted));
|
|
2347
|
+
} else {
|
|
2348
|
+
const display = cellValueToDisplay(formatted ?? calculated);
|
|
2349
|
+
const numeric = cellValueToNumber(calculated ?? formatted);
|
|
2350
|
+
values.push(display.length > 0 ? display : numeric !== null ? numeric : null);
|
|
2351
|
+
}
|
|
2352
|
+
}
|
|
2353
|
+
}
|
|
2354
|
+
return values;
|
|
2355
|
+
}
|
|
2356
|
+
function resolveSeriesName(workbook2, fallbackSheetIndex, rawName) {
|
|
2357
|
+
if (typeof rawName !== "string" || !rawName) {
|
|
2358
|
+
return void 0;
|
|
2359
|
+
}
|
|
2360
|
+
const resolved = resolveReferenceSheet(workbook2, fallbackSheetIndex, rawName);
|
|
2361
|
+
if (!resolved.sheet || !resolved.range) {
|
|
2362
|
+
return rawName;
|
|
2363
|
+
}
|
|
2364
|
+
const value = typeof resolved.sheet.getFormattedValueAt === "function" ? resolved.sheet.getFormattedValueAt(resolved.range.start.row, resolved.range.start.col) : null;
|
|
2365
|
+
const display = cellValueToDisplay(value);
|
|
2366
|
+
return display || rawName;
|
|
2367
|
+
}
|
|
2368
|
+
function normalizeChartReference(raw) {
|
|
2369
|
+
if (!raw || typeof raw !== "object") {
|
|
2370
|
+
return null;
|
|
2371
|
+
}
|
|
2372
|
+
const record = raw;
|
|
2373
|
+
return {
|
|
2374
|
+
formula: typeof record.formula === "string" ? record.formula : void 0,
|
|
2375
|
+
refType: typeof record.refType === "string" ? record.refType : void 0,
|
|
2376
|
+
values: Array.isArray(record.values) ? record.values : void 0
|
|
2377
|
+
};
|
|
2378
|
+
}
|
|
2379
|
+
function normalizeChartAxis(raw) {
|
|
2380
|
+
if (!raw || typeof raw !== "object") {
|
|
2381
|
+
return null;
|
|
2382
|
+
}
|
|
2383
|
+
const rawAxis = raw;
|
|
2384
|
+
const axis = rawAxis.axis && typeof rawAxis.axis === "object" ? rawAxis.axis : rawAxis;
|
|
2385
|
+
const numberFormat = axis.numberFormat && typeof axis.numberFormat === "object" ? axis.numberFormat : null;
|
|
2386
|
+
return {
|
|
2387
|
+
crossId: typeof rawAxis.crossId === "number" && Number.isFinite(rawAxis.crossId) ? rawAxis.crossId : void 0,
|
|
2388
|
+
crosses: typeof axis.crosses === "string" ? axis.crosses : void 0,
|
|
2389
|
+
crossBetween: typeof axis.crossBetween === "string" ? axis.crossBetween : void 0,
|
|
2390
|
+
delete: typeof axis.delete === "boolean" ? axis.delete : void 0,
|
|
2391
|
+
id: typeof rawAxis.id === "number" && Number.isFinite(rawAxis.id) ? rawAxis.id : void 0,
|
|
2392
|
+
labelPosition: typeof axis.labelPosition === "string" ? axis.labelPosition : void 0,
|
|
2393
|
+
logBase: typeof axis.logBase === "number" ? axis.logBase : void 0,
|
|
2394
|
+
orientation: typeof axis.orientation === "string" ? axis.orientation : void 0,
|
|
2395
|
+
majorUnit: typeof axis.majorUnit === "number" ? axis.majorUnit : void 0,
|
|
2396
|
+
max: typeof axis.max === "number" ? axis.max : void 0,
|
|
2397
|
+
min: typeof axis.min === "number" ? axis.min : void 0,
|
|
2398
|
+
majorGridlines: typeof axis.majorGridlines === "boolean" ? axis.majorGridlines : void 0,
|
|
2399
|
+
majorTickMark: typeof axis.majorTickMark === "string" ? axis.majorTickMark : void 0,
|
|
2400
|
+
minorUnit: typeof axis.minorUnit === "number" ? axis.minorUnit : void 0,
|
|
2401
|
+
minorGridlines: typeof axis.minorGridlines === "boolean" ? axis.minorGridlines : void 0,
|
|
2402
|
+
minorTickMark: typeof axis.minorTickMark === "string" ? axis.minorTickMark : void 0,
|
|
2403
|
+
numberFormat: numberFormat ? {
|
|
2404
|
+
formatCode: typeof numberFormat.formatCode === "string" ? numberFormat.formatCode : void 0,
|
|
2405
|
+
sourceLinked: typeof numberFormat.sourceLinked === "boolean" ? numberFormat.sourceLinked : void 0
|
|
2406
|
+
} : void 0,
|
|
2407
|
+
position: typeof axis.position === "string" ? axis.position : void 0,
|
|
2408
|
+
raw: axis,
|
|
2409
|
+
shapeProperties: axis.shapeProperties && typeof axis.shapeProperties === "object" ? axis.shapeProperties : void 0,
|
|
2410
|
+
tickLabelSkip: typeof axis.tickLabelSkip === "number" && Number.isFinite(axis.tickLabelSkip) ? axis.tickLabelSkip : void 0,
|
|
2411
|
+
tickMarkSkip: typeof axis.tickMarkSkip === "number" && Number.isFinite(axis.tickMarkSkip) ? axis.tickMarkSkip : void 0
|
|
2412
|
+
};
|
|
2413
|
+
}
|
|
2414
|
+
function mergeChartAxis(target, patch) {
|
|
2415
|
+
if (!patch) {
|
|
2416
|
+
return target ?? null;
|
|
2417
|
+
}
|
|
2418
|
+
return {
|
|
2419
|
+
...target ?? {},
|
|
2420
|
+
...patch
|
|
2421
|
+
};
|
|
2422
|
+
}
|
|
2423
|
+
function readChartAxisFromXml(axisNode) {
|
|
2424
|
+
if (!axisNode) {
|
|
2425
|
+
return null;
|
|
2426
|
+
}
|
|
2427
|
+
const numFmt = getFirstLocalChild(axisNode, "numFmt");
|
|
2428
|
+
const scalingNode = getFirstLocalChild(axisNode, "scaling");
|
|
2429
|
+
return {
|
|
2430
|
+
crossId: readChartNumericAttribute(axisNode, "crossAx"),
|
|
2431
|
+
crosses: getFirstLocalChild(axisNode, "crosses")?.getAttribute("val") ?? void 0,
|
|
2432
|
+
crossBetween: getFirstLocalChild(axisNode, "crossBetween")?.getAttribute("val") ?? void 0,
|
|
2433
|
+
delete: getFirstLocalChild(axisNode, "delete")?.getAttribute("val") === "1" ? true : getFirstLocalChild(axisNode, "delete")?.getAttribute("val") === "0" ? false : void 0,
|
|
2434
|
+
id: readChartNumericAttribute(axisNode, "axId"),
|
|
2435
|
+
labelPosition: getFirstLocalChild(axisNode, "tickLblPos")?.getAttribute("val") ?? void 0,
|
|
2436
|
+
logBase: readChartNumericAttribute(getFirstLocalChild(axisNode, "scaling"), "logBase"),
|
|
2437
|
+
orientation: getFirstLocalChild(scalingNode ?? axisNode, "orientation")?.getAttribute("val") ?? void 0,
|
|
2438
|
+
majorGridlines: Boolean(getFirstLocalChild(axisNode, "majorGridlines")),
|
|
2439
|
+
majorTickMark: getFirstLocalChild(axisNode, "majorTickMark")?.getAttribute("val") ?? void 0,
|
|
2440
|
+
majorUnit: readChartNumericAttribute(axisNode, "majorUnit"),
|
|
2441
|
+
max: readChartNumericAttribute(scalingNode, "max"),
|
|
2442
|
+
min: readChartNumericAttribute(scalingNode, "min"),
|
|
2443
|
+
minorGridlines: Boolean(getFirstLocalChild(axisNode, "minorGridlines")),
|
|
2444
|
+
minorTickMark: getFirstLocalChild(axisNode, "minorTickMark")?.getAttribute("val") ?? void 0,
|
|
2445
|
+
minorUnit: readChartNumericAttribute(axisNode, "minorUnit"),
|
|
2446
|
+
numberFormat: numFmt ? {
|
|
2447
|
+
formatCode: numFmt.getAttribute("formatCode") ?? void 0,
|
|
2448
|
+
sourceLinked: numFmt.getAttribute("sourceLinked") === "1" ? true : numFmt.getAttribute("sourceLinked") === "0" ? false : void 0
|
|
2449
|
+
} : void 0,
|
|
2450
|
+
position: getFirstLocalChild(axisNode, "axPos")?.getAttribute("val") ?? void 0,
|
|
2451
|
+
tickLabelSkip: readChartNumericAttribute(axisNode, "tickLblSkip"),
|
|
2452
|
+
tickMarkSkip: readChartNumericAttribute(axisNode, "tickMarkSkip")
|
|
2453
|
+
};
|
|
2454
|
+
}
|
|
2455
|
+
function readChartWallFromXml(wallNode, themePalette) {
|
|
2456
|
+
if (!wallNode) {
|
|
2457
|
+
return null;
|
|
2458
|
+
}
|
|
2459
|
+
const shapeProperties = getFirstLocalChild(wallNode, "spPr");
|
|
2460
|
+
const lineStyle = resolveChartLineStyle(shapeProperties, themePalette);
|
|
2461
|
+
return {
|
|
2462
|
+
fillColor: resolveChartFillColor(shapeProperties, themePalette) ?? void 0,
|
|
2463
|
+
hidden: shapeProperties ? getFirstLocalChild(shapeProperties, "noFill") != null : void 0,
|
|
2464
|
+
lineColor: lineStyle.color ?? void 0,
|
|
2465
|
+
thickness: readChartNumericAttribute(wallNode, "thickness")
|
|
2466
|
+
};
|
|
2467
|
+
}
|
|
2468
|
+
function normalizeChartDataLabels(raw) {
|
|
2469
|
+
if (!raw || typeof raw !== "object") {
|
|
2470
|
+
return null;
|
|
2471
|
+
}
|
|
2472
|
+
const labels = raw;
|
|
2473
|
+
const pointLabels = Array.isArray(labels.pointLabels) ? (() => {
|
|
2474
|
+
const normalized = [];
|
|
2475
|
+
for (const entry of labels.pointLabels) {
|
|
2476
|
+
if (!entry || typeof entry !== "object") {
|
|
2477
|
+
continue;
|
|
2478
|
+
}
|
|
2479
|
+
const point = entry;
|
|
2480
|
+
const index = typeof point.index === "number" && Number.isFinite(point.index) ? point.index : null;
|
|
2481
|
+
if (index == null) {
|
|
2482
|
+
continue;
|
|
2483
|
+
}
|
|
2484
|
+
const nextPoint = { index };
|
|
2485
|
+
if (typeof point.deleted === "boolean") {
|
|
2486
|
+
nextPoint.deleted = point.deleted;
|
|
2487
|
+
}
|
|
2488
|
+
if (typeof point.fontSizePt === "number" && Number.isFinite(point.fontSizePt)) {
|
|
2489
|
+
nextPoint.fontSizePt = point.fontSizePt;
|
|
2490
|
+
}
|
|
2491
|
+
if (typeof point.showBubbleSize === "boolean") {
|
|
2492
|
+
nextPoint.showBubbleSize = point.showBubbleSize;
|
|
2493
|
+
}
|
|
2494
|
+
if (typeof point.showCategoryName === "boolean") {
|
|
2495
|
+
nextPoint.showCategoryName = point.showCategoryName;
|
|
2496
|
+
}
|
|
2497
|
+
if (typeof point.showPercent === "boolean") {
|
|
2498
|
+
nextPoint.showPercent = point.showPercent;
|
|
2499
|
+
}
|
|
2500
|
+
if (typeof point.showSeriesName === "boolean") {
|
|
2501
|
+
nextPoint.showSeriesName = point.showSeriesName;
|
|
2502
|
+
}
|
|
2503
|
+
if (typeof point.showValue === "boolean") {
|
|
2504
|
+
nextPoint.showValue = point.showValue;
|
|
2505
|
+
}
|
|
2506
|
+
if (typeof point.x === "number" && Number.isFinite(point.x)) {
|
|
2507
|
+
nextPoint.x = point.x;
|
|
2508
|
+
}
|
|
2509
|
+
if (typeof point.y === "number" && Number.isFinite(point.y)) {
|
|
2510
|
+
nextPoint.y = point.y;
|
|
2511
|
+
}
|
|
2512
|
+
normalized.push(nextPoint);
|
|
2513
|
+
}
|
|
2514
|
+
return normalized;
|
|
2515
|
+
})() : void 0;
|
|
2516
|
+
return {
|
|
2517
|
+
pointLabels: pointLabels && pointLabels.length > 0 ? pointLabels : void 0,
|
|
2518
|
+
raw: labels,
|
|
2519
|
+
showBubbleSize: typeof labels.showBubbleSize === "boolean" ? labels.showBubbleSize : void 0,
|
|
2520
|
+
showCategoryName: typeof labels.showCategoryName === "boolean" ? labels.showCategoryName : void 0,
|
|
2521
|
+
showLegendKey: typeof labels.showLegendKey === "boolean" ? labels.showLegendKey : void 0,
|
|
2522
|
+
showPercent: typeof labels.showPercent === "boolean" ? labels.showPercent : void 0,
|
|
2523
|
+
showSeriesName: typeof labels.showSeriesName === "boolean" ? labels.showSeriesName : void 0,
|
|
2524
|
+
showValue: typeof labels.showValue === "boolean" ? labels.showValue : void 0
|
|
2525
|
+
};
|
|
2526
|
+
}
|
|
2527
|
+
function normalizeChartAnchor(raw) {
|
|
2528
|
+
if (!raw || typeof raw !== "object") {
|
|
2529
|
+
return {
|
|
2530
|
+
kind: "two-cell",
|
|
2531
|
+
from: { col: 0, colOffsetEmu: 0, row: 0, rowOffsetEmu: 0 },
|
|
2532
|
+
to: { col: 8, colOffsetEmu: 0, row: 15, rowOffsetEmu: 0 }
|
|
2533
|
+
};
|
|
2534
|
+
}
|
|
2535
|
+
const anchor = raw;
|
|
2536
|
+
const fromCol = typeof anchor.fromCol === "number" ? anchor.fromCol : 0;
|
|
2537
|
+
const fromColOffsetEmu = typeof anchor.fromColOffset === "number" ? anchor.fromColOffset : 0;
|
|
2538
|
+
const fromRow = typeof anchor.fromRow === "number" ? anchor.fromRow : 0;
|
|
2539
|
+
const fromRowOffsetEmu = typeof anchor.fromRowOffset === "number" ? anchor.fromRowOffset : 0;
|
|
2540
|
+
const rawToCol = typeof anchor.toCol === "number" ? anchor.toCol : null;
|
|
2541
|
+
const rawToColOffsetEmu = typeof anchor.toColOffset === "number" ? anchor.toColOffset : 0;
|
|
2542
|
+
const rawToRow = typeof anchor.toRow === "number" ? anchor.toRow : null;
|
|
2543
|
+
const rawToRowOffsetEmu = typeof anchor.toRowOffset === "number" ? anchor.toRowOffset : 0;
|
|
2544
|
+
const hasExplicitTo = rawToCol !== null && rawToRow !== null;
|
|
2545
|
+
const collapsedWidth = hasExplicitTo && (rawToCol < fromCol || rawToCol === fromCol && rawToColOffsetEmu <= fromColOffsetEmu);
|
|
2546
|
+
const collapsedHeight = hasExplicitTo && (rawToRow < fromRow || rawToRow === fromRow && rawToRowOffsetEmu <= fromRowOffsetEmu);
|
|
2547
|
+
const fallbackToCol = Math.max(fromCol + 8, 8);
|
|
2548
|
+
const fallbackToRow = Math.max(fromRow + 15, 15);
|
|
2549
|
+
return {
|
|
2550
|
+
kind: "two-cell",
|
|
2551
|
+
from: {
|
|
2552
|
+
col: fromCol,
|
|
2553
|
+
colOffsetEmu: fromColOffsetEmu,
|
|
2554
|
+
row: fromRow,
|
|
2555
|
+
rowOffsetEmu: fromRowOffsetEmu
|
|
2556
|
+
},
|
|
2557
|
+
to: {
|
|
2558
|
+
col: !hasExplicitTo || collapsedWidth ? fallbackToCol : rawToCol,
|
|
2559
|
+
colOffsetEmu: !hasExplicitTo || collapsedWidth ? 0 : rawToColOffsetEmu,
|
|
2560
|
+
row: !hasExplicitTo || collapsedHeight ? fallbackToRow : rawToRow,
|
|
2561
|
+
rowOffsetEmu: !hasExplicitTo || collapsedHeight ? 0 : rawToRowOffsetEmu
|
|
2562
|
+
}
|
|
2563
|
+
};
|
|
2564
|
+
}
|
|
2565
|
+
function parseMarkerNode(node) {
|
|
2566
|
+
if (!node) {
|
|
2567
|
+
return null;
|
|
2568
|
+
}
|
|
2569
|
+
const col = Number(getFirstLocalChild(node, "col")?.textContent ?? Number.NaN);
|
|
2570
|
+
const row = Number(getFirstLocalChild(node, "row")?.textContent ?? Number.NaN);
|
|
2571
|
+
const colOffsetEmu = Number(getFirstLocalChild(node, "colOff")?.textContent ?? 0);
|
|
2572
|
+
const rowOffsetEmu = Number(getFirstLocalChild(node, "rowOff")?.textContent ?? 0);
|
|
2573
|
+
if (!Number.isFinite(col) || !Number.isFinite(row)) {
|
|
2574
|
+
return null;
|
|
2575
|
+
}
|
|
2576
|
+
return {
|
|
2577
|
+
col: Math.max(0, Math.round(col)),
|
|
2578
|
+
colOffsetEmu: Number.isFinite(colOffsetEmu) ? Math.max(0, Math.round(colOffsetEmu)) : 0,
|
|
2579
|
+
row: Math.max(0, Math.round(row)),
|
|
2580
|
+
rowOffsetEmu: Number.isFinite(rowOffsetEmu) ? Math.max(0, Math.round(rowOffsetEmu)) : 0
|
|
2581
|
+
};
|
|
2582
|
+
}
|
|
2583
|
+
function parseChartAnchorNode(anchorNode) {
|
|
2584
|
+
if (anchorNode.localName === "twoCellAnchor") {
|
|
2585
|
+
const from = parseMarkerNode(getFirstLocalChild(anchorNode, "from"));
|
|
2586
|
+
const to = parseMarkerNode(getFirstLocalChild(anchorNode, "to"));
|
|
2587
|
+
return from && to ? { from, kind: "two-cell", to } : null;
|
|
2588
|
+
}
|
|
2589
|
+
if (anchorNode.localName === "oneCellAnchor") {
|
|
2590
|
+
const from = parseMarkerNode(getFirstLocalChild(anchorNode, "from"));
|
|
2591
|
+
const ext2 = getFirstLocalChild(anchorNode, "ext");
|
|
2592
|
+
const cx2 = Number(ext2?.getAttribute("cx") ?? Number.NaN);
|
|
2593
|
+
const cy2 = Number(ext2?.getAttribute("cy") ?? Number.NaN);
|
|
2594
|
+
return from && Number.isFinite(cx2) && Number.isFinite(cy2) ? {
|
|
2595
|
+
from,
|
|
2596
|
+
kind: "one-cell",
|
|
2597
|
+
sizeEmu: {
|
|
2598
|
+
cx: Math.max(0, Math.round(cx2)),
|
|
2599
|
+
cy: Math.max(0, Math.round(cy2))
|
|
2600
|
+
}
|
|
2601
|
+
} : null;
|
|
2602
|
+
}
|
|
2603
|
+
const pos = getFirstLocalChild(anchorNode, "pos");
|
|
2604
|
+
const ext = getFirstLocalChild(anchorNode, "ext");
|
|
2605
|
+
const x = Number(pos?.getAttribute("x") ?? Number.NaN);
|
|
2606
|
+
const y = Number(pos?.getAttribute("y") ?? Number.NaN);
|
|
2607
|
+
const cx = Number(ext?.getAttribute("cx") ?? Number.NaN);
|
|
2608
|
+
const cy = Number(ext?.getAttribute("cy") ?? Number.NaN);
|
|
2609
|
+
return Number.isFinite(x) && Number.isFinite(y) && Number.isFinite(cx) && Number.isFinite(cy) ? {
|
|
2610
|
+
kind: "absolute",
|
|
2611
|
+
positionEmu: {
|
|
2612
|
+
x: Math.round(x),
|
|
2613
|
+
y: Math.round(y)
|
|
2614
|
+
},
|
|
2615
|
+
sizeEmu: {
|
|
2616
|
+
cx: Math.max(0, Math.round(cx)),
|
|
2617
|
+
cy: Math.max(0, Math.round(cy))
|
|
2618
|
+
}
|
|
2619
|
+
} : null;
|
|
2620
|
+
}
|
|
2621
|
+
function isCollapsedChartAnchor(anchor) {
|
|
2622
|
+
if (anchor.kind !== "two-cell") {
|
|
2623
|
+
return false;
|
|
2624
|
+
}
|
|
2625
|
+
const collapsedWidth = anchor.to.col < anchor.from.col || anchor.to.col === anchor.from.col && anchor.to.colOffsetEmu <= anchor.from.colOffsetEmu;
|
|
2626
|
+
const collapsedHeight = anchor.to.row < anchor.from.row || anchor.to.row === anchor.from.row && anchor.to.rowOffsetEmu <= anchor.from.rowOffsetEmu;
|
|
2627
|
+
return collapsedWidth || collapsedHeight;
|
|
2628
|
+
}
|
|
2629
|
+
function normalizeChartSeries(workbook2, workbookSheetIndex, chartId, raw, index) {
|
|
2630
|
+
const series = raw && typeof raw === "object" ? raw : {};
|
|
2631
|
+
const categoriesRef = normalizeChartReference(series.categories);
|
|
2632
|
+
const valuesRef = normalizeChartReference(series.values);
|
|
2633
|
+
const shapeProperties = series.shapeProperties && typeof series.shapeProperties === "object" ? series.shapeProperties : void 0;
|
|
2634
|
+
const rawFillColor = typeof shapeProperties?.solidFillHex === "string" ? normalizeHexColor(shapeProperties.solidFillHex) : null;
|
|
2635
|
+
const rawLineColor = typeof shapeProperties?.lineColorHex === "string" ? normalizeHexColor(shapeProperties.lineColorHex) : null;
|
|
2636
|
+
const bubbleSizeRef = normalizeChartReference(series.bubbleSize ?? series.bubbleSizes ?? series.bubbles);
|
|
2637
|
+
return {
|
|
2638
|
+
bubbleSizeRef,
|
|
2639
|
+
bubbleSizes: resolveReferenceValues(workbook2, workbookSheetIndex, bubbleSizeRef, "value").map((value) => typeof value === "number" && Number.isFinite(value) ? value : null),
|
|
2640
|
+
categories: resolveReferenceValues(workbook2, workbookSheetIndex, categoriesRef, "category"),
|
|
2641
|
+
categoriesRef,
|
|
2642
|
+
color: rawFillColor ?? void 0,
|
|
2643
|
+
dataPoints: Array.isArray(series.dataPoints) ? series.dataPoints : [],
|
|
2644
|
+
dataPointStyles: void 0,
|
|
2645
|
+
id: `${chartId}-series-${index}`,
|
|
2646
|
+
invertIfNegative: typeof series.invertIfNegative === "boolean" ? series.invertIfNegative : void 0,
|
|
2647
|
+
lineColor: rawLineColor ?? rawFillColor ?? void 0,
|
|
2648
|
+
lineWidthPx: typeof shapeProperties?.lineWidth === "number" ? Math.max(1, Number(shapeProperties.lineWidth) / EMU_PER_PIXEL) : void 0,
|
|
2649
|
+
marker: series.marker && typeof series.marker === "object" ? series.marker : void 0,
|
|
2650
|
+
markerColor: void 0,
|
|
2651
|
+
markerLineColor: void 0,
|
|
2652
|
+
markerSize: series.marker && typeof series.marker === "object" && typeof series.marker.size === "number" ? Number(series.marker.size) : void 0,
|
|
2653
|
+
markerSymbol: series.marker && typeof series.marker === "object" && typeof series.marker.symbol === "string" ? String(series.marker.symbol) : void 0,
|
|
2654
|
+
name: resolveSeriesName(workbook2, workbookSheetIndex, series.name),
|
|
2655
|
+
negativeColor: void 0,
|
|
2656
|
+
negativeLineColor: void 0,
|
|
2657
|
+
raw: series,
|
|
2658
|
+
shapeProperties,
|
|
2659
|
+
smooth: typeof series.smooth === "boolean" ? series.smooth : void 0,
|
|
2660
|
+
values: resolveReferenceValues(workbook2, workbookSheetIndex, valuesRef, "value").map((value) => typeof value === "number" && Number.isFinite(value) ? value : null),
|
|
2661
|
+
valuesRef
|
|
2662
|
+
};
|
|
2663
|
+
}
|
|
2664
|
+
function normalizeChartTypeGroup(workbook2, workbookSheetIndex, chartId, raw, index) {
|
|
2665
|
+
if (!raw || typeof raw !== "object") {
|
|
2666
|
+
return null;
|
|
2667
|
+
}
|
|
2668
|
+
const group = raw;
|
|
2669
|
+
const rawSeries = Array.isArray(group.series) ? group.series : [];
|
|
2670
|
+
return {
|
|
2671
|
+
axisIds: Array.isArray(group.axisIds) ? group.axisIds.filter((value) => typeof value === "number" && Number.isFinite(value)) : void 0,
|
|
2672
|
+
chartType: typeof group.chartType === "string" ? group.chartType : "ColumnClustered",
|
|
2673
|
+
dataLabels: normalizeChartDataLabels(group.dataLabels),
|
|
2674
|
+
gapWidth: typeof group.gapWidth === "number" && Number.isFinite(group.gapWidth) ? group.gapWidth : void 0,
|
|
2675
|
+
is3d: typeof group.is3d === "boolean" ? group.is3d : void 0,
|
|
2676
|
+
overlap: typeof group.overlap === "number" && Number.isFinite(group.overlap) ? group.overlap : void 0,
|
|
2677
|
+
raw: group,
|
|
2678
|
+
series: rawSeries.map((entry, seriesIndex) => normalizeChartSeries(workbook2, workbookSheetIndex, `${chartId}-group-${index}`, entry, seriesIndex)),
|
|
2679
|
+
varyColors: typeof group.varyColors === "boolean" ? group.varyColors : void 0
|
|
2680
|
+
};
|
|
2681
|
+
}
|
|
2682
|
+
function normalizeChartsheet(raw, index) {
|
|
2683
|
+
const chartsheet = raw && typeof raw === "object" ? raw : {};
|
|
2684
|
+
return {
|
|
2685
|
+
chartIds: Array.isArray(chartsheet.chartIds) ? chartsheet.chartIds.filter((value) => typeof value === "string") : [],
|
|
2686
|
+
chartPath: typeof chartsheet.chartPath === "string" ? chartsheet.chartPath : void 0,
|
|
2687
|
+
id: `chartsheet-${index}`,
|
|
2688
|
+
index,
|
|
2689
|
+
name: typeof chartsheet.name === "string" ? chartsheet.name : `Chart ${index + 1}`,
|
|
2690
|
+
raw: chartsheet,
|
|
2691
|
+
workbookSheetIndex: typeof chartsheet.workbookSheetIndex === "number" ? chartsheet.workbookSheetIndex : void 0
|
|
2692
|
+
};
|
|
2693
|
+
}
|
|
2694
|
+
function buildTabs(workbook2, chartsheets2, visibleSheetIndexByWorkbookSheetIndex) {
|
|
2695
|
+
const rawOrder = Array.isArray(workbook2.sheetOrder) ? workbook2.sheetOrder : [];
|
|
2696
|
+
if (rawOrder.length === 0) {
|
|
2697
|
+
return workbook2.sheetNames.map((name, index) => ({
|
|
2698
|
+
id: `sheet-${index}`,
|
|
2699
|
+
index,
|
|
2700
|
+
kind: "sheet",
|
|
2701
|
+
name,
|
|
2702
|
+
sheetIndex: visibleSheetIndexByWorkbookSheetIndex.get(index) ?? index,
|
|
2703
|
+
workbookSheetIndex: index
|
|
2704
|
+
}));
|
|
2705
|
+
}
|
|
2706
|
+
return rawOrder.flatMap((entry, index) => {
|
|
2707
|
+
const slotType = typeof entry.slotType === "string" ? entry.slotType : "worksheet";
|
|
2708
|
+
const slotIndex = typeof entry.index === "number" ? entry.index : index;
|
|
2709
|
+
if (slotType === "chartsheet") {
|
|
2710
|
+
const chartsheet = chartsheets2[slotIndex];
|
|
2711
|
+
return chartsheet ? [{
|
|
2712
|
+
chartsheetIndex: slotIndex,
|
|
2713
|
+
id: `chartsheet-${slotIndex}`,
|
|
2714
|
+
index,
|
|
2715
|
+
kind: "chartsheet",
|
|
2716
|
+
name: chartsheet.name
|
|
2717
|
+
}] : [];
|
|
2718
|
+
}
|
|
2719
|
+
const worksheet = workbook2.getSheet(slotIndex);
|
|
2720
|
+
if (worksheet.visibility !== "visible") {
|
|
2721
|
+
return [];
|
|
2722
|
+
}
|
|
2723
|
+
return [{
|
|
2724
|
+
id: `sheet-${slotIndex}`,
|
|
2725
|
+
index,
|
|
2726
|
+
kind: "sheet",
|
|
2727
|
+
name: worksheet.name,
|
|
2728
|
+
sheetIndex: visibleSheetIndexByWorkbookSheetIndex.get(slotIndex) ?? slotIndex,
|
|
2729
|
+
workbookSheetIndex: slotIndex
|
|
2730
|
+
}];
|
|
2731
|
+
});
|
|
2732
|
+
}
|
|
2733
|
+
function collectChartOriginsForSheet(archive, origin) {
|
|
2734
|
+
if (!origin) {
|
|
2735
|
+
return [];
|
|
2736
|
+
}
|
|
2737
|
+
const chartOrigins = [];
|
|
2738
|
+
for (const attachment of origin.attachments) {
|
|
2739
|
+
const drawingXml = readArchiveText(archive, attachment.drawingPath);
|
|
2740
|
+
const relsXml = readArchiveText(archive, attachment.drawingRelsPath);
|
|
2741
|
+
if (!drawingXml || !relsXml) {
|
|
2742
|
+
continue;
|
|
2743
|
+
}
|
|
2744
|
+
const drawingDocument = parseXml(drawingXml);
|
|
2745
|
+
const relsDocument = parseXml(relsXml);
|
|
2746
|
+
if (!drawingDocument || !relsDocument) {
|
|
2747
|
+
continue;
|
|
2748
|
+
}
|
|
2749
|
+
const relationships = /* @__PURE__ */ new Map();
|
|
2750
|
+
for (const node of getLocalDescendants(relsDocument, "Relationship")) {
|
|
2751
|
+
const id = node.getAttribute("Id");
|
|
2752
|
+
const target = node.getAttribute("Target");
|
|
2753
|
+
const type = node.getAttribute("Type");
|
|
2754
|
+
if (id && target) {
|
|
2755
|
+
relationships.set(id, {
|
|
2756
|
+
target: resolveRelationshipPath(attachment.drawingRelsPath ?? attachment.drawingPath, target),
|
|
2757
|
+
type
|
|
2758
|
+
});
|
|
2759
|
+
}
|
|
2760
|
+
}
|
|
2761
|
+
const anchorNodes = Array.from(drawingDocument.documentElement.childNodes).filter(
|
|
2762
|
+
(node) => node.nodeType === Node.ELEMENT_NODE && (node.localName === "twoCellAnchor" || node.localName === "oneCellAnchor" || node.localName === "absoluteAnchor")
|
|
2763
|
+
);
|
|
2764
|
+
let chartAnchorIndex = 0;
|
|
2765
|
+
for (const anchorNode of anchorNodes) {
|
|
2766
|
+
const graphicFrame = getFirstLocalDescendant(anchorNode, "graphicFrame");
|
|
2767
|
+
const chartNode = graphicFrame ? getFirstLocalDescendant(graphicFrame, "chart") : null;
|
|
2768
|
+
const relationshipId = chartNode?.getAttributeNS("http://schemas.openxmlformats.org/officeDocument/2006/relationships", "id") ?? chartNode?.getAttribute("r:id") ?? chartNode?.getAttribute("id");
|
|
2769
|
+
if (!relationshipId) {
|
|
2770
|
+
continue;
|
|
2771
|
+
}
|
|
2772
|
+
const relationship = relationships.get(relationshipId);
|
|
2773
|
+
if (!relationship || relationship.type !== CHART_REL_TYPE && relationship.type !== CHART_EX_REL_TYPE) {
|
|
2774
|
+
continue;
|
|
2775
|
+
}
|
|
2776
|
+
chartOrigins.push({
|
|
2777
|
+
anchorIndex: chartAnchorIndex,
|
|
2778
|
+
anchor: parseChartAnchorNode(anchorNode),
|
|
2779
|
+
chartKind: relationship.type === CHART_EX_REL_TYPE ? "modern" : "classic",
|
|
2780
|
+
chartPath: relationship.target,
|
|
2781
|
+
drawingPath: attachment.drawingPath,
|
|
2782
|
+
workbookSheetIndex: origin.workbookSheetIndex
|
|
2783
|
+
});
|
|
2784
|
+
chartAnchorIndex += 1;
|
|
2785
|
+
}
|
|
2786
|
+
}
|
|
2787
|
+
return chartOrigins;
|
|
2788
|
+
}
|
|
2789
|
+
function applyChartOrigins(chartsByWorkbookSheetIndex2, chartOriginsById, archive, sheetOrigins) {
|
|
2790
|
+
for (let workbookSheetIndex = 0; workbookSheetIndex < chartsByWorkbookSheetIndex2.length; workbookSheetIndex += 1) {
|
|
2791
|
+
const charts = chartsByWorkbookSheetIndex2[workbookSheetIndex] ?? [];
|
|
2792
|
+
const origins = collectChartOriginsForSheet(archive, sheetOrigins[workbookSheetIndex] ?? null);
|
|
2793
|
+
const originsByKind = {
|
|
2794
|
+
classic: origins.filter((origin) => origin.chartKind === "classic"),
|
|
2795
|
+
modern: origins.filter((origin) => origin.chartKind === "modern")
|
|
2796
|
+
};
|
|
2797
|
+
const chartIndexByKind = {
|
|
2798
|
+
classic: 0,
|
|
2799
|
+
modern: 0
|
|
2800
|
+
};
|
|
2801
|
+
charts.forEach((chart) => {
|
|
2802
|
+
const chartKind = chart.id.startsWith("chart-ex-") ? "modern" : "classic";
|
|
2803
|
+
const origin = originsByKind[chartKind][chartIndexByKind[chartKind]];
|
|
2804
|
+
chartIndexByKind[chartKind] += 1;
|
|
2805
|
+
if (!origin) {
|
|
2806
|
+
return;
|
|
2807
|
+
}
|
|
2808
|
+
if (origin.anchor && isCollapsedChartAnchor(chart.anchor)) {
|
|
2809
|
+
chart.anchor = origin.anchor;
|
|
2810
|
+
} else if (origin.anchor && chart.anchor.kind === "two-cell" && chart.anchor.from.col === 0 && chart.anchor.from.row === 0) {
|
|
2811
|
+
chart.anchor = origin.anchor;
|
|
2812
|
+
}
|
|
2813
|
+
chart.chartPath = origin.chartPath ?? void 0;
|
|
2814
|
+
chartOriginsById.set(chart.id, origin);
|
|
2815
|
+
});
|
|
2816
|
+
}
|
|
2817
|
+
}
|
|
2818
|
+
function loadWorkbookChartAssets(workbook2, imageAssets, visibleSheetIndexByWorkbookSheetIndex) {
|
|
2819
|
+
const chartsByWorkbookSheetIndex2 = Array.from({ length: workbook2.sheetCount }, (_, workbookSheetIndex) => {
|
|
2820
|
+
const worksheet = workbook2.getSheet(workbookSheetIndex);
|
|
2821
|
+
const rawCharts = Array.isArray(worksheet.charts) ? worksheet.charts : [];
|
|
2822
|
+
const rawChartsEx = Array.isArray(worksheet.chartsEx) ? worksheet.chartsEx : [];
|
|
2823
|
+
const visibleSheetIndex = visibleSheetIndexByWorkbookSheetIndex.get(workbookSheetIndex) ?? workbookSheetIndex;
|
|
2824
|
+
const classicCharts = rawCharts.map((rawChart, chartIndex) => {
|
|
2825
|
+
const chartId = `chart-${workbookSheetIndex}-${chartIndex}`;
|
|
2826
|
+
const chart = rawChart && typeof rawChart === "object" ? rawChart : {};
|
|
2827
|
+
const rawView3d = chart.view3d && typeof chart.view3d === "object" ? chart.view3d : null;
|
|
2828
|
+
const rawSeries = Array.isArray(chart.series) ? chart.series : [];
|
|
2829
|
+
const chartLevelDataLabels = normalizeChartDataLabels(chart.dataLabels);
|
|
2830
|
+
const firstSeriesDataLabels = rawSeries.length > 0 && rawSeries[0] && typeof rawSeries[0] === "object" ? normalizeChartDataLabels(rawSeries[0].dataLabels) : null;
|
|
2831
|
+
return {
|
|
2832
|
+
anchor: normalizeChartAnchor(chart.anchor),
|
|
2833
|
+
autoTitleDeleted: typeof chart.autoTitleDeleted === "boolean" ? chart.autoTitleDeleted : void 0,
|
|
2834
|
+
axes: Array.isArray(chart.axes) ? chart.axes.map(normalizeChartAxis).filter((value) => Boolean(value)) : [],
|
|
2835
|
+
axisLabelColor: void 0,
|
|
2836
|
+
axisLineColor: void 0,
|
|
2837
|
+
categoryAxis: normalizeChartAxis(chart.categoryAxis),
|
|
2838
|
+
chartAreaBorderColor: void 0,
|
|
2839
|
+
chartAreaFillColor: void 0,
|
|
2840
|
+
chartColorPalette: void 0,
|
|
2841
|
+
chartColorPaletteOffset: void 0,
|
|
2842
|
+
chartPath: void 0,
|
|
2843
|
+
chartStyleId: void 0,
|
|
2844
|
+
chartType: typeof chart.chartType === "string" ? chart.chartType : "ColumnClustered",
|
|
2845
|
+
dataLabels: chartLevelDataLabels ?? firstSeriesDataLabels,
|
|
2846
|
+
displayBlanksAs: typeof chart.displayBlanksAs === "string" ? chart.displayBlanksAs : void 0,
|
|
2847
|
+
editable: true,
|
|
2848
|
+
firstSliceAngle: typeof chart.firstSliceAngle === "number" ? chart.firstSliceAngle : void 0,
|
|
2849
|
+
fontFamily: void 0,
|
|
2850
|
+
gapWidth: typeof chart.gapWidth === "number" ? chart.gapWidth : void 0,
|
|
2851
|
+
holeSize: typeof chart.holeSize === "number" ? chart.holeSize : void 0,
|
|
2852
|
+
id: chartId,
|
|
2853
|
+
is3d: typeof chart.is3d === "boolean" ? chart.is3d : void 0,
|
|
2854
|
+
legend: normalizeLegend(chart.legend) ? {
|
|
2855
|
+
...normalizeLegend(chart.legend),
|
|
2856
|
+
position: normalizeLegendPosition(normalizeLegend(chart.legend)?.position)
|
|
2857
|
+
} : null,
|
|
2858
|
+
name: typeof chart.name === "string" ? chart.name : void 0,
|
|
2859
|
+
overlap: typeof chart.overlap === "number" ? chart.overlap : void 0,
|
|
2860
|
+
plotVisibleOnly: typeof chart.plotVisibleOnly === "boolean" ? chart.plotVisibleOnly : void 0,
|
|
2861
|
+
raw: chart,
|
|
2862
|
+
radarStyle: typeof chart.radarStyle === "string" ? chart.radarStyle : void 0,
|
|
2863
|
+
scatterStyle: typeof chart.scatterStyle === "string" ? chart.scatterStyle : void 0,
|
|
2864
|
+
roundedCorners: typeof chart.roundedCorners === "boolean" ? chart.roundedCorners : void 0,
|
|
2865
|
+
shape3d: typeof chart.shape === "string" ? chart.shape : typeof chart.shape3d === "string" ? chart.shape3d : void 0,
|
|
2866
|
+
seriesAxis: null,
|
|
2867
|
+
series: rawSeries.map((entry, seriesIndex) => normalizeChartSeries(workbook2, workbookSheetIndex, chartId, entry, seriesIndex)),
|
|
2868
|
+
sheetIndex: visibleSheetIndex,
|
|
2869
|
+
showDlblsOverMax: typeof chart.showDlblsOverMax === "boolean" ? chart.showDlblsOverMax : void 0,
|
|
2870
|
+
sideWall: null,
|
|
2871
|
+
backWall: null,
|
|
2872
|
+
bubbleScale: typeof chart.bubbleScale === "number" ? chart.bubbleScale : void 0,
|
|
2873
|
+
bubble3d: typeof chart.bubble3d === "boolean" ? chart.bubble3d : void 0,
|
|
2874
|
+
floor: null,
|
|
2875
|
+
surfaceMaterial: void 0,
|
|
2876
|
+
textColor: void 0,
|
|
2877
|
+
title: typeof chart.title === "string" ? chart.title : void 0,
|
|
2878
|
+
titleColor: void 0,
|
|
2879
|
+
titleFontFamily: void 0,
|
|
2880
|
+
typeGroups: Array.isArray(chart.typeGroups) ? chart.typeGroups.map((entry, groupIndex) => normalizeChartTypeGroup(workbook2, workbookSheetIndex, chartId, entry, groupIndex)).filter((value) => value != null) : [],
|
|
2881
|
+
valueAxis: normalizeChartAxis(chart.valueAxis),
|
|
2882
|
+
varyColors: typeof chart.varyColors === "boolean" ? chart.varyColors : void 0,
|
|
2883
|
+
view3d: rawView3d ? {
|
|
2884
|
+
depthPercent: typeof rawView3d.depthPercent === "number" ? rawView3d.depthPercent : void 0,
|
|
2885
|
+
perspective: typeof rawView3d.perspective === "number" ? rawView3d.perspective : void 0,
|
|
2886
|
+
rAngAx: typeof rawView3d.rAngAx === "boolean" ? rawView3d.rAngAx : typeof rawView3d.rightAngleAxes === "boolean" ? rawView3d.rightAngleAxes : void 0,
|
|
2887
|
+
rotX: typeof rawView3d.rotX === "number" ? rawView3d.rotX : typeof rawView3d.rotateX === "number" ? rawView3d.rotateX : void 0,
|
|
2888
|
+
rotY: typeof rawView3d.rotY === "number" ? rawView3d.rotY : typeof rawView3d.rotateY === "number" ? rawView3d.rotateY : void 0
|
|
2889
|
+
} : void 0,
|
|
2890
|
+
wireframe: typeof chart.wireframe === "boolean" ? chart.wireframe : void 0,
|
|
2891
|
+
workbookSheetIndex,
|
|
2892
|
+
zIndex: 200 + chartIndex
|
|
2893
|
+
};
|
|
2894
|
+
});
|
|
2895
|
+
const modernCharts = rawChartsEx.map((rawChartEx, chartExIndex) => normalizeChartExChart(
|
|
2896
|
+
workbook2,
|
|
2897
|
+
workbookSheetIndex,
|
|
2898
|
+
visibleSheetIndex,
|
|
2899
|
+
rawChartEx,
|
|
2900
|
+
chartExIndex,
|
|
2901
|
+
imageAssets?.themePalette ?? null
|
|
2902
|
+
));
|
|
2903
|
+
return [...classicCharts, ...modernCharts];
|
|
2904
|
+
});
|
|
2905
|
+
const chartsheets2 = Array.isArray(workbook2.chartsheets) ? workbook2.chartsheets.map((entry, index) => normalizeChartsheet(entry, index)) : [];
|
|
2906
|
+
const tabs2 = buildTabs(workbook2, chartsheets2, visibleSheetIndexByWorkbookSheetIndex);
|
|
2907
|
+
const chartOriginsById = /* @__PURE__ */ new Map();
|
|
2908
|
+
if (imageAssets) {
|
|
2909
|
+
applyChartOrigins(chartsByWorkbookSheetIndex2, chartOriginsById, imageAssets.archive, imageAssets.sheetOrigins);
|
|
2910
|
+
for (const charts of chartsByWorkbookSheetIndex2) {
|
|
2911
|
+
for (const chart of charts) {
|
|
2912
|
+
applyChartStyleFromXml(chart, chart.chartPath, imageAssets.archive, imageAssets.themePalette);
|
|
2913
|
+
applyBuiltinChartDefaults(chart, imageAssets.themePalette);
|
|
2914
|
+
}
|
|
2915
|
+
}
|
|
2916
|
+
} else {
|
|
2917
|
+
for (const charts of chartsByWorkbookSheetIndex2) {
|
|
2918
|
+
for (const chart of charts) {
|
|
2919
|
+
applyBuiltinChartDefaults(chart, null);
|
|
2920
|
+
}
|
|
2921
|
+
}
|
|
2922
|
+
}
|
|
2923
|
+
return {
|
|
2924
|
+
chartOriginsById,
|
|
2925
|
+
chartsByWorkbookSheetIndex: chartsByWorkbookSheetIndex2,
|
|
2926
|
+
chartsheets: chartsheets2,
|
|
2927
|
+
tabs: tabs2
|
|
2928
|
+
};
|
|
2929
|
+
}
|
|
2930
|
+
|
|
2931
|
+
// src/images.ts
|
|
2932
|
+
import { strFromU8 as strFromU82, strToU8 as strToU82, unzipSync, zipSync } from "fflate";
|
|
2933
|
+
|
|
2934
|
+
// src/colors.ts
|
|
2935
|
+
function normalizeHexColor2(value) {
|
|
2936
|
+
const hex = value.replace(/^#/, "");
|
|
2937
|
+
if (hex.length === 8) {
|
|
2938
|
+
return `#${hex.slice(2).toLowerCase()}`;
|
|
2939
|
+
}
|
|
2940
|
+
if (hex.length === 6) {
|
|
2941
|
+
return `#${hex.toLowerCase()}`;
|
|
2942
|
+
}
|
|
2943
|
+
return null;
|
|
2944
|
+
}
|
|
2945
|
+
function parseHexColor2(color) {
|
|
2946
|
+
const normalized = normalizeHexColor2(color);
|
|
2947
|
+
const match = normalized ? /^#([0-9a-f]{6})$/.exec(normalized) : null;
|
|
2948
|
+
if (!match) {
|
|
2949
|
+
return null;
|
|
2950
|
+
}
|
|
2951
|
+
const hex = match[1];
|
|
2952
|
+
return [
|
|
2953
|
+
Number.parseInt(hex.slice(0, 2), 16),
|
|
2954
|
+
Number.parseInt(hex.slice(2, 4), 16),
|
|
2955
|
+
Number.parseInt(hex.slice(4, 6), 16)
|
|
2956
|
+
];
|
|
2957
|
+
}
|
|
2958
|
+
function rgbToHsl2(red, green, blue) {
|
|
2959
|
+
const normalizedRed = red / 255;
|
|
2960
|
+
const normalizedGreen = green / 255;
|
|
2961
|
+
const normalizedBlue = blue / 255;
|
|
2962
|
+
const max = Math.max(normalizedRed, normalizedGreen, normalizedBlue);
|
|
2963
|
+
const min = Math.min(normalizedRed, normalizedGreen, normalizedBlue);
|
|
2964
|
+
const lightness = (max + min) / 2;
|
|
2965
|
+
if (max === min) {
|
|
2966
|
+
return [0, 0, lightness];
|
|
2967
|
+
}
|
|
2968
|
+
const delta = max - min;
|
|
2969
|
+
const saturation = lightness > 0.5 ? delta / (2 - max - min) : delta / (max + min);
|
|
2970
|
+
let hue = 0;
|
|
2971
|
+
switch (max) {
|
|
2972
|
+
case normalizedRed:
|
|
2973
|
+
hue = (normalizedGreen - normalizedBlue) / delta + (normalizedGreen < normalizedBlue ? 6 : 0);
|
|
2974
|
+
break;
|
|
2975
|
+
case normalizedGreen:
|
|
2976
|
+
hue = (normalizedBlue - normalizedRed) / delta + 2;
|
|
2977
|
+
break;
|
|
2978
|
+
default:
|
|
2979
|
+
hue = (normalizedRed - normalizedGreen) / delta + 4;
|
|
2980
|
+
break;
|
|
2981
|
+
}
|
|
2982
|
+
return [hue / 6, saturation, lightness];
|
|
2983
|
+
}
|
|
2984
|
+
function hueToRgb2(p, q, t) {
|
|
2985
|
+
let nextT = t;
|
|
2986
|
+
if (nextT < 0) {
|
|
2987
|
+
nextT += 1;
|
|
2988
|
+
}
|
|
2989
|
+
if (nextT > 1) {
|
|
2990
|
+
nextT -= 1;
|
|
2991
|
+
}
|
|
2992
|
+
if (nextT < 1 / 6) {
|
|
2993
|
+
return p + (q - p) * 6 * nextT;
|
|
2994
|
+
}
|
|
2995
|
+
if (nextT < 1 / 2) {
|
|
2996
|
+
return q;
|
|
2997
|
+
}
|
|
2998
|
+
if (nextT < 2 / 3) {
|
|
2999
|
+
return p + (q - p) * (2 / 3 - nextT) * 6;
|
|
3000
|
+
}
|
|
3001
|
+
return p;
|
|
3002
|
+
}
|
|
3003
|
+
function hslToRgb2(hue, saturation, lightness) {
|
|
3004
|
+
if (saturation === 0) {
|
|
3005
|
+
const gray = Math.round(lightness * 255);
|
|
3006
|
+
return [gray, gray, gray];
|
|
3007
|
+
}
|
|
3008
|
+
const q = lightness < 0.5 ? lightness * (1 + saturation) : lightness + saturation - lightness * saturation;
|
|
3009
|
+
const p = 2 * lightness - q;
|
|
3010
|
+
return [
|
|
3011
|
+
Math.round(hueToRgb2(p, q, hue + 1 / 3) * 255),
|
|
3012
|
+
Math.round(hueToRgb2(p, q, hue) * 255),
|
|
3013
|
+
Math.round(hueToRgb2(p, q, hue - 1 / 3) * 255)
|
|
3014
|
+
];
|
|
3015
|
+
}
|
|
3016
|
+
function rgbToHex2(red, green, blue) {
|
|
3017
|
+
return `#${[red, green, blue].map((channel) => Math.max(0, Math.min(255, channel)).toString(16).padStart(2, "0")).join("")}`;
|
|
3018
|
+
}
|
|
3019
|
+
function applyExcelTint(baseColor, tint) {
|
|
3020
|
+
const rgb = parseHexColor2(baseColor);
|
|
3021
|
+
if (!rgb || !Number.isFinite(tint) || tint === 0) {
|
|
3022
|
+
return normalizeHexColor2(baseColor);
|
|
3023
|
+
}
|
|
3024
|
+
const [hue, saturation, lightness] = rgbToHsl2(rgb[0], rgb[1], rgb[2]);
|
|
3025
|
+
const nextLightness = tint < 0 ? lightness * (1 + tint) : lightness * (1 - tint) + tint;
|
|
3026
|
+
const [nextRed, nextGreen, nextBlue] = hslToRgb2(hue, saturation, Math.max(0, Math.min(1, nextLightness)));
|
|
3027
|
+
return rgbToHex2(nextRed, nextGreen, nextBlue);
|
|
3028
|
+
}
|
|
3029
|
+
function resolveWorkbookColor(color, themePalette) {
|
|
3030
|
+
if (!color) {
|
|
3031
|
+
return null;
|
|
3032
|
+
}
|
|
3033
|
+
const directHex = ["hex", "rgb", "argb"].map((key) => color[key]).find((value) => typeof value === "string" && value.trim().length > 0);
|
|
3034
|
+
if (directHex) {
|
|
3035
|
+
return normalizeHexColor2(directHex);
|
|
3036
|
+
}
|
|
3037
|
+
const themeValue = color.theme;
|
|
3038
|
+
const numericTheme = typeof themeValue === "number" ? themeValue : typeof themeValue === "string" && themeValue.trim().length > 0 ? Number(themeValue) : Number.NaN;
|
|
3039
|
+
const themeColor = Number.isFinite(numericTheme) ? themePalette?.colorsByIndex[numericTheme] ?? null : null;
|
|
3040
|
+
if (!themeColor) {
|
|
3041
|
+
return null;
|
|
3042
|
+
}
|
|
3043
|
+
const tintValue = color.tint;
|
|
3044
|
+
const tint = typeof tintValue === "number" ? tintValue : typeof tintValue === "string" && tintValue.trim().length > 0 ? Number(tintValue) : Number.NaN;
|
|
3045
|
+
return Number.isFinite(tint) ? applyExcelTint(themeColor, tint) : themeColor;
|
|
3046
|
+
}
|
|
3047
|
+
|
|
3048
|
+
// src/images.ts
|
|
3049
|
+
var REL_NS = "http://schemas.openxmlformats.org/officeDocument/2006/relationships";
|
|
3050
|
+
var SPREADSHEET_NS = "http://schemas.openxmlformats.org/spreadsheetml/2006/main";
|
|
3051
|
+
var DRAWING_REL_TYPE = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/drawing";
|
|
3052
|
+
var EMU_PER_PIXEL2 = 9525;
|
|
3053
|
+
var MIN_COL_WIDTH_PX = 30;
|
|
3054
|
+
var MIN_ROW_HEIGHT_PX = 16;
|
|
3055
|
+
var DEFAULT_COL_WIDTH_EMU = 64 * EMU_PER_PIXEL2;
|
|
3056
|
+
var DEFAULT_ROW_HEIGHT_EMU = 20 * EMU_PER_PIXEL2;
|
|
3057
|
+
var DEFAULT_COLUMN_CHARACTER_WIDTH_PX = 7;
|
|
3058
|
+
var columnCharacterWidthCache = /* @__PURE__ */ new Map();
|
|
3059
|
+
function measureColumnCharacterWidthPx(fontFamily, fontSizePt) {
|
|
3060
|
+
const normalizedFamily = typeof fontFamily === "string" && fontFamily.trim().length > 0 ? fontFamily.trim() : "Calibri";
|
|
3061
|
+
const normalizedSizePt = typeof fontSizePt === "number" && Number.isFinite(fontSizePt) && fontSizePt > 0 ? fontSizePt : 11;
|
|
3062
|
+
const cacheKey = `${normalizedFamily}|${normalizedSizePt}`;
|
|
3063
|
+
const cached = columnCharacterWidthCache.get(cacheKey);
|
|
3064
|
+
if (cached !== void 0) {
|
|
3065
|
+
return cached;
|
|
3066
|
+
}
|
|
3067
|
+
const fontSizePx = normalizedSizePt * (96 / 72);
|
|
3068
|
+
const font = `${fontSizePx}px "${normalizedFamily}"`;
|
|
3069
|
+
let width = DEFAULT_COLUMN_CHARACTER_WIDTH_PX;
|
|
3070
|
+
try {
|
|
3071
|
+
const context = typeof document !== "undefined" ? document.createElement("canvas").getContext("2d") : typeof OffscreenCanvas !== "undefined" ? new OffscreenCanvas(32, 32).getContext("2d") : null;
|
|
3072
|
+
if (context) {
|
|
3073
|
+
context.font = font;
|
|
3074
|
+
width = Math.max(1, context.measureText("0").width);
|
|
3075
|
+
}
|
|
3076
|
+
} catch {
|
|
3077
|
+
width = DEFAULT_COLUMN_CHARACTER_WIDTH_PX;
|
|
3078
|
+
}
|
|
3079
|
+
columnCharacterWidthCache.set(cacheKey, width);
|
|
3080
|
+
return width;
|
|
3081
|
+
}
|
|
3082
|
+
function sheetColumnWidthToPixels(width, columnCharacterWidthPx = DEFAULT_COLUMN_CHARACTER_WIDTH_PX) {
|
|
3083
|
+
if (!Number.isFinite(width) || width <= 0) {
|
|
3084
|
+
return MIN_COL_WIDTH_PX;
|
|
3085
|
+
}
|
|
3086
|
+
const digitWidth = Math.max(1, columnCharacterWidthPx);
|
|
3087
|
+
const pixels = width < 1 ? Math.floor(width * (digitWidth + 5) + 0.5) : Math.floor((256 * width + Math.floor(128 / digitWidth)) / 256 * digitWidth);
|
|
3088
|
+
return Math.max(MIN_COL_WIDTH_PX, pixels);
|
|
3089
|
+
}
|
|
3090
|
+
function buildThemePalette(theme) {
|
|
3091
|
+
const themeOrder = ["lt1", "dk1", "lt2", "dk2", "accent1", "accent2", "accent3", "accent4", "accent5", "accent6", "hlink", "folHlink"];
|
|
3092
|
+
const colorsByIndex = {};
|
|
3093
|
+
themeOrder.forEach((key, index) => {
|
|
3094
|
+
const color = theme.colors.get(key);
|
|
3095
|
+
if (color) {
|
|
3096
|
+
colorsByIndex[index] = color;
|
|
3097
|
+
}
|
|
3098
|
+
});
|
|
3099
|
+
return {
|
|
3100
|
+
colorsByIndex,
|
|
3101
|
+
majorLatinFont: theme.majorLatinFont ?? void 0,
|
|
3102
|
+
minorLatinFont: theme.minorLatinFont ?? void 0
|
|
3103
|
+
};
|
|
3104
|
+
}
|
|
3105
|
+
function normalizeArchivePath2(path) {
|
|
3106
|
+
return path.replace(/\\/g, "/").replace(/^\/+/, "");
|
|
3107
|
+
}
|
|
3108
|
+
function joinArchivePath(...parts) {
|
|
3109
|
+
return normalizeArchivePath2(parts.join("/"));
|
|
3110
|
+
}
|
|
3111
|
+
function dirname2(path) {
|
|
3112
|
+
const normalized = normalizeArchivePath2(path);
|
|
3113
|
+
const lastSlash = normalized.lastIndexOf("/");
|
|
3114
|
+
return lastSlash >= 0 ? normalized.slice(0, lastSlash) : "";
|
|
3115
|
+
}
|
|
3116
|
+
function resolveArchiveTarget(baseDocumentPath, target) {
|
|
3117
|
+
if (!target) {
|
|
3118
|
+
return normalizeArchivePath2(baseDocumentPath);
|
|
3119
|
+
}
|
|
3120
|
+
if (target.startsWith("#")) {
|
|
3121
|
+
return target;
|
|
3122
|
+
}
|
|
3123
|
+
if (target.startsWith("/")) {
|
|
3124
|
+
return normalizeArchivePath2(target);
|
|
3125
|
+
}
|
|
3126
|
+
const baseParts = dirname2(baseDocumentPath).split("/").filter(Boolean);
|
|
3127
|
+
for (const segment of target.split("/")) {
|
|
3128
|
+
if (!segment || segment === ".") {
|
|
3129
|
+
continue;
|
|
3130
|
+
}
|
|
3131
|
+
if (segment === "..") {
|
|
3132
|
+
baseParts.pop();
|
|
3133
|
+
continue;
|
|
3134
|
+
}
|
|
3135
|
+
baseParts.push(segment);
|
|
3136
|
+
}
|
|
3137
|
+
return normalizeArchivePath2(baseParts.join("/"));
|
|
3138
|
+
}
|
|
3139
|
+
function relsPathForDocument(documentPath) {
|
|
3140
|
+
const baseName = documentPath.split("/").pop();
|
|
3141
|
+
const parentDir = dirname2(documentPath);
|
|
3142
|
+
return joinArchivePath(parentDir, "_rels", `${baseName}.rels`);
|
|
3143
|
+
}
|
|
3144
|
+
function parseXml2(xml) {
|
|
3145
|
+
const parser = new DOMParser();
|
|
3146
|
+
const document2 = parser.parseFromString(xml, "application/xml");
|
|
3147
|
+
if (document2.querySelector("parsererror")) {
|
|
3148
|
+
return null;
|
|
3149
|
+
}
|
|
3150
|
+
return document2;
|
|
3151
|
+
}
|
|
3152
|
+
function readArchiveText2(archive, path) {
|
|
3153
|
+
const entry = archive[path];
|
|
3154
|
+
return entry ? strFromU82(entry) : null;
|
|
3155
|
+
}
|
|
3156
|
+
function parseColumnReference(reference) {
|
|
3157
|
+
let value = 0;
|
|
3158
|
+
for (const character of reference.toUpperCase()) {
|
|
3159
|
+
if (character < "A" || character > "Z") {
|
|
3160
|
+
return null;
|
|
3161
|
+
}
|
|
3162
|
+
value = value * 26 + (character.charCodeAt(0) - 64);
|
|
3163
|
+
}
|
|
3164
|
+
return value > 0 ? value - 1 : null;
|
|
3165
|
+
}
|
|
3166
|
+
function parseA1CellReference(reference) {
|
|
3167
|
+
const match = /^\$?([A-Za-z]+)\$?(\d+)$/.exec(reference.trim());
|
|
3168
|
+
if (!match) {
|
|
3169
|
+
return null;
|
|
3170
|
+
}
|
|
3171
|
+
const col = parseColumnReference(match[1] ?? "");
|
|
3172
|
+
const row = Number(match[2] ?? Number.NaN) - 1;
|
|
3173
|
+
if (col === null || !Number.isFinite(row) || row < 0) {
|
|
3174
|
+
return null;
|
|
3175
|
+
}
|
|
3176
|
+
return { col, row };
|
|
3177
|
+
}
|
|
3178
|
+
function parseA1RangeReference(reference) {
|
|
3179
|
+
const [startRef, endRef] = reference.split(":");
|
|
3180
|
+
const start = parseA1CellReference(startRef ?? "");
|
|
3181
|
+
const end = parseA1CellReference(endRef ?? startRef ?? "");
|
|
3182
|
+
return start && end ? { end, start } : null;
|
|
3183
|
+
}
|
|
3184
|
+
function stripSheetNameFromFormulaReference(reference) {
|
|
3185
|
+
const trimmed = reference.trim();
|
|
3186
|
+
const bangIndex = trimmed.lastIndexOf("!");
|
|
3187
|
+
return bangIndex >= 0 ? trimmed.slice(bangIndex + 1) : trimmed;
|
|
3188
|
+
}
|
|
3189
|
+
function parseFormulaCellReference(reference) {
|
|
3190
|
+
const normalized = stripSheetNameFromFormulaReference(reference).split(/\s+/)[0] ?? "";
|
|
3191
|
+
return parseA1CellReference(normalized);
|
|
3192
|
+
}
|
|
3193
|
+
function parseFormulaRangeReference(reference) {
|
|
3194
|
+
return parseA1RangeReference(stripSheetNameFromFormulaReference(reference));
|
|
3195
|
+
}
|
|
3196
|
+
function isElementNode2(node) {
|
|
3197
|
+
return Boolean(node && node.nodeType === 1);
|
|
3198
|
+
}
|
|
3199
|
+
function getLocalElements(parent, localName) {
|
|
3200
|
+
return Array.from(parent.getElementsByTagName("*")).filter((node) => isElementNode2(node) && node.localName === localName);
|
|
3201
|
+
}
|
|
3202
|
+
function getChildElements(parent, localName) {
|
|
3203
|
+
return Array.from(parent.childNodes).filter((node) => isElementNode2(node) && node.localName === localName);
|
|
3204
|
+
}
|
|
3205
|
+
function getFirstChild(parent, localName) {
|
|
3206
|
+
return getChildElements(parent, localName)[0] ?? null;
|
|
3207
|
+
}
|
|
3208
|
+
function getFirstDescendant(parent, localName) {
|
|
3209
|
+
return getLocalElements(parent, localName)[0] ?? null;
|
|
3210
|
+
}
|
|
3211
|
+
function readFeaturePropertyBagCheckboxComplements(archive) {
|
|
3212
|
+
const xml = readArchiveText2(archive, "xl/featurePropertyBag/featurePropertyBag.xml");
|
|
3213
|
+
if (!xml) {
|
|
3214
|
+
return /* @__PURE__ */ new Set();
|
|
3215
|
+
}
|
|
3216
|
+
const document2 = parseXml2(xml);
|
|
3217
|
+
if (!document2?.documentElement) {
|
|
3218
|
+
return /* @__PURE__ */ new Set();
|
|
3219
|
+
}
|
|
3220
|
+
const bagNodes = getChildElements(document2.documentElement, "bag");
|
|
3221
|
+
const bagTypeById = bagNodes.map((node) => node.getAttribute("type") ?? "");
|
|
3222
|
+
const checkboxComplementIndices = /* @__PURE__ */ new Set();
|
|
3223
|
+
const xfComplementsBag = bagNodes.find((node) => node.getAttribute("type") === "XFComplements") ?? null;
|
|
3224
|
+
const mappedBagIds = xfComplementsBag ? getLocalElements(xfComplementsBag, "bagId").map((node) => Number(node.textContent ?? Number.NaN)).filter((value) => Number.isFinite(value)) : [];
|
|
3225
|
+
mappedBagIds.forEach((bagId, complementIndex) => {
|
|
3226
|
+
const xfComplementBag = bagNodes[bagId];
|
|
3227
|
+
if (!xfComplementBag || bagTypeById[bagId] !== "XFComplement") {
|
|
3228
|
+
return;
|
|
3229
|
+
}
|
|
3230
|
+
const xfControlsBagId = getLocalElements(xfComplementBag, "bagId").map((node) => Number(node.textContent ?? Number.NaN)).find((value) => Number.isFinite(value));
|
|
3231
|
+
if (xfControlsBagId === void 0) {
|
|
3232
|
+
return;
|
|
3233
|
+
}
|
|
3234
|
+
const xfControlsBag = bagNodes[xfControlsBagId];
|
|
3235
|
+
if (!xfControlsBag || bagTypeById[xfControlsBagId] !== "XFControls") {
|
|
3236
|
+
return;
|
|
3237
|
+
}
|
|
3238
|
+
const cellControlBagId = getLocalElements(xfControlsBag, "bagId").map((node) => Number(node.textContent ?? Number.NaN)).find((value) => Number.isFinite(value));
|
|
3239
|
+
if (cellControlBagId === void 0) {
|
|
3240
|
+
return;
|
|
3241
|
+
}
|
|
3242
|
+
if (bagTypeById[cellControlBagId] === "Checkbox") {
|
|
3243
|
+
checkboxComplementIndices.add(complementIndex);
|
|
3244
|
+
}
|
|
3245
|
+
});
|
|
3246
|
+
return checkboxComplementIndices;
|
|
3247
|
+
}
|
|
3248
|
+
function getRelationshipId(element) {
|
|
3249
|
+
return element.getAttributeNS(REL_NS, "id") ?? element.getAttribute("r:id") ?? element.getAttribute("id");
|
|
3250
|
+
}
|
|
3251
|
+
function parseContentTypes(archive) {
|
|
3252
|
+
const xml = readArchiveText2(archive, "[Content_Types].xml");
|
|
3253
|
+
const defaultEntries = /* @__PURE__ */ new Map();
|
|
3254
|
+
const overrideEntries = /* @__PURE__ */ new Map();
|
|
3255
|
+
if (!xml) {
|
|
3256
|
+
return { defaultEntries, overrideEntries };
|
|
3257
|
+
}
|
|
3258
|
+
const document2 = parseXml2(xml);
|
|
3259
|
+
if (!document2) {
|
|
3260
|
+
return { defaultEntries, overrideEntries };
|
|
3261
|
+
}
|
|
3262
|
+
for (const defaultNode of getLocalElements(document2, "Default")) {
|
|
3263
|
+
const extension = defaultNode.getAttribute("Extension");
|
|
3264
|
+
const contentType = defaultNode.getAttribute("ContentType");
|
|
3265
|
+
if (extension && contentType) {
|
|
3266
|
+
defaultEntries.set(extension.toLowerCase(), contentType);
|
|
3267
|
+
}
|
|
3268
|
+
}
|
|
3269
|
+
for (const overrideNode of getLocalElements(document2, "Override")) {
|
|
3270
|
+
const partName = overrideNode.getAttribute("PartName");
|
|
3271
|
+
const contentType = overrideNode.getAttribute("ContentType");
|
|
3272
|
+
if (partName && contentType) {
|
|
3273
|
+
overrideEntries.set(normalizeArchivePath2(partName), contentType);
|
|
3274
|
+
}
|
|
3275
|
+
}
|
|
3276
|
+
return { defaultEntries, overrideEntries };
|
|
3277
|
+
}
|
|
3278
|
+
function parseRelationships(archive, relsPath, baseDocumentPath) {
|
|
3279
|
+
const xml = readArchiveText2(archive, relsPath);
|
|
3280
|
+
const relationships = /* @__PURE__ */ new Map();
|
|
3281
|
+
if (!xml) {
|
|
3282
|
+
return relationships;
|
|
3283
|
+
}
|
|
3284
|
+
const document2 = parseXml2(xml);
|
|
3285
|
+
if (!document2) {
|
|
3286
|
+
return relationships;
|
|
3287
|
+
}
|
|
3288
|
+
for (const relationshipNode of getLocalElements(document2, "Relationship")) {
|
|
3289
|
+
const id = relationshipNode.getAttribute("Id");
|
|
3290
|
+
const target = relationshipNode.getAttribute("Target");
|
|
3291
|
+
const type = relationshipNode.getAttribute("Type");
|
|
3292
|
+
if (!id || !target || !type) {
|
|
3293
|
+
continue;
|
|
3294
|
+
}
|
|
3295
|
+
relationships.set(id, {
|
|
3296
|
+
id,
|
|
3297
|
+
target: resolveArchiveTarget(baseDocumentPath, target),
|
|
3298
|
+
targetMode: relationshipNode.getAttribute("TargetMode"),
|
|
3299
|
+
type
|
|
3300
|
+
});
|
|
3301
|
+
}
|
|
3302
|
+
return relationships;
|
|
3303
|
+
}
|
|
3304
|
+
function parseWorkbookSheets(archive) {
|
|
3305
|
+
const workbookXml = readArchiveText2(archive, "xl/workbook.xml");
|
|
3306
|
+
if (!workbookXml) {
|
|
3307
|
+
return [];
|
|
3308
|
+
}
|
|
3309
|
+
const workbookDocument = parseXml2(workbookXml);
|
|
3310
|
+
if (!workbookDocument) {
|
|
3311
|
+
return [];
|
|
3312
|
+
}
|
|
3313
|
+
const workbookRelationships = parseRelationships(archive, "xl/_rels/workbook.xml.rels", "xl/workbook.xml");
|
|
3314
|
+
const sheets2 = [];
|
|
3315
|
+
for (const sheetNode of getLocalElements(workbookDocument, "sheet")) {
|
|
3316
|
+
const relationshipId = getRelationshipId(sheetNode);
|
|
3317
|
+
if (!relationshipId) {
|
|
3318
|
+
continue;
|
|
3319
|
+
}
|
|
3320
|
+
const relationship = workbookRelationships.get(relationshipId);
|
|
3321
|
+
if (!relationship) {
|
|
3322
|
+
continue;
|
|
3323
|
+
}
|
|
3324
|
+
sheets2.push({
|
|
3325
|
+
name: sheetNode.getAttribute("name") ?? `Sheet ${sheets2.length + 1}`,
|
|
3326
|
+
path: relationship.target
|
|
3327
|
+
});
|
|
3328
|
+
}
|
|
3329
|
+
return sheets2;
|
|
3330
|
+
}
|
|
3331
|
+
function parseWorkbookTheme(archive) {
|
|
3332
|
+
const defaultTheme = {
|
|
3333
|
+
colors: /* @__PURE__ */ new Map([
|
|
3334
|
+
["accent1", "#5b9bd5"],
|
|
3335
|
+
["accent2", "#ed7d31"],
|
|
3336
|
+
["accent3", "#a5a5a5"],
|
|
3337
|
+
["accent4", "#ffc000"],
|
|
3338
|
+
["accent5", "#4472c4"],
|
|
3339
|
+
["accent6", "#70ad47"],
|
|
3340
|
+
["bg1", "#ffffff"],
|
|
3341
|
+
["bg2", "#e7e6e6"],
|
|
3342
|
+
["dk1", "#000000"],
|
|
3343
|
+
["dk2", "#6e747a"],
|
|
3344
|
+
["folHlink", "#993366"],
|
|
3345
|
+
["hlink", "#085296"],
|
|
3346
|
+
["lt1", "#ffffff"],
|
|
3347
|
+
["lt2", "#e7e6e6"],
|
|
3348
|
+
["tx1", "#000000"],
|
|
3349
|
+
["tx2", "#6e747a"]
|
|
3350
|
+
]),
|
|
3351
|
+
majorLatinFont: null,
|
|
3352
|
+
minorLatinFont: null
|
|
3353
|
+
};
|
|
3354
|
+
const themeXml = readArchiveText2(archive, "xl/theme/theme1.xml");
|
|
3355
|
+
if (!themeXml) {
|
|
3356
|
+
return defaultTheme;
|
|
3357
|
+
}
|
|
3358
|
+
const themeDocument = parseXml2(themeXml);
|
|
3359
|
+
if (!themeDocument) {
|
|
3360
|
+
return defaultTheme;
|
|
3361
|
+
}
|
|
3362
|
+
const colors = new Map(defaultTheme.colors);
|
|
3363
|
+
const colorSchemeNode = getLocalElements(themeDocument, "clrScheme")[0] ?? null;
|
|
3364
|
+
if (colorSchemeNode) {
|
|
3365
|
+
for (const colorNode of Array.from(colorSchemeNode.childNodes).filter(isElementNode2)) {
|
|
3366
|
+
const key = colorNode.localName;
|
|
3367
|
+
const srgbNode = getFirstChild(colorNode, "srgbClr");
|
|
3368
|
+
const sysNode = getFirstChild(colorNode, "sysClr");
|
|
3369
|
+
const hex = srgbNode?.getAttribute("val") ?? sysNode?.getAttribute("lastClr");
|
|
3370
|
+
if (hex) {
|
|
3371
|
+
colors.set(key, normalizeHexColor3(hex));
|
|
3372
|
+
}
|
|
3373
|
+
}
|
|
3374
|
+
}
|
|
3375
|
+
const fontSchemeNode = getLocalElements(themeDocument, "fontScheme")[0] ?? null;
|
|
3376
|
+
const majorLatinFont = getFirstChild(getFirstChild(fontSchemeNode, "majorFont"), "latin")?.getAttribute("typeface") ?? null;
|
|
3377
|
+
const minorLatinFont = getFirstChild(getFirstChild(fontSchemeNode, "minorFont"), "latin")?.getAttribute("typeface") ?? null;
|
|
3378
|
+
colors.set("bg1", colors.get("lt1") ?? defaultTheme.colors.get("bg1") ?? "#ffffff");
|
|
3379
|
+
colors.set("tx1", colors.get("dk1") ?? defaultTheme.colors.get("tx1") ?? "#000000");
|
|
3380
|
+
colors.set("bg2", colors.get("lt2") ?? defaultTheme.colors.get("bg2") ?? "#e7e6e6");
|
|
3381
|
+
colors.set("tx2", colors.get("dk2") ?? defaultTheme.colors.get("tx2") ?? "#6e747a");
|
|
3382
|
+
return {
|
|
3383
|
+
colors,
|
|
3384
|
+
majorLatinFont,
|
|
3385
|
+
minorLatinFont
|
|
3386
|
+
};
|
|
3387
|
+
}
|
|
3388
|
+
function parseSpreadsheetColor(node) {
|
|
3389
|
+
if (!node) {
|
|
3390
|
+
return void 0;
|
|
3391
|
+
}
|
|
3392
|
+
const color = {};
|
|
3393
|
+
const rgb = node.getAttribute("rgb");
|
|
3394
|
+
const theme = node.getAttribute("theme");
|
|
3395
|
+
const tint = node.getAttribute("tint");
|
|
3396
|
+
const indexed = node.getAttribute("indexed");
|
|
3397
|
+
if (rgb) {
|
|
3398
|
+
color.rgb = normalizeHexColor3(rgb);
|
|
3399
|
+
}
|
|
3400
|
+
if (theme !== null) {
|
|
3401
|
+
color.theme = Number(theme);
|
|
3402
|
+
}
|
|
3403
|
+
if (tint !== null) {
|
|
3404
|
+
color.tint = Number(tint);
|
|
3405
|
+
}
|
|
3406
|
+
if (indexed !== null) {
|
|
3407
|
+
color.indexed = Number(indexed);
|
|
3408
|
+
}
|
|
3409
|
+
return Object.keys(color).length > 0 ? color : void 0;
|
|
3410
|
+
}
|
|
3411
|
+
function hasEnabledSpreadsheetFlag(node) {
|
|
3412
|
+
if (!node) {
|
|
3413
|
+
return false;
|
|
3414
|
+
}
|
|
3415
|
+
const value = node.getAttribute("val");
|
|
3416
|
+
return value === null || value !== "0" && value !== "false";
|
|
3417
|
+
}
|
|
3418
|
+
function parseSheetSparklines(document2, themePalette) {
|
|
3419
|
+
const sparklines = [];
|
|
3420
|
+
for (const groupNode of getLocalElements(document2, "sparklineGroup")) {
|
|
3421
|
+
const rawType = groupNode.getAttribute("type");
|
|
3422
|
+
const sparklineType = rawType === "column" ? "column" : rawType === "stacked" ? "winLoss" : "line";
|
|
3423
|
+
const markersNode = getFirstChild(groupNode, "markers");
|
|
3424
|
+
const negativeNode = getFirstChild(groupNode, "negative");
|
|
3425
|
+
const colorSeries = resolveWorkbookColor(parseSpreadsheetColor(getFirstChild(groupNode, "colorSeries")), themePalette);
|
|
3426
|
+
const colorNegative = resolveWorkbookColor(parseSpreadsheetColor(getFirstChild(groupNode, "colorNegative")), themePalette);
|
|
3427
|
+
const colorMarkers = resolveWorkbookColor(parseSpreadsheetColor(getFirstChild(groupNode, "colorMarkers")), themePalette);
|
|
3428
|
+
const colorFirst = resolveWorkbookColor(parseSpreadsheetColor(getFirstChild(groupNode, "colorFirst")), themePalette);
|
|
3429
|
+
const colorLast = resolveWorkbookColor(parseSpreadsheetColor(getFirstChild(groupNode, "colorLast")), themePalette);
|
|
3430
|
+
const colorHigh = resolveWorkbookColor(parseSpreadsheetColor(getFirstChild(groupNode, "colorHigh")), themePalette);
|
|
3431
|
+
const colorLow = resolveWorkbookColor(parseSpreadsheetColor(getFirstChild(groupNode, "colorLow")), themePalette);
|
|
3432
|
+
const sparklineCollectionNode = getFirstChild(groupNode, "sparklines");
|
|
3433
|
+
if (!sparklineCollectionNode) {
|
|
3434
|
+
continue;
|
|
3435
|
+
}
|
|
3436
|
+
for (const sparklineNode of getChildElements(sparklineCollectionNode, "sparkline")) {
|
|
3437
|
+
const formula = getFirstChild(sparklineNode, "f")?.textContent ?? "";
|
|
3438
|
+
const targetReference = getFirstChild(sparklineNode, "sqref")?.textContent ?? "";
|
|
3439
|
+
const range = parseFormulaRangeReference(formula);
|
|
3440
|
+
const target = parseFormulaCellReference(targetReference);
|
|
3441
|
+
if (!range || !target) {
|
|
3442
|
+
continue;
|
|
3443
|
+
}
|
|
3444
|
+
sparklines.push({
|
|
3445
|
+
color: colorSeries ?? void 0,
|
|
3446
|
+
firstColor: colorFirst ?? void 0,
|
|
3447
|
+
highColor: colorHigh ?? void 0,
|
|
3448
|
+
lastColor: colorLast ?? void 0,
|
|
3449
|
+
lowColor: colorLow ?? void 0,
|
|
3450
|
+
markerColor: colorMarkers ?? void 0,
|
|
3451
|
+
markers: hasEnabledSpreadsheetFlag(markersNode),
|
|
3452
|
+
negative: hasEnabledSpreadsheetFlag(negativeNode),
|
|
3453
|
+
negativeColor: colorNegative ?? void 0,
|
|
3454
|
+
range,
|
|
3455
|
+
target,
|
|
3456
|
+
type: sparklineType
|
|
3457
|
+
});
|
|
3458
|
+
}
|
|
3459
|
+
}
|
|
3460
|
+
return sparklines;
|
|
3461
|
+
}
|
|
3462
|
+
function parseSpreadsheetFont(node) {
|
|
3463
|
+
if (!node) {
|
|
3464
|
+
return void 0;
|
|
3465
|
+
}
|
|
3466
|
+
const font = {};
|
|
3467
|
+
const size = getFirstChild(node, "sz")?.getAttribute("val");
|
|
3468
|
+
const name = getFirstChild(node, "name")?.getAttribute("val");
|
|
3469
|
+
const family = getFirstChild(node, "family")?.getAttribute("val");
|
|
3470
|
+
const scheme = getFirstChild(node, "scheme")?.getAttribute("val");
|
|
3471
|
+
const charset = getFirstChild(node, "charset")?.getAttribute("val");
|
|
3472
|
+
const verticalAlign = getFirstChild(node, "vertAlign")?.getAttribute("val");
|
|
3473
|
+
const color = parseSpreadsheetColor(getFirstChild(node, "color"));
|
|
3474
|
+
if (hasEnabledSpreadsheetFlag(getFirstChild(node, "b"))) {
|
|
3475
|
+
font.bold = true;
|
|
3476
|
+
}
|
|
3477
|
+
if (hasEnabledSpreadsheetFlag(getFirstChild(node, "i"))) {
|
|
3478
|
+
font.italic = true;
|
|
3479
|
+
}
|
|
3480
|
+
if (hasEnabledSpreadsheetFlag(getFirstChild(node, "strike"))) {
|
|
3481
|
+
font.strikethrough = true;
|
|
3482
|
+
}
|
|
3483
|
+
if (getFirstChild(node, "u")) {
|
|
3484
|
+
font.underline = getFirstChild(node, "u")?.getAttribute("val") ?? "single";
|
|
3485
|
+
}
|
|
3486
|
+
if (size !== null && size !== void 0) {
|
|
3487
|
+
font.size = Number(size);
|
|
3488
|
+
}
|
|
3489
|
+
if (name) {
|
|
3490
|
+
font.name = name;
|
|
3491
|
+
}
|
|
3492
|
+
if (family !== null && family !== void 0) {
|
|
3493
|
+
font.family = Number(family);
|
|
3494
|
+
}
|
|
3495
|
+
if (scheme) {
|
|
3496
|
+
font.scheme = scheme;
|
|
3497
|
+
}
|
|
3498
|
+
if (charset !== null && charset !== void 0) {
|
|
3499
|
+
font.charset = Number(charset);
|
|
3500
|
+
}
|
|
3501
|
+
if (verticalAlign) {
|
|
3502
|
+
font.verticalAlign = verticalAlign;
|
|
3503
|
+
}
|
|
3504
|
+
if (hasEnabledSpreadsheetFlag(getFirstChild(node, "shadow"))) {
|
|
3505
|
+
font.shadow = true;
|
|
3506
|
+
}
|
|
3507
|
+
if (hasEnabledSpreadsheetFlag(getFirstChild(node, "outline"))) {
|
|
3508
|
+
font.outline = true;
|
|
3509
|
+
}
|
|
3510
|
+
if (hasEnabledSpreadsheetFlag(getFirstChild(node, "condense"))) {
|
|
3511
|
+
font.condense = true;
|
|
3512
|
+
}
|
|
3513
|
+
if (hasEnabledSpreadsheetFlag(getFirstChild(node, "extend"))) {
|
|
3514
|
+
font.extend = true;
|
|
3515
|
+
}
|
|
3516
|
+
if (color) {
|
|
3517
|
+
font.color = color;
|
|
3518
|
+
}
|
|
3519
|
+
return Object.keys(font).length > 0 ? font : void 0;
|
|
3520
|
+
}
|
|
3521
|
+
function parseSpreadsheetFill(node) {
|
|
3522
|
+
if (!node) {
|
|
3523
|
+
return void 0;
|
|
3524
|
+
}
|
|
3525
|
+
const gradientFill = getFirstChild(node, "gradientFill");
|
|
3526
|
+
if (gradientFill) {
|
|
3527
|
+
const stops = Array.from(gradientFill.childNodes).filter(isElementNode2).filter((child) => child.localName === "stop").map((stopNode) => ({
|
|
3528
|
+
color: parseSpreadsheetColor(Array.from(stopNode.childNodes).find(isElementNode2) ?? null),
|
|
3529
|
+
position: Number(stopNode.getAttribute("position") ?? Number.NaN)
|
|
3530
|
+
})).filter((stop) => stop.color && Number.isFinite(stop.position));
|
|
3531
|
+
if (stops.length > 0) {
|
|
3532
|
+
return {
|
|
3533
|
+
degree: Number(gradientFill.getAttribute("degree") ?? 0),
|
|
3534
|
+
fillType: "gradient",
|
|
3535
|
+
gradientType: gradientFill.getAttribute("type") ?? "linear",
|
|
3536
|
+
stops
|
|
3537
|
+
};
|
|
3538
|
+
}
|
|
3539
|
+
}
|
|
3540
|
+
const patternFill = getFirstChild(node, "patternFill");
|
|
3541
|
+
if (!patternFill) {
|
|
3542
|
+
return void 0;
|
|
3543
|
+
}
|
|
3544
|
+
const patternType = patternFill.getAttribute("patternType") ?? "none";
|
|
3545
|
+
const foreground = parseSpreadsheetColor(getFirstChild(patternFill, "fgColor"));
|
|
3546
|
+
const background = parseSpreadsheetColor(getFirstChild(patternFill, "bgColor"));
|
|
3547
|
+
const solidColor = foreground ?? background;
|
|
3548
|
+
if (patternType === "solid" && solidColor) {
|
|
3549
|
+
return {
|
|
3550
|
+
color: solidColor,
|
|
3551
|
+
fillType: "solid"
|
|
3552
|
+
};
|
|
3553
|
+
}
|
|
3554
|
+
if ((patternType === "none" || patternType === "gray125") && (foreground || background)) {
|
|
3555
|
+
return {
|
|
3556
|
+
background,
|
|
3557
|
+
fillType: "pattern",
|
|
3558
|
+
foreground,
|
|
3559
|
+
patternType
|
|
3560
|
+
};
|
|
3561
|
+
}
|
|
3562
|
+
if (patternType !== "none" && patternType !== "gray125" && (foreground || background)) {
|
|
3563
|
+
return {
|
|
3564
|
+
background,
|
|
3565
|
+
fillType: "pattern",
|
|
3566
|
+
foreground,
|
|
3567
|
+
patternType
|
|
3568
|
+
};
|
|
3569
|
+
}
|
|
3570
|
+
return void 0;
|
|
3571
|
+
}
|
|
3572
|
+
function parseSpreadsheetBorderEdge(node) {
|
|
3573
|
+
if (!node) {
|
|
3574
|
+
return void 0;
|
|
3575
|
+
}
|
|
3576
|
+
const style = node.getAttribute("style");
|
|
3577
|
+
const color = parseSpreadsheetColor(getFirstChild(node, "color"));
|
|
3578
|
+
if (!style || style === "none") {
|
|
3579
|
+
return void 0;
|
|
3580
|
+
}
|
|
3581
|
+
return {
|
|
3582
|
+
color,
|
|
3583
|
+
style
|
|
3584
|
+
};
|
|
3585
|
+
}
|
|
3586
|
+
function parseSpreadsheetBorder(node) {
|
|
3587
|
+
if (!node) {
|
|
3588
|
+
return void 0;
|
|
3589
|
+
}
|
|
3590
|
+
const border = {};
|
|
3591
|
+
["top", "right", "bottom", "left", "horizontal", "vertical"].forEach((edge) => {
|
|
3592
|
+
const parsedEdge = parseSpreadsheetBorderEdge(getFirstChild(node, edge));
|
|
3593
|
+
if (parsedEdge) {
|
|
3594
|
+
border[edge] = parsedEdge;
|
|
3595
|
+
}
|
|
3596
|
+
});
|
|
3597
|
+
return Object.keys(border).length > 0 ? border : void 0;
|
|
3598
|
+
}
|
|
3599
|
+
function parseSpreadsheetAlignment(node) {
|
|
3600
|
+
if (!node) {
|
|
3601
|
+
return void 0;
|
|
3602
|
+
}
|
|
3603
|
+
const alignment = {};
|
|
3604
|
+
const horizontal = node.getAttribute("horizontal");
|
|
3605
|
+
const vertical = node.getAttribute("vertical");
|
|
3606
|
+
const wrapText = node.getAttribute("wrapText");
|
|
3607
|
+
const indent = node.getAttribute("indent");
|
|
3608
|
+
if (horizontal) {
|
|
3609
|
+
alignment.horizontal = horizontal;
|
|
3610
|
+
}
|
|
3611
|
+
if (vertical) {
|
|
3612
|
+
alignment.vertical = vertical;
|
|
3613
|
+
}
|
|
3614
|
+
if (wrapText !== null) {
|
|
3615
|
+
alignment.wrapText = wrapText === "1";
|
|
3616
|
+
}
|
|
3617
|
+
if (indent !== null) {
|
|
3618
|
+
alignment.indent = Number(indent);
|
|
3619
|
+
}
|
|
3620
|
+
return Object.keys(alignment).length > 0 ? alignment : void 0;
|
|
3621
|
+
}
|
|
3622
|
+
function parseDifferentialStyle(node) {
|
|
3623
|
+
if (!node) {
|
|
3624
|
+
return {};
|
|
3625
|
+
}
|
|
3626
|
+
const style = {};
|
|
3627
|
+
const font = parseSpreadsheetFont(getFirstChild(node, "font"));
|
|
3628
|
+
const fill = parseSpreadsheetFill(getFirstChild(node, "fill"));
|
|
3629
|
+
const border = parseSpreadsheetBorder(getFirstChild(node, "border"));
|
|
3630
|
+
const alignment = parseSpreadsheetAlignment(getFirstChild(node, "alignment"));
|
|
3631
|
+
if (font) {
|
|
3632
|
+
style.font = font;
|
|
3633
|
+
}
|
|
3634
|
+
if (fill) {
|
|
3635
|
+
style.fill = fill;
|
|
3636
|
+
}
|
|
3637
|
+
if (border) {
|
|
3638
|
+
style.border = border;
|
|
3639
|
+
}
|
|
3640
|
+
if (alignment) {
|
|
3641
|
+
style.alignment = alignment;
|
|
3642
|
+
}
|
|
3643
|
+
return style;
|
|
3644
|
+
}
|
|
3645
|
+
function parseResolvedXfStyle(xfNode, fonts, fills, borders, checkboxComplementIndices) {
|
|
3646
|
+
const style = {};
|
|
3647
|
+
const fontId = Number(xfNode.getAttribute("fontId") ?? Number.NaN);
|
|
3648
|
+
const fillId = Number(xfNode.getAttribute("fillId") ?? Number.NaN);
|
|
3649
|
+
const borderId = Number(xfNode.getAttribute("borderId") ?? Number.NaN);
|
|
3650
|
+
const alignment = parseSpreadsheetAlignment(getFirstChild(xfNode, "alignment"));
|
|
3651
|
+
if (Number.isFinite(fontId) && fonts[fontId]) {
|
|
3652
|
+
style.font = fonts[fontId];
|
|
3653
|
+
}
|
|
3654
|
+
if (Number.isFinite(fillId) && fills[fillId]) {
|
|
3655
|
+
style.fill = fills[fillId];
|
|
3656
|
+
}
|
|
3657
|
+
if (Number.isFinite(borderId) && borders[borderId]) {
|
|
3658
|
+
style.border = borders[borderId];
|
|
3659
|
+
}
|
|
3660
|
+
if (alignment) {
|
|
3661
|
+
style.alignment = alignment;
|
|
3662
|
+
}
|
|
3663
|
+
const xfComplementNode = getFirstDescendant(xfNode, "xfComplement");
|
|
3664
|
+
const xfComplementIndex = Number(xfComplementNode?.getAttribute("i") ?? Number.NaN);
|
|
3665
|
+
if (Number.isFinite(xfComplementIndex) && checkboxComplementIndices?.has(xfComplementIndex)) {
|
|
3666
|
+
style.cellControl = { kind: "checkbox" };
|
|
3667
|
+
}
|
|
3668
|
+
return style;
|
|
3669
|
+
}
|
|
3670
|
+
function parseWorkbookStyles(archive) {
|
|
3671
|
+
const xml = readArchiveText2(archive, "xl/styles.xml");
|
|
3672
|
+
if (!xml) {
|
|
3673
|
+
return {
|
|
3674
|
+
defaultFont: null,
|
|
3675
|
+
namedCellStyleByName: {},
|
|
3676
|
+
styleById: {},
|
|
3677
|
+
tableStyleByName: {}
|
|
3678
|
+
};
|
|
3679
|
+
}
|
|
3680
|
+
const document2 = parseXml2(xml);
|
|
3681
|
+
if (!document2) {
|
|
3682
|
+
return {
|
|
3683
|
+
defaultFont: null,
|
|
3684
|
+
namedCellStyleByName: {},
|
|
3685
|
+
styleById: {},
|
|
3686
|
+
tableStyleByName: {}
|
|
3687
|
+
};
|
|
3688
|
+
}
|
|
3689
|
+
const fontsNode = getFirstDescendant(document2, "fonts");
|
|
3690
|
+
const fillsNode = getFirstDescendant(document2, "fills");
|
|
3691
|
+
const bordersNode = getFirstDescendant(document2, "borders");
|
|
3692
|
+
const cellStyleXfsNode = getFirstDescendant(document2, "cellStyleXfs");
|
|
3693
|
+
const cellStylesNode = getFirstDescendant(document2, "cellStyles");
|
|
3694
|
+
const cellXfsNode = getFirstDescendant(document2, "cellXfs");
|
|
3695
|
+
const dxfsNode = getFirstDescendant(document2, "dxfs");
|
|
3696
|
+
const tableStylesNode = getFirstDescendant(document2, "tableStyles");
|
|
3697
|
+
if (!cellXfsNode) {
|
|
3698
|
+
return {
|
|
3699
|
+
defaultFont: null,
|
|
3700
|
+
namedCellStyleByName: {},
|
|
3701
|
+
styleById: {},
|
|
3702
|
+
tableStyleByName: {}
|
|
3703
|
+
};
|
|
3704
|
+
}
|
|
3705
|
+
const checkboxComplementIndices = readFeaturePropertyBagCheckboxComplements(archive);
|
|
3706
|
+
const fonts = getChildElements(fontsNode ?? document2.documentElement, "font").map((node) => parseSpreadsheetFont(node));
|
|
3707
|
+
const fills = getChildElements(fillsNode ?? document2.documentElement, "fill").map((node) => parseSpreadsheetFill(node));
|
|
3708
|
+
const borders = getChildElements(bordersNode ?? document2.documentElement, "border").map((node) => parseSpreadsheetBorder(node));
|
|
3709
|
+
const differentialStyles = getChildElements(dxfsNode ?? document2.documentElement, "dxf").map((node) => parseDifferentialStyle(node));
|
|
3710
|
+
const cellStyleXfs = getChildElements(cellStyleXfsNode ?? document2.documentElement, "xf").map(
|
|
3711
|
+
(node) => parseResolvedXfStyle(node, fonts, fills, borders, checkboxComplementIndices)
|
|
3712
|
+
);
|
|
3713
|
+
const namedCellStyleByName = {};
|
|
3714
|
+
const styleById = {};
|
|
3715
|
+
const tableStyleByName = {};
|
|
3716
|
+
getChildElements(cellXfsNode, "xf").forEach((xfNode, index) => {
|
|
3717
|
+
styleById[index] = parseResolvedXfStyle(xfNode, fonts, fills, borders, checkboxComplementIndices);
|
|
3718
|
+
});
|
|
3719
|
+
getChildElements(cellStylesNode ?? document2.documentElement, "cellStyle").forEach((cellStyleNode) => {
|
|
3720
|
+
const name = cellStyleNode.getAttribute("name");
|
|
3721
|
+
const xfId = Number(cellStyleNode.getAttribute("xfId") ?? Number.NaN);
|
|
3722
|
+
if (!name || !Number.isFinite(xfId)) {
|
|
3723
|
+
return;
|
|
3724
|
+
}
|
|
3725
|
+
const resolvedStyle = cellStyleXfs[xfId];
|
|
3726
|
+
if (resolvedStyle) {
|
|
3727
|
+
namedCellStyleByName[name] = resolvedStyle;
|
|
3728
|
+
}
|
|
3729
|
+
});
|
|
3730
|
+
getChildElements(tableStylesNode ?? document2.documentElement, "tableStyle").forEach((tableStyleNode) => {
|
|
3731
|
+
const name = tableStyleNode.getAttribute("name");
|
|
3732
|
+
if (!name) {
|
|
3733
|
+
return;
|
|
3734
|
+
}
|
|
3735
|
+
const elements = {};
|
|
3736
|
+
getChildElements(tableStyleNode, "tableStyleElement").forEach((elementNode) => {
|
|
3737
|
+
const type = elementNode.getAttribute("type");
|
|
3738
|
+
const dxfId = Number(elementNode.getAttribute("dxfId") ?? Number.NaN);
|
|
3739
|
+
if (!type || !Number.isFinite(dxfId)) {
|
|
3740
|
+
return;
|
|
3741
|
+
}
|
|
3742
|
+
const differentialStyle = differentialStyles[dxfId];
|
|
3743
|
+
if (differentialStyle) {
|
|
3744
|
+
elements[type] = differentialStyle;
|
|
3745
|
+
}
|
|
3746
|
+
});
|
|
3747
|
+
tableStyleByName[name] = elements;
|
|
3748
|
+
});
|
|
3749
|
+
const normalFont = namedCellStyleByName.Normal?.font ?? styleById[0]?.font ?? fonts[0];
|
|
3750
|
+
const defaultFont = normalFont ? {
|
|
3751
|
+
family: typeof normalFont.name === "string" ? normalFont.name : void 0,
|
|
3752
|
+
sizePt: typeof normalFont.size === "number" ? normalFont.size : void 0
|
|
3753
|
+
} : null;
|
|
3754
|
+
return {
|
|
3755
|
+
defaultFont,
|
|
3756
|
+
namedCellStyleByName,
|
|
3757
|
+
styleById,
|
|
3758
|
+
tableStyleByName
|
|
3759
|
+
};
|
|
3760
|
+
}
|
|
3761
|
+
function parseWorkbookTableMetadata(archive, workbookSheets) {
|
|
3762
|
+
return workbookSheets.map((sheet) => {
|
|
3763
|
+
const sheetRelationships = parseRelationships(archive, relsPathForDocument(sheet.path), sheet.path);
|
|
3764
|
+
const sheetXml = readArchiveText2(archive, sheet.path);
|
|
3765
|
+
if (!sheetXml) {
|
|
3766
|
+
return [];
|
|
3767
|
+
}
|
|
3768
|
+
const sheetDocument = parseXml2(sheetXml);
|
|
3769
|
+
if (!sheetDocument) {
|
|
3770
|
+
return [];
|
|
3771
|
+
}
|
|
3772
|
+
return getLocalElements(sheetDocument, "tablePart").flatMap((tablePartNode) => {
|
|
3773
|
+
const relationshipId = getRelationshipId(tablePartNode);
|
|
3774
|
+
if (!relationshipId) {
|
|
3775
|
+
return [];
|
|
3776
|
+
}
|
|
3777
|
+
const relationship = sheetRelationships.get(relationshipId);
|
|
3778
|
+
if (!relationship) {
|
|
3779
|
+
return [];
|
|
3780
|
+
}
|
|
3781
|
+
const tableXml = readArchiveText2(archive, relationship.target);
|
|
3782
|
+
if (!tableXml) {
|
|
3783
|
+
return [];
|
|
3784
|
+
}
|
|
3785
|
+
const tableDocument = parseXml2(tableXml);
|
|
3786
|
+
const tableNode = tableDocument?.documentElement;
|
|
3787
|
+
if (!tableNode || tableNode.localName !== "table") {
|
|
3788
|
+
return [];
|
|
3789
|
+
}
|
|
3790
|
+
return [{
|
|
3791
|
+
displayName: tableNode.getAttribute("displayName") ?? void 0,
|
|
3792
|
+
headerRowCellStyle: tableNode.getAttribute("headerRowCellStyle") ?? void 0,
|
|
3793
|
+
name: tableNode.getAttribute("name") ?? void 0,
|
|
3794
|
+
reference: tableNode.getAttribute("ref") ?? void 0
|
|
3795
|
+
}];
|
|
3796
|
+
});
|
|
3797
|
+
});
|
|
3798
|
+
}
|
|
3799
|
+
function parseSqrefRanges(sqref) {
|
|
3800
|
+
if (!sqref) {
|
|
3801
|
+
return [];
|
|
3802
|
+
}
|
|
3803
|
+
return sqref.trim().split(/\s+/).flatMap((reference) => {
|
|
3804
|
+
const range = parseA1RangeReference(reference);
|
|
3805
|
+
return range ? [range] : [];
|
|
3806
|
+
});
|
|
3807
|
+
}
|
|
3808
|
+
function parseConditionalFormatValueObject(node) {
|
|
3809
|
+
if (!node) {
|
|
3810
|
+
return null;
|
|
3811
|
+
}
|
|
3812
|
+
const type = node.getAttribute("type");
|
|
3813
|
+
if (!type) {
|
|
3814
|
+
return null;
|
|
3815
|
+
}
|
|
3816
|
+
const rawValue = node.getAttribute("val") ?? getFirstChild(node, "f")?.textContent ?? void 0;
|
|
3817
|
+
const numericValue = rawValue !== void 0 ? Number(rawValue) : Number.NaN;
|
|
3818
|
+
return {
|
|
3819
|
+
type,
|
|
3820
|
+
value: Number.isFinite(numericValue) ? numericValue : void 0
|
|
3821
|
+
};
|
|
3822
|
+
}
|
|
3823
|
+
function parseSpreadsheetBooleanAttribute(node, name) {
|
|
3824
|
+
if (!node) {
|
|
3825
|
+
return void 0;
|
|
3826
|
+
}
|
|
3827
|
+
const value = node.getAttribute(name);
|
|
3828
|
+
if (value === null) {
|
|
3829
|
+
return void 0;
|
|
3830
|
+
}
|
|
3831
|
+
return value !== "0" && value !== "false";
|
|
3832
|
+
}
|
|
3833
|
+
function parseStandardConditionalFormatRule(cfRuleNode, ranges) {
|
|
3834
|
+
const type = cfRuleNode.getAttribute("type");
|
|
3835
|
+
const rawPriority = Number(cfRuleNode.getAttribute("priority") ?? Number.NaN);
|
|
3836
|
+
const priority = Number.isFinite(rawPriority) ? rawPriority : Number.MAX_SAFE_INTEGER;
|
|
3837
|
+
if (type === "colorScale") {
|
|
3838
|
+
const colorScaleNode = getFirstChild(cfRuleNode, "colorScale");
|
|
3839
|
+
if (!colorScaleNode) {
|
|
3840
|
+
return null;
|
|
3841
|
+
}
|
|
3842
|
+
const cfvos = getChildElements(colorScaleNode, "cfvo").map((node) => parseConditionalFormatValueObject(node)).filter((value) => Boolean(value));
|
|
3843
|
+
const colors = getChildElements(colorScaleNode, "color").map((node) => parseSpreadsheetColor(node)).filter((value) => Boolean(value));
|
|
3844
|
+
if (cfvos.length === 0 || colors.length === 0) {
|
|
3845
|
+
return null;
|
|
3846
|
+
}
|
|
3847
|
+
return {
|
|
3848
|
+
cfvos,
|
|
3849
|
+
colors,
|
|
3850
|
+
kind: "colorScale",
|
|
3851
|
+
priority,
|
|
3852
|
+
ranges
|
|
3853
|
+
};
|
|
3854
|
+
}
|
|
3855
|
+
if (type === "dataBar") {
|
|
3856
|
+
const dataBarNode = getFirstChild(cfRuleNode, "dataBar");
|
|
3857
|
+
if (!dataBarNode) {
|
|
3858
|
+
return null;
|
|
3859
|
+
}
|
|
3860
|
+
const cfvos = getChildElements(dataBarNode, "cfvo").map((node) => parseConditionalFormatValueObject(node)).filter((value) => Boolean(value));
|
|
3861
|
+
if (cfvos.length === 0) {
|
|
3862
|
+
return null;
|
|
3863
|
+
}
|
|
3864
|
+
const extId = getFirstDescendant(cfRuleNode, "id")?.textContent?.trim() || void 0;
|
|
3865
|
+
return {
|
|
3866
|
+
cfvos,
|
|
3867
|
+
color: parseSpreadsheetColor(getFirstChild(dataBarNode, "color")),
|
|
3868
|
+
kind: "dataBar",
|
|
3869
|
+
priority,
|
|
3870
|
+
ranges,
|
|
3871
|
+
id: extId
|
|
3872
|
+
};
|
|
3873
|
+
}
|
|
3874
|
+
if (type === "iconSet") {
|
|
3875
|
+
const iconSetNode = getFirstChild(cfRuleNode, "iconSet");
|
|
3876
|
+
if (!iconSetNode) {
|
|
3877
|
+
return null;
|
|
3878
|
+
}
|
|
3879
|
+
const iconSetName = iconSetNode.getAttribute("iconSet");
|
|
3880
|
+
const cfvos = getChildElements(iconSetNode, "cfvo").map((node) => parseConditionalFormatValueObject(node)).filter((value) => Boolean(value));
|
|
3881
|
+
if (!iconSetName || cfvos.length === 0) {
|
|
3882
|
+
return null;
|
|
3883
|
+
}
|
|
3884
|
+
return {
|
|
3885
|
+
cfvos,
|
|
3886
|
+
icons: cfvos.map((_, index) => ({
|
|
3887
|
+
iconId: index,
|
|
3888
|
+
iconSet: iconSetName
|
|
3889
|
+
})),
|
|
3890
|
+
kind: "iconSet",
|
|
3891
|
+
priority,
|
|
3892
|
+
ranges,
|
|
3893
|
+
reverse: parseSpreadsheetBooleanAttribute(iconSetNode, "reverse"),
|
|
3894
|
+
showValue: parseSpreadsheetBooleanAttribute(iconSetNode, "showValue")
|
|
3895
|
+
};
|
|
3896
|
+
}
|
|
3897
|
+
return null;
|
|
3898
|
+
}
|
|
3899
|
+
function parseExtendedConditionalFormatRule(cfRuleNode, ranges) {
|
|
3900
|
+
const type = cfRuleNode.getAttribute("type");
|
|
3901
|
+
const ruleId = cfRuleNode.getAttribute("id") ?? void 0;
|
|
3902
|
+
const rawPriority = Number(cfRuleNode.getAttribute("priority") ?? Number.NaN);
|
|
3903
|
+
const priority = Number.isFinite(rawPriority) ? rawPriority : Number.MAX_SAFE_INTEGER;
|
|
3904
|
+
if (type === "dataBar") {
|
|
3905
|
+
const dataBarNode = getFirstChild(cfRuleNode, "dataBar");
|
|
3906
|
+
if (!dataBarNode) {
|
|
3907
|
+
return null;
|
|
3908
|
+
}
|
|
3909
|
+
const cfvos = getChildElements(dataBarNode, "cfvo").map((node) => parseConditionalFormatValueObject(node)).filter((value) => Boolean(value));
|
|
3910
|
+
if (cfvos.length === 0) {
|
|
3911
|
+
return null;
|
|
3912
|
+
}
|
|
3913
|
+
return {
|
|
3914
|
+
axisColor: parseSpreadsheetColor(getFirstChild(dataBarNode, "axisColor")),
|
|
3915
|
+
border: parseSpreadsheetBooleanAttribute(dataBarNode, "border"),
|
|
3916
|
+
borderColor: parseSpreadsheetColor(getFirstChild(dataBarNode, "borderColor")),
|
|
3917
|
+
cfvos,
|
|
3918
|
+
color: parseSpreadsheetColor(getFirstChild(dataBarNode, "fillColor")),
|
|
3919
|
+
gradient: parseSpreadsheetBooleanAttribute(dataBarNode, "gradient"),
|
|
3920
|
+
kind: "dataBar",
|
|
3921
|
+
maxLength: Number(dataBarNode.getAttribute("maxLength") ?? Number.NaN),
|
|
3922
|
+
minLength: Number(dataBarNode.getAttribute("minLength") ?? Number.NaN),
|
|
3923
|
+
negativeBarBorderColorSameAsPositive: parseSpreadsheetBooleanAttribute(dataBarNode, "negativeBarBorderColorSameAsPositive"),
|
|
3924
|
+
negativeBorderColor: parseSpreadsheetColor(getFirstChild(dataBarNode, "negativeBorderColor")),
|
|
3925
|
+
negativeFillColor: parseSpreadsheetColor(getFirstChild(dataBarNode, "negativeFillColor")),
|
|
3926
|
+
priority,
|
|
3927
|
+
ranges,
|
|
3928
|
+
showValue: parseSpreadsheetBooleanAttribute(dataBarNode, "showValue"),
|
|
3929
|
+
id: ruleId
|
|
3930
|
+
};
|
|
3931
|
+
}
|
|
3932
|
+
if (type === "iconSet") {
|
|
3933
|
+
const iconSetNode = getFirstChild(cfRuleNode, "iconSet");
|
|
3934
|
+
if (!iconSetNode) {
|
|
3935
|
+
return null;
|
|
3936
|
+
}
|
|
3937
|
+
const cfvos = getChildElements(iconSetNode, "cfvo").map((node) => parseConditionalFormatValueObject(node)).filter((value) => Boolean(value));
|
|
3938
|
+
const icons = getChildElements(iconSetNode, "cfIcon").map((iconNode) => {
|
|
3939
|
+
const iconSet = iconNode.getAttribute("iconSet");
|
|
3940
|
+
const rawIconId = Number(iconNode.getAttribute("iconId") ?? Number.NaN);
|
|
3941
|
+
if (!iconSet || !Number.isFinite(rawIconId)) {
|
|
3942
|
+
return null;
|
|
3943
|
+
}
|
|
3944
|
+
return {
|
|
3945
|
+
iconId: rawIconId,
|
|
3946
|
+
iconSet
|
|
3947
|
+
};
|
|
3948
|
+
}).filter((icon) => Boolean(icon));
|
|
3949
|
+
if (cfvos.length === 0 || icons.length === 0) {
|
|
3950
|
+
return null;
|
|
3951
|
+
}
|
|
3952
|
+
return {
|
|
3953
|
+
cfvos,
|
|
3954
|
+
icons,
|
|
3955
|
+
kind: "iconSet",
|
|
3956
|
+
priority,
|
|
3957
|
+
ranges,
|
|
3958
|
+
reverse: parseSpreadsheetBooleanAttribute(iconSetNode, "reverse"),
|
|
3959
|
+
showValue: parseSpreadsheetBooleanAttribute(iconSetNode, "showValue"),
|
|
3960
|
+
id: ruleId
|
|
3961
|
+
};
|
|
3962
|
+
}
|
|
3963
|
+
return null;
|
|
3964
|
+
}
|
|
3965
|
+
function mergeConditionalFormatRule(baseRule, extendedRule) {
|
|
3966
|
+
if (baseRule.kind !== extendedRule.kind) {
|
|
3967
|
+
return baseRule;
|
|
3968
|
+
}
|
|
3969
|
+
if (baseRule.kind === "colorScale" && extendedRule.kind === "colorScale") {
|
|
3970
|
+
return {
|
|
3971
|
+
...baseRule,
|
|
3972
|
+
...extendedRule,
|
|
3973
|
+
cfvos: extendedRule.cfvos.length > 0 ? extendedRule.cfvos : baseRule.cfvos,
|
|
3974
|
+
colors: extendedRule.colors.length > 0 ? extendedRule.colors : baseRule.colors,
|
|
3975
|
+
priority: Number.isFinite(extendedRule.priority) ? extendedRule.priority : baseRule.priority,
|
|
3976
|
+
ranges: extendedRule.ranges.length > 0 ? extendedRule.ranges : baseRule.ranges
|
|
3977
|
+
};
|
|
3978
|
+
}
|
|
3979
|
+
if (baseRule.kind === "dataBar" && extendedRule.kind === "dataBar") {
|
|
3980
|
+
const merged = {
|
|
3981
|
+
...baseRule,
|
|
3982
|
+
...extendedRule,
|
|
3983
|
+
axisColor: extendedRule.axisColor ?? baseRule.axisColor,
|
|
3984
|
+
border: extendedRule.border ?? baseRule.border,
|
|
3985
|
+
cfvos: extendedRule.cfvos.length > 0 ? extendedRule.cfvos : baseRule.cfvos,
|
|
3986
|
+
color: extendedRule.color ?? baseRule.color,
|
|
3987
|
+
negativeBarBorderColorSameAsPositive: extendedRule.negativeBarBorderColorSameAsPositive ?? baseRule.negativeBarBorderColorSameAsPositive,
|
|
3988
|
+
negativeBorderColor: extendedRule.negativeBorderColor ?? baseRule.negativeBorderColor,
|
|
3989
|
+
negativeFillColor: extendedRule.negativeFillColor ?? baseRule.negativeFillColor,
|
|
3990
|
+
priority: Number.isFinite(extendedRule.priority) ? extendedRule.priority : baseRule.priority,
|
|
3991
|
+
ranges: extendedRule.ranges.length > 0 ? extendedRule.ranges : baseRule.ranges
|
|
3992
|
+
};
|
|
3993
|
+
return merged;
|
|
3994
|
+
}
|
|
3995
|
+
if (baseRule.kind === "iconSet" && extendedRule.kind === "iconSet") {
|
|
3996
|
+
const merged = {
|
|
3997
|
+
...baseRule,
|
|
3998
|
+
...extendedRule,
|
|
3999
|
+
cfvos: extendedRule.cfvos.length > 0 ? extendedRule.cfvos : baseRule.cfvos,
|
|
4000
|
+
icons: extendedRule.icons.length > 0 ? extendedRule.icons : baseRule.icons,
|
|
4001
|
+
priority: Number.isFinite(extendedRule.priority) ? extendedRule.priority : baseRule.priority,
|
|
4002
|
+
ranges: extendedRule.ranges.length > 0 ? extendedRule.ranges : baseRule.ranges
|
|
4003
|
+
};
|
|
4004
|
+
return merged;
|
|
4005
|
+
}
|
|
4006
|
+
return baseRule;
|
|
4007
|
+
}
|
|
4008
|
+
function parseConditionalFormatRules(document2) {
|
|
4009
|
+
const standardRules = [];
|
|
4010
|
+
const extendedRules = [];
|
|
4011
|
+
getLocalElements(document2, "conditionalFormatting").forEach((conditionalFormattingNode) => {
|
|
4012
|
+
const isExtended = conditionalFormattingNode.namespaceURI !== SPREADSHEET_NS;
|
|
4013
|
+
const ranges = isExtended ? parseSqrefRanges(getFirstChild(conditionalFormattingNode, "sqref")?.textContent ?? "") : parseSqrefRanges(conditionalFormattingNode.getAttribute("sqref"));
|
|
4014
|
+
getChildElements(conditionalFormattingNode, "cfRule").forEach((cfRuleNode) => {
|
|
4015
|
+
const parsedRule = isExtended ? parseExtendedConditionalFormatRule(cfRuleNode, ranges) : parseStandardConditionalFormatRule(cfRuleNode, ranges);
|
|
4016
|
+
if (parsedRule) {
|
|
4017
|
+
if (isExtended) {
|
|
4018
|
+
extendedRules.push(parsedRule);
|
|
4019
|
+
} else {
|
|
4020
|
+
standardRules.push(parsedRule);
|
|
4021
|
+
}
|
|
4022
|
+
}
|
|
4023
|
+
});
|
|
4024
|
+
});
|
|
4025
|
+
const mergedRules = [];
|
|
4026
|
+
const usedExtendedRuleIds = /* @__PURE__ */ new Set();
|
|
4027
|
+
const extendedRulesById = new Map(
|
|
4028
|
+
extendedRules.filter((rule) => typeof rule.id === "string" && rule.id.length > 0).map((rule) => [rule.id, rule])
|
|
4029
|
+
);
|
|
4030
|
+
standardRules.forEach((rule) => {
|
|
4031
|
+
const matchingExtendedRule = rule.id ? extendedRulesById.get(rule.id) : void 0;
|
|
4032
|
+
if (matchingExtendedRule) {
|
|
4033
|
+
usedExtendedRuleIds.add(rule.id);
|
|
4034
|
+
mergedRules.push(mergeConditionalFormatRule(rule, matchingExtendedRule));
|
|
4035
|
+
return;
|
|
4036
|
+
}
|
|
4037
|
+
mergedRules.push(rule);
|
|
4038
|
+
});
|
|
4039
|
+
extendedRules.forEach((rule) => {
|
|
4040
|
+
if (rule.id && usedExtendedRuleIds.has(rule.id)) {
|
|
4041
|
+
return;
|
|
4042
|
+
}
|
|
4043
|
+
mergedRules.push(rule);
|
|
4044
|
+
});
|
|
4045
|
+
return mergedRules.map((rule) => {
|
|
4046
|
+
const nextRule = { ...rule };
|
|
4047
|
+
delete nextRule.id;
|
|
4048
|
+
return nextRule;
|
|
4049
|
+
}).filter((rule) => rule.ranges.length > 0).sort((left, right) => left.priority - right.priority);
|
|
4050
|
+
}
|
|
4051
|
+
function parseSheetState(archive, path, options) {
|
|
4052
|
+
const xml = readArchiveText2(archive, path);
|
|
4053
|
+
if (!xml) {
|
|
4054
|
+
return null;
|
|
4055
|
+
}
|
|
4056
|
+
const document2 = parseXml2(xml);
|
|
4057
|
+
if (!document2) {
|
|
4058
|
+
return null;
|
|
4059
|
+
}
|
|
4060
|
+
const includeCachedFormulaValues = options?.includeCachedFormulaValues ?? true;
|
|
4061
|
+
const cachedFormulaValues = {};
|
|
4062
|
+
const conditionalFormatRules = parseConditionalFormatRules(document2);
|
|
4063
|
+
const sparklines = parseSheetSparklines(document2, options?.themePalette);
|
|
4064
|
+
const sheetFormatNode = getLocalElements(document2, "sheetFormatPr")[0] ?? null;
|
|
4065
|
+
const sheetViewNode = getLocalElements(document2, "sheetView")[0] ?? null;
|
|
4066
|
+
const rowHeightOverridesPx = {};
|
|
4067
|
+
const colWidthOverridesPx = {};
|
|
4068
|
+
const rowStyleIds = {};
|
|
4069
|
+
const colStyleIds = {};
|
|
4070
|
+
const hiddenRows = /* @__PURE__ */ new Set();
|
|
4071
|
+
const hiddenCols = /* @__PURE__ */ new Set();
|
|
4072
|
+
let hasHorizontalMerges = false;
|
|
4073
|
+
let hasVerticalMerges = false;
|
|
4074
|
+
let maxHorizontalMergeEndCol = -1;
|
|
4075
|
+
let maxVerticalMergeEndRow = -1;
|
|
4076
|
+
const columnWidthCharacterWidthPx = measureColumnCharacterWidthPx(
|
|
4077
|
+
options?.defaultFont?.family,
|
|
4078
|
+
options?.defaultFont?.sizePt
|
|
4079
|
+
);
|
|
4080
|
+
const defaultRowHeight = Number(sheetFormatNode?.getAttribute("defaultRowHeight") ?? 15);
|
|
4081
|
+
const defaultColWidth = Number(
|
|
4082
|
+
sheetFormatNode?.getAttribute("defaultColWidth") ?? sheetFormatNode?.getAttribute("baseColWidth") ?? 8.43
|
|
4083
|
+
);
|
|
4084
|
+
const rawZoomScale = Number(
|
|
4085
|
+
sheetViewNode?.getAttribute("zoomScale") ?? sheetViewNode?.getAttribute("zoomScaleNormal") ?? Number.NaN
|
|
4086
|
+
);
|
|
4087
|
+
const zoomScale = Number.isFinite(rawZoomScale) && rawZoomScale > 0 ? rawZoomScale : 100;
|
|
4088
|
+
getLocalElements(document2, "row").forEach((rowNode) => {
|
|
4089
|
+
const rowIndex = Number(rowNode.getAttribute("r") ?? 0) - 1;
|
|
4090
|
+
const height = Number(rowNode.getAttribute("ht") ?? Number.NaN);
|
|
4091
|
+
const styleId = Number(rowNode.getAttribute("s") ?? Number.NaN);
|
|
4092
|
+
const isHidden = (rowNode.getAttribute("hidden") ?? "0") === "1";
|
|
4093
|
+
if (rowIndex >= 0 && Number.isFinite(height)) {
|
|
4094
|
+
rowHeightOverridesPx[rowIndex] = Math.max(MIN_ROW_HEIGHT_PX, Math.round(height * 1.33));
|
|
4095
|
+
}
|
|
4096
|
+
if (rowIndex >= 0 && Number.isFinite(styleId)) {
|
|
4097
|
+
rowStyleIds[rowIndex] = styleId;
|
|
4098
|
+
}
|
|
4099
|
+
if (rowIndex >= 0 && isHidden) {
|
|
4100
|
+
hiddenRows.add(rowIndex);
|
|
4101
|
+
}
|
|
4102
|
+
if (includeCachedFormulaValues) {
|
|
4103
|
+
getChildElements(rowNode, "c").forEach((cellNode) => {
|
|
4104
|
+
const formulaNode = getFirstChild(cellNode, "f");
|
|
4105
|
+
const valueNode = getFirstChild(cellNode, "v");
|
|
4106
|
+
const cellRef = cellNode.getAttribute("r");
|
|
4107
|
+
if (formulaNode && valueNode && cellRef) {
|
|
4108
|
+
cachedFormulaValues[cellRef] = valueNode.textContent ?? "";
|
|
4109
|
+
}
|
|
4110
|
+
});
|
|
4111
|
+
}
|
|
4112
|
+
});
|
|
4113
|
+
getLocalElements(document2, "col").forEach((colNode) => {
|
|
4114
|
+
const min = Number(colNode.getAttribute("min") ?? 0) - 1;
|
|
4115
|
+
const max = Number(colNode.getAttribute("max") ?? 0) - 1;
|
|
4116
|
+
const width = Number(colNode.getAttribute("width") ?? Number.NaN);
|
|
4117
|
+
const styleId = Number(colNode.getAttribute("style") ?? Number.NaN);
|
|
4118
|
+
const isHidden = (colNode.getAttribute("hidden") ?? "0") === "1";
|
|
4119
|
+
if (!Number.isFinite(width)) {
|
|
4120
|
+
if (!Number.isFinite(styleId)) {
|
|
4121
|
+
return;
|
|
4122
|
+
}
|
|
4123
|
+
}
|
|
4124
|
+
for (let col = min; col <= max; col += 1) {
|
|
4125
|
+
if (col >= 0) {
|
|
4126
|
+
if (Number.isFinite(width)) {
|
|
4127
|
+
const widthPx = sheetColumnWidthToPixels(width, columnWidthCharacterWidthPx);
|
|
4128
|
+
colWidthOverridesPx[col] = widthPx;
|
|
4129
|
+
}
|
|
4130
|
+
if (Number.isFinite(styleId)) {
|
|
4131
|
+
colStyleIds[col] = styleId;
|
|
4132
|
+
}
|
|
4133
|
+
if (isHidden) {
|
|
4134
|
+
hiddenCols.add(col);
|
|
4135
|
+
}
|
|
4136
|
+
}
|
|
4137
|
+
}
|
|
4138
|
+
});
|
|
4139
|
+
getLocalElements(document2, "mergeCell").forEach((mergeNode) => {
|
|
4140
|
+
const reference = mergeNode.getAttribute("ref");
|
|
4141
|
+
const range = reference ? parseA1RangeReference(reference) : null;
|
|
4142
|
+
if (!range) {
|
|
4143
|
+
return;
|
|
4144
|
+
}
|
|
4145
|
+
if (range.end.col > range.start.col) {
|
|
4146
|
+
hasHorizontalMerges = true;
|
|
4147
|
+
maxHorizontalMergeEndCol = Math.max(maxHorizontalMergeEndCol, range.end.col);
|
|
4148
|
+
}
|
|
4149
|
+
if (range.end.row > range.start.row) {
|
|
4150
|
+
hasVerticalMerges = true;
|
|
4151
|
+
maxVerticalMergeEndRow = Math.max(maxVerticalMergeEndRow, range.end.row);
|
|
4152
|
+
}
|
|
4153
|
+
});
|
|
4154
|
+
return {
|
|
4155
|
+
cachedFormulaValues,
|
|
4156
|
+
columnWidthCharacterWidthPx,
|
|
4157
|
+
colWidthOverridesPx,
|
|
4158
|
+
colStyleIds,
|
|
4159
|
+
conditionalFormatRules,
|
|
4160
|
+
defaultColWidthPx: sheetColumnWidthToPixels(defaultColWidth, columnWidthCharacterWidthPx),
|
|
4161
|
+
defaultRowHeightPx: Math.max(MIN_ROW_HEIGHT_PX, Math.round(defaultRowHeight * 1.33)),
|
|
4162
|
+
hasHorizontalMerges,
|
|
4163
|
+
hasVerticalMerges,
|
|
4164
|
+
maxHorizontalMergeEndCol,
|
|
4165
|
+
maxVerticalMergeEndRow,
|
|
4166
|
+
hiddenCols: [...hiddenCols].sort((left, right) => left - right),
|
|
4167
|
+
hiddenRows: [...hiddenRows].sort((left, right) => left - right),
|
|
4168
|
+
rowHeightOverridesPx,
|
|
4169
|
+
rowStyleIds,
|
|
4170
|
+
showGridLines: (sheetViewNode?.getAttribute("showGridLines") ?? "1") !== "0",
|
|
4171
|
+
sparklines,
|
|
4172
|
+
zoomScale
|
|
4173
|
+
};
|
|
4174
|
+
}
|
|
4175
|
+
function normalizeHexColor3(value) {
|
|
4176
|
+
const hex = value.replace(/^#/, "");
|
|
4177
|
+
if (hex.length === 8) {
|
|
4178
|
+
return `#${hex.slice(2).toLowerCase()}`;
|
|
4179
|
+
}
|
|
4180
|
+
if (hex.length === 6) {
|
|
4181
|
+
return `#${hex.toLowerCase()}`;
|
|
4182
|
+
}
|
|
4183
|
+
return "#000000";
|
|
4184
|
+
}
|
|
4185
|
+
function parseWorkbookStructureAssetsFromArchive(archive, options) {
|
|
4186
|
+
const contentTypes = parseContentTypes(archive);
|
|
4187
|
+
const workbookSheets = parseWorkbookSheets(archive);
|
|
4188
|
+
const theme = parseWorkbookTheme(archive);
|
|
4189
|
+
const themePalette = buildThemePalette(theme);
|
|
4190
|
+
const { defaultFont, namedCellStyleByName, styleById, tableStyleByName } = parseWorkbookStyles(archive);
|
|
4191
|
+
const tableMetadataByWorkbookSheetIndex = parseWorkbookTableMetadata(archive, workbookSheets);
|
|
4192
|
+
return {
|
|
4193
|
+
contentTypes,
|
|
4194
|
+
namedCellStyleByName,
|
|
4195
|
+
sheetStatesByWorkbookSheetIndex: workbookSheets.map((sheet) => parseSheetState(archive, sheet.path, {
|
|
4196
|
+
...options,
|
|
4197
|
+
defaultFont,
|
|
4198
|
+
themePalette
|
|
4199
|
+
})),
|
|
4200
|
+
styleById,
|
|
4201
|
+
tableMetadataByWorkbookSheetIndex,
|
|
4202
|
+
tableStyleByName,
|
|
4203
|
+
theme,
|
|
4204
|
+
themePalette,
|
|
4205
|
+
workbookSheets
|
|
4206
|
+
};
|
|
4207
|
+
}
|
|
4208
|
+
function parseWorkbookStructureAssets(bytes, options) {
|
|
4209
|
+
const archive = unzipSync(bytes);
|
|
4210
|
+
const {
|
|
4211
|
+
namedCellStyleByName,
|
|
4212
|
+
sheetStatesByWorkbookSheetIndex,
|
|
4213
|
+
styleById,
|
|
4214
|
+
tableMetadataByWorkbookSheetIndex,
|
|
4215
|
+
tableStyleByName,
|
|
4216
|
+
themePalette
|
|
4217
|
+
} = parseWorkbookStructureAssetsFromArchive(archive, options);
|
|
4218
|
+
return {
|
|
4219
|
+
namedCellStyleByName,
|
|
4220
|
+
sheetStatesByWorkbookSheetIndex,
|
|
4221
|
+
styleById,
|
|
4222
|
+
tableMetadataByWorkbookSheetIndex,
|
|
4223
|
+
tableStyleByName,
|
|
4224
|
+
themePalette
|
|
4225
|
+
};
|
|
4226
|
+
}
|
|
4227
|
+
function parseWorkbookChartStyleAssets(bytes) {
|
|
4228
|
+
const archive = unzipSync(bytes);
|
|
4229
|
+
const {
|
|
4230
|
+
themePalette,
|
|
4231
|
+
workbookSheets
|
|
4232
|
+
} = parseWorkbookStructureAssetsFromArchive(archive);
|
|
4233
|
+
const sheetOrigins = [];
|
|
4234
|
+
workbookSheets.forEach((sheet, workbookSheetIndex) => {
|
|
4235
|
+
const sheetRelationships = parseRelationships(archive, relsPathForDocument(sheet.path), sheet.path);
|
|
4236
|
+
const attachments = [];
|
|
4237
|
+
for (const relationship of sheetRelationships.values()) {
|
|
4238
|
+
if (relationship.type !== DRAWING_REL_TYPE) {
|
|
4239
|
+
continue;
|
|
4240
|
+
}
|
|
4241
|
+
const drawingPath = relationship.target;
|
|
4242
|
+
const drawingRelsPath = relsPathForDocument(drawingPath);
|
|
4243
|
+
attachments.push({
|
|
4244
|
+
drawingPath,
|
|
4245
|
+
drawingRelsPath: archive[drawingRelsPath] ? drawingRelsPath : null,
|
|
4246
|
+
mediaPaths: []
|
|
4247
|
+
});
|
|
4248
|
+
}
|
|
4249
|
+
sheetOrigins[workbookSheetIndex] = attachments.length > 0 ? {
|
|
4250
|
+
attachments,
|
|
4251
|
+
workbookSheetIndex
|
|
4252
|
+
} : null;
|
|
4253
|
+
});
|
|
4254
|
+
return {
|
|
4255
|
+
archive,
|
|
4256
|
+
sheetOrigins,
|
|
4257
|
+
themePalette
|
|
4258
|
+
};
|
|
4259
|
+
}
|
|
4260
|
+
function resolveSheetColumnWidthPixels(width, columnWidthCharacterWidthPx) {
|
|
4261
|
+
return sheetColumnWidthToPixels(width, columnWidthCharacterWidthPx);
|
|
4262
|
+
}
|
|
4263
|
+
|
|
4264
|
+
// src/wasm.ts
|
|
4265
|
+
var wasmModulePromise = null;
|
|
4266
|
+
function getSheetsWasmModule() {
|
|
4267
|
+
if (!wasmModulePromise) {
|
|
4268
|
+
wasmModulePromise = import("@dukelib/sheets-wasm").then(async (mod) => {
|
|
4269
|
+
try {
|
|
4270
|
+
const wasmAsset = await import("@dukelib/sheets-wasm/duke_sheets_wasm_bg.wasm?url");
|
|
4271
|
+
await mod.default(wasmAsset.default);
|
|
4272
|
+
} catch {
|
|
4273
|
+
await mod.default();
|
|
4274
|
+
}
|
|
4275
|
+
return mod;
|
|
4276
|
+
});
|
|
4277
|
+
}
|
|
4278
|
+
return wasmModulePromise;
|
|
4279
|
+
}
|
|
4280
|
+
|
|
4281
|
+
// src/xlsx-worker.ts
|
|
4282
|
+
var DEFAULT_ROW_HEIGHT = 24;
|
|
4283
|
+
var DEFAULT_COL_WIDTH = 80;
|
|
4284
|
+
var DEFAULT_ZOOM_SCALE = 100;
|
|
4285
|
+
var FORMULA_COUNT_THRESHOLD = 1e3;
|
|
4286
|
+
var FAST_STRUCTURE_PARSE_THRESHOLD_BYTES = 5 * 1024 * 1024;
|
|
4287
|
+
var workbook = null;
|
|
4288
|
+
var chartsByWorkbookSheetIndex = [];
|
|
4289
|
+
var chartsheets = [];
|
|
4290
|
+
var sheets = [];
|
|
4291
|
+
var tablesByWorkbookSheetIndex = [];
|
|
4292
|
+
var tabs = [];
|
|
4293
|
+
function buildVisibleSheetIndexByWorkbookSheetIndex(nextWorkbook) {
|
|
4294
|
+
const mapping = /* @__PURE__ */ new Map();
|
|
4295
|
+
let visibleIndex = 0;
|
|
4296
|
+
for (let workbookSheetIndex = 0; workbookSheetIndex < nextWorkbook.sheetCount; workbookSheetIndex += 1) {
|
|
4297
|
+
const worksheet = nextWorkbook.getSheet(workbookSheetIndex);
|
|
4298
|
+
if (worksheet.visibility !== "visible") {
|
|
4299
|
+
continue;
|
|
4300
|
+
}
|
|
4301
|
+
mapping.set(workbookSheetIndex, visibleIndex);
|
|
4302
|
+
visibleIndex += 1;
|
|
4303
|
+
}
|
|
4304
|
+
return mapping;
|
|
4305
|
+
}
|
|
4306
|
+
function normalizeRange(range) {
|
|
4307
|
+
return {
|
|
4308
|
+
start: {
|
|
4309
|
+
col: Math.min(range.start.col, range.end.col),
|
|
4310
|
+
row: Math.min(range.start.row, range.end.row)
|
|
4311
|
+
},
|
|
4312
|
+
end: {
|
|
4313
|
+
col: Math.max(range.start.col, range.end.col),
|
|
4314
|
+
row: Math.max(range.start.row, range.end.row)
|
|
4315
|
+
}
|
|
4316
|
+
};
|
|
4317
|
+
}
|
|
4318
|
+
function parseA1CellReference2(reference) {
|
|
4319
|
+
const match = /^([A-Z]+)(\d+)$/i.exec(reference.trim());
|
|
4320
|
+
if (!match) {
|
|
4321
|
+
return null;
|
|
4322
|
+
}
|
|
4323
|
+
const [, columnPart, rowPart] = match;
|
|
4324
|
+
let col = 0;
|
|
4325
|
+
for (const char of columnPart.toUpperCase()) {
|
|
4326
|
+
col = col * 26 + (char.charCodeAt(0) - 64);
|
|
4327
|
+
}
|
|
4328
|
+
return {
|
|
4329
|
+
col: col - 1,
|
|
4330
|
+
row: Number(rowPart) - 1
|
|
4331
|
+
};
|
|
4332
|
+
}
|
|
4333
|
+
function parseA1RangeReference2(reference) {
|
|
4334
|
+
const [startRef, endRef = startRef] = reference.split(":");
|
|
4335
|
+
const start = parseA1CellReference2(startRef ?? "");
|
|
4336
|
+
const end = parseA1CellReference2(endRef ?? "");
|
|
4337
|
+
if (!start || !end) {
|
|
4338
|
+
return null;
|
|
4339
|
+
}
|
|
4340
|
+
return normalizeRange({ end, start });
|
|
4341
|
+
}
|
|
4342
|
+
function parseWorksheetFreezePanes(worksheet) {
|
|
4343
|
+
const rawFreezePanes = worksheet.freezePanes;
|
|
4344
|
+
const row = typeof rawFreezePanes?.row === "number" && rawFreezePanes.row >= 0 ? rawFreezePanes.row : null;
|
|
4345
|
+
const col = typeof rawFreezePanes?.col === "number" && rawFreezePanes.col >= 0 ? rawFreezePanes.col : null;
|
|
4346
|
+
if (row === null && col === null) {
|
|
4347
|
+
return null;
|
|
4348
|
+
}
|
|
4349
|
+
return {
|
|
4350
|
+
col: col ?? 0,
|
|
4351
|
+
row: row ?? 0
|
|
4352
|
+
};
|
|
4353
|
+
}
|
|
4354
|
+
function parseWorksheetDataValidations(worksheet) {
|
|
4355
|
+
const rawDataValidations = Array.isArray(worksheet.dataValidations) ? worksheet.dataValidations : [];
|
|
4356
|
+
return rawDataValidations.flatMap((entry) => {
|
|
4357
|
+
if (!entry || typeof entry !== "object") {
|
|
4358
|
+
return [];
|
|
4359
|
+
}
|
|
4360
|
+
const validation = entry;
|
|
4361
|
+
const ranges = Array.isArray(validation.ranges) ? validation.ranges.flatMap((range) => {
|
|
4362
|
+
if (typeof range !== "string") {
|
|
4363
|
+
return [];
|
|
4364
|
+
}
|
|
4365
|
+
const parsedRange = parseA1RangeReference2(range);
|
|
4366
|
+
return parsedRange ? [parsedRange] : [];
|
|
4367
|
+
}) : [];
|
|
4368
|
+
const validationType = typeof validation.validationType === "string" ? validation.validationType : null;
|
|
4369
|
+
if (!validationType || ranges.length === 0) {
|
|
4370
|
+
return [];
|
|
4371
|
+
}
|
|
4372
|
+
return [{
|
|
4373
|
+
allowBlank: typeof validation.allowBlank === "boolean" ? validation.allowBlank : void 0,
|
|
4374
|
+
errorMessage: typeof validation.errorMessage === "string" ? validation.errorMessage : void 0,
|
|
4375
|
+
errorStyle: typeof validation.errorStyle === "string" ? validation.errorStyle : void 0,
|
|
4376
|
+
inputMessage: typeof validation.inputMessage === "string" ? validation.inputMessage : void 0,
|
|
4377
|
+
listSource: typeof validation.listSource === "string" ? validation.listSource : void 0,
|
|
4378
|
+
ranges,
|
|
4379
|
+
showDropdown: typeof validation.showDropdown === "boolean" ? validation.showDropdown : void 0,
|
|
4380
|
+
showErrorAlert: typeof validation.showErrorAlert === "boolean" ? validation.showErrorAlert : void 0,
|
|
4381
|
+
showInputMessage: typeof validation.showInputMessage === "boolean" ? validation.showInputMessage : void 0,
|
|
4382
|
+
validationType
|
|
4383
|
+
}];
|
|
4384
|
+
});
|
|
4385
|
+
}
|
|
4386
|
+
function resolveWorksheetZoomScale(worksheet, sheetState) {
|
|
4387
|
+
const candidates = [
|
|
4388
|
+
sheetState?.zoomScale,
|
|
4389
|
+
typeof worksheet.zoomScale === "number" ? worksheet.zoomScale : void 0
|
|
4390
|
+
];
|
|
4391
|
+
const value = candidates.find((entry) => typeof entry === "number" && Number.isFinite(entry) && entry > 0);
|
|
4392
|
+
return value ?? DEFAULT_ZOOM_SCALE;
|
|
4393
|
+
}
|
|
4394
|
+
function buildSheetList(nextWorkbook, structureAssets) {
|
|
4395
|
+
const sheetsByWorkbookSheetIndex = [];
|
|
4396
|
+
for (let index = 0; index < nextWorkbook.sheetCount; index += 1) {
|
|
4397
|
+
const worksheet = nextWorkbook.getSheet(index);
|
|
4398
|
+
const sheetState = structureAssets?.sheetStatesByWorkbookSheetIndex[index] ?? null;
|
|
4399
|
+
if (worksheet.visibility !== "visible") {
|
|
4400
|
+
continue;
|
|
4401
|
+
}
|
|
4402
|
+
const resolveColumnWidthPx = (col) => {
|
|
4403
|
+
const width = worksheet.getColumnWidth(col);
|
|
4404
|
+
if (width !== void 0 && width !== null) {
|
|
4405
|
+
return resolveSheetColumnWidthPixels(width, sheetState?.columnWidthCharacterWidthPx);
|
|
4406
|
+
}
|
|
4407
|
+
return sheetState?.colWidthOverridesPx?.[col] ?? sheetState?.defaultColWidthPx ?? DEFAULT_COL_WIDTH;
|
|
4408
|
+
};
|
|
4409
|
+
const resolveRowHeightPx = (row) => {
|
|
4410
|
+
const height = worksheet.getRowHeight(row);
|
|
4411
|
+
if (height !== void 0 && height !== null) {
|
|
4412
|
+
return Math.max(Math.round(height * 1.33), 16);
|
|
4413
|
+
}
|
|
4414
|
+
return sheetState?.rowHeightOverridesPx?.[row] ?? sheetState?.defaultRowHeightPx ?? DEFAULT_ROW_HEIGHT;
|
|
4415
|
+
};
|
|
4416
|
+
const usedRange = worksheet.usedRange();
|
|
4417
|
+
if (!usedRange) {
|
|
4418
|
+
sheetsByWorkbookSheetIndex.push({
|
|
4419
|
+
cachedFormulaValues: sheetState?.cachedFormulaValues ?? {},
|
|
4420
|
+
columnWidthCharacterWidthPx: sheetState?.columnWidthCharacterWidthPx,
|
|
4421
|
+
colCount: 0,
|
|
4422
|
+
colStyleIds: sheetState?.colStyleIds ?? {},
|
|
4423
|
+
colWidthOverridesPx: sheetState?.colWidthOverridesPx ?? {},
|
|
4424
|
+
colWidths: [],
|
|
4425
|
+
conditionalFormatRules: sheetState?.conditionalFormatRules ?? [],
|
|
4426
|
+
dataValidations: parseWorksheetDataValidations(worksheet),
|
|
4427
|
+
defaultColWidthPx: sheetState?.defaultColWidthPx ?? DEFAULT_COL_WIDTH,
|
|
4428
|
+
defaultRowHeightPx: sheetState?.defaultRowHeightPx ?? DEFAULT_ROW_HEIGHT,
|
|
4429
|
+
freezePanes: parseWorksheetFreezePanes(worksheet),
|
|
4430
|
+
hasHorizontalMerges: sheetState?.hasHorizontalMerges ?? false,
|
|
4431
|
+
hasVerticalMerges: sheetState?.hasVerticalMerges ?? false,
|
|
4432
|
+
maxHorizontalMergeEndCol: sheetState?.maxHorizontalMergeEndCol ?? -1,
|
|
4433
|
+
maxVerticalMergeEndRow: sheetState?.maxVerticalMergeEndRow ?? -1,
|
|
4434
|
+
hiddenCols: sheetState?.hiddenCols ?? [],
|
|
4435
|
+
hiddenRows: sheetState?.hiddenRows ?? [],
|
|
4436
|
+
maxUsedCol: -1,
|
|
4437
|
+
maxUsedRow: -1,
|
|
4438
|
+
name: worksheet.name,
|
|
4439
|
+
namedCellStyleByName: structureAssets?.namedCellStyleByName ?? {},
|
|
4440
|
+
rowCount: 0,
|
|
4441
|
+
rowHeightOverridesPx: sheetState?.rowHeightOverridesPx ?? {},
|
|
4442
|
+
rowHeights: [],
|
|
4443
|
+
rowStyleIds: sheetState?.rowStyleIds ?? {},
|
|
4444
|
+
showGridLines: sheetState?.showGridLines ?? true,
|
|
4445
|
+
sparklines: sheetState?.sparklines ?? [],
|
|
4446
|
+
styleById: structureAssets?.styleById ?? {},
|
|
4447
|
+
tableStyleByName: structureAssets?.tableStyleByName ?? {},
|
|
4448
|
+
themePalette: structureAssets?.themePalette ?? { colorsByIndex: {} },
|
|
4449
|
+
visibleCols: [],
|
|
4450
|
+
visibleRows: [],
|
|
4451
|
+
workbookSheetIndex: index,
|
|
4452
|
+
zoomScale: resolveWorksheetZoomScale(worksheet, sheetState)
|
|
4453
|
+
});
|
|
4454
|
+
continue;
|
|
4455
|
+
}
|
|
4456
|
+
const [, , maxRow, maxCol] = usedRange;
|
|
4457
|
+
const hiddenRows = (sheetState?.hiddenRows ?? []).filter((row) => row >= 0 && row <= maxRow);
|
|
4458
|
+
const hiddenCols = (sheetState?.hiddenCols ?? []).filter((col) => col >= 0 && col <= maxCol);
|
|
4459
|
+
sheetsByWorkbookSheetIndex.push({
|
|
4460
|
+
cachedFormulaValues: sheetState?.cachedFormulaValues ?? {},
|
|
4461
|
+
columnWidthCharacterWidthPx: sheetState?.columnWidthCharacterWidthPx,
|
|
4462
|
+
colCount: Math.max(0, maxCol + 1 - hiddenCols.length),
|
|
4463
|
+
colStyleIds: sheetState?.colStyleIds ?? {},
|
|
4464
|
+
colWidthOverridesPx: sheetState?.colWidthOverridesPx ?? {},
|
|
4465
|
+
colWidths: [],
|
|
4466
|
+
conditionalFormatRules: sheetState?.conditionalFormatRules ?? [],
|
|
4467
|
+
dataValidations: parseWorksheetDataValidations(worksheet),
|
|
4468
|
+
defaultColWidthPx: sheetState?.defaultColWidthPx ?? DEFAULT_COL_WIDTH,
|
|
4469
|
+
defaultRowHeightPx: sheetState?.defaultRowHeightPx ?? DEFAULT_ROW_HEIGHT,
|
|
4470
|
+
freezePanes: parseWorksheetFreezePanes(worksheet),
|
|
4471
|
+
hasHorizontalMerges: sheetState?.hasHorizontalMerges ?? false,
|
|
4472
|
+
hasVerticalMerges: sheetState?.hasVerticalMerges ?? false,
|
|
4473
|
+
maxHorizontalMergeEndCol: sheetState?.maxHorizontalMergeEndCol ?? -1,
|
|
4474
|
+
maxVerticalMergeEndRow: sheetState?.maxVerticalMergeEndRow ?? -1,
|
|
4475
|
+
hiddenCols,
|
|
4476
|
+
hiddenRows,
|
|
4477
|
+
maxUsedCol: maxCol,
|
|
4478
|
+
maxUsedRow: maxRow,
|
|
4479
|
+
name: worksheet.name,
|
|
4480
|
+
namedCellStyleByName: structureAssets?.namedCellStyleByName ?? {},
|
|
4481
|
+
rowCount: Math.max(0, maxRow + 1 - hiddenRows.length),
|
|
4482
|
+
rowHeightOverridesPx: sheetState?.rowHeightOverridesPx ?? {},
|
|
4483
|
+
rowHeights: [],
|
|
4484
|
+
rowStyleIds: sheetState?.rowStyleIds ?? {},
|
|
4485
|
+
showGridLines: sheetState?.showGridLines ?? true,
|
|
4486
|
+
sparklines: sheetState?.sparklines ?? [],
|
|
4487
|
+
styleById: structureAssets?.styleById ?? {},
|
|
4488
|
+
tableStyleByName: structureAssets?.tableStyleByName ?? {},
|
|
4489
|
+
themePalette: structureAssets?.themePalette ?? { colorsByIndex: {} },
|
|
4490
|
+
visibleCols: [],
|
|
4491
|
+
visibleRows: [],
|
|
4492
|
+
workbookSheetIndex: index,
|
|
4493
|
+
zoomScale: resolveWorksheetZoomScale(worksheet, sheetState)
|
|
4494
|
+
});
|
|
4495
|
+
}
|
|
4496
|
+
return sheetsByWorkbookSheetIndex;
|
|
4497
|
+
}
|
|
4498
|
+
function mapWorksheetTables(worksheet, metadataForSheet) {
|
|
4499
|
+
const rawTables = worksheet?.tables ?? [];
|
|
4500
|
+
return rawTables.flatMap((table, index) => {
|
|
4501
|
+
const reference = typeof table.reference === "string" ? table.reference : "";
|
|
4502
|
+
const parsedRange = parseA1RangeReference2(reference);
|
|
4503
|
+
if (!parsedRange) {
|
|
4504
|
+
return [];
|
|
4505
|
+
}
|
|
4506
|
+
const rawColumns = Array.isArray(table.columns) ? table.columns : [];
|
|
4507
|
+
const rawName = typeof table.name === "string" ? table.name : `Table${index + 1}`;
|
|
4508
|
+
const rawDisplayName = typeof table.displayName === "string" ? table.displayName : typeof table.name === "string" ? table.name : `Table ${index + 1}`;
|
|
4509
|
+
const metadata = metadataForSheet?.find(
|
|
4510
|
+
(entry) => entry.name && entry.name === rawName || entry.displayName && entry.displayName === rawDisplayName || entry.reference && entry.reference === reference
|
|
4511
|
+
);
|
|
4512
|
+
return [{
|
|
4513
|
+
columns: rawColumns.map((column, columnIndex) => ({
|
|
4514
|
+
id: typeof column.id === "number" ? column.id ?? columnIndex + 1 : columnIndex + 1,
|
|
4515
|
+
index: columnIndex,
|
|
4516
|
+
name: typeof column.name === "string" ? column.name ?? `Column ${columnIndex + 1}` : `Column ${columnIndex + 1}`
|
|
4517
|
+
})),
|
|
4518
|
+
displayName: rawDisplayName,
|
|
4519
|
+
end: parsedRange.end,
|
|
4520
|
+
headerRowCount: typeof table.headerRowCount === "number" ? table.headerRowCount : 1,
|
|
4521
|
+
headerRowCellStyle: metadata?.headerRowCellStyle,
|
|
4522
|
+
name: rawName,
|
|
4523
|
+
reference,
|
|
4524
|
+
start: parsedRange.start,
|
|
4525
|
+
styleInfo: table.styleInfo,
|
|
4526
|
+
totalsRowCount: typeof table.totalsRowCount === "number" ? table.totalsRowCount : 0,
|
|
4527
|
+
totalsRowShown: Boolean(table.totalsRowShown)
|
|
4528
|
+
}];
|
|
4529
|
+
});
|
|
4530
|
+
}
|
|
4531
|
+
function decodeHtmlEntities(value) {
|
|
4532
|
+
return value.replace(/"/g, '"').replace(/"/g, '"').replace(/'/g, "'").replace(/'/g, "'").replace(/</g, "<").replace(/>/g, ">").replace(/&/g, "&");
|
|
4533
|
+
}
|
|
4534
|
+
function getCellDisplayValue(worksheet, row, col, activeSheet) {
|
|
4535
|
+
const formula = worksheet.getFormulaAt(row, col);
|
|
4536
|
+
const cachedFormulaValue = formula ? activeSheet?.cachedFormulaValues?.[cellAddressToA1({ row, col })] : void 0;
|
|
4537
|
+
const formatted = worksheet.getFormattedValueAt(row, col);
|
|
4538
|
+
if (formatted && !(formula && cachedFormulaValue !== void 0 && formatted.startsWith("#"))) {
|
|
4539
|
+
return decodeHtmlEntities(formatted);
|
|
4540
|
+
}
|
|
4541
|
+
const cellValue = worksheet.getCalculatedValueAt(row, col);
|
|
4542
|
+
if (formula && cachedFormulaValue !== void 0 && cellValue.is_error) {
|
|
4543
|
+
return cachedFormulaValue;
|
|
4544
|
+
}
|
|
4545
|
+
if (cellValue.is_error) {
|
|
4546
|
+
return cellValue.asError() ?? "";
|
|
4547
|
+
}
|
|
4548
|
+
if (cellValue.is_empty) {
|
|
4549
|
+
return "";
|
|
4550
|
+
}
|
|
4551
|
+
return cellValue.toString();
|
|
4552
|
+
}
|
|
4553
|
+
function cellAddressToA1(cell) {
|
|
4554
|
+
let col = cell.col + 1;
|
|
4555
|
+
let label = "";
|
|
4556
|
+
while (col > 0) {
|
|
4557
|
+
const remainder = (col - 1) % 26;
|
|
4558
|
+
label = String.fromCharCode(65 + remainder) + label;
|
|
4559
|
+
col = Math.floor((col - 1) / 26);
|
|
4560
|
+
}
|
|
4561
|
+
return `${label}${cell.row + 1}`;
|
|
4562
|
+
}
|
|
4563
|
+
async function loadWorkbook(buffer) {
|
|
4564
|
+
const wasmModule = await getSheetsWasmModule();
|
|
4565
|
+
const bytes = new Uint8Array(buffer);
|
|
4566
|
+
const nextWorkbook = wasmModule.Workbook.fromBytes(bytes);
|
|
4567
|
+
let totalFormulas = 0;
|
|
4568
|
+
for (let index = 0; index < nextWorkbook.sheetCount; index += 1) {
|
|
4569
|
+
totalFormulas += nextWorkbook.getSheet(index).formulaCount;
|
|
4570
|
+
}
|
|
4571
|
+
if (totalFormulas <= FORMULA_COUNT_THRESHOLD) {
|
|
4572
|
+
nextWorkbook.calculate();
|
|
4573
|
+
}
|
|
4574
|
+
const shouldUseFastStructureParse = bytes.byteLength >= FAST_STRUCTURE_PARSE_THRESHOLD_BYTES && totalFormulas <= FORMULA_COUNT_THRESHOLD;
|
|
4575
|
+
const structureAssets = shouldUseFastStructureParse ? null : parseWorkbookStructureAssets(bytes, {
|
|
4576
|
+
includeCachedFormulaValues: true
|
|
4577
|
+
});
|
|
4578
|
+
workbook = nextWorkbook;
|
|
4579
|
+
sheets = buildSheetList(nextWorkbook, structureAssets);
|
|
4580
|
+
tablesByWorkbookSheetIndex = Array.from(
|
|
4581
|
+
{ length: nextWorkbook.sheetCount },
|
|
4582
|
+
(_, workbookSheetIndex) => mapWorksheetTables(
|
|
4583
|
+
nextWorkbook.getSheet(workbookSheetIndex),
|
|
4584
|
+
structureAssets?.tableMetadataByWorkbookSheetIndex[workbookSheetIndex] ?? null
|
|
4585
|
+
)
|
|
4586
|
+
);
|
|
4587
|
+
const visibleSheetIndexByWorkbookSheetIndex = new Map(sheets.map((sheet, index) => [sheet.workbookSheetIndex, index]));
|
|
4588
|
+
const hasCharts = Array.from({ length: nextWorkbook.sheetCount }, (_, workbookSheetIndex) => {
|
|
4589
|
+
const worksheet = nextWorkbook.getSheet(workbookSheetIndex);
|
|
4590
|
+
const hasClassicCharts = Array.isArray(worksheet.charts) && worksheet.charts.length > 0;
|
|
4591
|
+
const hasModernCharts = Array.isArray(worksheet.chartsEx) && worksheet.chartsEx.length > 0;
|
|
4592
|
+
return hasClassicCharts || hasModernCharts;
|
|
4593
|
+
}).some(Boolean);
|
|
4594
|
+
const chartStyleAssets = hasCharts ? parseWorkbookChartStyleAssets(bytes) : null;
|
|
4595
|
+
const chartAssets = loadWorkbookChartAssets(nextWorkbook, chartStyleAssets, visibleSheetIndexByWorkbookSheetIndex);
|
|
4596
|
+
chartsByWorkbookSheetIndex = chartAssets.chartsByWorkbookSheetIndex;
|
|
4597
|
+
chartsheets = chartAssets.chartsheets;
|
|
4598
|
+
tabs = chartAssets.tabs;
|
|
4599
|
+
return {
|
|
4600
|
+
chartsByWorkbookSheetIndex,
|
|
4601
|
+
chartsheets,
|
|
4602
|
+
sheets,
|
|
4603
|
+
tablesByWorkbookSheetIndex,
|
|
4604
|
+
tabs
|
|
4605
|
+
};
|
|
4606
|
+
}
|
|
4607
|
+
async function parseCharts(buffer) {
|
|
4608
|
+
const wasmModule = await getSheetsWasmModule();
|
|
4609
|
+
const bytes = new Uint8Array(buffer);
|
|
4610
|
+
const nextWorkbook = wasmModule.Workbook.fromBytes(bytes);
|
|
4611
|
+
let totalFormulas = 0;
|
|
4612
|
+
for (let index = 0; index < nextWorkbook.sheetCount; index += 1) {
|
|
4613
|
+
totalFormulas += nextWorkbook.getSheet(index).formulaCount;
|
|
4614
|
+
}
|
|
4615
|
+
if (totalFormulas <= FORMULA_COUNT_THRESHOLD) {
|
|
4616
|
+
nextWorkbook.calculate();
|
|
4617
|
+
}
|
|
4618
|
+
const visibleSheetIndexByWorkbookSheetIndex = buildVisibleSheetIndexByWorkbookSheetIndex(nextWorkbook);
|
|
4619
|
+
const chartStyleAssets = parseWorkbookChartStyleAssets(bytes);
|
|
4620
|
+
const chartAssets = loadWorkbookChartAssets(nextWorkbook, chartStyleAssets, visibleSheetIndexByWorkbookSheetIndex);
|
|
4621
|
+
return {
|
|
4622
|
+
chartsByWorkbookSheetIndex: chartAssets.chartsByWorkbookSheetIndex,
|
|
4623
|
+
chartsheets: chartAssets.chartsheets,
|
|
4624
|
+
tabs: chartAssets.tabs
|
|
4625
|
+
};
|
|
4626
|
+
}
|
|
4627
|
+
function respond(message) {
|
|
4628
|
+
self.postMessage(message);
|
|
4629
|
+
}
|
|
4630
|
+
async function handleMessage(message) {
|
|
4631
|
+
switch (message.type) {
|
|
4632
|
+
case "load": {
|
|
4633
|
+
return loadWorkbook(message.payload.buffer);
|
|
4634
|
+
}
|
|
4635
|
+
case "parseCharts": {
|
|
4636
|
+
return parseCharts(message.payload.buffer);
|
|
4637
|
+
}
|
|
4638
|
+
case "getCellSnapshot": {
|
|
4639
|
+
if (!workbook) {
|
|
4640
|
+
return {
|
|
4641
|
+
displayValue: "",
|
|
4642
|
+
formula: ""
|
|
4643
|
+
};
|
|
4644
|
+
}
|
|
4645
|
+
const targetSheet = sheets.find((sheet) => sheet.workbookSheetIndex === message.payload.workbookSheetIndex) ?? null;
|
|
4646
|
+
const worksheet = workbook.getSheet(message.payload.workbookSheetIndex);
|
|
4647
|
+
return {
|
|
4648
|
+
displayValue: getCellDisplayValue(worksheet, message.payload.row, message.payload.col, targetSheet),
|
|
4649
|
+
formula: worksheet.getFormulaAt(message.payload.row, message.payload.col) ?? ""
|
|
4650
|
+
};
|
|
4651
|
+
}
|
|
4652
|
+
case "getRowsBatch": {
|
|
4653
|
+
if (!workbook) {
|
|
4654
|
+
return null;
|
|
4655
|
+
}
|
|
4656
|
+
const worksheet = workbook.getSheet(message.payload.workbookSheetIndex);
|
|
4657
|
+
if (typeof worksheet.getRowsBatch !== "function") {
|
|
4658
|
+
return null;
|
|
4659
|
+
}
|
|
4660
|
+
return worksheet.getRowsBatch(message.payload.startRow, message.payload.rowCount, {
|
|
4661
|
+
includeFormulas: true,
|
|
4662
|
+
includeHyperlinks: true,
|
|
4663
|
+
includeMergeInfo: true,
|
|
4664
|
+
includeStyles: true,
|
|
4665
|
+
useFormattedValues: true
|
|
4666
|
+
});
|
|
4667
|
+
}
|
|
4668
|
+
default:
|
|
4669
|
+
return null;
|
|
4670
|
+
}
|
|
4671
|
+
}
|
|
4672
|
+
self.addEventListener("message", (event) => {
|
|
4673
|
+
const message = event.data;
|
|
4674
|
+
void handleMessage(message).then((result) => {
|
|
4675
|
+
respond({
|
|
4676
|
+
id: message.id,
|
|
4677
|
+
result,
|
|
4678
|
+
success: true
|
|
4679
|
+
});
|
|
4680
|
+
}).catch((error) => {
|
|
4681
|
+
respond({
|
|
4682
|
+
error: error instanceof Error ? error.message : "Worker request failed.",
|
|
4683
|
+
id: message.id,
|
|
4684
|
+
success: false
|
|
4685
|
+
});
|
|
4686
|
+
});
|
|
4687
|
+
});
|
|
4688
|
+
//# sourceMappingURL=xlsx-worker.js.map
|