ooxml-core 1.17.0 → 1.19.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{PptxHandler-K7GMS2ST.mjs → PptxHandler-5GBBVJCR.mjs} +2 -2
- package/dist/{PptxHandler-L3JPWOBN.mjs → PptxHandler-H43MAMTO.mjs} +1 -1
- package/dist/{PptxHandler-U6EFO73T.cjs → PptxHandler-ZHPGBSAF.cjs} +2 -2
- package/dist/{PresentationBuilder-XC3F3OPY.mjs → PresentationBuilder-7ZSUKCX5.mjs} +1 -1
- package/dist/{PresentationBuilder-OK526SZ4.mjs → PresentationBuilder-IJW42L3R.mjs} +2 -2
- package/dist/{PresentationBuilder-LUR6LGHU.cjs → PresentationBuilder-O4H4MMWB.cjs} +4 -4
- package/dist/automation/index.cjs +5198 -3235
- package/dist/automation/index.mjs +5198 -3235
- package/dist/chart/axis-range-auto.d.ts +10 -0
- package/dist/chart/axis-range-auto.d.ts.map +1 -0
- package/dist/chart/axis-range-types.d.ts +27 -0
- package/dist/chart/axis-range-types.d.ts.map +1 -0
- package/dist/chart/axis-range.d.ts +37 -0
- package/dist/chart/axis-range.d.ts.map +1 -0
- package/dist/chart/axis-ticks.d.ts +8 -0
- package/dist/chart/axis-ticks.d.ts.map +1 -0
- package/dist/chart/data-label-text.d.ts +70 -0
- package/dist/chart/data-label-text.d.ts.map +1 -0
- package/dist/chart/formatting-nodes.d.ts +6 -0
- package/dist/chart/formatting-nodes.d.ts.map +1 -1
- package/dist/chart/index.cjs +1536 -571
- package/dist/chart/index.d.ts +7 -0
- package/dist/chart/index.d.ts.map +1 -1
- package/dist/chart/index.mjs +1512 -572
- package/dist/chart/line-dash.d.ts +2 -0
- package/dist/chart/line-dash.d.ts.map +1 -0
- package/dist/chart/marker-shape.d.ts +70 -0
- package/dist/chart/marker-shape.d.ts.map +1 -0
- package/dist/chart/read-formatting.d.ts.map +1 -1
- package/dist/chart/render/chart-svg-axes.d.ts +9 -0
- package/dist/chart/render/chart-svg-axes.d.ts.map +1 -0
- package/dist/chart/render/chart-svg-bars.d.ts.map +1 -1
- package/dist/chart/render/chart-svg-cartesian.d.ts.map +1 -1
- package/dist/chart/render/chart-svg-labels.d.ts +42 -0
- package/dist/chart/render/chart-svg-labels.d.ts.map +1 -0
- package/dist/chart/render/chart-svg-markers.d.ts +6 -0
- package/dist/chart/render/chart-svg-markers.d.ts.map +1 -0
- package/dist/chart/render/chart-svg-radial.d.ts.map +1 -1
- package/dist/chart/render/chart-svg-xy.d.ts.map +1 -1
- package/dist/chart/render/chart-view-axes.d.ts +30 -0
- package/dist/chart/render/chart-view-axes.d.ts.map +1 -0
- package/dist/chart/render/chart-view-labels.d.ts +16 -0
- package/dist/chart/render/chart-view-labels.d.ts.map +1 -0
- package/dist/chart/render/chart-view-markers.d.ts +27 -0
- package/dist/chart/render/chart-view-markers.d.ts.map +1 -0
- package/dist/chart/render/chart-view-series.d.ts.map +1 -1
- package/dist/chart/render/chart-view.d.ts +7 -1
- package/dist/chart/render/chart-view.d.ts.map +1 -1
- package/dist/chart/render/index.d.ts +2 -0
- package/dist/chart/render/index.d.ts.map +1 -1
- package/dist/chart/render/summary-from-space.d.ts +2 -2
- package/dist/chart/render/summary-from-space.d.ts.map +1 -1
- package/dist/chart/render/summary-labels.d.ts +9 -0
- package/dist/chart/render/summary-labels.d.ts.map +1 -0
- package/dist/chart/render/summary.d.ts +29 -1
- package/dist/chart/render/summary.d.ts.map +1 -1
- package/dist/{chunk-IM5LFEA2.mjs → chunk-3XFPCZKB.mjs} +1 -1
- package/dist/{chunk-YS43OMM3.mjs → chunk-75GLSRZE.mjs} +4 -4
- package/dist/{chunk-A7S2NYAU.mjs → chunk-BIVNVDAH.mjs} +1 -1
- package/dist/{chunk-UFGJNXRG.mjs → chunk-QBJRB6WW.mjs} +1 -1
- package/dist/{chunk-HLZIALC5.mjs → chunk-RUZEMWDI.mjs} +1 -1
- package/dist/docx/embedded.cjs +15 -0
- package/dist/docx/embedded.mjs +15 -0
- package/dist/docx/index.cjs +1825 -693
- package/dist/docx/index.mjs +1825 -693
- package/dist/docx/layout/index.cjs +1684 -567
- package/dist/docx/layout/index.mjs +1684 -567
- package/dist/docx/load/index.cjs +15 -0
- package/dist/docx/load/index.mjs +15 -0
- package/dist/docx/ui/index.cjs +1696 -579
- package/dist/docx/ui/index.mjs +1696 -579
- package/dist/index.cjs +1623 -658
- package/dist/index.mjs +1623 -658
- package/dist/pptx/automation/index.cjs +61 -0
- package/dist/pptx/automation/index.mjs +5 -5
- package/dist/pptx/cli/index.cjs +61 -0
- package/dist/pptx/cli/index.mjs +4 -4
- package/dist/pptx/converter/index.mjs +2 -2
- package/dist/pptx/editor/render/slide-operations.cjs +1 -1
- package/dist/pptx/editor/render/slide-operations.mjs +1 -1
- package/dist/pptx/index.cjs +61 -0
- package/dist/pptx/index.mjs +5 -5
- package/dist/teams/index.cjs +212 -50
- package/dist/teams/index.mjs +212 -50
- package/dist/visio/edit-chart-object-commands.d.ts +36 -0
- package/dist/visio/edit-chart-object-commands.d.ts.map +1 -0
- package/dist/visio/edit-chart-object.d.ts +7 -0
- package/dist/visio/edit-chart-object.d.ts.map +1 -0
- package/dist/visio/edit-commands.d.ts +2 -1
- package/dist/visio/edit-commands.d.ts.map +1 -1
- package/dist/visio/edit-foreign-frame.d.ts +8 -0
- package/dist/visio/edit-foreign-frame.d.ts.map +1 -0
- package/dist/visio/edit-metadata-commands.d.ts +7 -0
- package/dist/visio/edit-metadata-commands.d.ts.map +1 -1
- package/dist/visio/edit-picture.d.ts +8 -0
- package/dist/visio/edit-picture.d.ts.map +1 -1
- package/dist/visio/edit.d.ts.map +1 -1
- package/dist/visio/emf-bitmap.d.ts +8 -0
- package/dist/visio/emf-bitmap.d.ts.map +1 -0
- package/dist/visio/index.cjs +17505 -6279
- package/dist/visio/index.d.ts +2 -0
- package/dist/visio/index.d.ts.map +1 -1
- package/dist/visio/index.mjs +17503 -6280
- package/dist/visio/model.d.ts +18 -0
- package/dist/visio/model.d.ts.map +1 -1
- package/dist/visio/prepare-embedded.d.ts +10 -0
- package/dist/visio/prepare-embedded.d.ts.map +1 -0
- package/dist/visio/prepare-images.d.ts.map +1 -1
- package/dist/visio/shapes.d.ts.map +1 -1
- package/dist/visio/sheet.d.ts +2 -1
- package/dist/visio/sheet.d.ts.map +1 -1
- package/dist/visio/ui/edit-commands.d.ts.map +1 -1
- package/dist/visio/ui/index.cjs +33580 -22875
- package/dist/visio/ui/index.mjs +33578 -22875
- package/dist/visio/ui/insert.d.ts +11 -0
- package/dist/visio/ui/insert.d.ts.map +1 -1
- package/dist/xlsx/edit/chart-colors.d.ts.map +1 -1
- package/dist/xlsx/index.cjs +1965 -817
- package/dist/xlsx/index.mjs +1965 -817
- package/dist/xlsx/load/index.cjs +190 -51
- package/dist/xlsx/load/index.mjs +190 -51
- package/dist/xlsx/model.d.ts +5 -0
- package/dist/xlsx/model.d.ts.map +1 -1
- package/dist/xlsx/read/chart.d.ts.map +1 -1
- package/dist/xlsx/read/load.d.ts.map +1 -1
- package/dist/xlsx/read/workbook-part.d.ts +2 -0
- package/dist/xlsx/read/workbook-part.d.ts.map +1 -1
- package/dist/xlsx/ui/dialogs/grid-chart.d.ts +22 -1
- package/dist/xlsx/ui/dialogs/grid-chart.d.ts.map +1 -1
- package/dist/xlsx/ui/index.cjs +17482 -4364
- package/dist/xlsx/ui/index.mjs +17472 -4362
- package/dist/xlsx/write/workbook-part.d.ts.map +1 -1
- package/package.json +1 -1
- package/dist/visio/edit-foreign-bitmap.d.ts +0 -7
- package/dist/visio/edit-foreign-bitmap.d.ts.map +0 -1
- /package/dist/{chunk-KU3SMBFU.mjs → chunk-H6TNNXJK.mjs} +0 -0
- /package/dist/{chunk-UWWS6VVJ.cjs → chunk-MHMVD23Y.cjs} +0 -0
|
@@ -48,17 +48,17 @@ function checkXmlLimits(xml, label, limits = {}) {
|
|
|
48
48
|
throw new Error(`${label} XML exceeds the nesting depth limit of ${maxDepth}`);
|
|
49
49
|
}
|
|
50
50
|
}
|
|
51
|
-
function parseXml(xml,
|
|
52
|
-
const label =
|
|
51
|
+
function parseXml(xml, options2 = {}) {
|
|
52
|
+
const label = options2.label ?? "OOXML";
|
|
53
53
|
if (/<!DOCTYPE|<!ENTITY/i.test(xml))
|
|
54
54
|
throw new Error(`${label} XML with DTD or entity declarations is not supported`);
|
|
55
|
-
checkXmlLimits(xml, label,
|
|
55
|
+
checkXmlLimits(xml, label, options2.limits);
|
|
56
56
|
let parseError = "";
|
|
57
57
|
let parsed;
|
|
58
58
|
try {
|
|
59
59
|
parsed = new DOMParser({
|
|
60
|
-
onError: (
|
|
61
|
-
if (
|
|
60
|
+
onError: (level2, message) => {
|
|
61
|
+
if (level2 !== "warning") parseError = message;
|
|
62
62
|
}
|
|
63
63
|
}).parseFromString(xml, "application/xml");
|
|
64
64
|
} catch (error) {
|
|
@@ -728,8 +728,8 @@ function resolveRunFormatting(run, context = {}) {
|
|
|
728
728
|
if (state) result[key] = true;
|
|
729
729
|
}
|
|
730
730
|
for (const key of OVERRIDE_KEYS) {
|
|
731
|
-
for (const
|
|
732
|
-
const value =
|
|
731
|
+
for (const level2 of levels) {
|
|
732
|
+
const value = level2[key];
|
|
733
733
|
if (value !== void 0) result[key] = value;
|
|
734
734
|
}
|
|
735
735
|
}
|
|
@@ -802,8 +802,8 @@ function rgbToHsl(r, g, b) {
|
|
|
802
802
|
}
|
|
803
803
|
return { h, s: clampUnitInterval(s), l: clampUnitInterval(l) };
|
|
804
804
|
}
|
|
805
|
-
function hslToRgb(h, s, l, roundChannel = Math.round,
|
|
806
|
-
const sC =
|
|
805
|
+
function hslToRgb(h, s, l, roundChannel = Math.round, options2) {
|
|
806
|
+
const sC = options2?.clampSaturation === false ? s : clampUnitInterval(s);
|
|
807
807
|
const lC = clampUnitInterval(l);
|
|
808
808
|
const hN = (h % 360 + 360) % 360;
|
|
809
809
|
const c = (1 - Math.abs(2 * lC - 1)) * sC;
|
|
@@ -1292,13 +1292,13 @@ var APPLIED = /* @__PURE__ */ new Set([
|
|
|
1292
1292
|
"lumMod",
|
|
1293
1293
|
"lumOff"
|
|
1294
1294
|
]);
|
|
1295
|
-
function resolveDrawingColor(color, theme,
|
|
1295
|
+
function resolveDrawingColor(color, theme, options2) {
|
|
1296
1296
|
const base = baseHex(color, theme);
|
|
1297
1297
|
const rgb = base ? hexToRgbChannels(base) : null;
|
|
1298
1298
|
if (!rgb) return void 0;
|
|
1299
|
-
if (
|
|
1299
|
+
if (options2?.transformOrder === "document") {
|
|
1300
1300
|
const value = orderedColorTransforms(rgb, color.transforms);
|
|
1301
|
-
const round3 =
|
|
1301
|
+
const round3 = options2.hslRounding === "halfDown" ? (channel) => Math.ceil(channel - 0.5) : Math.round;
|
|
1302
1302
|
return {
|
|
1303
1303
|
hex: `#${toHex(round3(value.r))}${toHex(round3(value.g))}${toHex(round3(value.b))}`,
|
|
1304
1304
|
alpha: value.alpha,
|
|
@@ -1349,7 +1349,7 @@ function resolveDrawingColor(color, theme, options) {
|
|
|
1349
1349
|
if (lumMod !== void 0) hsl.l = clampUnitInterval(hsl.l * lumMod);
|
|
1350
1350
|
const lumOff = parseDrawingFraction(find("lumOff"));
|
|
1351
1351
|
if (lumOff !== void 0) hsl.l = clampUnitInterval(hsl.l + lumOff);
|
|
1352
|
-
const round3 =
|
|
1352
|
+
const round3 = options2?.hslRounding === "halfDown" ? (value) => Math.ceil(value - 0.5) : Math.round;
|
|
1353
1353
|
({ r, g, b } = hslToRgb(hsl.h, hsl.s, hsl.l, round3));
|
|
1354
1354
|
}
|
|
1355
1355
|
let alpha = parseDrawingPercent(find("alpha")) ?? 1;
|
|
@@ -1806,7 +1806,7 @@ function resolveInnerRect(fillToRect, focalPoint) {
|
|
|
1806
1806
|
function lerpEdge(inner, outer, t) {
|
|
1807
1807
|
return inner + (outer - inner) * t;
|
|
1808
1808
|
}
|
|
1809
|
-
function buildRectPathGradientSvg(stops, focalPoint, fillToRect,
|
|
1809
|
+
function buildRectPathGradientSvg(stops, focalPoint, fillToRect, options2) {
|
|
1810
1810
|
if (stops.length === 0) {
|
|
1811
1811
|
return '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100"/>';
|
|
1812
1812
|
}
|
|
@@ -1815,7 +1815,7 @@ function buildRectPathGradientSvg(stops, focalPoint, fillToRect, options) {
|
|
|
1815
1815
|
const rects = [];
|
|
1816
1816
|
const alphaRects = [];
|
|
1817
1817
|
const masked = sorted.some((stop) => (stop.opacity ?? 1) < 1);
|
|
1818
|
-
const bands =
|
|
1818
|
+
const bands = options2?.bands;
|
|
1819
1819
|
if (!Number.isInteger(bands) || bands < 1) throw new RangeError("Invalid gradient band count");
|
|
1820
1820
|
for (let i = bands; i >= 0; i -= 1) {
|
|
1821
1821
|
const t = i / bands;
|
|
@@ -11339,13 +11339,297 @@ function groupRowsByCategory(rawCategories) {
|
|
|
11339
11339
|
return { uniqueCategories, rowIndexesByCategory };
|
|
11340
11340
|
}
|
|
11341
11341
|
|
|
11342
|
+
// chart/number-format-pattern.ts
|
|
11343
|
+
var NAMED_FORMAT_COLORS = {
|
|
11344
|
+
black: "#000000",
|
|
11345
|
+
blue: "#0000FF",
|
|
11346
|
+
cyan: "#00FFFF",
|
|
11347
|
+
green: "#00FF00",
|
|
11348
|
+
magenta: "#FF00FF",
|
|
11349
|
+
red: "#FF0000",
|
|
11350
|
+
white: "#FFFFFF",
|
|
11351
|
+
yellow: "#FFFF00"
|
|
11352
|
+
};
|
|
11353
|
+
var PLACEHOLDER = /[0#?]/u;
|
|
11354
|
+
function parsePattern(code) {
|
|
11355
|
+
let scale = 1;
|
|
11356
|
+
let scientific = false;
|
|
11357
|
+
let color;
|
|
11358
|
+
const chars = [];
|
|
11359
|
+
let inQuotes = false;
|
|
11360
|
+
for (let i = 0; i < code.length; i += 1) {
|
|
11361
|
+
const ch = code[i] ?? "";
|
|
11362
|
+
if (ch === '"') {
|
|
11363
|
+
inQuotes = !inQuotes;
|
|
11364
|
+
continue;
|
|
11365
|
+
}
|
|
11366
|
+
if (inQuotes) {
|
|
11367
|
+
chars.push({ ch, literal: true });
|
|
11368
|
+
continue;
|
|
11369
|
+
}
|
|
11370
|
+
if (ch === "\\" || ch === "*" || ch === "_") {
|
|
11371
|
+
const next = code[i + 1];
|
|
11372
|
+
i += 1;
|
|
11373
|
+
if (ch === "\\" && next !== void 0) {
|
|
11374
|
+
chars.push({ ch: next, literal: true });
|
|
11375
|
+
}
|
|
11376
|
+
continue;
|
|
11377
|
+
}
|
|
11378
|
+
if (ch === "%") {
|
|
11379
|
+
scale *= 100;
|
|
11380
|
+
chars.push({ ch, literal: true });
|
|
11381
|
+
continue;
|
|
11382
|
+
}
|
|
11383
|
+
if (ch === "E" && (code[i + 1] === "+" || code[i + 1] === "-")) {
|
|
11384
|
+
scientific = true;
|
|
11385
|
+
chars.push({ ch: "E", literal: false });
|
|
11386
|
+
i += 1;
|
|
11387
|
+
continue;
|
|
11388
|
+
}
|
|
11389
|
+
if (ch === "[") {
|
|
11390
|
+
const close = code.indexOf("]", i);
|
|
11391
|
+
const token = code.slice(i + 1, close === -1 ? code.length : close);
|
|
11392
|
+
const named3 = NAMED_FORMAT_COLORS[token.trim().toLowerCase()];
|
|
11393
|
+
if (named3 && color === void 0) {
|
|
11394
|
+
color = named3;
|
|
11395
|
+
}
|
|
11396
|
+
i = close === -1 ? code.length : close;
|
|
11397
|
+
continue;
|
|
11398
|
+
}
|
|
11399
|
+
chars.push({ ch, literal: false });
|
|
11400
|
+
}
|
|
11401
|
+
const firstDigit = chars.findIndex((c) => !c.literal && PLACEHOLDER.test(c.ch));
|
|
11402
|
+
if (firstDigit === -1) {
|
|
11403
|
+
return void 0;
|
|
11404
|
+
}
|
|
11405
|
+
let lastDigit = firstDigit;
|
|
11406
|
+
for (let i = chars.length - 1; i >= firstDigit; i -= 1) {
|
|
11407
|
+
const c = chars[i];
|
|
11408
|
+
if (c && !c.literal && (PLACEHOLDER.test(c.ch) || c.ch === "." || c.ch === "," || c.ch === "E")) {
|
|
11409
|
+
lastDigit = i;
|
|
11410
|
+
break;
|
|
11411
|
+
}
|
|
11412
|
+
}
|
|
11413
|
+
const numeric = chars.slice(firstDigit, lastDigit + 1);
|
|
11414
|
+
const prefix2 = chars.slice(0, firstDigit).map((c) => c.ch).join("");
|
|
11415
|
+
const suffix = chars.slice(lastDigit + 1).map((c) => c.ch).join("");
|
|
11416
|
+
let grouped = false;
|
|
11417
|
+
let intDigits = 0;
|
|
11418
|
+
let required = 0;
|
|
11419
|
+
let optional = 0;
|
|
11420
|
+
let afterPoint = false;
|
|
11421
|
+
let inExponent = false;
|
|
11422
|
+
for (let i = 0; i < numeric.length; i += 1) {
|
|
11423
|
+
const { ch, literal } = numeric[i] ?? { ch: "", literal: true };
|
|
11424
|
+
if (literal) {
|
|
11425
|
+
continue;
|
|
11426
|
+
}
|
|
11427
|
+
if (ch === "E") {
|
|
11428
|
+
inExponent = true;
|
|
11429
|
+
continue;
|
|
11430
|
+
}
|
|
11431
|
+
if (inExponent) {
|
|
11432
|
+
continue;
|
|
11433
|
+
}
|
|
11434
|
+
if (ch === ".") {
|
|
11435
|
+
afterPoint = true;
|
|
11436
|
+
continue;
|
|
11437
|
+
}
|
|
11438
|
+
if (ch === ",") {
|
|
11439
|
+
const next = numeric.slice(i + 1).find((c) => !c.literal);
|
|
11440
|
+
if (!next || next.ch === "." || !PLACEHOLDER.test(next.ch)) {
|
|
11441
|
+
scale /= 1e3;
|
|
11442
|
+
} else {
|
|
11443
|
+
grouped = true;
|
|
11444
|
+
}
|
|
11445
|
+
continue;
|
|
11446
|
+
}
|
|
11447
|
+
if (!PLACEHOLDER.test(ch)) {
|
|
11448
|
+
continue;
|
|
11449
|
+
}
|
|
11450
|
+
if (afterPoint) {
|
|
11451
|
+
if (ch === "0") {
|
|
11452
|
+
required += 1;
|
|
11453
|
+
} else {
|
|
11454
|
+
optional += 1;
|
|
11455
|
+
}
|
|
11456
|
+
} else if (ch === "0") {
|
|
11457
|
+
intDigits += 1;
|
|
11458
|
+
}
|
|
11459
|
+
}
|
|
11460
|
+
return {
|
|
11461
|
+
prefix: prefix2,
|
|
11462
|
+
suffix,
|
|
11463
|
+
intDigits,
|
|
11464
|
+
decimals: { required, optional },
|
|
11465
|
+
grouped,
|
|
11466
|
+
scale,
|
|
11467
|
+
scientific,
|
|
11468
|
+
color
|
|
11469
|
+
};
|
|
11470
|
+
}
|
|
11471
|
+
function group(intPart) {
|
|
11472
|
+
return intPart.replace(/\B(?=(\d{3})+(?!\d))/gu, ",");
|
|
11473
|
+
}
|
|
11474
|
+
function applyPattern(value, pattern, forcePositive) {
|
|
11475
|
+
const scaled = value * pattern.scale;
|
|
11476
|
+
const magnitude = forcePositive ? Math.abs(scaled) : scaled;
|
|
11477
|
+
if (pattern.scientific) {
|
|
11478
|
+
const digits = pattern.decimals.required + pattern.decimals.optional;
|
|
11479
|
+
const exponential = magnitude.toExponential(digits);
|
|
11480
|
+
const [mantissa = "", exponent = "0"] = exponential.split("e");
|
|
11481
|
+
const sign = exponent.startsWith("-") ? "-" : "+";
|
|
11482
|
+
const power = Math.abs(Number(exponent)).toString().padStart(2, "0");
|
|
11483
|
+
return `${pattern.prefix}${mantissa}E${sign}${power}${pattern.suffix}`;
|
|
11484
|
+
}
|
|
11485
|
+
const maxDecimals = pattern.decimals.required + pattern.decimals.optional;
|
|
11486
|
+
let body = magnitude.toFixed(maxDecimals);
|
|
11487
|
+
if (pattern.decimals.optional > 0) {
|
|
11488
|
+
body = body.replace(/(\.\d*?)0+$/u, "$1").replace(/\.$/u, "");
|
|
11489
|
+
const [, frac = ""] = body.split(".");
|
|
11490
|
+
if (frac.length < pattern.decimals.required) {
|
|
11491
|
+
body = Number(body).toFixed(pattern.decimals.required);
|
|
11492
|
+
}
|
|
11493
|
+
}
|
|
11494
|
+
const [rawIntPart = "", fracPart] = body.split(".");
|
|
11495
|
+
let intPart = rawIntPart;
|
|
11496
|
+
const hasMinusChar = intPart.startsWith("-");
|
|
11497
|
+
const negative = hasMinusChar && Number(body) !== 0;
|
|
11498
|
+
if (hasMinusChar) {
|
|
11499
|
+
intPart = intPart.slice(1);
|
|
11500
|
+
}
|
|
11501
|
+
if (intPart.length < pattern.intDigits) {
|
|
11502
|
+
intPart = intPart.padStart(pattern.intDigits, "0");
|
|
11503
|
+
}
|
|
11504
|
+
if (pattern.intDigits === 0 && intPart === "0" && fracPart !== void 0) {
|
|
11505
|
+
intPart = "";
|
|
11506
|
+
}
|
|
11507
|
+
if (pattern.grouped) {
|
|
11508
|
+
intPart = group(intPart);
|
|
11509
|
+
}
|
|
11510
|
+
const number = fracPart === void 0 ? intPart : `${intPart}.${fracPart}`;
|
|
11511
|
+
return `${negative ? "-" : ""}${pattern.prefix}${number}${pattern.suffix}`;
|
|
11512
|
+
}
|
|
11513
|
+
|
|
11514
|
+
// chart/number-format.ts
|
|
11515
|
+
var GENERAL = /* @__PURE__ */ new Set(["", "general", "@"]);
|
|
11516
|
+
function sections(code) {
|
|
11517
|
+
const out = [];
|
|
11518
|
+
let current = "";
|
|
11519
|
+
let inQuotes = false;
|
|
11520
|
+
for (let i = 0; i < code.length; i += 1) {
|
|
11521
|
+
const ch = code[i];
|
|
11522
|
+
if (ch === '"') {
|
|
11523
|
+
inQuotes = !inQuotes;
|
|
11524
|
+
current += ch;
|
|
11525
|
+
continue;
|
|
11526
|
+
}
|
|
11527
|
+
if (ch === "\\") {
|
|
11528
|
+
current += ch + (code[i + 1] ?? "");
|
|
11529
|
+
i += 1;
|
|
11530
|
+
continue;
|
|
11531
|
+
}
|
|
11532
|
+
if (ch === ";" && !inQuotes) {
|
|
11533
|
+
out.push(current);
|
|
11534
|
+
current = "";
|
|
11535
|
+
continue;
|
|
11536
|
+
}
|
|
11537
|
+
current += ch;
|
|
11538
|
+
}
|
|
11539
|
+
out.push(current);
|
|
11540
|
+
return out;
|
|
11541
|
+
}
|
|
11542
|
+
function sectionFor(value, parts) {
|
|
11543
|
+
if (parts.length === 1) {
|
|
11544
|
+
return { code: parts[0] ?? "", forcePositive: false };
|
|
11545
|
+
}
|
|
11546
|
+
if (value < 0 && parts[1] !== void 0) {
|
|
11547
|
+
return { code: parts[1] ?? "", forcePositive: true };
|
|
11548
|
+
}
|
|
11549
|
+
if (value === 0 && parts[2] !== void 0) {
|
|
11550
|
+
return { code: parts[2] ?? "", forcePositive: false };
|
|
11551
|
+
}
|
|
11552
|
+
return { code: parts[0] ?? "", forcePositive: false };
|
|
11553
|
+
}
|
|
11554
|
+
function formatChartNumberWithColor(value, formatCode) {
|
|
11555
|
+
if (!Number.isFinite(value)) {
|
|
11556
|
+
return void 0;
|
|
11557
|
+
}
|
|
11558
|
+
const code = (formatCode ?? "").trim();
|
|
11559
|
+
if (GENERAL.has(code.toLowerCase())) {
|
|
11560
|
+
return void 0;
|
|
11561
|
+
}
|
|
11562
|
+
if (/(?:^|[^\\"])(?:yy|mm?m|dd?|hh|ss)/iu.test(code) && !/[0#?]/u.test(code)) {
|
|
11563
|
+
return void 0;
|
|
11564
|
+
}
|
|
11565
|
+
const { code: section, forcePositive } = sectionFor(value, sections(code));
|
|
11566
|
+
const pattern = parsePattern(section);
|
|
11567
|
+
if (!pattern) {
|
|
11568
|
+
return void 0;
|
|
11569
|
+
}
|
|
11570
|
+
try {
|
|
11571
|
+
return { text: applyPattern(value, pattern, forcePositive), color: pattern.color };
|
|
11572
|
+
} catch {
|
|
11573
|
+
return void 0;
|
|
11574
|
+
}
|
|
11575
|
+
}
|
|
11576
|
+
function formatChartNumber(value, formatCode) {
|
|
11577
|
+
return formatChartNumberWithColor(value, formatCode)?.text;
|
|
11578
|
+
}
|
|
11579
|
+
|
|
11580
|
+
// chart/data-label-text.ts
|
|
11581
|
+
var DATA_LABEL_SEPARATOR = ", ";
|
|
11582
|
+
var DATA_LABEL_CATEGORY_PERCENT_SEPARATOR = "\n";
|
|
11583
|
+
var FLAG_KEYS = [
|
|
11584
|
+
"showValue",
|
|
11585
|
+
"showCategory",
|
|
11586
|
+
"showSeriesName",
|
|
11587
|
+
"showPercent",
|
|
11588
|
+
"showBubbleSize"
|
|
11589
|
+
];
|
|
11590
|
+
function resolveDataLabelFlags(levels) {
|
|
11591
|
+
const { point, series, chart } = levels;
|
|
11592
|
+
const picked = {};
|
|
11593
|
+
for (const key of FLAG_KEYS) picked[key] = point?.[key] ?? series?.[key] ?? chart?.[key];
|
|
11594
|
+
const anyDeclared = FLAG_KEYS.some((key) => picked[key] !== void 0);
|
|
11595
|
+
return {
|
|
11596
|
+
showValue: anyDeclared ? picked.showValue === true : levels.siblingOwnsLabels !== true,
|
|
11597
|
+
showCategory: picked.showCategory === true,
|
|
11598
|
+
showSeriesName: picked.showSeriesName === true,
|
|
11599
|
+
showPercent: picked.showPercent === true,
|
|
11600
|
+
showBubbleSize: picked.showBubbleSize === true,
|
|
11601
|
+
separator: point?.separator ?? series?.separator ?? chart?.separator ?? (picked.showCategory === true && picked.showPercent === true ? DATA_LABEL_CATEGORY_PERCENT_SEPARATOR : DATA_LABEL_SEPARATOR)
|
|
11602
|
+
};
|
|
11603
|
+
}
|
|
11604
|
+
function composeDataLabelText(input) {
|
|
11605
|
+
const { flags, value, numberFormat } = input;
|
|
11606
|
+
const parts = [];
|
|
11607
|
+
let valueColor;
|
|
11608
|
+
if (flags.showSeriesName && input.seriesName) parts.push(input.seriesName);
|
|
11609
|
+
if (flags.showCategory && input.category) parts.push(input.category);
|
|
11610
|
+
if (flags.showValue) {
|
|
11611
|
+
const formatted = formatChartNumberWithColor(value, numberFormat);
|
|
11612
|
+
parts.push(formatted?.text ?? (input.formatValue ?? String)(value, numberFormat));
|
|
11613
|
+
valueColor = formatted?.color;
|
|
11614
|
+
}
|
|
11615
|
+
if (flags.showPercent) {
|
|
11616
|
+
const base = input.percentBase;
|
|
11617
|
+
parts.push(base > 0 ? `${Math.round(Math.abs(value) / base * 100)}%` : "0%");
|
|
11618
|
+
}
|
|
11619
|
+
if (flags.showBubbleSize && input.bubbleSize !== void 0)
|
|
11620
|
+
parts.push((input.formatBubbleSize ?? String)(input.bubbleSize));
|
|
11621
|
+
const text2 = parts.join(flags.separator);
|
|
11622
|
+
if (text2.length === 0) return void 0;
|
|
11623
|
+
return { text: text2, color: parts.length === 1 && flags.showValue ? valueColor : void 0 };
|
|
11624
|
+
}
|
|
11625
|
+
|
|
11342
11626
|
// chart/bubble-radius.ts
|
|
11343
|
-
function computeBubbleRadius(sizeVal, maxBubble, medianRadius,
|
|
11344
|
-
const scale = (
|
|
11627
|
+
function computeBubbleRadius(sizeVal, maxBubble, medianRadius, options2) {
|
|
11628
|
+
const scale = (options2?.bubbleScale ?? 100) / 100;
|
|
11345
11629
|
if (sizeVal === void 0) return medianRadius * scale;
|
|
11346
11630
|
const denom = maxBubble > 0 ? maxBubble : 1;
|
|
11347
11631
|
const magnitude = Math.abs(sizeVal);
|
|
11348
|
-
const ratio = (
|
|
11632
|
+
const ratio = (options2?.sizeRepresents ?? "w") === "area" ? Math.sqrt(magnitude) / Math.sqrt(denom) : magnitude / denom;
|
|
11349
11633
|
return medianRadius * scale * 0.5 + ratio * medianRadius * scale * 1.5;
|
|
11350
11634
|
}
|
|
11351
11635
|
function maxBubbleSize(sizes) {
|
|
@@ -11451,10 +11735,10 @@ function squarify(nodes, box) {
|
|
|
11451
11735
|
|
|
11452
11736
|
// chart/hierarchy.ts
|
|
11453
11737
|
function normalizeLevels(levels, pointCount) {
|
|
11454
|
-
return levels.map((
|
|
11738
|
+
return levels.map((level2) => {
|
|
11455
11739
|
let previous = "";
|
|
11456
11740
|
return Array.from({ length: pointCount }, (_, index) => {
|
|
11457
|
-
const label =
|
|
11741
|
+
const label = level2[index]?.trim() ?? "";
|
|
11458
11742
|
if (label) previous = label;
|
|
11459
11743
|
return label || previous;
|
|
11460
11744
|
});
|
|
@@ -11612,12 +11896,12 @@ function computeSunburstArcs(series, cx, cy, maxR) {
|
|
|
11612
11896
|
});
|
|
11613
11897
|
return out;
|
|
11614
11898
|
}
|
|
11615
|
-
function hierarchyKey(levels,
|
|
11616
|
-
return levels.slice(
|
|
11899
|
+
function hierarchyKey(levels, level2, index) {
|
|
11900
|
+
return levels.slice(level2).map((labels) => labels[index] ?? "").join("\0");
|
|
11617
11901
|
}
|
|
11618
11902
|
function computeHierarchicalSunburstArcs(categoryLevels, values, cx, cy, maxR) {
|
|
11619
|
-
const levels = categoryLevels.filter((
|
|
11620
|
-
const leafCount = Math.max(values.length, ...levels.map((
|
|
11903
|
+
const levels = categoryLevels.filter((level2) => level2.length > 0);
|
|
11904
|
+
const leafCount = Math.max(values.length, ...levels.map((level2) => level2.length), 0);
|
|
11621
11905
|
if (levels.length === 0 || leafCount === 0) return [];
|
|
11622
11906
|
const rawWeights = Array.from({ length: leafCount }, (_, index) => Math.abs(values[index] ?? 0));
|
|
11623
11907
|
const weights = rawWeights.some((value) => value !== 0) ? rawWeights : rawWeights.map(() => 1);
|
|
@@ -11628,15 +11912,15 @@ function computeHierarchicalSunburstArcs(categoryLevels, values, cx, cy, maxR) {
|
|
|
11628
11912
|
const rootLabels = levels[levels.length - 1] ?? [];
|
|
11629
11913
|
const rootColors = /* @__PURE__ */ new Map();
|
|
11630
11914
|
const out = [];
|
|
11631
|
-
for (let
|
|
11632
|
-
const ringIndex = levels.length - 1 -
|
|
11915
|
+
for (let level2 = levels.length - 1; level2 >= 0; level2--) {
|
|
11916
|
+
const ringIndex = levels.length - 1 - level2;
|
|
11633
11917
|
const innerRadius = ringWidth * (ringIndex + 0.5);
|
|
11634
11918
|
const outerRadius = ringWidth * (ringIndex + 1.5);
|
|
11635
11919
|
let start = 0;
|
|
11636
11920
|
while (start < leafCount) {
|
|
11637
|
-
const key = hierarchyKey(levels,
|
|
11921
|
+
const key = hierarchyKey(levels, level2, start);
|
|
11638
11922
|
let end = start + 1;
|
|
11639
|
-
while (end < leafCount && hierarchyKey(levels,
|
|
11923
|
+
while (end < leafCount && hierarchyKey(levels, level2, end) === key) end++;
|
|
11640
11924
|
const startAngle = -Math.PI / 2 + (prefix2[start] ?? 0) / total * Math.PI * 2;
|
|
11641
11925
|
const endAngle = -Math.PI / 2 + (prefix2[end] ?? 0) / total * Math.PI * 2;
|
|
11642
11926
|
const rootLabel = rootLabels[start] ?? "";
|
|
@@ -11646,8 +11930,8 @@ function computeHierarchicalSunburstArcs(categoryLevels, values, cx, cy, maxR) {
|
|
|
11646
11930
|
colorIndex: rootColors.get(rootLabel) ?? start,
|
|
11647
11931
|
opacity: Math.max(0.1, 0.9 - ringIndex * 0.1),
|
|
11648
11932
|
level: ringIndex,
|
|
11649
|
-
label: levels[
|
|
11650
|
-
...
|
|
11933
|
+
label: levels[level2]?.[start] ?? "",
|
|
11934
|
+
...level2 === 0 && end === start + 1 ? { pointIndex: start } : {},
|
|
11651
11935
|
...arcLabelPlacement(cx, cy, (innerRadius + outerRadius) / 2, startAngle, endAngle)
|
|
11652
11936
|
});
|
|
11653
11937
|
start = end;
|
|
@@ -11673,14 +11957,14 @@ function scottBinCount(values, min, max) {
|
|
|
11673
11957
|
const width = 3.49 * sd * values.length ** (-1 / 3);
|
|
11674
11958
|
return Math.max(1, Math.ceil((max - min) / width));
|
|
11675
11959
|
}
|
|
11676
|
-
function computeHistogramBins(values,
|
|
11677
|
-
const closed =
|
|
11960
|
+
function computeHistogramBins(values, options2, format = String) {
|
|
11961
|
+
const closed = options2.intervalClosed ?? "l";
|
|
11678
11962
|
const finite2 = values.map((value, sourceIndex) => ({ value, sourceIndex })).filter((item) => Number.isFinite(item.value));
|
|
11679
11963
|
if (finite2.length === 0) {
|
|
11680
11964
|
return [];
|
|
11681
11965
|
}
|
|
11682
|
-
const underflow = typeof
|
|
11683
|
-
const overflow = typeof
|
|
11966
|
+
const underflow = typeof options2.underflow === "number" ? options2.underflow : void 0;
|
|
11967
|
+
const overflow = typeof options2.overflow === "number" ? options2.overflow : void 0;
|
|
11684
11968
|
const under = underflow === void 0 ? [] : finite2.filter(
|
|
11685
11969
|
(item) => closed === "r" ? item.value <= underflow : item.value < underflow
|
|
11686
11970
|
);
|
|
@@ -11697,8 +11981,8 @@ function computeHistogramBins(values, options, format = String) {
|
|
|
11697
11981
|
if (regular.length > 0) {
|
|
11698
11982
|
const min = Math.min(...regular.map((item) => item.value));
|
|
11699
11983
|
const max = Math.max(...regular.map((item) => item.value));
|
|
11700
|
-
const requestedSize =
|
|
11701
|
-
const requestedCount =
|
|
11984
|
+
const requestedSize = options2.binSize && options2.binSize > 0 ? options2.binSize : void 0;
|
|
11985
|
+
const requestedCount = options2.binCount && options2.binCount > 0 ? options2.binCount : void 0;
|
|
11702
11986
|
const start = requestedSize ? Math.floor(min / requestedSize) * requestedSize : min;
|
|
11703
11987
|
const count = requestedSize ? Math.max(
|
|
11704
11988
|
closed === "l" ? Math.floor((max - start) / requestedSize) + 1 : Math.ceil((max - start) / requestedSize),
|
|
@@ -11749,9 +12033,9 @@ function aggregateByCategory(values, rawCategories) {
|
|
|
11749
12033
|
}
|
|
11750
12034
|
|
|
11751
12035
|
// chart/waterfall.ts
|
|
11752
|
-
function buildWaterfallSteps(values,
|
|
12036
|
+
function buildWaterfallSteps(values, options2) {
|
|
11753
12037
|
const subtotalIndices = new Set(
|
|
11754
|
-
|
|
12038
|
+
options2?.subtotalIndices ?? (values.length > 0 ? [values.length - 1] : [])
|
|
11755
12039
|
);
|
|
11756
12040
|
const steps = [];
|
|
11757
12041
|
let runningTotal = 0;
|
|
@@ -11811,13 +12095,13 @@ var noFit = () => ({
|
|
|
11811
12095
|
rSquared: 0,
|
|
11812
12096
|
coefficients: []
|
|
11813
12097
|
});
|
|
11814
|
-
function fitModel(
|
|
12098
|
+
function fitModel(options2, xVals, yVals) {
|
|
11815
12099
|
const xs = [...xVals];
|
|
11816
12100
|
const ys = [...yVals];
|
|
11817
|
-
switch (
|
|
12101
|
+
switch (options2.kind) {
|
|
11818
12102
|
case "linear": {
|
|
11819
12103
|
const reg = computeLinearRegression(xs, ys);
|
|
11820
|
-
const fixed =
|
|
12104
|
+
const fixed = options2.intercept;
|
|
11821
12105
|
const slope = fixed !== void 0 ? ys.reduce((s, y, i) => s + (y - fixed) * xs[i], 0) / xs.reduce((s, x) => s + x * x, 0) : reg.slope;
|
|
11822
12106
|
const b = fixed ?? reg.intercept;
|
|
11823
12107
|
return {
|
|
@@ -11867,7 +12151,7 @@ function fitModel(options, xVals, yVals) {
|
|
|
11867
12151
|
};
|
|
11868
12152
|
}
|
|
11869
12153
|
case "polynomial": {
|
|
11870
|
-
const order = Math.min(
|
|
12154
|
+
const order = Math.min(options2.order ?? 2, 6);
|
|
11871
12155
|
const coeffs = fitPolynomial(xs, ys, order);
|
|
11872
12156
|
const evaluate = (x) => coeffs.reduce((s, c, i) => s + c * x ** i, 0);
|
|
11873
12157
|
return {
|
|
@@ -11881,11 +12165,11 @@ function fitModel(options, xVals, yVals) {
|
|
|
11881
12165
|
return void 0;
|
|
11882
12166
|
}
|
|
11883
12167
|
}
|
|
11884
|
-
function fitChartTrendline(
|
|
12168
|
+
function fitChartTrendline(options2, xVals, yVals) {
|
|
11885
12169
|
const count = yVals.length;
|
|
11886
12170
|
if (count < 2) return noFit();
|
|
11887
|
-
if (
|
|
11888
|
-
const period =
|
|
12171
|
+
if (options2.kind === "movingAvg") {
|
|
12172
|
+
const period = options2.period ?? 2;
|
|
11889
12173
|
const points2 = [];
|
|
11890
12174
|
for (let i = period - 1; i < count; i++) {
|
|
11891
12175
|
let sum = 0;
|
|
@@ -11894,10 +12178,10 @@ function fitChartTrendline(options, xVals, yVals) {
|
|
|
11894
12178
|
}
|
|
11895
12179
|
return { points: points2, equation: `${period}-period moving average`, rSquared: 0, coefficients: [] };
|
|
11896
12180
|
}
|
|
11897
|
-
const model = fitModel(
|
|
12181
|
+
const model = fitModel(options2, xVals, yVals);
|
|
11898
12182
|
if (!model) return noFit();
|
|
11899
|
-
const startX = Math.min(...xVals) - (
|
|
11900
|
-
const endX = Math.max(...xVals) + (
|
|
12183
|
+
const startX = Math.min(...xVals) - (options2.backward ?? 0);
|
|
12184
|
+
const endX = Math.max(...xVals) + (options2.forward ?? 0);
|
|
11901
12185
|
const steps = Math.max(Math.ceil((endX - startX) * 4), 20);
|
|
11902
12186
|
const points = [];
|
|
11903
12187
|
for (let step = 0; step <= steps; step++) {
|
|
@@ -11920,19 +12204,78 @@ function chartSampleVariance(values) {
|
|
|
11920
12204
|
const mean = values.reduce((sum, value) => sum + value, 0) / count;
|
|
11921
12205
|
return values.reduce((sum, value) => sum + (value - mean) ** 2, 0) / Math.max(count - 1, 1);
|
|
11922
12206
|
}
|
|
11923
|
-
function chartErrorBarAmount(
|
|
11924
|
-
switch (
|
|
12207
|
+
function chartErrorBarAmount(options2, values, displayIndex, sourceIndex, side) {
|
|
12208
|
+
switch (options2.valueType) {
|
|
11925
12209
|
case "fixedVal":
|
|
11926
|
-
return
|
|
12210
|
+
return options2.value ?? 0;
|
|
11927
12211
|
case "percentage":
|
|
11928
|
-
return Math.abs(values[displayIndex] ?? 0) * ((
|
|
12212
|
+
return Math.abs(values[displayIndex] ?? 0) * ((options2.value ?? 0) / 100);
|
|
11929
12213
|
case "stdDev":
|
|
11930
|
-
return Math.sqrt(chartSampleVariance(values)) * (
|
|
12214
|
+
return Math.sqrt(chartSampleVariance(values)) * (options2.value ?? 1);
|
|
11931
12215
|
case "stdErr":
|
|
11932
12216
|
return Math.sqrt(chartSampleVariance(values) / Math.max(values.length, 1));
|
|
11933
12217
|
case "cust":
|
|
11934
|
-
return side === "plus" ?
|
|
12218
|
+
return side === "plus" ? options2.customPlus?.[sourceIndex] ?? 0 : options2.customMinus?.[sourceIndex] ?? 0;
|
|
12219
|
+
}
|
|
12220
|
+
}
|
|
12221
|
+
|
|
12222
|
+
// chart/pie-best-fit.ts
|
|
12223
|
+
var PX_PER_PT = 4 / 3;
|
|
12224
|
+
var BEST_FIT_RIM_INSET = 4 * PX_PER_PT;
|
|
12225
|
+
var BEST_FIT_EDGE_TOLERANCE = 1.5 * PX_PER_PT;
|
|
12226
|
+
var BEST_FIT_OUTSIDE_GAP = 2 * PX_PER_PT;
|
|
12227
|
+
function farCorner(x, y, w, h) {
|
|
12228
|
+
return Math.hypot(Math.abs(x) + w / 2, Math.abs(y) + h / 2);
|
|
12229
|
+
}
|
|
12230
|
+
function insideDistance(ux, uy, w, h, limit) {
|
|
12231
|
+
if (farCorner(0, 0, w, h) > limit) {
|
|
12232
|
+
return void 0;
|
|
11935
12233
|
}
|
|
12234
|
+
let lo = 0;
|
|
12235
|
+
let hi = limit;
|
|
12236
|
+
for (let i = 0; i < 40; i++) {
|
|
12237
|
+
const mid = (lo + hi) / 2;
|
|
12238
|
+
if (farCorner(mid * ux, mid * uy, w, h) > limit) {
|
|
12239
|
+
hi = mid;
|
|
12240
|
+
} else {
|
|
12241
|
+
lo = mid;
|
|
12242
|
+
}
|
|
12243
|
+
}
|
|
12244
|
+
return lo;
|
|
12245
|
+
}
|
|
12246
|
+
function edgeOverhang(x, y, w, h, slice) {
|
|
12247
|
+
let worst = Number.NEGATIVE_INFINITY;
|
|
12248
|
+
const corners = [
|
|
12249
|
+
[-w / 2, -h / 2],
|
|
12250
|
+
[w / 2, -h / 2],
|
|
12251
|
+
[-w / 2, h / 2],
|
|
12252
|
+
[w / 2, h / 2]
|
|
12253
|
+
];
|
|
12254
|
+
for (const [dx, dy] of corners) {
|
|
12255
|
+
const px = x + dx;
|
|
12256
|
+
const py = y + dy;
|
|
12257
|
+
const fromStart = Math.cos(slice.startAngle) * py - Math.sin(slice.startAngle) * px;
|
|
12258
|
+
const fromEnd = Math.sin(slice.endAngle) * px - Math.cos(slice.endAngle) * py;
|
|
12259
|
+
worst = Math.max(worst, -fromStart, -fromEnd);
|
|
12260
|
+
}
|
|
12261
|
+
return worst;
|
|
12262
|
+
}
|
|
12263
|
+
function placeBestFitLabel(slice, w, h) {
|
|
12264
|
+
const mid = (slice.startAngle + slice.endAngle) / 2;
|
|
12265
|
+
const ux = Math.cos(mid);
|
|
12266
|
+
const uy = Math.sin(mid);
|
|
12267
|
+
const distance = insideDistance(ux, uy, w, h, slice.outerR - BEST_FIT_RIM_INSET);
|
|
12268
|
+
if (distance !== void 0) {
|
|
12269
|
+
const x = distance * ux;
|
|
12270
|
+
const y = distance * uy;
|
|
12271
|
+
const reflex = slice.endAngle - slice.startAngle >= Math.PI;
|
|
12272
|
+
if (reflex || edgeOverhang(x, y, w, h, slice) <= BEST_FIT_EDGE_TOLERANCE) {
|
|
12273
|
+
return { x: slice.cx + x, y: slice.cy + y, inside: true };
|
|
12274
|
+
}
|
|
12275
|
+
}
|
|
12276
|
+
const extent = Math.abs(ux) * w / 2 + Math.abs(uy) * h / 2;
|
|
12277
|
+
const outside = slice.outerR + BEST_FIT_OUTSIDE_GAP + extent;
|
|
12278
|
+
return { x: slice.cx + outside * ux, y: slice.cy + outside * uy, inside: false };
|
|
11936
12279
|
}
|
|
11937
12280
|
|
|
11938
12281
|
// chart/color-palettes.ts
|
|
@@ -12248,6 +12591,191 @@ function chartCacheValues(cache2) {
|
|
|
12248
12591
|
}
|
|
12249
12592
|
var chartSourceValues = (source) => chartCacheValues(source?.cache ?? source?.levels?.[0]);
|
|
12250
12593
|
|
|
12594
|
+
// chart/marker-shape.ts
|
|
12595
|
+
var CHART_PX_PER_PT = 4 / 3;
|
|
12596
|
+
var DEFAULT_MARKER_OUTLINE_PT = 0.75;
|
|
12597
|
+
var AUTOMATIC_MARKER_CYCLE = [
|
|
12598
|
+
"diamond",
|
|
12599
|
+
"square",
|
|
12600
|
+
"triangle",
|
|
12601
|
+
"x",
|
|
12602
|
+
"star",
|
|
12603
|
+
"circle",
|
|
12604
|
+
"plus",
|
|
12605
|
+
"dot",
|
|
12606
|
+
"dash"
|
|
12607
|
+
];
|
|
12608
|
+
function automaticMarkerSymbol(seriesIdx) {
|
|
12609
|
+
const length = AUTOMATIC_MARKER_CYCLE.length;
|
|
12610
|
+
const normalized = (Math.trunc(seriesIdx) % length + length) % length;
|
|
12611
|
+
return AUTOMATIC_MARKER_CYCLE[Number.isFinite(normalized) ? normalized : 0];
|
|
12612
|
+
}
|
|
12613
|
+
function markerRadius(size, defaultRadius) {
|
|
12614
|
+
if (size === void 0 || !Number.isFinite(size) || size <= 0) {
|
|
12615
|
+
return defaultRadius;
|
|
12616
|
+
}
|
|
12617
|
+
return size / 2;
|
|
12618
|
+
}
|
|
12619
|
+
function polygonPoints(vertices) {
|
|
12620
|
+
return vertices.map(([x, y]) => `${x.toFixed(2)},${y.toFixed(2)}`).join(" ");
|
|
12621
|
+
}
|
|
12622
|
+
function starVertices(cx, cy, r) {
|
|
12623
|
+
const inner = r * 0.5;
|
|
12624
|
+
const out = [];
|
|
12625
|
+
for (let i = 0; i < 10; i++) {
|
|
12626
|
+
const radius = i % 2 === 0 ? r : inner;
|
|
12627
|
+
const angle = -Math.PI / 2 + Math.PI * i / 5;
|
|
12628
|
+
out.push([cx + radius * Math.cos(angle), cy + radius * Math.sin(angle)]);
|
|
12629
|
+
}
|
|
12630
|
+
return out;
|
|
12631
|
+
}
|
|
12632
|
+
function rectPolygon(x, y, w, h) {
|
|
12633
|
+
return polygonPoints([
|
|
12634
|
+
[x, y],
|
|
12635
|
+
[x + w, y],
|
|
12636
|
+
[x + w, y + h],
|
|
12637
|
+
[x, y + h]
|
|
12638
|
+
]);
|
|
12639
|
+
}
|
|
12640
|
+
function buildMarkerPrimitive(input) {
|
|
12641
|
+
const { symbol, cx, cy, fill } = input;
|
|
12642
|
+
const part = input.part === void 0 ? {} : { part: input.part };
|
|
12643
|
+
if (symbol === "none") {
|
|
12644
|
+
return null;
|
|
12645
|
+
}
|
|
12646
|
+
const r = markerRadius(input.size, input.defaultRadius);
|
|
12647
|
+
const outline = input.stroke ? {
|
|
12648
|
+
stroke: input.stroke,
|
|
12649
|
+
strokeWidth: input.strokeWidth ?? DEFAULT_MARKER_OUTLINE_PT * CHART_PX_PER_PT
|
|
12650
|
+
} : void 0;
|
|
12651
|
+
const polygonStroke = outline ?? { stroke: fill, strokeWidth: 0 };
|
|
12652
|
+
const lineStroke = input.stroke ?? fill;
|
|
12653
|
+
switch (symbol) {
|
|
12654
|
+
case "square":
|
|
12655
|
+
case "dash": {
|
|
12656
|
+
const h = symbol === "dash" ? r * 0.64 : r * 2;
|
|
12657
|
+
const y = cy - h / 2;
|
|
12658
|
+
if (outline) {
|
|
12659
|
+
return {
|
|
12660
|
+
kind: "polygon",
|
|
12661
|
+
points: rectPolygon(cx - r, y, r * 2, h),
|
|
12662
|
+
fill,
|
|
12663
|
+
...outline,
|
|
12664
|
+
...part
|
|
12665
|
+
};
|
|
12666
|
+
}
|
|
12667
|
+
return { kind: "rect", x: cx - r, y, w: r * 2, h, fill, ...part };
|
|
12668
|
+
}
|
|
12669
|
+
case "diamond":
|
|
12670
|
+
return {
|
|
12671
|
+
kind: "polygon",
|
|
12672
|
+
points: polygonPoints([
|
|
12673
|
+
[cx, cy - r],
|
|
12674
|
+
[cx + r, cy],
|
|
12675
|
+
[cx, cy + r],
|
|
12676
|
+
[cx - r, cy]
|
|
12677
|
+
]),
|
|
12678
|
+
fill,
|
|
12679
|
+
...polygonStroke,
|
|
12680
|
+
...part
|
|
12681
|
+
};
|
|
12682
|
+
case "triangle":
|
|
12683
|
+
return {
|
|
12684
|
+
kind: "polygon",
|
|
12685
|
+
points: polygonPoints([
|
|
12686
|
+
[cx, cy - r],
|
|
12687
|
+
[cx + r * 0.9, cy + r * 0.75],
|
|
12688
|
+
[cx - r * 0.9, cy + r * 0.75]
|
|
12689
|
+
]),
|
|
12690
|
+
fill,
|
|
12691
|
+
...polygonStroke,
|
|
12692
|
+
...part
|
|
12693
|
+
};
|
|
12694
|
+
case "star":
|
|
12695
|
+
return {
|
|
12696
|
+
kind: "polygon",
|
|
12697
|
+
points: polygonPoints(starVertices(cx, cy, r)),
|
|
12698
|
+
fill,
|
|
12699
|
+
...polygonStroke,
|
|
12700
|
+
...part
|
|
12701
|
+
};
|
|
12702
|
+
case "plus":
|
|
12703
|
+
return {
|
|
12704
|
+
kind: "path",
|
|
12705
|
+
d: `M${(cx - r).toFixed(2)},${cy.toFixed(2)} L${(cx + r).toFixed(2)},${cy.toFixed(2)} M${cx.toFixed(2)},${(cy - r).toFixed(2)} L${cx.toFixed(2)},${(cy + r).toFixed(2)}`,
|
|
12706
|
+
fill: "none",
|
|
12707
|
+
stroke: lineStroke,
|
|
12708
|
+
strokeWidth: Math.max(1, r * 0.4),
|
|
12709
|
+
...part
|
|
12710
|
+
};
|
|
12711
|
+
case "x":
|
|
12712
|
+
return {
|
|
12713
|
+
kind: "path",
|
|
12714
|
+
d: `M${(cx - r).toFixed(2)},${(cy - r).toFixed(2)} L${(cx + r).toFixed(2)},${(cy + r).toFixed(2)} M${(cx + r).toFixed(2)},${(cy - r).toFixed(2)} L${(cx - r).toFixed(2)},${(cy + r).toFixed(2)}`,
|
|
12715
|
+
fill: "none",
|
|
12716
|
+
stroke: lineStroke,
|
|
12717
|
+
strokeWidth: Math.max(1, r * 0.4),
|
|
12718
|
+
...part
|
|
12719
|
+
};
|
|
12720
|
+
case "dot":
|
|
12721
|
+
return { kind: "circle", cx, cy, r: Math.max(r * 0.6, 1), fill, ...part, ...outline };
|
|
12722
|
+
default:
|
|
12723
|
+
return { kind: "circle", cx, cy, r, fill, ...part, ...outline };
|
|
12724
|
+
}
|
|
12725
|
+
}
|
|
12726
|
+
|
|
12727
|
+
// chart/render/chart-view-markers.ts
|
|
12728
|
+
function summaryMarkers(source, group2, seriesPosition) {
|
|
12729
|
+
if (!["line", "scatter", "radar"].includes(group2.kind)) return {};
|
|
12730
|
+
const enabled = group2.kind === "line" ? group2.marker === true : group2.kind === "radar" ? group2.radarStyle === "marker" : !["line", "smooth", "none"].includes(group2.scatterStyle ?? "marker");
|
|
12731
|
+
const symbol = source.marker?.symbol;
|
|
12732
|
+
const marker = {
|
|
12733
|
+
...source.marker,
|
|
12734
|
+
symbol: symbol && symbol !== "auto" ? symbol : source.marker || enabled ? automaticMarkerSymbol(source.index ?? seriesPosition) : "none"
|
|
12735
|
+
};
|
|
12736
|
+
const pointMarkers = {};
|
|
12737
|
+
for (const point of source.dataPoints) {
|
|
12738
|
+
if (point.index === void 0 || !point.marker) continue;
|
|
12739
|
+
const override = point.marker;
|
|
12740
|
+
pointMarkers[point.index] = {
|
|
12741
|
+
...marker,
|
|
12742
|
+
...override,
|
|
12743
|
+
...override.symbol === "auto" || !source.marker && override.symbol === void 0 ? { symbol: automaticMarkerSymbol(source.index ?? seriesPosition) } : {},
|
|
12744
|
+
...marker.spPr || override.spPr ? {
|
|
12745
|
+
spPr: {
|
|
12746
|
+
...marker.spPr,
|
|
12747
|
+
...override.spPr,
|
|
12748
|
+
...marker.spPr?.line || override.spPr?.line ? { line: { ...marker.spPr?.line, ...override.spPr?.line } } : {}
|
|
12749
|
+
}
|
|
12750
|
+
} : {}
|
|
12751
|
+
};
|
|
12752
|
+
}
|
|
12753
|
+
return { marker, ...Object.keys(pointMarkers).length ? { pointMarkers } : {} };
|
|
12754
|
+
}
|
|
12755
|
+
function seriesMarkerViews(source, drawingColor) {
|
|
12756
|
+
const fillColor = (fill) => fill?.kind === "none" ? "none" : fill?.kind === "solid" ? drawingColor(fill.color) : void 0;
|
|
12757
|
+
const resolve = (marker) => {
|
|
12758
|
+
const fill = fillColor(marker.spPr?.fill);
|
|
12759
|
+
const stroke = fillColor(marker.spPr?.line?.fill);
|
|
12760
|
+
const width = marker.spPr?.line?.widthEmu;
|
|
12761
|
+
return {
|
|
12762
|
+
...marker.symbol !== void 0 ? { symbol: marker.symbol } : {},
|
|
12763
|
+
...marker.size !== void 0 ? { size: marker.size } : {},
|
|
12764
|
+
...fill !== void 0 ? { fill } : {},
|
|
12765
|
+
...stroke !== void 0 ? { stroke } : {},
|
|
12766
|
+
...width !== void 0 ? { strokeWidth: width / 9525 } : {}
|
|
12767
|
+
};
|
|
12768
|
+
};
|
|
12769
|
+
return {
|
|
12770
|
+
...source.marker ? { marker: resolve(source.marker) } : {},
|
|
12771
|
+
...source.pointMarkers ? {
|
|
12772
|
+
pointMarkers: Object.fromEntries(
|
|
12773
|
+
Object.entries(source.pointMarkers).map(([i, marker]) => [i, resolve(marker)])
|
|
12774
|
+
)
|
|
12775
|
+
} : {}
|
|
12776
|
+
};
|
|
12777
|
+
}
|
|
12778
|
+
|
|
12251
12779
|
// chart/render/summary-analysis.ts
|
|
12252
12780
|
function summaryTrendline(source) {
|
|
12253
12781
|
const kind = chartTrendlineKind(source.trendlineType);
|
|
@@ -12288,6 +12816,41 @@ function summaryAnalysis(series) {
|
|
|
12288
12816
|
};
|
|
12289
12817
|
}
|
|
12290
12818
|
|
|
12819
|
+
// chart/render/summary-labels.ts
|
|
12820
|
+
function level(options2, custom) {
|
|
12821
|
+
const out = {};
|
|
12822
|
+
if (options2.deleted !== void 0) out.deleted = options2.deleted;
|
|
12823
|
+
if (options2.showValue !== void 0) out.showValue = options2.showValue;
|
|
12824
|
+
if (options2.showCategoryName !== void 0) out.showCategory = options2.showCategoryName;
|
|
12825
|
+
if (options2.showSeriesName !== void 0) out.showSeriesName = options2.showSeriesName;
|
|
12826
|
+
if (options2.showPercent !== void 0) out.showPercent = options2.showPercent;
|
|
12827
|
+
if (options2.showBubbleSize !== void 0) out.showBubbleSize = options2.showBubbleSize;
|
|
12828
|
+
if (options2.separator !== void 0) out.separator = options2.separator;
|
|
12829
|
+
if (options2.position) out.position = options2.position;
|
|
12830
|
+
if (options2.numberFormat?.formatCode) out.numberFormat = options2.numberFormat.formatCode;
|
|
12831
|
+
if (custom?.text !== void 0) out.text = custom.text;
|
|
12832
|
+
return out;
|
|
12833
|
+
}
|
|
12834
|
+
function shows(levels, point) {
|
|
12835
|
+
const flags = resolveDataLabelFlags({ ...levels, ...point ? { point } : {} });
|
|
12836
|
+
return point?.text !== void 0 || Object.values(flags).some((value) => value === true);
|
|
12837
|
+
}
|
|
12838
|
+
function summaryDataLabels(series, group2) {
|
|
12839
|
+
const own2 = series.dataLabels;
|
|
12840
|
+
if (!own2 && !group2) return void 0;
|
|
12841
|
+
const out = {};
|
|
12842
|
+
if (group2) out.chart = level(group2);
|
|
12843
|
+
if (own2) out.series = level(own2);
|
|
12844
|
+
const points = {};
|
|
12845
|
+
for (const labels of [group2, own2])
|
|
12846
|
+
for (const label of labels?.labels ?? [])
|
|
12847
|
+
if (label.index !== void 0)
|
|
12848
|
+
points[label.index] = { ...points[label.index], ...level(label, label.tx) };
|
|
12849
|
+
if (Object.keys(points).length) out.points = points;
|
|
12850
|
+
if (!shows(out) && !Object.values(points).some((point) => shows(out, point))) return void 0;
|
|
12851
|
+
return out;
|
|
12852
|
+
}
|
|
12853
|
+
|
|
12291
12854
|
// chart/render/summary-from-space.ts
|
|
12292
12855
|
var solidColor = (fill) => fill?.kind === "solid" ? fill.color : void 0;
|
|
12293
12856
|
var isSolidFill = (fill) => fill?.kind === "solid" || fill?.kind === "unsupported" && fill.element === "solidFill";
|
|
@@ -12305,7 +12868,7 @@ var GROUP_TYPES = {
|
|
|
12305
12868
|
surface: "surface"
|
|
12306
12869
|
};
|
|
12307
12870
|
var GROUPINGS = /* @__PURE__ */ new Set(["clustered", "stacked", "percentStacked", "standard"]);
|
|
12308
|
-
function chartSummarySeries(source, chartType) {
|
|
12871
|
+
function chartSummarySeries(source, chartType, groupLabels) {
|
|
12309
12872
|
const categories = source.categories ?? source.xValues;
|
|
12310
12873
|
const values = source.values ?? source.yValues;
|
|
12311
12874
|
const numeric = (v) => typeof v === "number" ? v : v === "" ? null : Number.isFinite(Number(v)) ? Number(v) : null;
|
|
@@ -12313,6 +12876,7 @@ function chartSummarySeries(source, chartType) {
|
|
|
12313
12876
|
categories: chartSourceValues(categories),
|
|
12314
12877
|
values: chartSourceValues(values).map(numeric)
|
|
12315
12878
|
};
|
|
12879
|
+
if (values?.cache?.formatCode !== void 0) out.numberFormat = values.cache.formatCode;
|
|
12316
12880
|
if (source.bubbleSizes) {
|
|
12317
12881
|
out.bubbleSizes = chartSourceValues(source.bubbleSizes).map(numeric);
|
|
12318
12882
|
if (source.bubbleSizes.formula) out.bubbleSizesRef = source.bubbleSizes.formula;
|
|
@@ -12341,6 +12905,8 @@ function chartSummarySeries(source, chartType) {
|
|
|
12341
12905
|
}
|
|
12342
12906
|
if (Object.keys(points).length) out.pointColors = points;
|
|
12343
12907
|
if (Object.keys(pointFills).length) out.pointFills = pointFills;
|
|
12908
|
+
const dataLabels = summaryDataLabels(source, groupLabels);
|
|
12909
|
+
if (dataLabels) out.dataLabels = dataLabels;
|
|
12344
12910
|
Object.assign(out, summaryAnalysis(source));
|
|
12345
12911
|
return out;
|
|
12346
12912
|
}
|
|
@@ -12349,12 +12915,12 @@ function valueAxisId(chartSpace, axisIds) {
|
|
|
12349
12915
|
(id) => chartSpace.plotArea.axes.some((a) => a.id === id && a.kind === "val")
|
|
12350
12916
|
);
|
|
12351
12917
|
}
|
|
12352
|
-
function stockStyle(
|
|
12918
|
+
function stockStyle(group2) {
|
|
12353
12919
|
return {
|
|
12354
|
-
...
|
|
12355
|
-
...
|
|
12356
|
-
...
|
|
12357
|
-
...
|
|
12920
|
+
...group2.hiLowLinesSpPr ? { hiLowLines: group2.hiLowLinesSpPr } : {},
|
|
12921
|
+
...group2.upBars?.spPr ? { upBars: group2.upBars.spPr } : {},
|
|
12922
|
+
...group2.downBars?.spPr ? { downBars: group2.downBars.spPr } : {},
|
|
12923
|
+
...group2.upDownBarsGapWidth === void 0 ? {} : { gapWidth: group2.upDownBarsGapWidth }
|
|
12358
12924
|
};
|
|
12359
12925
|
}
|
|
12360
12926
|
function extraGroups(chartSpace, firstType) {
|
|
@@ -12362,54 +12928,62 @@ function extraGroups(chartSpace, firstType) {
|
|
|
12362
12928
|
if (!first3 || !["column", "line", "area"].includes(firstType)) return [];
|
|
12363
12929
|
const primary = valueAxisId(chartSpace, first3.axisIds);
|
|
12364
12930
|
const out = [];
|
|
12365
|
-
for (const
|
|
12366
|
-
const stockOverColumns =
|
|
12367
|
-
if (
|
|
12368
|
-
const type =
|
|
12931
|
+
for (const group2 of rest) {
|
|
12932
|
+
const stockOverColumns = group2.kind === "stock" && firstType === "column";
|
|
12933
|
+
if (group2.is3D || !(["bar", "line", "area"].includes(group2.kind) || stockOverColumns)) continue;
|
|
12934
|
+
const type = group2.kind === "bar" ? "column" : group2.kind;
|
|
12369
12935
|
const entry = {
|
|
12370
12936
|
chartType: type,
|
|
12371
|
-
series:
|
|
12372
|
-
|
|
12937
|
+
series: group2.series.map((source, index) => ({
|
|
12938
|
+
...chartSummarySeries(source, type, group2.dataLabels),
|
|
12939
|
+
...summaryMarkers(source, group2, index)
|
|
12940
|
+
})),
|
|
12941
|
+
secondary: valueAxisId(chartSpace, group2.axisIds) !== primary
|
|
12373
12942
|
};
|
|
12374
|
-
if (
|
|
12375
|
-
entry.grouping =
|
|
12376
|
-
if (type === "stock") entry.stock = stockStyle(
|
|
12943
|
+
if (group2.grouping && GROUPINGS.has(group2.grouping))
|
|
12944
|
+
entry.grouping = group2.grouping;
|
|
12945
|
+
if (type === "stock") entry.stock = stockStyle(group2);
|
|
12377
12946
|
if (type === "column") {
|
|
12378
|
-
if (
|
|
12379
|
-
if (
|
|
12947
|
+
if (group2.gapWidth !== void 0) entry.barGapWidth = group2.gapWidth;
|
|
12948
|
+
if (group2.overlap !== void 0) entry.barOverlap = group2.overlap;
|
|
12380
12949
|
}
|
|
12381
12950
|
if (entry.series.length) out.push(entry);
|
|
12382
12951
|
}
|
|
12383
12952
|
return out;
|
|
12384
12953
|
}
|
|
12385
12954
|
function chartSummaryFromSpace(chartSpace, extras = {}) {
|
|
12386
|
-
const
|
|
12387
|
-
let chartType =
|
|
12388
|
-
if (chartType === "bar" &&
|
|
12389
|
-
const series = (
|
|
12955
|
+
const group2 = chartSpace.plotArea.groups[0];
|
|
12956
|
+
let chartType = group2 ? GROUP_TYPES[group2.kind] : "column";
|
|
12957
|
+
if (chartType === "bar" && group2?.barDirection !== "bar") chartType = "column";
|
|
12958
|
+
const series = (group2?.series ?? []).map((source, index) => ({
|
|
12959
|
+
...chartSummarySeries(source, chartType, group2?.dataLabels),
|
|
12960
|
+
...group2 ? summaryMarkers(source, group2, index) : {}
|
|
12961
|
+
}));
|
|
12390
12962
|
const summary = {
|
|
12391
12963
|
chartType,
|
|
12392
12964
|
series,
|
|
12393
|
-
showLegend: chartSpace.legend !== void 0
|
|
12965
|
+
showLegend: chartSpace.legend !== void 0,
|
|
12966
|
+
axes: chartSpace.plotArea.axes,
|
|
12967
|
+
axisIds: group2?.axisIds ?? []
|
|
12394
12968
|
};
|
|
12395
12969
|
const combined = extraGroups(chartSpace, chartType);
|
|
12396
12970
|
if (combined.length) summary.extraGroups = combined;
|
|
12397
|
-
if (chartType === "stock" &&
|
|
12398
|
-
if (chartType === "bubble" &&
|
|
12399
|
-
const sizeRepresents =
|
|
12971
|
+
if (chartType === "stock" && group2) summary.stock = stockStyle(group2);
|
|
12972
|
+
if (chartType === "bubble" && group2) {
|
|
12973
|
+
const sizeRepresents = group2.sizeRepresents === "w" ? "w" : "area";
|
|
12400
12974
|
summary.bubble = {
|
|
12401
12975
|
sizeRepresents,
|
|
12402
|
-
...
|
|
12403
|
-
showNegativeBubbles:
|
|
12976
|
+
...group2.bubbleScale === void 0 ? {} : { bubbleScale: group2.bubbleScale },
|
|
12977
|
+
showNegativeBubbles: group2.showNegativeBubbles === true
|
|
12404
12978
|
};
|
|
12405
12979
|
}
|
|
12406
|
-
const grouping =
|
|
12980
|
+
const grouping = group2?.grouping;
|
|
12407
12981
|
if (grouping && GROUPINGS.has(grouping))
|
|
12408
12982
|
summary.grouping = grouping;
|
|
12409
12983
|
if (chartType === "bar" || chartType === "column") {
|
|
12410
12984
|
for (const [value, field, fallback, min, max] of [
|
|
12411
|
-
[
|
|
12412
|
-
[
|
|
12985
|
+
[group2?.gapWidth, "barGapWidth", 150, 0, 500],
|
|
12986
|
+
[group2?.overlap, "barOverlap", 0, -100, 100]
|
|
12413
12987
|
]) {
|
|
12414
12988
|
const resolved = value ?? fallback;
|
|
12415
12989
|
if (Number.isInteger(resolved) && resolved >= min && resolved <= max)
|
|
@@ -12471,72 +13045,438 @@ function chartBarSpacing(chart) {
|
|
|
12471
13045
|
};
|
|
12472
13046
|
}
|
|
12473
13047
|
|
|
12474
|
-
// chart/render/
|
|
12475
|
-
|
|
12476
|
-
|
|
12477
|
-
|
|
12478
|
-
|
|
12479
|
-
|
|
12480
|
-
|
|
12481
|
-
|
|
12482
|
-
|
|
12483
|
-
|
|
12484
|
-
|
|
12485
|
-
|
|
12486
|
-
|
|
12487
|
-
|
|
12488
|
-
|
|
12489
|
-
|
|
12490
|
-
|
|
12491
|
-
|
|
12492
|
-
|
|
12493
|
-
|
|
12494
|
-
|
|
12495
|
-
|
|
12496
|
-
|
|
12497
|
-
|
|
12498
|
-
|
|
12499
|
-
|
|
12500
|
-
|
|
12501
|
-
|
|
12502
|
-
|
|
12503
|
-
|
|
12504
|
-
|
|
12505
|
-
|
|
12506
|
-
const gradient = s.pointGradients?.[i] ?? (s.pointColors?.[i] === void 0 ? s.gradient : void 0);
|
|
12507
|
-
if (gradient && (gradient.path === "circle" || gradient.path === "shape")) {
|
|
12508
|
-
const baseId = color.match(/^url\(#(.+)\)$/)?.[1];
|
|
12509
|
-
if (baseId) {
|
|
12510
|
-
const id = baseId.replace(/(-s\d+(?:-p\d+)?)$/, `-mark${i}$1`);
|
|
12511
|
-
const def = buildChartGradientDef(id, gradient, {
|
|
12512
|
-
width: Number(n(width)),
|
|
12513
|
-
height: Number(n(height)),
|
|
12514
|
-
shape: "rect"
|
|
12515
|
-
});
|
|
12516
|
-
out.push(`<defs>${chartGradientMarkup(def)}</defs>`);
|
|
12517
|
-
color = `url(#${id})`;
|
|
12518
|
-
}
|
|
12519
|
-
}
|
|
12520
|
-
out.push(`<g data-chart-series="${si}" data-chart-point="${i}">`);
|
|
12521
|
-
if (model.horizontal)
|
|
12522
|
-
out.push(
|
|
12523
|
-
rect2(Math.min(a, b), center + offset, Math.abs(b - a), barSize, color, s.shadowFilter)
|
|
12524
|
-
);
|
|
12525
|
-
else
|
|
12526
|
-
out.push(
|
|
12527
|
-
rect2(center + offset, Math.min(a, b), barSize, Math.abs(b - a), color, s.shadowFilter)
|
|
12528
|
-
);
|
|
12529
|
-
out.push("</g>");
|
|
12530
|
-
});
|
|
12531
|
-
});
|
|
13048
|
+
// chart/render/theme-palette.ts
|
|
13049
|
+
var THEME_SLOTS = [
|
|
13050
|
+
"lt1",
|
|
13051
|
+
"dk1",
|
|
13052
|
+
"lt2",
|
|
13053
|
+
"dk2",
|
|
13054
|
+
"accent1",
|
|
13055
|
+
"accent2",
|
|
13056
|
+
"accent3",
|
|
13057
|
+
"accent4",
|
|
13058
|
+
"accent5",
|
|
13059
|
+
"accent6",
|
|
13060
|
+
"hlink",
|
|
13061
|
+
"folHlink"
|
|
13062
|
+
];
|
|
13063
|
+
var DEFAULT_THEME_COLORS = [
|
|
13064
|
+
"FFFFFF",
|
|
13065
|
+
"000000",
|
|
13066
|
+
"E7E6E6",
|
|
13067
|
+
"44546A",
|
|
13068
|
+
"4472C4",
|
|
13069
|
+
"ED7D31",
|
|
13070
|
+
"A5A5A5",
|
|
13071
|
+
"FFC000",
|
|
13072
|
+
"5B9BD5",
|
|
13073
|
+
"70AD47",
|
|
13074
|
+
"0563C1",
|
|
13075
|
+
"954F72"
|
|
13076
|
+
];
|
|
13077
|
+
function themeColor(theme, index) {
|
|
13078
|
+
const hex = theme.colors[index] ?? DEFAULT_THEME_COLORS[index];
|
|
13079
|
+
return hex && parseArgbHex(hex) ? hex.replace(/^#/, "") : void 0;
|
|
12532
13080
|
}
|
|
12533
13081
|
|
|
12534
|
-
// chart/render/chart-
|
|
12535
|
-
|
|
12536
|
-
|
|
12537
|
-
|
|
12538
|
-
|
|
12539
|
-
|
|
13082
|
+
// chart/render/chart-colors.ts
|
|
13083
|
+
function chartColorScheme(theme) {
|
|
13084
|
+
const slots = Object.fromEntries(
|
|
13085
|
+
THEME_SLOTS.map((slot, index) => [slot, `#${themeColor(theme, index) ?? "000000"}`])
|
|
13086
|
+
);
|
|
13087
|
+
return {
|
|
13088
|
+
...slots,
|
|
13089
|
+
bg1: slots.lt1,
|
|
13090
|
+
tx1: slots.dk1,
|
|
13091
|
+
bg2: slots.lt2,
|
|
13092
|
+
tx2: slots.dk2
|
|
13093
|
+
};
|
|
13094
|
+
}
|
|
13095
|
+
function autoSeriesColor(theme, index) {
|
|
13096
|
+
const i = Math.max(0, Math.floor(index));
|
|
13097
|
+
return chartPaletteSeriesColor(findChartColorPalette(10), i, i + 1, chartColorScheme(theme));
|
|
13098
|
+
}
|
|
13099
|
+
|
|
13100
|
+
// chart/text-inheritance.ts
|
|
13101
|
+
var TEXT_KEYS = [
|
|
13102
|
+
"fontSize",
|
|
13103
|
+
"bold",
|
|
13104
|
+
"italic",
|
|
13105
|
+
"underline",
|
|
13106
|
+
"typeface",
|
|
13107
|
+
"textColor",
|
|
13108
|
+
"fontRef"
|
|
13109
|
+
];
|
|
13110
|
+
var TEXT_PARTS = [
|
|
13111
|
+
"title",
|
|
13112
|
+
"axisTitle",
|
|
13113
|
+
"categoryAxis",
|
|
13114
|
+
"valueAxis",
|
|
13115
|
+
"legend",
|
|
13116
|
+
"dataLabel"
|
|
13117
|
+
];
|
|
13118
|
+
function inheritChartText(part, entry, builtIn, root) {
|
|
13119
|
+
if (!root || !TEXT_PARTS.includes(part)) return entry;
|
|
13120
|
+
const out = { ...entry };
|
|
13121
|
+
for (const key of TEXT_KEYS) {
|
|
13122
|
+
delete out[key];
|
|
13123
|
+
const value = root[key] ?? builtIn?.[key];
|
|
13124
|
+
if (value !== void 0) Object.assign(out, { [key]: value });
|
|
13125
|
+
}
|
|
13126
|
+
if (part === "title" && root.fontSize !== void 0) out.fontSize = root.fontSize * 1.2;
|
|
13127
|
+
if (root.textEffectsXml !== void 0) out.textEffectsXml = root.textEffectsXml;
|
|
13128
|
+
return out;
|
|
13129
|
+
}
|
|
13130
|
+
|
|
13131
|
+
// chart/render/chart-appearance.ts
|
|
13132
|
+
var chartPointsToPixels = (points) => points * EMU_PER_POINT / EMU_PER_PIXEL;
|
|
13133
|
+
function typeface(entry, theme) {
|
|
13134
|
+
const name = entry.typeface;
|
|
13135
|
+
if (name?.startsWith("+mj-")) return theme.majorFont;
|
|
13136
|
+
if (name?.startsWith("+mn-")) return theme.minorFont;
|
|
13137
|
+
return name ?? (entry.fontRef?.index === "major" ? theme.majorFont : entry.fontRef?.index === "minor" ? theme.minorFont : void 0);
|
|
13138
|
+
}
|
|
13139
|
+
function chartAppearance(chart, theme) {
|
|
13140
|
+
const defaults = builtInChartTextStyle(effectiveBuiltInChartStyle(chart.formatting));
|
|
13141
|
+
const entries = {};
|
|
13142
|
+
for (const part of CHART_STYLE_PARTS) {
|
|
13143
|
+
const base = chart.styleDefinition?.entries[part];
|
|
13144
|
+
const direct = chart.formatting?.entries[part];
|
|
13145
|
+
if (!defaults[part] && !base && !direct) continue;
|
|
13146
|
+
const entry = {
|
|
13147
|
+
...inheritChartText(
|
|
13148
|
+
part,
|
|
13149
|
+
{ ...defaults[part], ...base, sourceXml: base?.sourceXml ?? "" },
|
|
13150
|
+
defaults[part],
|
|
13151
|
+
chart.formatting?.textDefaults
|
|
13152
|
+
),
|
|
13153
|
+
...direct,
|
|
13154
|
+
sourceXml: direct?.sourceXml ?? base?.sourceXml ?? ""
|
|
13155
|
+
};
|
|
13156
|
+
if (base?.line || direct?.line) entry.line = { ...base?.line, ...direct?.line };
|
|
13157
|
+
entries[part] = entry;
|
|
13158
|
+
}
|
|
13159
|
+
const scheme = chartColorScheme(theme);
|
|
13160
|
+
const resolve = (color) => resolveDrawingColor(
|
|
13161
|
+
color,
|
|
13162
|
+
{ scheme: (name) => scheme[name] },
|
|
13163
|
+
{ hslRounding: "halfDown", transformOrder: "document" }
|
|
13164
|
+
);
|
|
13165
|
+
const out = resolveChartStyleDefinition(
|
|
13166
|
+
{ entries},
|
|
13167
|
+
(color) => drawingColorCss(resolve(color))
|
|
13168
|
+
) ?? {};
|
|
13169
|
+
for (const part of CHART_STYLE_PARTS) {
|
|
13170
|
+
const entry = entries[part];
|
|
13171
|
+
if (!entry) continue;
|
|
13172
|
+
const family = typeface(entry, theme);
|
|
13173
|
+
const shadow = resolveDrawingShadowXml(entry.textEffectsXml, {
|
|
13174
|
+
scheme: (name) => scheme[name]
|
|
13175
|
+
});
|
|
13176
|
+
if (shadow) (out[part] ??= {}).textShadow = shadow;
|
|
13177
|
+
if (family) (out[part] ??= {}).typeface = family;
|
|
13178
|
+
if (entry.axisVisible !== void 0) (out[part] ??= {}).axisVisible = entry.axisVisible;
|
|
13179
|
+
if (entry.labelsVisible !== void 0) (out[part] ??= {}).labelsVisible = entry.labelsVisible;
|
|
13180
|
+
if (entry.line?.widthEmu === 0) (out[part] ??= {}).lineWidth = 0;
|
|
13181
|
+
if (entry.fill?.kind === "gradient") {
|
|
13182
|
+
(out[part] ??= {}).gradient = resolveChartGradient(entry.fill, resolve);
|
|
13183
|
+
}
|
|
13184
|
+
}
|
|
13185
|
+
return out;
|
|
13186
|
+
}
|
|
13187
|
+
|
|
13188
|
+
// text/css-font-family.ts
|
|
13189
|
+
var FALLBACKS = {
|
|
13190
|
+
calibri: '"Calibri", "Carlito", "Segoe UI", Arial, sans-serif',
|
|
13191
|
+
"calibri light": '"Calibri Light", "Calibri", "Carlito", "Segoe UI", Arial, sans-serif',
|
|
13192
|
+
cambria: '"Cambria", "Caladea", Georgia, serif',
|
|
13193
|
+
arial: 'Arial, "Liberation Sans", Helvetica, sans-serif',
|
|
13194
|
+
"times new roman": '"Times New Roman", "Liberation Serif", Times, serif',
|
|
13195
|
+
"courier new": '"Courier New", "Liberation Mono", monospace',
|
|
13196
|
+
aptos: '"Aptos", "Calibri", "Carlito", "Segoe UI", sans-serif'
|
|
13197
|
+
};
|
|
13198
|
+
function cssFontFamily(name) {
|
|
13199
|
+
const known = FALLBACKS[name.toLowerCase()];
|
|
13200
|
+
if (known) return known;
|
|
13201
|
+
const quoted = `"${name.replace(/["\\]/g, "")}"`;
|
|
13202
|
+
return `${quoted}, "Calibri", "Carlito", "Segoe UI", sans-serif`;
|
|
13203
|
+
}
|
|
13204
|
+
|
|
13205
|
+
// chart/render/chart-svg-appearance.ts
|
|
13206
|
+
var nextPaintId = 0;
|
|
13207
|
+
function chartGradientPaint(model, width = 1024, height = 768) {
|
|
13208
|
+
const prefix2 = `xlsx-chart-${++nextPaintId}`;
|
|
13209
|
+
const appearance = { ...model.appearance };
|
|
13210
|
+
const defs = [];
|
|
13211
|
+
const shadowPaint = (shadow, suffix) => {
|
|
13212
|
+
const id = `${prefix2}-${suffix}`;
|
|
13213
|
+
const pad = Math.max(4, shadow.blur * 3 + Math.abs(shadow.dx) + Math.abs(shadow.dy));
|
|
13214
|
+
defs.push(
|
|
13215
|
+
`<filter id="${id}" filterUnits="userSpaceOnUse" x="${n(-pad)}" y="${n(-pad)}" width="${n(width + pad * 2)}" height="${n(height + pad * 2)}" color-interpolation-filters="sRGB">${svgDropShadowElement(shadow, { number: n, color: (value) => esc(value) })}</filter>`
|
|
13216
|
+
);
|
|
13217
|
+
return `url(#${id})`;
|
|
13218
|
+
};
|
|
13219
|
+
for (const [part, entry] of Object.entries(appearance)) {
|
|
13220
|
+
if (entry?.textShadow)
|
|
13221
|
+
appearance[part] = {
|
|
13222
|
+
...entry,
|
|
13223
|
+
textShadowFilter: shadowPaint(entry.textShadow, `${part}-text-shadow`)
|
|
13224
|
+
};
|
|
13225
|
+
}
|
|
13226
|
+
const paint2 = (gradient, suffix, bounds) => {
|
|
13227
|
+
const def = buildChartGradientDef(`${prefix2}-${suffix}`, gradient, bounds);
|
|
13228
|
+
defs.push(chartGradientMarkup(def));
|
|
13229
|
+
return `url(#${def.id})`;
|
|
13230
|
+
};
|
|
13231
|
+
for (const part of ["chartArea", "plotArea"]) {
|
|
13232
|
+
const entry = appearance[part];
|
|
13233
|
+
if (!entry?.gradient) continue;
|
|
13234
|
+
if (part === "plotArea" && ["circle", "shape"].includes(entry.gradient.path ?? "")) continue;
|
|
13235
|
+
appearance[part] = {
|
|
13236
|
+
...entry,
|
|
13237
|
+
fillColor: paint2(entry.gradient, part, { width, height, shape: "rect" })
|
|
13238
|
+
};
|
|
13239
|
+
}
|
|
13240
|
+
const series = model.series.map((source, index) => {
|
|
13241
|
+
const view = { ...source };
|
|
13242
|
+
if (source.shadow) view.shadowFilter = shadowPaint(source.shadow, `s${index}-shadow`);
|
|
13243
|
+
const bounds = model.type === "bar" || model.type === "column" ? { width: 1, height: 1, shape: "rect" } : void 0;
|
|
13244
|
+
if (source.gradient) view.color = paint2(source.gradient, `s${index}`, bounds);
|
|
13245
|
+
if (source.pointGradients) {
|
|
13246
|
+
view.pointColors = [...source.pointColors ?? []];
|
|
13247
|
+
for (const [key, gradient] of Object.entries(source.pointGradients))
|
|
13248
|
+
view.pointColors[Number(key)] = paint2(gradient, `s${index}-p${key}`, bounds);
|
|
13249
|
+
}
|
|
13250
|
+
return view;
|
|
13251
|
+
});
|
|
13252
|
+
return defs.length ? { model: { ...model, appearance, series }, defs: `<defs>${defs.join("")}</defs>` } : { model, defs: "" };
|
|
13253
|
+
}
|
|
13254
|
+
function chartTextAttributes(model, part, fallbackSize = FONT_SIZE) {
|
|
13255
|
+
const entry = model.appearance?.[part];
|
|
13256
|
+
return {
|
|
13257
|
+
size: entry?.fontSize === void 0 ? fallbackSize : chartPointsToPixels(entry.fontSize),
|
|
13258
|
+
...entry?.color === void 0 ? {} : { fill: entry.color },
|
|
13259
|
+
...entry?.bold === void 0 ? {} : { weight: entry.bold ? "bold" : "normal" },
|
|
13260
|
+
...entry?.italic === void 0 ? {} : { italic: entry.italic },
|
|
13261
|
+
...entry?.underline === void 0 ? {} : { underline: entry.underline },
|
|
13262
|
+
...entry?.typeface === void 0 ? {} : { family: cssFontFamily(entry.typeface) },
|
|
13263
|
+
...entry?.textShadowFilter === void 0 ? {} : { filter: entry.textShadowFilter }
|
|
13264
|
+
};
|
|
13265
|
+
}
|
|
13266
|
+
function chartStroke(model, part) {
|
|
13267
|
+
const entry = model.appearance?.[part];
|
|
13268
|
+
return {
|
|
13269
|
+
color: entry?.axisVisible === false ? "none" : entry?.lineColor ?? (part.startsWith("gridline") ? GRID_COLOR : AXIS_COLOR),
|
|
13270
|
+
width: entry?.lineWidth === void 0 ? 1 : chartPointsToPixels(entry.lineWidth)
|
|
13271
|
+
};
|
|
13272
|
+
}
|
|
13273
|
+
function chartAreaRect(model, part, area) {
|
|
13274
|
+
if (area.w <= 0 || area.h <= 0) return "";
|
|
13275
|
+
const entry = model.appearance?.[part];
|
|
13276
|
+
let fill = entry?.fillColor ?? (part === "chartArea" ? "#FFFFFF" : "none");
|
|
13277
|
+
let defs = "";
|
|
13278
|
+
if (part !== "chartArea" && entry?.gradient && (part !== "plotArea" || ["circle", "shape"].includes(entry.gradient.path ?? ""))) {
|
|
13279
|
+
const def = buildChartGradientDef(`xlsx-chart-${++nextPaintId}-${part}`, entry.gradient, {
|
|
13280
|
+
width: area.w,
|
|
13281
|
+
height: area.h,
|
|
13282
|
+
shape: "rect"
|
|
13283
|
+
});
|
|
13284
|
+
defs = `<defs>${chartGradientMarkup(def)}</defs>`;
|
|
13285
|
+
fill = `url(#${def.id})`;
|
|
13286
|
+
}
|
|
13287
|
+
const stroke = entry?.lineColor ?? "none";
|
|
13288
|
+
if (fill === "none" && stroke === "none") return "";
|
|
13289
|
+
const width = entry?.lineWidth === void 0 ? 1 : chartPointsToPixels(entry.lineWidth);
|
|
13290
|
+
return `${defs}<rect x="${n(area.x)}" y="${n(area.y)}" width="${n(area.w)}" height="${n(area.h)}" fill="${esc(fill)}" stroke="${esc(stroke)}" stroke-width="${n(width)}" data-chart-part="${part}"/>`;
|
|
13291
|
+
}
|
|
13292
|
+
|
|
13293
|
+
// chart/render/chart-svg-labels.ts
|
|
13294
|
+
var GAP = 3;
|
|
13295
|
+
var LINE = 1.2;
|
|
13296
|
+
var NAMED_COLORS = /^(black|blue|cyan|green|magenta|red|white|yellow)$/iu;
|
|
13297
|
+
function measure(model, label) {
|
|
13298
|
+
const attrs = chartTextAttributes(model, "dataLabel", 10);
|
|
13299
|
+
const size = attrs.size ?? 10;
|
|
13300
|
+
const lines = label.text.split("\n");
|
|
13301
|
+
return {
|
|
13302
|
+
lines,
|
|
13303
|
+
size,
|
|
13304
|
+
w: Math.max(...lines.map((l) => textWidth(l, size))),
|
|
13305
|
+
h: lines.length * size * LINE,
|
|
13306
|
+
attrs
|
|
13307
|
+
};
|
|
13308
|
+
}
|
|
13309
|
+
function draw(m, label, x, y, anchor, out) {
|
|
13310
|
+
const fill = label.color && NAMED_COLORS.test(label.color) ? label.color.toLowerCase() : void 0;
|
|
13311
|
+
m.lines.forEach((line3, k) => {
|
|
13312
|
+
const lineY = y - m.h / 2 + (k + 0.5) * m.size * LINE + m.size * 0.35;
|
|
13313
|
+
out.push(text(x, lineY, line3, { ...m.attrs, ...fill ? { fill } : {}, anchor }));
|
|
13314
|
+
});
|
|
13315
|
+
}
|
|
13316
|
+
function barLabels(model, marks, out) {
|
|
13317
|
+
const stacked = model.grouping === "stacked" || model.grouping === "percentStacked";
|
|
13318
|
+
for (const mark of marks) {
|
|
13319
|
+
const label = mark.series.labels?.[mark.index];
|
|
13320
|
+
if (!label) continue;
|
|
13321
|
+
const m = measure(model, label);
|
|
13322
|
+
let position = label.position ?? (stacked ? "ctr" : "outEnd");
|
|
13323
|
+
if (stacked && position === "outEnd") position = "ctr";
|
|
13324
|
+
const cx = mark.x + mark.w / 2;
|
|
13325
|
+
const cy = mark.y + mark.h / 2;
|
|
13326
|
+
if (model.horizontal) {
|
|
13327
|
+
const end = mark.negative ? mark.x : mark.x + mark.w;
|
|
13328
|
+
const base = mark.negative ? mark.x + mark.w : mark.x;
|
|
13329
|
+
const dir2 = mark.negative ? -1 : 1;
|
|
13330
|
+
const side = (at, outward) => [
|
|
13331
|
+
at + (outward ? dir2 : -dir2) * GAP,
|
|
13332
|
+
(outward ? dir2 : -dir2) > 0 ? "start" : "end"
|
|
13333
|
+
];
|
|
13334
|
+
const [x, anchor] = position === "ctr" ? [cx, "middle"] : position === "inEnd" ? side(end, false) : position === "inBase" ? side(base, true) : side(end, true);
|
|
13335
|
+
draw(m, label, x, cy, anchor, out);
|
|
13336
|
+
continue;
|
|
13337
|
+
}
|
|
13338
|
+
const top = mark.negative ? mark.y + mark.h : mark.y;
|
|
13339
|
+
const bottom = mark.negative ? mark.y : mark.y + mark.h;
|
|
13340
|
+
const dir = mark.negative ? 1 : -1;
|
|
13341
|
+
const y = position === "ctr" ? cy : position === "inEnd" ? top - dir * (GAP + m.h / 2) : position === "inBase" ? bottom + dir * (GAP + m.h / 2) : top + dir * (GAP + m.h / 2);
|
|
13342
|
+
draw(m, label, cx, y, "middle", out);
|
|
13343
|
+
}
|
|
13344
|
+
}
|
|
13345
|
+
function pointLabels(model, marks, out) {
|
|
13346
|
+
for (const mark of marks) {
|
|
13347
|
+
const label = mark.series.labels?.[mark.index];
|
|
13348
|
+
if (!label) continue;
|
|
13349
|
+
const m = measure(model, label);
|
|
13350
|
+
const reach = mark.radius + GAP;
|
|
13351
|
+
switch (model.type === "area" ? "ctr" : label.position ?? "r") {
|
|
13352
|
+
case "ctr":
|
|
13353
|
+
draw(m, label, mark.x, mark.y, "middle", out);
|
|
13354
|
+
break;
|
|
13355
|
+
case "t":
|
|
13356
|
+
draw(m, label, mark.x, mark.y - reach - m.h / 2, "middle", out);
|
|
13357
|
+
break;
|
|
13358
|
+
case "b":
|
|
13359
|
+
draw(m, label, mark.x, mark.y + reach + m.h / 2, "middle", out);
|
|
13360
|
+
break;
|
|
13361
|
+
case "l":
|
|
13362
|
+
draw(m, label, mark.x - reach, mark.y, "end", out);
|
|
13363
|
+
break;
|
|
13364
|
+
default:
|
|
13365
|
+
draw(m, label, mark.x + reach, mark.y, "start", out);
|
|
13366
|
+
}
|
|
13367
|
+
}
|
|
13368
|
+
}
|
|
13369
|
+
function sliceLabels(model, marks, out) {
|
|
13370
|
+
for (const mark of marks) {
|
|
13371
|
+
const label = mark.series.labels?.[mark.index];
|
|
13372
|
+
if (!label) continue;
|
|
13373
|
+
const m = measure(model, label);
|
|
13374
|
+
const mid = (mark.start + mark.end) / 2;
|
|
13375
|
+
const ux = Math.sin(mid);
|
|
13376
|
+
const uy = -Math.cos(mid);
|
|
13377
|
+
const place2 = (radius) => [
|
|
13378
|
+
mark.cx + radius * ux,
|
|
13379
|
+
mark.cy + radius * uy
|
|
13380
|
+
];
|
|
13381
|
+
const position = model.type === "doughnut" ? "ctr" : label.position ?? "bestFit";
|
|
13382
|
+
let x;
|
|
13383
|
+
let y;
|
|
13384
|
+
if (position === "ctr") [x, y] = place2(mark.inner + (mark.outer - mark.inner) / 2);
|
|
13385
|
+
else if (position === "inEnd") {
|
|
13386
|
+
const extent = Math.abs(ux) * m.w / 2 + Math.abs(uy) * m.h / 2;
|
|
13387
|
+
[x, y] = place2(Math.max(0, mark.outer - GAP - extent));
|
|
13388
|
+
} else if (position === "outEnd") {
|
|
13389
|
+
const extent = Math.abs(ux) * m.w / 2 + Math.abs(uy) * m.h / 2;
|
|
13390
|
+
[x, y] = place2(mark.outer + GAP + extent);
|
|
13391
|
+
} else {
|
|
13392
|
+
const placed2 = placeBestFitLabel(
|
|
13393
|
+
{
|
|
13394
|
+
cx: mark.cx,
|
|
13395
|
+
cy: mark.cy,
|
|
13396
|
+
outerR: mark.outer,
|
|
13397
|
+
startAngle: mark.start - Math.PI / 2,
|
|
13398
|
+
endAngle: mark.end - Math.PI / 2
|
|
13399
|
+
},
|
|
13400
|
+
m.w,
|
|
13401
|
+
m.h
|
|
13402
|
+
);
|
|
13403
|
+
x = placed2.x;
|
|
13404
|
+
y = placed2.y;
|
|
13405
|
+
}
|
|
13406
|
+
draw(m, label, x, y, "middle", out);
|
|
13407
|
+
}
|
|
13408
|
+
}
|
|
13409
|
+
function hasOutsideLabels(model) {
|
|
13410
|
+
return model.series.some(
|
|
13411
|
+
(s) => s.labels?.some(
|
|
13412
|
+
(l) => l !== void 0 && ["bestFit", "outEnd"].includes(l.position ?? "bestFit")
|
|
13413
|
+
)
|
|
13414
|
+
);
|
|
13415
|
+
}
|
|
13416
|
+
|
|
13417
|
+
// chart/render/chart-svg-bars.ts
|
|
13418
|
+
function barLayout(model, frame2) {
|
|
13419
|
+
const count = Math.max(1, model.series.length);
|
|
13420
|
+
const geometry = clusteredBarGeometry(frame2.bandSize, count, chartBarSpacing(model));
|
|
13421
|
+
const barSize = geometry.singleBarWidth;
|
|
13422
|
+
const offset = (si) => model.horizontal ? geometry.clusterWidth / 2 - barSize - si * geometry.step : -geometry.clusterWidth / 2 + si * geometry.step;
|
|
13423
|
+
return { barSize, offset };
|
|
13424
|
+
}
|
|
13425
|
+
function bars(model, frame2, out, values) {
|
|
13426
|
+
const stacked = model.grouping === "stacked" || model.grouping === "percentStacked";
|
|
13427
|
+
const { barSize, offset: barOffset } = barLayout(model, frame2);
|
|
13428
|
+
const base = frame2.value(0);
|
|
13429
|
+
const pos = new Array(model.categories.length).fill(0);
|
|
13430
|
+
const neg = new Array(model.categories.length).fill(0);
|
|
13431
|
+
const marks = [];
|
|
13432
|
+
model.series.forEach((s, si) => {
|
|
13433
|
+
values[si]?.forEach((v, i) => {
|
|
13434
|
+
if (v === null || i >= model.categories.length) return;
|
|
13435
|
+
let from = 0;
|
|
13436
|
+
let to = v;
|
|
13437
|
+
if (stacked) {
|
|
13438
|
+
const acc = v >= 0 ? pos : neg;
|
|
13439
|
+
from = acc[i] ?? 0;
|
|
13440
|
+
to = from + v;
|
|
13441
|
+
acc[i] = to;
|
|
13442
|
+
}
|
|
13443
|
+
const a = stacked ? frame2.value(from) : base;
|
|
13444
|
+
const b = frame2.value(to);
|
|
13445
|
+
const offset = barOffset(si);
|
|
13446
|
+
const center = frame2.band(i);
|
|
13447
|
+
const width = model.horizontal ? Math.abs(b - a) : barSize;
|
|
13448
|
+
const height = model.horizontal ? barSize : Math.abs(b - a);
|
|
13449
|
+
let color = s.pointColors?.[i] ?? s.color;
|
|
13450
|
+
const gradient = s.pointGradients?.[i] ?? (s.pointColors?.[i] === void 0 ? s.gradient : void 0);
|
|
13451
|
+
if (gradient && (gradient.path === "circle" || gradient.path === "shape")) {
|
|
13452
|
+
const baseId = color.match(/^url\(#(.+)\)$/)?.[1];
|
|
13453
|
+
if (baseId) {
|
|
13454
|
+
const id = baseId.replace(/(-s\d+(?:-p\d+)?)$/, `-mark${i}$1`);
|
|
13455
|
+
const def = buildChartGradientDef(id, gradient, {
|
|
13456
|
+
width: Number(n(width)),
|
|
13457
|
+
height: Number(n(height)),
|
|
13458
|
+
shape: "rect"
|
|
13459
|
+
});
|
|
13460
|
+
out.push(`<defs>${chartGradientMarkup(def)}</defs>`);
|
|
13461
|
+
color = `url(#${id})`;
|
|
13462
|
+
}
|
|
13463
|
+
}
|
|
13464
|
+
out.push(`<g data-chart-series="${si}" data-chart-point="${i}">`);
|
|
13465
|
+
const box = model.horizontal ? { x: Math.min(a, b), y: center + offset, w: Math.abs(b - a), h: barSize } : { x: center + offset, y: Math.min(a, b), w: barSize, h: Math.abs(b - a) };
|
|
13466
|
+
out.push(rect2(box.x, box.y, box.w, box.h, color, s.shadowFilter));
|
|
13467
|
+
out.push("</g>");
|
|
13468
|
+
marks.push({ series: s, index: i, ...box, negative: v < 0 });
|
|
13469
|
+
});
|
|
13470
|
+
});
|
|
13471
|
+
barLabels(model, marks, out);
|
|
13472
|
+
}
|
|
13473
|
+
|
|
13474
|
+
// chart/render/chart-svg-analysis.ts
|
|
13475
|
+
var DASHES = {
|
|
13476
|
+
dot: [1, 3],
|
|
13477
|
+
dash: [4, 3],
|
|
13478
|
+
lgDash: [8, 3],
|
|
13479
|
+
dashDot: [4, 3, 1, 3],
|
|
12540
13480
|
lgDashDot: [8, 3, 1, 3],
|
|
12541
13481
|
lgDashDotDot: [8, 3, 1, 3, 1, 3],
|
|
12542
13482
|
sysDash: [3, 1],
|
|
@@ -12617,6 +13557,60 @@ function scatterAnalysis(model, px, py, out) {
|
|
|
12617
13557
|
});
|
|
12618
13558
|
}
|
|
12619
13559
|
|
|
13560
|
+
// chart/render/chart-svg-markers.ts
|
|
13561
|
+
function chartMarkerRadius(series, index, defaultRadius = 3) {
|
|
13562
|
+
const marker = { ...series.marker, ...series.pointMarkers?.[index] };
|
|
13563
|
+
if (marker.symbol === "none") return 0;
|
|
13564
|
+
const radius = markerRadius(marker.size, defaultRadius);
|
|
13565
|
+
return marker.symbol === "dot" ? Math.max(radius * 0.6, 1) : radius;
|
|
13566
|
+
}
|
|
13567
|
+
function chartSeriesMarkerSvg(series, index, cx, cy, defaultRadius = 3) {
|
|
13568
|
+
const marker = { ...series.marker, ...series.pointMarkers?.[index] };
|
|
13569
|
+
const primitive = buildMarkerPrimitive({
|
|
13570
|
+
...marker,
|
|
13571
|
+
symbol: marker.symbol,
|
|
13572
|
+
size: marker.size,
|
|
13573
|
+
cx,
|
|
13574
|
+
cy,
|
|
13575
|
+
fill: marker.fill ?? series.pointColors?.[index] ?? series.color,
|
|
13576
|
+
defaultRadius
|
|
13577
|
+
});
|
|
13578
|
+
if (!primitive) return "";
|
|
13579
|
+
let geometry;
|
|
13580
|
+
switch (primitive.kind) {
|
|
13581
|
+
case "circle":
|
|
13582
|
+
geometry = `cx="${n(primitive.cx)}" cy="${n(primitive.cy)}" r="${n(primitive.r)}"`;
|
|
13583
|
+
break;
|
|
13584
|
+
case "rect":
|
|
13585
|
+
geometry = `x="${n(primitive.x)}" y="${n(primitive.y)}" width="${n(primitive.w)}" height="${n(primitive.h)}"`;
|
|
13586
|
+
break;
|
|
13587
|
+
case "path":
|
|
13588
|
+
geometry = `d="${esc(primitive.d)}"`;
|
|
13589
|
+
break;
|
|
13590
|
+
case "polygon":
|
|
13591
|
+
geometry = `points="${esc(primitive.points)}"`;
|
|
13592
|
+
break;
|
|
13593
|
+
}
|
|
13594
|
+
const outline = primitive.stroke ? ` stroke="${esc(primitive.stroke)}" stroke-width="${n(primitive.strokeWidth ?? 1)}"` : "";
|
|
13595
|
+
const filter = series.shadowFilter ? ` filter="${esc(series.shadowFilter)}"` : "";
|
|
13596
|
+
return `<${primitive.kind} ${geometry} fill="${esc(primitive.fill)}"${outline}${filter}/>`;
|
|
13597
|
+
}
|
|
13598
|
+
|
|
13599
|
+
// chart/line-dash.ts
|
|
13600
|
+
function chartLineDashArray(style, width) {
|
|
13601
|
+
if (!style || style === "solid") {
|
|
13602
|
+
return void 0;
|
|
13603
|
+
}
|
|
13604
|
+
const unit = Math.max(width, 1);
|
|
13605
|
+
if (style === "dot" || style === "sysDot") {
|
|
13606
|
+
return `${unit} ${unit * 2}`;
|
|
13607
|
+
}
|
|
13608
|
+
if (style === "lgDash") {
|
|
13609
|
+
return `${unit * 6} ${unit * 3}`;
|
|
13610
|
+
}
|
|
13611
|
+
return `${unit * 3} ${unit * 2}`;
|
|
13612
|
+
}
|
|
13613
|
+
|
|
12620
13614
|
// chart/render/chart-scale.ts
|
|
12621
13615
|
var clean = (n2) => Number(n2.toPrecision(12));
|
|
12622
13616
|
function* units(raw) {
|
|
@@ -12627,14 +13621,14 @@ function* units(raw) {
|
|
|
12627
13621
|
exp++;
|
|
12628
13622
|
}
|
|
12629
13623
|
}
|
|
12630
|
-
function niceScale(dataMin, dataMax,
|
|
12631
|
-
const maxIntervals = Math.max(1,
|
|
13624
|
+
function niceScale(dataMin, dataMax, options2 = {}) {
|
|
13625
|
+
const maxIntervals = Math.max(1, options2.maxIntervals ?? 10);
|
|
12632
13626
|
let lo = Number.isFinite(dataMin) ? dataMin : 0;
|
|
12633
13627
|
let hi = Number.isFinite(dataMax) ? dataMax : 0;
|
|
12634
13628
|
if (lo > hi) [lo, hi] = [hi, lo];
|
|
12635
13629
|
if (lo === hi) {
|
|
12636
13630
|
if (lo === 0) hi = 1;
|
|
12637
|
-
else if (
|
|
13631
|
+
else if (options2.noZero) {
|
|
12638
13632
|
const pad = Math.abs(lo) * 0.1 || 1;
|
|
12639
13633
|
lo -= pad;
|
|
12640
13634
|
hi += pad;
|
|
@@ -12643,7 +13637,7 @@ function niceScale(dataMin, dataMax, options = {}) {
|
|
|
12643
13637
|
}
|
|
12644
13638
|
let fixedLo = false;
|
|
12645
13639
|
let fixedHi = false;
|
|
12646
|
-
if (!
|
|
13640
|
+
if (!options2.noZero) {
|
|
12647
13641
|
if (lo >= 0 && hi - lo >= hi / 6) {
|
|
12648
13642
|
lo = 0;
|
|
12649
13643
|
fixedLo = true;
|
|
@@ -12683,144 +13677,231 @@ function formatAxisValue(value, percent = false) {
|
|
|
12683
13677
|
return `${v < 0 ? "-" : ""}${grouped}${frac ? `.${frac}` : ""}`;
|
|
12684
13678
|
}
|
|
12685
13679
|
|
|
12686
|
-
// chart/render/
|
|
12687
|
-
|
|
12688
|
-
|
|
12689
|
-
|
|
12690
|
-
|
|
12691
|
-
"
|
|
12692
|
-
|
|
12693
|
-
|
|
12694
|
-
|
|
12695
|
-
|
|
12696
|
-
|
|
12697
|
-
"
|
|
12698
|
-
|
|
12699
|
-
|
|
12700
|
-
|
|
12701
|
-
|
|
12702
|
-
|
|
12703
|
-
|
|
12704
|
-
|
|
12705
|
-
|
|
12706
|
-
|
|
12707
|
-
|
|
12708
|
-
|
|
12709
|
-
|
|
12710
|
-
|
|
12711
|
-
|
|
12712
|
-
"
|
|
12713
|
-
"
|
|
12714
|
-
|
|
12715
|
-
function themeColor(theme, index) {
|
|
12716
|
-
const hex = theme.colors[index] ?? DEFAULT_THEME_COLORS[index];
|
|
12717
|
-
return hex && parseArgbHex(hex) ? hex.replace(/^#/, "") : void 0;
|
|
13680
|
+
// chart/render/chart-svg-axes.ts
|
|
13681
|
+
function axisTickText(value, axis, percent = false) {
|
|
13682
|
+
return formatChartNumber(value, axis?.source.numberFormat?.formatCode) ?? formatAxisValue(value, percent);
|
|
13683
|
+
}
|
|
13684
|
+
function axisLine(model, axis, part, x1, y1, x2, y2) {
|
|
13685
|
+
if (axis?.source.deleted) return "";
|
|
13686
|
+
return styledAxisLine(x1, y1, x2, y2, axis?.line, chartStroke(model, part));
|
|
13687
|
+
}
|
|
13688
|
+
function styledAxisLine(x1, y1, x2, y2, paint2, fallback) {
|
|
13689
|
+
const color = paint2?.color ?? fallback.color;
|
|
13690
|
+
const width = paint2?.width ?? fallback.width;
|
|
13691
|
+
if (color === "none" || width === 0) return "";
|
|
13692
|
+
const dash = chartLineDashArray(paint2?.dash, width);
|
|
13693
|
+
return line2(x1, y1, x2, y2, esc(color), width).replace(
|
|
13694
|
+
"/>",
|
|
13695
|
+
dash ? ` stroke-dasharray="${dash}"/>` : "/>"
|
|
13696
|
+
);
|
|
13697
|
+
}
|
|
13698
|
+
function axisGridlines(model, axis, ticks, position, plot, vertical) {
|
|
13699
|
+
const draw2 = (values, paint2, minor2) => {
|
|
13700
|
+
const fallback = chartStroke(model, minor2 ? "gridlineMinor" : "gridlineMajor");
|
|
13701
|
+
return values.map((value) => {
|
|
13702
|
+
const p = position(value);
|
|
13703
|
+
return vertical ? styledAxisLine(p, plot.y, p, plot.y + plot.h, paint2, fallback) : styledAxisLine(plot.x, p, plot.x + plot.w, p, paint2, fallback);
|
|
13704
|
+
}).join("");
|
|
13705
|
+
};
|
|
13706
|
+
const major = !axis || axis.source.majorGridlines ? draw2(ticks, axis?.majorGrid, false) : "";
|
|
13707
|
+
const minor = axis?.source.minorGridlines ? draw2(axis.minorTicks, axis.minorGrid, true) : "";
|
|
13708
|
+
return major + minor;
|
|
12718
13709
|
}
|
|
12719
13710
|
|
|
12720
|
-
// chart/
|
|
12721
|
-
function
|
|
12722
|
-
const
|
|
12723
|
-
|
|
12724
|
-
|
|
13711
|
+
// chart/axis-range.ts
|
|
13712
|
+
function computeLogValueRange(series, logBase) {
|
|
13713
|
+
const allValues = series.flatMap((item) => item.values).filter((value) => value !== null && Number.isFinite(value) && value > 0);
|
|
13714
|
+
if (allValues.length === 0) {
|
|
13715
|
+
return { min: 1, max: logBase, span: 1, logScale: true, logBase };
|
|
13716
|
+
}
|
|
13717
|
+
const dataMin = Math.min(...allValues);
|
|
13718
|
+
const dataMax = Math.max(...allValues);
|
|
13719
|
+
const logMin = Math.floor(Math.log(dataMin) / Math.log(logBase));
|
|
13720
|
+
const logMax = Math.ceil(Math.log(dataMax) / Math.log(logBase));
|
|
13721
|
+
const min = logBase ** logMin;
|
|
13722
|
+
const max = logBase ** Math.max(logMax, logMin + 1);
|
|
12725
13723
|
return {
|
|
12726
|
-
|
|
12727
|
-
|
|
12728
|
-
|
|
12729
|
-
|
|
12730
|
-
|
|
13724
|
+
min,
|
|
13725
|
+
max,
|
|
13726
|
+
span: Math.max(Math.log(max) / Math.log(logBase) - Math.log(min) / Math.log(logBase), 1),
|
|
13727
|
+
logScale: true,
|
|
13728
|
+
logBase
|
|
13729
|
+
};
|
|
13730
|
+
}
|
|
13731
|
+
function withAxisBounds(automatic, axis, logBase) {
|
|
13732
|
+
const validMin = typeof axis?.min === "number" && Number.isFinite(axis.min) && (!logBase || axis.min > 0) ? axis.min : void 0;
|
|
13733
|
+
const validMax = typeof axis?.max === "number" && Number.isFinite(axis.max) && (!logBase || axis.max > 0) ? axis.max : void 0;
|
|
13734
|
+
const min = validMin ?? automatic.min;
|
|
13735
|
+
let max = validMax ?? automatic.max;
|
|
13736
|
+
const majorUnit = validMin === void 0 && validMax === void 0 ? automatic.majorUnit : void 0;
|
|
13737
|
+
if (max <= min) {
|
|
13738
|
+
max = logBase ? min * logBase : min + 1;
|
|
13739
|
+
}
|
|
13740
|
+
const span = logBase ? Math.log(max) / Math.log(logBase) - Math.log(min) / Math.log(logBase) : max - min;
|
|
13741
|
+
return {
|
|
13742
|
+
min,
|
|
13743
|
+
max,
|
|
13744
|
+
span: Math.max(span, Number.EPSILON),
|
|
13745
|
+
...majorUnit !== void 0 ? { majorUnit } : {},
|
|
13746
|
+
...logBase ? { logScale: true, logBase } : {},
|
|
13747
|
+
...axis?.orientation === "maxMin" ? { reverseOrder: true } : {}
|
|
12731
13748
|
};
|
|
12732
13749
|
}
|
|
12733
|
-
|
|
12734
|
-
|
|
12735
|
-
|
|
13750
|
+
|
|
13751
|
+
// chart/axis-ticks.ts
|
|
13752
|
+
var LOG_EXPONENT_TOLERANCE = 1e-12;
|
|
13753
|
+
function generateLogTicks(range) {
|
|
13754
|
+
if (!range.logScale || !range.logBase) {
|
|
13755
|
+
return [];
|
|
13756
|
+
}
|
|
13757
|
+
const base = range.logBase;
|
|
13758
|
+
const logMin = Math.log(range.min) / Math.log(base);
|
|
13759
|
+
const logMax = Math.log(range.max) / Math.log(base);
|
|
13760
|
+
const firstExponent = Math.ceil(logMin - LOG_EXPONENT_TOLERANCE);
|
|
13761
|
+
const lastExponent = Math.floor(logMax + LOG_EXPONENT_TOLERANCE);
|
|
13762
|
+
if (lastExponent < firstExponent) {
|
|
13763
|
+
return range.min === range.max ? [range.min] : [range.min, range.max];
|
|
13764
|
+
}
|
|
13765
|
+
return Array.from(
|
|
13766
|
+
{ length: lastExponent - firstExponent + 1 },
|
|
13767
|
+
(_unused, index) => base ** (firstExponent + index)
|
|
13768
|
+
);
|
|
13769
|
+
}
|
|
13770
|
+
function generateIntervalTicks(range, unit) {
|
|
13771
|
+
if (!Number.isFinite(unit) || unit <= 0 || range.logScale) {
|
|
13772
|
+
return [];
|
|
13773
|
+
}
|
|
13774
|
+
const tolerance = Math.max(1, Math.abs(range.min), Math.abs(range.max)) * 1e-12;
|
|
13775
|
+
const first3 = Math.ceil((range.min - tolerance) / unit);
|
|
13776
|
+
const last = Math.floor((range.max + tolerance) / unit);
|
|
13777
|
+
const count = Math.min(Math.max(last - first3 + 1, 0), 2e3);
|
|
13778
|
+
return Array.from({ length: count }, (_, index) => (first3 + index) * unit);
|
|
13779
|
+
}
|
|
13780
|
+
function generateAxisTicks(range, axis, defaultIntervals) {
|
|
13781
|
+
if (range.logScale && range.logBase) {
|
|
13782
|
+
return generateLogTicks(range);
|
|
13783
|
+
}
|
|
13784
|
+
const explicit = generateIntervalTicks(range, axis?.majorUnit ?? 0);
|
|
13785
|
+
if (explicit.length > 0) {
|
|
13786
|
+
return explicit;
|
|
13787
|
+
}
|
|
13788
|
+
const automatic = generateIntervalTicks(range, range.majorUnit ?? 0);
|
|
13789
|
+
if (automatic.length > 0) {
|
|
13790
|
+
return automatic;
|
|
13791
|
+
}
|
|
13792
|
+
return Array.from(
|
|
13793
|
+
{ length: defaultIntervals + 1 },
|
|
13794
|
+
(_, index) => range.min + range.span / defaultIntervals * index
|
|
13795
|
+
);
|
|
12736
13796
|
}
|
|
12737
|
-
|
|
12738
|
-
|
|
12739
|
-
|
|
12740
|
-
|
|
12741
|
-
"bold",
|
|
12742
|
-
"italic",
|
|
12743
|
-
"underline",
|
|
12744
|
-
"typeface",
|
|
12745
|
-
"textColor",
|
|
12746
|
-
"fontRef"
|
|
12747
|
-
];
|
|
12748
|
-
var TEXT_PARTS = [
|
|
12749
|
-
"title",
|
|
12750
|
-
"axisTitle",
|
|
12751
|
-
"categoryAxis",
|
|
12752
|
-
"valueAxis",
|
|
12753
|
-
"legend",
|
|
12754
|
-
"dataLabel"
|
|
12755
|
-
];
|
|
12756
|
-
function inheritChartText(part, entry, builtIn, root) {
|
|
12757
|
-
if (!root || !TEXT_PARTS.includes(part)) return entry;
|
|
12758
|
-
const out = { ...entry };
|
|
12759
|
-
for (const key of TEXT_KEYS) {
|
|
12760
|
-
delete out[key];
|
|
12761
|
-
const value = root[key] ?? builtIn?.[key];
|
|
12762
|
-
if (value !== void 0) Object.assign(out, { [key]: value });
|
|
13797
|
+
function generateMinorAxisTicks(range, axis) {
|
|
13798
|
+
const minor = generateIntervalTicks(range, axis?.minorUnit ?? 0);
|
|
13799
|
+
if (minor.length === 0) {
|
|
13800
|
+
return [];
|
|
12763
13801
|
}
|
|
12764
|
-
|
|
12765
|
-
if (
|
|
12766
|
-
|
|
13802
|
+
const majorUnit = axis?.majorUnit;
|
|
13803
|
+
if (!majorUnit || !Number.isFinite(majorUnit) || majorUnit <= 0) {
|
|
13804
|
+
return minor;
|
|
13805
|
+
}
|
|
13806
|
+
const tolerance = Math.max(1, Math.abs(range.min), Math.abs(range.max)) * 1e-10;
|
|
13807
|
+
return minor.filter(
|
|
13808
|
+
(value) => Math.abs(value / majorUnit - Math.round(value / majorUnit)) > tolerance
|
|
13809
|
+
);
|
|
12767
13810
|
}
|
|
12768
13811
|
|
|
12769
|
-
// chart/render/chart-
|
|
12770
|
-
|
|
12771
|
-
|
|
12772
|
-
const
|
|
12773
|
-
|
|
12774
|
-
if (name?.startsWith("+mn-")) return theme.minorFont;
|
|
12775
|
-
return name ?? (entry.fontRef?.index === "major" ? theme.majorFont : entry.fontRef?.index === "minor" ? theme.minorFont : void 0);
|
|
13812
|
+
// chart/render/chart-view-axes.ts
|
|
13813
|
+
function chartAxisRatio(value, scale, axis) {
|
|
13814
|
+
const range = axis?.range;
|
|
13815
|
+
const ratio = range?.logScale ? Math.log(Math.max(value, range.min) / range.min) / Math.log(range.max / range.min) : (value - scale.min) / (scale.max - scale.min || 1);
|
|
13816
|
+
return range?.reverseOrder ? 1 - ratio : ratio;
|
|
12776
13817
|
}
|
|
12777
|
-
function
|
|
12778
|
-
|
|
12779
|
-
|
|
12780
|
-
|
|
12781
|
-
|
|
12782
|
-
|
|
12783
|
-
|
|
12784
|
-
|
|
12785
|
-
|
|
12786
|
-
|
|
12787
|
-
|
|
12788
|
-
|
|
12789
|
-
|
|
12790
|
-
|
|
12791
|
-
|
|
12792
|
-
|
|
12793
|
-
|
|
12794
|
-
|
|
12795
|
-
|
|
12796
|
-
|
|
12797
|
-
const scheme = chartColorScheme(theme);
|
|
12798
|
-
const resolve = (color) => resolveDrawingColor(
|
|
12799
|
-
color,
|
|
12800
|
-
{ scheme: (name) => scheme[name] },
|
|
12801
|
-
{ hslRounding: "halfDown", transformOrder: "document" }
|
|
13818
|
+
function chartAxisLabels(axis) {
|
|
13819
|
+
return axis?.source.deleted !== true && axis?.source.tickLabelPosition !== "none";
|
|
13820
|
+
}
|
|
13821
|
+
function options(axis) {
|
|
13822
|
+
return {
|
|
13823
|
+
...axis.scaling,
|
|
13824
|
+
...axis.scaling.logBase === void 0 ? {} : { logScale: true },
|
|
13825
|
+
...axis.majorUnit === void 0 ? {} : { majorUnit: axis.majorUnit },
|
|
13826
|
+
...axis.minorUnit === void 0 ? {} : { minorUnit: axis.minorUnit }
|
|
13827
|
+
};
|
|
13828
|
+
}
|
|
13829
|
+
function applyChartAxes(model, chart, color) {
|
|
13830
|
+
if (!chart.axes?.length) return;
|
|
13831
|
+
const axes = chart.axes;
|
|
13832
|
+
const linked = axes.filter((axis) => axis.id !== void 0 && chart.axisIds?.includes(axis.id));
|
|
13833
|
+
const candidates = linked.length ? linked : axes;
|
|
13834
|
+
const xy = model.type === "scatter" || model.type === "bubble";
|
|
13835
|
+
const value = candidates.find((axis) => axis.kind === "val" && !["b", "t"].includes(axis.position ?? "")) ?? candidates.find((axis) => axis.kind === "val");
|
|
13836
|
+
const category = candidates.find(
|
|
13837
|
+
(axis) => xy ? axis.kind === "val" && axis !== value : axis.kind === "cat" || axis.kind === "date"
|
|
12802
13838
|
);
|
|
12803
|
-
const
|
|
12804
|
-
|
|
12805
|
-
|
|
12806
|
-
|
|
12807
|
-
|
|
12808
|
-
|
|
12809
|
-
|
|
12810
|
-
|
|
12811
|
-
|
|
12812
|
-
|
|
12813
|
-
|
|
12814
|
-
|
|
12815
|
-
|
|
12816
|
-
|
|
12817
|
-
|
|
12818
|
-
|
|
12819
|
-
|
|
12820
|
-
|
|
13839
|
+
const secondary = axes.find((axis) => axis.kind === "val" && axis !== value && axis !== category);
|
|
13840
|
+
const paint2 = (shape) => {
|
|
13841
|
+
const ln = shape?.line;
|
|
13842
|
+
const fill = ln?.fill;
|
|
13843
|
+
const resolved = fill?.kind === "none" ? "none" : color(fill?.kind === "solid" ? fill.color : void 0);
|
|
13844
|
+
return {
|
|
13845
|
+
...resolved === void 0 ? {} : { color: resolved },
|
|
13846
|
+
...ln?.widthEmu === void 0 ? {} : { width: ln.widthEmu / EMU_PER_PIXEL },
|
|
13847
|
+
...ln?.dash === void 0 ? {} : { dash: ln.dash }
|
|
13848
|
+
};
|
|
13849
|
+
};
|
|
13850
|
+
const bind = (axis, scale, values) => {
|
|
13851
|
+
const opts = options(axis);
|
|
13852
|
+
const automatic = opts.logScale ? computeLogValueRange(
|
|
13853
|
+
[{ values: values ?? [] }],
|
|
13854
|
+
opts.logBase && Number.isFinite(opts.logBase) && opts.logBase > 1 ? opts.logBase : 10
|
|
13855
|
+
) : {
|
|
13856
|
+
min: scale?.min ?? 0,
|
|
13857
|
+
max: scale?.max ?? 1,
|
|
13858
|
+
span: (scale?.max ?? 1) - (scale?.min ?? 0),
|
|
13859
|
+
...scale ? { majorUnit: scale.majorUnit } : {}
|
|
13860
|
+
};
|
|
13861
|
+
const logBase = automatic.logBase;
|
|
13862
|
+
const range = withAxisBounds(automatic, opts, logBase);
|
|
13863
|
+
if (scale) {
|
|
13864
|
+
scale.min = range.min;
|
|
13865
|
+
scale.max = range.max;
|
|
13866
|
+
scale.ticks = generateAxisTicks(range, opts, 5);
|
|
12821
13867
|
}
|
|
12822
|
-
|
|
12823
|
-
|
|
13868
|
+
return {
|
|
13869
|
+
source: axis,
|
|
13870
|
+
range,
|
|
13871
|
+
minorTicks: generateMinorAxisTicks(range, opts),
|
|
13872
|
+
line: paint2(axis.spPr),
|
|
13873
|
+
majorGrid: paint2(axis.majorGridlinesSpPr),
|
|
13874
|
+
minorGrid: paint2(axis.minorGridlinesSpPr)
|
|
13875
|
+
};
|
|
13876
|
+
};
|
|
13877
|
+
const out = {};
|
|
13878
|
+
if (value)
|
|
13879
|
+
out.value = bind(
|
|
13880
|
+
value,
|
|
13881
|
+
model.valueAxis,
|
|
13882
|
+
[
|
|
13883
|
+
...model.series,
|
|
13884
|
+
...model.extraGroups?.filter((g) => !g.secondary).flatMap((g) => g.series) ?? []
|
|
13885
|
+
].flatMap((s) => s.values)
|
|
13886
|
+
);
|
|
13887
|
+
if (category)
|
|
13888
|
+
out.category = bind(
|
|
13889
|
+
category,
|
|
13890
|
+
model.xAxis ?? {
|
|
13891
|
+
min: 0,
|
|
13892
|
+
max: Math.max(1, model.categories.length - 1),
|
|
13893
|
+
majorUnit: 1,
|
|
13894
|
+
ticks: []
|
|
13895
|
+
},
|
|
13896
|
+
model.series.flatMap((s) => s.xValues ?? [])
|
|
13897
|
+
);
|
|
13898
|
+
if (secondary)
|
|
13899
|
+
out.secondary = bind(
|
|
13900
|
+
secondary,
|
|
13901
|
+
model.secondaryAxis,
|
|
13902
|
+
model.extraGroups?.filter((g) => g.secondary).flatMap((g) => g.series.flatMap((s) => s.values))
|
|
13903
|
+
);
|
|
13904
|
+
model.axes = out;
|
|
12824
13905
|
}
|
|
12825
13906
|
|
|
12826
13907
|
// chart/render/chart-view-analysis.ts
|
|
@@ -12872,15 +13953,15 @@ function seriesName(series, index, evaluateRef) {
|
|
|
12872
13953
|
const fromRef = resolveRef(series.nameRef, evaluateRef)?.map(toText).filter((t) => t !== "").join(" ");
|
|
12873
13954
|
return fromRef || series.name || `Series${index + 1}`;
|
|
12874
13955
|
}
|
|
12875
|
-
function seriesContext(chart, theme,
|
|
13956
|
+
function seriesContext(chart, theme, options2) {
|
|
12876
13957
|
const scheme = chartColorScheme(theme);
|
|
12877
13958
|
const resolver = { scheme: (name) => scheme[name] };
|
|
12878
13959
|
return {
|
|
12879
13960
|
theme,
|
|
12880
13961
|
scheme,
|
|
12881
13962
|
palette: chart.colorPalette === void 0 ? void 0 : findChartColorPalette(chart.colorPalette),
|
|
12882
|
-
evaluateRef:
|
|
12883
|
-
seriesColor:
|
|
13963
|
+
evaluateRef: options2.evaluateRef ?? (() => []),
|
|
13964
|
+
seriesColor: options2.seriesColor,
|
|
12884
13965
|
drawingColor: (color) => color && drawingColorCss(resolveDrawingColor(color, resolver, { transformOrder: "document" })),
|
|
12885
13966
|
gradient: (fill) => fill?.kind === "gradient" ? resolveChartGradient(
|
|
12886
13967
|
fill,
|
|
@@ -12906,7 +13987,11 @@ function seriesView(ctx, s, index, total, categoriesOf) {
|
|
|
12906
13987
|
})
|
|
12907
13988
|
);
|
|
12908
13989
|
if (Object.keys(points).length) view.pointGradients = points;
|
|
12909
|
-
Object.assign(
|
|
13990
|
+
Object.assign(
|
|
13991
|
+
view,
|
|
13992
|
+
analysisView(s, color, ctx.drawingColor),
|
|
13993
|
+
seriesMarkerViews(s, ctx.drawingColor)
|
|
13994
|
+
);
|
|
12910
13995
|
return view;
|
|
12911
13996
|
}
|
|
12912
13997
|
|
|
@@ -13079,12 +14164,70 @@ function chartTitleText(chart, theme) {
|
|
|
13079
14164
|
};
|
|
13080
14165
|
}
|
|
13081
14166
|
|
|
14167
|
+
// chart/render/chart-view-labels.ts
|
|
14168
|
+
function labelsOf(source, view, categories, numberFormat) {
|
|
14169
|
+
const { chart, series, points } = source;
|
|
14170
|
+
if ((series?.deleted ?? chart?.deleted) === true) return void 0;
|
|
14171
|
+
const percentBase = view.values.reduce(
|
|
14172
|
+
(sum, v) => sum + (v === null ? 0 : Math.abs(v)),
|
|
14173
|
+
0
|
|
14174
|
+
);
|
|
14175
|
+
const out = [];
|
|
14176
|
+
let any = false;
|
|
14177
|
+
view.values.forEach((value, i) => {
|
|
14178
|
+
const point = points?.[i];
|
|
14179
|
+
if (value === null || point?.deleted === true) return;
|
|
14180
|
+
const position = point?.position ?? series?.position ?? chart?.position;
|
|
14181
|
+
const x = view.xValues?.[i];
|
|
14182
|
+
const category = x === void 0 || x === null ? categories[i] : formatAxisValue(x);
|
|
14183
|
+
let built;
|
|
14184
|
+
if (point?.text !== void 0) built = { text: point.text };
|
|
14185
|
+
else {
|
|
14186
|
+
const flags = resolveDataLabelFlags({
|
|
14187
|
+
...point ? { point } : {},
|
|
14188
|
+
...series ? { series } : {},
|
|
14189
|
+
...chart ? { chart } : {}
|
|
14190
|
+
});
|
|
14191
|
+
built = composeDataLabelText({
|
|
14192
|
+
flags,
|
|
14193
|
+
seriesName: view.name,
|
|
14194
|
+
category,
|
|
14195
|
+
value,
|
|
14196
|
+
numberFormat: point?.numberFormat ?? series?.numberFormat ?? chart?.numberFormat ?? numberFormat,
|
|
14197
|
+
percentBase,
|
|
14198
|
+
bubbleSize: view.sizes?.[i] ?? void 0,
|
|
14199
|
+
formatValue: (v) => formatAxisValue(v),
|
|
14200
|
+
formatBubbleSize: (size) => formatAxisValue(size)
|
|
14201
|
+
});
|
|
14202
|
+
}
|
|
14203
|
+
if (!built) return;
|
|
14204
|
+
any = true;
|
|
14205
|
+
out[i] = {
|
|
14206
|
+
text: built.text,
|
|
14207
|
+
...position ? { position } : {},
|
|
14208
|
+
...built.color ? { color: built.color } : {}
|
|
14209
|
+
};
|
|
14210
|
+
});
|
|
14211
|
+
return any ? out : void 0;
|
|
14212
|
+
}
|
|
14213
|
+
function applyDataLabels(model, sources, extra) {
|
|
14214
|
+
const apply = (source, view) => {
|
|
14215
|
+
if (!source?.dataLabels) return;
|
|
14216
|
+
const labels = labelsOf(source.dataLabels, view, model.categories, source.numberFormat);
|
|
14217
|
+
if (labels) view.labels = labels;
|
|
14218
|
+
};
|
|
14219
|
+
model.series.forEach((view, i) => apply(sources[i], view));
|
|
14220
|
+
model.extraGroups?.forEach(
|
|
14221
|
+
(group2, g) => group2.series.forEach((view, i) => apply(extra[g]?.series[i], view))
|
|
14222
|
+
);
|
|
14223
|
+
}
|
|
14224
|
+
|
|
13082
14225
|
// chart/render/chart-view-ex.ts
|
|
13083
14226
|
function groupsAxis(groups, categories) {
|
|
13084
14227
|
let min = Infinity;
|
|
13085
14228
|
let max = -Infinity;
|
|
13086
|
-
for (const
|
|
13087
|
-
const extent = valueExtent(
|
|
14229
|
+
for (const group2 of groups) {
|
|
14230
|
+
const extent = valueExtent(group2.type, group2.grouping, group2.series, categories);
|
|
13088
14231
|
min = Math.min(min, extent.min);
|
|
13089
14232
|
max = Math.max(max, extent.max);
|
|
13090
14233
|
}
|
|
@@ -13093,17 +14236,17 @@ function groupsAxis(groups, categories) {
|
|
|
13093
14236
|
function chartExtraView(chart, model, ctx, total, categoriesOf) {
|
|
13094
14237
|
let index = chart.series.length;
|
|
13095
14238
|
const groups = [];
|
|
13096
|
-
for (const
|
|
13097
|
-
const series =
|
|
14239
|
+
for (const group2 of chart.extraGroups ?? []) {
|
|
14240
|
+
const series = group2.series.map((s) => seriesView(ctx, s, index++, total, categoriesOf));
|
|
13098
14241
|
const view = {
|
|
13099
|
-
type:
|
|
13100
|
-
grouping:
|
|
14242
|
+
type: group2.chartType,
|
|
14243
|
+
grouping: group2.grouping ?? (group2.chartType === "column" ? "clustered" : "standard"),
|
|
13101
14244
|
series,
|
|
13102
|
-
secondary:
|
|
14245
|
+
secondary: group2.secondary
|
|
13103
14246
|
};
|
|
13104
|
-
if (
|
|
13105
|
-
if (
|
|
13106
|
-
if (
|
|
14247
|
+
if (group2.chartType === "stock") view.stock = stockView(group2.stock, ctx);
|
|
14248
|
+
if (group2.barGapWidth !== void 0) view.barGapWidth = group2.barGapWidth;
|
|
14249
|
+
if (group2.barOverlap !== void 0) view.barOverlap = group2.barOverlap;
|
|
13107
14250
|
groups.push(view);
|
|
13108
14251
|
}
|
|
13109
14252
|
if (!groups.length) return;
|
|
@@ -13120,8 +14263,8 @@ function chartExtraAxes(model) {
|
|
|
13120
14263
|
const own2 = valueExtent(model.type, model.grouping, model.series, count);
|
|
13121
14264
|
let min = own2.min;
|
|
13122
14265
|
let max = own2.max;
|
|
13123
|
-
for (const
|
|
13124
|
-
const extent = valueExtent(
|
|
14266
|
+
for (const group2 of shared) {
|
|
14267
|
+
const extent = valueExtent(group2.type, group2.grouping, group2.series, count);
|
|
13125
14268
|
min = Math.min(min, extent.min);
|
|
13126
14269
|
max = Math.max(max, extent.max);
|
|
13127
14270
|
}
|
|
@@ -13148,11 +14291,11 @@ function histogramView(chart, model) {
|
|
|
13148
14291
|
const first3 = model.series[0];
|
|
13149
14292
|
if (!first3) return;
|
|
13150
14293
|
const raw = first3.values.map((v) => v ?? Number.NaN);
|
|
13151
|
-
const
|
|
13152
|
-
const bins =
|
|
14294
|
+
const options2 = chart.histogram ?? {};
|
|
14295
|
+
const bins = options2.aggregateByCategory ? aggregateByCategory(
|
|
13153
14296
|
first3.values.map((v) => v ?? 0),
|
|
13154
14297
|
model.categories
|
|
13155
|
-
) : computeHistogramBins(raw,
|
|
14298
|
+
) : computeHistogramBins(raw, options2, formatAxisValue);
|
|
13156
14299
|
model.categories = bins.map((bin) => bin.label);
|
|
13157
14300
|
first3.values = bins.map((bin) => bin.value);
|
|
13158
14301
|
model.barGapWidth = 0;
|
|
@@ -13176,11 +14319,11 @@ var SUPPORTED = /* @__PURE__ */ new Set([
|
|
|
13176
14319
|
"treemap",
|
|
13177
14320
|
"sunburst"
|
|
13178
14321
|
]);
|
|
13179
|
-
function chartSummaryView(chart, theme,
|
|
14322
|
+
function chartSummaryView(chart, theme, options2 = {}) {
|
|
13180
14323
|
const type = chart.chartType;
|
|
13181
14324
|
const radial = type === "pie" || type === "doughnut";
|
|
13182
14325
|
const byPoint = radial || type === "treemap" || type === "sunburst";
|
|
13183
|
-
const ctx = seriesContext(chart, theme,
|
|
14326
|
+
const ctx = seriesContext(chart, theme, options2);
|
|
13184
14327
|
const { palette, scheme, drawingColor } = ctx;
|
|
13185
14328
|
const grouping = chart.grouping ?? (type === "bar" || type === "column" ? "clustered" : "standard");
|
|
13186
14329
|
const rawCategories = [];
|
|
@@ -13264,128 +14407,23 @@ function chartSummaryView(chart, theme, options = {}) {
|
|
|
13264
14407
|
chartExtraView(chart, model, ctx, total, collect);
|
|
13265
14408
|
if (type === "waterfall") waterfallView(chart, model, ctx);
|
|
13266
14409
|
else if (!byPoint) model.valueAxis = valueAxis(model);
|
|
14410
|
+
applyDataLabels(model, chart.series, extra);
|
|
13267
14411
|
chartExtraAxes(model);
|
|
14412
|
+
applyChartAxes(model, chart, ctx.drawingColor);
|
|
13268
14413
|
return model;
|
|
13269
14414
|
}
|
|
13270
14415
|
|
|
13271
|
-
// text/css-font-family.ts
|
|
13272
|
-
var FALLBACKS = {
|
|
13273
|
-
calibri: '"Calibri", "Carlito", "Segoe UI", Arial, sans-serif',
|
|
13274
|
-
"calibri light": '"Calibri Light", "Calibri", "Carlito", "Segoe UI", Arial, sans-serif',
|
|
13275
|
-
cambria: '"Cambria", "Caladea", Georgia, serif',
|
|
13276
|
-
arial: 'Arial, "Liberation Sans", Helvetica, sans-serif',
|
|
13277
|
-
"times new roman": '"Times New Roman", "Liberation Serif", Times, serif',
|
|
13278
|
-
"courier new": '"Courier New", "Liberation Mono", monospace',
|
|
13279
|
-
aptos: '"Aptos", "Calibri", "Carlito", "Segoe UI", sans-serif'
|
|
13280
|
-
};
|
|
13281
|
-
function cssFontFamily(name) {
|
|
13282
|
-
const known = FALLBACKS[name.toLowerCase()];
|
|
13283
|
-
if (known) return known;
|
|
13284
|
-
const quoted = `"${name.replace(/["\\]/g, "")}"`;
|
|
13285
|
-
return `${quoted}, "Calibri", "Carlito", "Segoe UI", sans-serif`;
|
|
13286
|
-
}
|
|
13287
|
-
|
|
13288
|
-
// chart/render/chart-svg-appearance.ts
|
|
13289
|
-
var nextPaintId = 0;
|
|
13290
|
-
function chartGradientPaint(model, width = 1024, height = 768) {
|
|
13291
|
-
const prefix2 = `xlsx-chart-${++nextPaintId}`;
|
|
13292
|
-
const appearance = { ...model.appearance };
|
|
13293
|
-
const defs = [];
|
|
13294
|
-
const shadowPaint = (shadow, suffix) => {
|
|
13295
|
-
const id = `${prefix2}-${suffix}`;
|
|
13296
|
-
const pad = Math.max(4, shadow.blur * 3 + Math.abs(shadow.dx) + Math.abs(shadow.dy));
|
|
13297
|
-
defs.push(
|
|
13298
|
-
`<filter id="${id}" filterUnits="userSpaceOnUse" x="${n(-pad)}" y="${n(-pad)}" width="${n(width + pad * 2)}" height="${n(height + pad * 2)}" color-interpolation-filters="sRGB">${svgDropShadowElement(shadow, { number: n, color: (value) => esc(value) })}</filter>`
|
|
13299
|
-
);
|
|
13300
|
-
return `url(#${id})`;
|
|
13301
|
-
};
|
|
13302
|
-
for (const [part, entry] of Object.entries(appearance)) {
|
|
13303
|
-
if (entry?.textShadow)
|
|
13304
|
-
appearance[part] = {
|
|
13305
|
-
...entry,
|
|
13306
|
-
textShadowFilter: shadowPaint(entry.textShadow, `${part}-text-shadow`)
|
|
13307
|
-
};
|
|
13308
|
-
}
|
|
13309
|
-
const paint2 = (gradient, suffix, bounds) => {
|
|
13310
|
-
const def = buildChartGradientDef(`${prefix2}-${suffix}`, gradient, bounds);
|
|
13311
|
-
defs.push(chartGradientMarkup(def));
|
|
13312
|
-
return `url(#${def.id})`;
|
|
13313
|
-
};
|
|
13314
|
-
for (const part of ["chartArea", "plotArea"]) {
|
|
13315
|
-
const entry = appearance[part];
|
|
13316
|
-
if (!entry?.gradient) continue;
|
|
13317
|
-
if (part === "plotArea" && ["circle", "shape"].includes(entry.gradient.path ?? "")) continue;
|
|
13318
|
-
appearance[part] = {
|
|
13319
|
-
...entry,
|
|
13320
|
-
fillColor: paint2(entry.gradient, part, { width, height, shape: "rect" })
|
|
13321
|
-
};
|
|
13322
|
-
}
|
|
13323
|
-
const series = model.series.map((source, index) => {
|
|
13324
|
-
const view = { ...source };
|
|
13325
|
-
if (source.shadow) view.shadowFilter = shadowPaint(source.shadow, `s${index}-shadow`);
|
|
13326
|
-
const bounds = model.type === "bar" || model.type === "column" ? { width: 1, height: 1, shape: "rect" } : void 0;
|
|
13327
|
-
if (source.gradient) view.color = paint2(source.gradient, `s${index}`, bounds);
|
|
13328
|
-
if (source.pointGradients) {
|
|
13329
|
-
view.pointColors = [...source.pointColors ?? []];
|
|
13330
|
-
for (const [key, gradient] of Object.entries(source.pointGradients))
|
|
13331
|
-
view.pointColors[Number(key)] = paint2(gradient, `s${index}-p${key}`, bounds);
|
|
13332
|
-
}
|
|
13333
|
-
return view;
|
|
13334
|
-
});
|
|
13335
|
-
return defs.length ? { model: { ...model, appearance, series }, defs: `<defs>${defs.join("")}</defs>` } : { model, defs: "" };
|
|
13336
|
-
}
|
|
13337
|
-
function chartTextAttributes(model, part, fallbackSize = FONT_SIZE) {
|
|
13338
|
-
const entry = model.appearance?.[part];
|
|
13339
|
-
return {
|
|
13340
|
-
size: entry?.fontSize === void 0 ? fallbackSize : chartPointsToPixels(entry.fontSize),
|
|
13341
|
-
...entry?.color === void 0 ? {} : { fill: entry.color },
|
|
13342
|
-
...entry?.bold === void 0 ? {} : { weight: entry.bold ? "bold" : "normal" },
|
|
13343
|
-
...entry?.italic === void 0 ? {} : { italic: entry.italic },
|
|
13344
|
-
...entry?.underline === void 0 ? {} : { underline: entry.underline },
|
|
13345
|
-
...entry?.typeface === void 0 ? {} : { family: cssFontFamily(entry.typeface) },
|
|
13346
|
-
...entry?.textShadowFilter === void 0 ? {} : { filter: entry.textShadowFilter }
|
|
13347
|
-
};
|
|
13348
|
-
}
|
|
13349
|
-
function chartStroke(model, part) {
|
|
13350
|
-
const entry = model.appearance?.[part];
|
|
13351
|
-
return {
|
|
13352
|
-
color: entry?.axisVisible === false ? "none" : entry?.lineColor ?? (part === "gridlineMajor" ? GRID_COLOR : AXIS_COLOR),
|
|
13353
|
-
width: entry?.lineWidth === void 0 ? 1 : chartPointsToPixels(entry.lineWidth)
|
|
13354
|
-
};
|
|
13355
|
-
}
|
|
13356
|
-
function chartAreaRect(model, part, area) {
|
|
13357
|
-
if (area.w <= 0 || area.h <= 0) return "";
|
|
13358
|
-
const entry = model.appearance?.[part];
|
|
13359
|
-
let fill = entry?.fillColor ?? (part === "chartArea" ? "#FFFFFF" : "none");
|
|
13360
|
-
let defs = "";
|
|
13361
|
-
if (part !== "chartArea" && entry?.gradient && (part !== "plotArea" || ["circle", "shape"].includes(entry.gradient.path ?? ""))) {
|
|
13362
|
-
const def = buildChartGradientDef(`xlsx-chart-${++nextPaintId}-${part}`, entry.gradient, {
|
|
13363
|
-
width: area.w,
|
|
13364
|
-
height: area.h,
|
|
13365
|
-
shape: "rect"
|
|
13366
|
-
});
|
|
13367
|
-
defs = `<defs>${chartGradientMarkup(def)}</defs>`;
|
|
13368
|
-
fill = `url(#${def.id})`;
|
|
13369
|
-
}
|
|
13370
|
-
const stroke = entry?.lineColor ?? "none";
|
|
13371
|
-
if (fill === "none" && stroke === "none") return "";
|
|
13372
|
-
const width = entry?.lineWidth === void 0 ? 1 : chartPointsToPixels(entry.lineWidth);
|
|
13373
|
-
return `${defs}<rect x="${n(area.x)}" y="${n(area.y)}" width="${n(area.w)}" height="${n(area.h)}" fill="${esc(fill)}" stroke="${esc(stroke)}" stroke-width="${n(width)}" data-chart-part="${part}"/>`;
|
|
13374
|
-
}
|
|
13375
|
-
|
|
13376
14416
|
// chart/render/chart-svg-cartesian.ts
|
|
13377
14417
|
function cartesianAxes(model, area, out) {
|
|
13378
14418
|
const scale = model.valueAxis;
|
|
13379
14419
|
if (!scale) return void 0;
|
|
13380
|
-
const labels = scale.ticks.map((t) =>
|
|
14420
|
+
const labels = scale.ticks.map((t) => axisTickText(t, model.axes?.value, scale.percent));
|
|
13381
14421
|
const valueAttrs = chartTextAttributes(model, "valueAxis");
|
|
13382
14422
|
const categoryAttrs = chartTextAttributes(model, "categoryAxis");
|
|
13383
14423
|
const valueSize = valueAttrs.size ?? 10;
|
|
13384
14424
|
const categorySize = categoryAttrs.size ?? 10;
|
|
13385
|
-
const
|
|
13386
|
-
const
|
|
13387
|
-
const valueLabels = model.appearance?.valueAxis?.labelsVisible !== false;
|
|
13388
|
-
const categoryLabels = model.appearance?.categoryAxis?.labelsVisible !== false;
|
|
14425
|
+
const valueLabels = chartAxisLabels(model.axes?.value) && model.appearance?.valueAxis?.labelsVisible !== false;
|
|
14426
|
+
const categoryLabels = chartAxisLabels(model.axes?.category) && model.appearance?.categoryAxis?.labelsVisible !== false;
|
|
13389
14427
|
const labelW = valueLabels ? Math.max(...labels.map((l) => textWidth(l, valueSize)), 8) + 6 : 4;
|
|
13390
14428
|
const horizontal = model.horizontal;
|
|
13391
14429
|
const cats = Math.max(1, model.categories.length);
|
|
@@ -13394,7 +14432,7 @@ function cartesianAxes(model, area, out) {
|
|
|
13394
14432
|
Math.max(...model.categories.map((c) => textWidth(c, categorySize)), 8) + 6
|
|
13395
14433
|
);
|
|
13396
14434
|
const second = horizontal ? void 0 : model.secondaryAxis;
|
|
13397
|
-
const secondLabels = second?.ticks.map((t) =>
|
|
14435
|
+
const secondLabels = second?.ticks.map((t) => axisTickText(t, model.axes?.secondary, second.percent)) ?? [];
|
|
13398
14436
|
const secondW = second ? valueLabels ? Math.max(...secondLabels.map((l) => textWidth(l, valueSize)), 8) + 8 : 4 : 0;
|
|
13399
14437
|
const plot = horizontal ? {
|
|
13400
14438
|
x: area.x + catW,
|
|
@@ -13407,29 +14445,47 @@ function cartesianAxes(model, area, out) {
|
|
|
13407
14445
|
w: Math.max(1, area.w - labelW - 4 - secondW),
|
|
13408
14446
|
h: Math.max(1, area.h - Math.max(20, categorySize * 1.5))
|
|
13409
14447
|
};
|
|
13410
|
-
const
|
|
13411
|
-
const value = horizontal ? (v) => plot.x + (v - scale.min) / span * plot.w : (v) => plot.y + plot.h - (v - scale.min) / span * plot.h;
|
|
14448
|
+
const value = horizontal ? (v) => plot.x + chartAxisRatio(v, scale, model.axes?.value) * plot.w : (v) => plot.y + plot.h - chartAxisRatio(v, scale, model.axes?.value) * plot.h;
|
|
13412
14449
|
const bandSize = (horizontal ? plot.h : plot.w) / cats;
|
|
13413
|
-
const
|
|
14450
|
+
const index = (i) => model.axes?.category?.range.reverseOrder ? cats - 1 - i : i;
|
|
14451
|
+
const band = horizontal ? (i) => plot.y + plot.h - bandSize * (index(i) + 0.5) : (i) => plot.x + bandSize * (index(i) + 0.5);
|
|
13414
14452
|
out.push(chartAreaRect(model, "plotArea", plot));
|
|
14453
|
+
out.push(axisGridlines(model, model.axes?.value, scale.ticks, value, plot, horizontal));
|
|
14454
|
+
if (model.axes?.category?.source.majorGridlines || model.axes?.category?.source.minorGridlines)
|
|
14455
|
+
out.push(
|
|
14456
|
+
axisGridlines(
|
|
14457
|
+
model,
|
|
14458
|
+
model.axes.category,
|
|
14459
|
+
model.categories.map((_, i) => i),
|
|
14460
|
+
band,
|
|
14461
|
+
plot,
|
|
14462
|
+
!horizontal
|
|
14463
|
+
)
|
|
14464
|
+
);
|
|
13415
14465
|
scale.ticks.forEach((t, i) => {
|
|
13416
14466
|
const p = value(t);
|
|
13417
14467
|
const label = labels[i] ?? "";
|
|
13418
14468
|
if (horizontal) {
|
|
13419
|
-
out.push(line2(p, plot.y, p, plot.y + plot.h, grid.color, grid.width));
|
|
13420
14469
|
if (valueLabels)
|
|
13421
14470
|
out.push(
|
|
13422
14471
|
text(p, plot.y + plot.h + valueSize + 2, label, { anchor: "middle", ...valueAttrs })
|
|
13423
14472
|
);
|
|
13424
14473
|
} else {
|
|
13425
|
-
out.push(line2(plot.x, p, plot.x + plot.w, p, grid.color, grid.width));
|
|
13426
14474
|
if (valueLabels)
|
|
13427
14475
|
out.push(text(plot.x - 4, p + valueSize * 0.3, label, { anchor: "end", ...valueAttrs }));
|
|
13428
14476
|
}
|
|
13429
14477
|
});
|
|
13430
|
-
const
|
|
13431
|
-
|
|
13432
|
-
|
|
14478
|
+
const source = model.axes?.value?.source;
|
|
14479
|
+
const crossing = source?.crosses === "max" ? scale.max : source?.crosses === "min" ? scale.min : source?.crossesAt ?? 0;
|
|
14480
|
+
const zero = value(Math.min(Math.max(crossing, scale.min), scale.max));
|
|
14481
|
+
if (horizontal)
|
|
14482
|
+
out.push(
|
|
14483
|
+
axisLine(model, model.axes?.category, "categoryAxis", zero, plot.y, zero, plot.y + plot.h)
|
|
14484
|
+
);
|
|
14485
|
+
else
|
|
14486
|
+
out.push(
|
|
14487
|
+
axisLine(model, model.axes?.category, "categoryAxis", plot.x, zero, plot.x + plot.w, zero)
|
|
14488
|
+
);
|
|
13433
14489
|
const step = Math.max(
|
|
13434
14490
|
1,
|
|
13435
14491
|
Math.ceil(cats / Math.max(1, Math.floor((horizontal ? plot.h : plot.w) / 14)))
|
|
@@ -13454,20 +14510,23 @@ function cartesianAxes(model, area, out) {
|
|
|
13454
14510
|
});
|
|
13455
14511
|
const frame2 = { plot, value, band, bandSize };
|
|
13456
14512
|
if (second) {
|
|
13457
|
-
|
|
13458
|
-
frame2.secondary = (v) => plot.y + plot.h - (v - second.min) / secondSpan * plot.h;
|
|
13459
|
-
const secondAxis = chartStroke(model, "valueAxis");
|
|
14513
|
+
frame2.secondary = (v) => plot.y + plot.h - chartAxisRatio(v, second, model.axes?.secondary) * plot.h;
|
|
13460
14514
|
out.push(
|
|
13461
|
-
|
|
14515
|
+
axisLine(
|
|
14516
|
+
model,
|
|
14517
|
+
model.axes?.secondary,
|
|
14518
|
+
"valueAxis",
|
|
13462
14519
|
plot.x + plot.w,
|
|
13463
14520
|
plot.y,
|
|
13464
14521
|
plot.x + plot.w,
|
|
13465
|
-
plot.y + plot.h
|
|
13466
|
-
secondAxis.color,
|
|
13467
|
-
secondAxis.width
|
|
14522
|
+
plot.y + plot.h
|
|
13468
14523
|
)
|
|
13469
14524
|
);
|
|
13470
|
-
if (
|
|
14525
|
+
if (model.axes?.secondary?.source.majorGridlines || model.axes?.secondary?.source.minorGridlines)
|
|
14526
|
+
out.push(
|
|
14527
|
+
axisGridlines(model, model.axes.secondary, second.ticks, frame2.secondary, plot, false)
|
|
14528
|
+
);
|
|
14529
|
+
if (chartAxisLabels(model.axes?.secondary))
|
|
13471
14530
|
second.ticks.forEach(
|
|
13472
14531
|
(t, i) => out.push(
|
|
13473
14532
|
text(plot.x + plot.w + 4, frame2.secondary(t) + valueSize * 0.3, secondLabels[i] ?? "", {
|
|
@@ -13491,6 +14550,7 @@ function linesAndAreas(model, frame2, out) {
|
|
|
13491
14550
|
const stacked = model.grouping === "stacked" || model.grouping === "percentStacked";
|
|
13492
14551
|
const acc = new Array(model.categories.length).fill(0);
|
|
13493
14552
|
const area = model.type === "area";
|
|
14553
|
+
const marks = [];
|
|
13494
14554
|
const layers = [];
|
|
13495
14555
|
model.series.forEach((s, si) => {
|
|
13496
14556
|
const points = [];
|
|
@@ -13505,16 +14565,24 @@ function linesAndAreas(model, frame2, out) {
|
|
|
13505
14565
|
const top = below2 + (v ?? 0);
|
|
13506
14566
|
if (stacked) acc[i] = top;
|
|
13507
14567
|
points.push([frame2.band(i), frame2.value(top)]);
|
|
14568
|
+
marks.push({
|
|
14569
|
+
series: s,
|
|
14570
|
+
index: i,
|
|
14571
|
+
x: frame2.band(i),
|
|
14572
|
+
y: frame2.value(top),
|
|
14573
|
+
radius: area ? 0 : chartMarkerRadius(s, i, 2.5)
|
|
14574
|
+
});
|
|
13508
14575
|
lower.push([frame2.band(i), frame2.value(below2)]);
|
|
13509
14576
|
});
|
|
13510
14577
|
layers.push({
|
|
14578
|
+
series: s,
|
|
13511
14579
|
points,
|
|
13512
14580
|
lower,
|
|
13513
14581
|
color: s.color,
|
|
13514
14582
|
filter: s.shadowFilter ? ` filter="${s.shadowFilter}"` : ""
|
|
13515
14583
|
});
|
|
13516
14584
|
});
|
|
13517
|
-
for (const { points, lower, color, filter } of area ? [...layers].reverse() : layers) {
|
|
14585
|
+
for (const { points, lower, color, filter, series } of area ? [...layers].reverse() : layers) {
|
|
13518
14586
|
if (area) {
|
|
13519
14587
|
const poly = [...points, ...[...lower].reverse()].map(([x, y]) => `${n(x)},${n(y)}`).join(" ");
|
|
13520
14588
|
out.push(`<polygon points="${poly}" fill="${color}" fill-opacity="0.85"${filter}/>`);
|
|
@@ -13533,10 +14601,11 @@ function linesAndAreas(model, frame2, out) {
|
|
|
13533
14601
|
else segment2.push(`${n(x)},${n(y)}`);
|
|
13534
14602
|
}
|
|
13535
14603
|
flush();
|
|
13536
|
-
|
|
13537
|
-
if (!Number.isNaN(x))
|
|
13538
|
-
|
|
14604
|
+
points.forEach(([x, y], index) => {
|
|
14605
|
+
if (!Number.isNaN(x)) out.push(chartSeriesMarkerSvg(series, index, x, y, 2.5));
|
|
14606
|
+
});
|
|
13539
14607
|
}
|
|
14608
|
+
pointLabels(model, marks, out);
|
|
13540
14609
|
}
|
|
13541
14610
|
|
|
13542
14611
|
// chart/render/chart-svg-xy.ts
|
|
@@ -13544,16 +14613,14 @@ function scatter(model, area, out) {
|
|
|
13544
14613
|
const ys = model.valueAxis;
|
|
13545
14614
|
const xs = model.xAxis;
|
|
13546
14615
|
if (!ys || !xs) return;
|
|
13547
|
-
const yLabels = ys.ticks.map((t) =>
|
|
14616
|
+
const yLabels = ys.ticks.map((t) => axisTickText(t, model.axes?.value));
|
|
13548
14617
|
const valueAttrs = chartTextAttributes(model, "valueAxis");
|
|
13549
14618
|
const categoryAttrs = chartTextAttributes(model, "categoryAxis");
|
|
13550
14619
|
const valueSize = valueAttrs.size ?? 10;
|
|
13551
14620
|
const categorySize = categoryAttrs.size ?? 10;
|
|
13552
|
-
const grid = chartStroke(model, "gridlineMajor");
|
|
13553
14621
|
const xAxis = chartStroke(model, "categoryAxis");
|
|
13554
|
-
const
|
|
13555
|
-
const
|
|
13556
|
-
const categoryLabels = model.appearance?.categoryAxis?.labelsVisible !== false;
|
|
14622
|
+
const valueLabels = chartAxisLabels(model.axes?.value) && model.appearance?.valueAxis?.labelsVisible !== false;
|
|
14623
|
+
const categoryLabels = chartAxisLabels(model.axes?.category) && model.appearance?.categoryAxis?.labelsVisible !== false;
|
|
13557
14624
|
const labelW = valueLabels ? Math.max(...yLabels.map((l) => textWidth(l, valueSize)), 8) + 6 : 4;
|
|
13558
14625
|
const plot = {
|
|
13559
14626
|
x: area.x + labelW,
|
|
@@ -13573,17 +14640,24 @@ function scatter(model, area, out) {
|
|
|
13573
14640
|
s.values.forEach((_, i) => {
|
|
13574
14641
|
reach = Math.max(reach, radiusOf(s.sizes?.[i] ?? void 0) ?? 0);
|
|
13575
14642
|
});
|
|
13576
|
-
const widen = (s, length) => {
|
|
14643
|
+
const widen = (s, length, axis) => {
|
|
14644
|
+
if (axis?.range.logScale) return s;
|
|
13577
14645
|
const pad = reach * (s.max - s.min || 1) / Math.max(1, length - 2 * reach);
|
|
13578
|
-
return {
|
|
14646
|
+
return {
|
|
14647
|
+
...s,
|
|
14648
|
+
min: axis?.source.scaling.min === void 0 ? s.min - pad : s.min,
|
|
14649
|
+
max: axis?.source.scaling.max === void 0 ? s.max + pad : s.max
|
|
14650
|
+
};
|
|
13579
14651
|
};
|
|
13580
|
-
const xView = widen(xs, plot.w);
|
|
13581
|
-
const yView = widen(ys, plot.h);
|
|
13582
|
-
const px = (v) => plot.x + (v
|
|
13583
|
-
const py = (v) => plot.y + plot.h - (v
|
|
14652
|
+
const xView = widen(xs, plot.w, model.axes?.category);
|
|
14653
|
+
const yView = widen(ys, plot.h, model.axes?.value);
|
|
14654
|
+
const px = (v) => plot.x + chartAxisRatio(v, xView, model.axes?.category) * plot.w;
|
|
14655
|
+
const py = (v) => plot.y + plot.h - chartAxisRatio(v, yView, model.axes?.value) * plot.h;
|
|
13584
14656
|
out.push(chartAreaRect(model, "plotArea", plot));
|
|
14657
|
+
out.push(axisGridlines(model, model.axes?.value, ys.ticks, py, plot, false));
|
|
14658
|
+
if (model.axes?.category)
|
|
14659
|
+
out.push(axisGridlines(model, model.axes.category, xs.ticks, px, plot, true));
|
|
13585
14660
|
ys.ticks.forEach((t, i) => {
|
|
13586
|
-
out.push(line2(plot.x, py(t), plot.x + plot.w, py(t), grid.color, grid.width));
|
|
13587
14661
|
if (valueLabels)
|
|
13588
14662
|
out.push(
|
|
13589
14663
|
text(plot.x - 4, py(t) + valueSize * 0.3, yLabels[i] ?? "", {
|
|
@@ -13593,19 +14667,31 @@ function scatter(model, area, out) {
|
|
|
13593
14667
|
);
|
|
13594
14668
|
});
|
|
13595
14669
|
for (const t of xs.ticks) {
|
|
13596
|
-
|
|
14670
|
+
if (!model.axes?.category?.source.deleted)
|
|
14671
|
+
out.push(line2(px(t), plot.y + plot.h, px(t), plot.y + plot.h + 3, xAxis.color, xAxis.width));
|
|
13597
14672
|
if (categoryLabels)
|
|
13598
14673
|
out.push(
|
|
13599
|
-
text(px(t), plot.y + plot.h + categorySize + 3,
|
|
14674
|
+
text(px(t), plot.y + plot.h + categorySize + 3, axisTickText(t, model.axes?.category), {
|
|
13600
14675
|
anchor: "middle",
|
|
13601
14676
|
...categoryAttrs
|
|
13602
14677
|
})
|
|
13603
14678
|
);
|
|
13604
14679
|
}
|
|
13605
14680
|
out.push(
|
|
13606
|
-
|
|
14681
|
+
axisLine(
|
|
14682
|
+
model,
|
|
14683
|
+
model.axes?.category,
|
|
14684
|
+
"categoryAxis",
|
|
14685
|
+
plot.x,
|
|
14686
|
+
plot.y + plot.h,
|
|
14687
|
+
plot.x + plot.w,
|
|
14688
|
+
plot.y + plot.h
|
|
14689
|
+
)
|
|
14690
|
+
);
|
|
14691
|
+
out.push(
|
|
14692
|
+
axisLine(model, model.axes?.value, "valueAxis", plot.x, plot.y, plot.x, plot.y + plot.h)
|
|
13607
14693
|
);
|
|
13608
|
-
|
|
14694
|
+
const marks = [];
|
|
13609
14695
|
for (const [si, s] of model.series.entries())
|
|
13610
14696
|
s.values.forEach((v, i) => {
|
|
13611
14697
|
const x = s.xValues?.[i] ?? null;
|
|
@@ -13613,15 +14699,18 @@ function scatter(model, area, out) {
|
|
|
13613
14699
|
const filter = s.shadowFilter ? ` filter="${s.shadowFilter}"` : "";
|
|
13614
14700
|
const fill = s.pointColors?.[i] ?? s.color;
|
|
13615
14701
|
if (!bubble) {
|
|
13616
|
-
out.push(
|
|
14702
|
+
out.push(chartSeriesMarkerSvg(s, i, px(x), py(v)));
|
|
14703
|
+
marks.push({ series: s, index: i, x: px(x), y: py(v), radius: chartMarkerRadius(s, i) });
|
|
13617
14704
|
return;
|
|
13618
14705
|
}
|
|
13619
14706
|
const r = radiusOf(s.sizes?.[i] ?? void 0);
|
|
13620
14707
|
if (r === void 0) return;
|
|
14708
|
+
marks.push({ series: s, index: i, x: px(x), y: py(v), radius: r });
|
|
13621
14709
|
out.push(
|
|
13622
14710
|
`<circle cx="${n(px(x))}" cy="${n(py(v))}" r="${n(r)}" fill="${fill}" fill-opacity="0.6" data-chart-series="${si}" data-chart-point="${i}"${filter}/>`
|
|
13623
14711
|
);
|
|
13624
14712
|
});
|
|
14713
|
+
pointLabels(model, marks, out);
|
|
13625
14714
|
scatterAnalysis(model, px, py, out);
|
|
13626
14715
|
}
|
|
13627
14716
|
|
|
@@ -13738,21 +14827,21 @@ function cartesianSvg(model, area) {
|
|
|
13738
14827
|
return out.join("");
|
|
13739
14828
|
}
|
|
13740
14829
|
const layers = [{ model, frame: frame2 }];
|
|
13741
|
-
for (const
|
|
14830
|
+
for (const group2 of model.extraGroups ?? []) {
|
|
13742
14831
|
const grouped = {
|
|
13743
14832
|
...model,
|
|
13744
|
-
type:
|
|
13745
|
-
grouping:
|
|
13746
|
-
series:
|
|
14833
|
+
type: group2.type,
|
|
14834
|
+
grouping: group2.grouping,
|
|
14835
|
+
series: group2.series,
|
|
13747
14836
|
horizontal: false
|
|
13748
14837
|
};
|
|
13749
|
-
if (
|
|
14838
|
+
if (group2.stock) grouped.stock = group2.stock;
|
|
13750
14839
|
else delete grouped.stock;
|
|
13751
|
-
if (
|
|
14840
|
+
if (group2.barGapWidth !== void 0) grouped.barGapWidth = group2.barGapWidth;
|
|
13752
14841
|
else delete grouped.barGapWidth;
|
|
13753
|
-
if (
|
|
14842
|
+
if (group2.barOverlap !== void 0) grouped.barOverlap = group2.barOverlap;
|
|
13754
14843
|
else delete grouped.barOverlap;
|
|
13755
|
-
const value =
|
|
14844
|
+
const value = group2.secondary && frame2.secondary ? frame2.secondary : frame2.value;
|
|
13756
14845
|
layers.push({ model: grouped, frame: { ...frame2, value } });
|
|
13757
14846
|
}
|
|
13758
14847
|
layers.map((layer, order) => ({ layer, order })).sort(
|
|
@@ -13786,7 +14875,9 @@ function pieSvg(model, area) {
|
|
|
13786
14875
|
const out = [chartAreaRect(model, "plotArea", area)];
|
|
13787
14876
|
const cx = area.x + area.w / 2;
|
|
13788
14877
|
const cy = area.y + area.h / 2;
|
|
13789
|
-
const
|
|
14878
|
+
const margin = hasOutsideLabels(model) ? Math.min(area.w, area.h) * 0.12 : 0;
|
|
14879
|
+
const radius = Math.max(1, Math.min(area.w, area.h) / 2 - 4 - margin);
|
|
14880
|
+
const slices = [];
|
|
13790
14881
|
const rings = model.type === "doughnut" ? model.series : model.series.slice(0, 1);
|
|
13791
14882
|
const hole = model.type === "doughnut" ? radius * 0.5 : 0;
|
|
13792
14883
|
const ringSize = (radius - hole) / Math.max(1, rings.length);
|
|
@@ -13803,9 +14894,20 @@ function pieSvg(model, area) {
|
|
|
13803
14894
|
out.push(
|
|
13804
14895
|
`<path d="${slicePath(cx, cy, outer, inner, angle, angle + sweep)}" fill="${color}" stroke="#FFFFFF" stroke-width="1"${s.shadowFilter ? ` filter="${s.shadowFilter}"` : ""}/>`
|
|
13805
14896
|
);
|
|
14897
|
+
slices.push({
|
|
14898
|
+
series: s,
|
|
14899
|
+
index: i,
|
|
14900
|
+
cx,
|
|
14901
|
+
cy,
|
|
14902
|
+
outer,
|
|
14903
|
+
inner,
|
|
14904
|
+
start: angle,
|
|
14905
|
+
end: angle + sweep
|
|
14906
|
+
});
|
|
13806
14907
|
angle += sweep;
|
|
13807
14908
|
});
|
|
13808
14909
|
});
|
|
14910
|
+
sliceLabels(model, slices, out);
|
|
13809
14911
|
return out.join("");
|
|
13810
14912
|
}
|
|
13811
14913
|
function radarSvg(model, area) {
|
|
@@ -13818,32 +14920,37 @@ function radarSvg(model, area) {
|
|
|
13818
14920
|
const valueSize = valueAttrs.size ?? 9;
|
|
13819
14921
|
const categorySize = categoryAttrs.size ?? 10;
|
|
13820
14922
|
const grid = chartStroke(model, "gridlineMajor");
|
|
13821
|
-
const axis = chartStroke(model, "categoryAxis");
|
|
13822
14923
|
const cx = area.x + area.w / 2;
|
|
13823
14924
|
const cy = area.y + area.h / 2 + 4;
|
|
13824
14925
|
const radius = Math.max(1, Math.min(area.w, area.h) / 2 - Math.max(18, categorySize * 1.8));
|
|
13825
14926
|
const angle = (i) => i / count * Math.PI * 2;
|
|
13826
|
-
const r = (v) => (v
|
|
14927
|
+
const r = (v) => chartAxisRatio(v, scale, model.axes?.value) * radius;
|
|
13827
14928
|
const labelEvery = Math.max(
|
|
13828
14929
|
1,
|
|
13829
14930
|
Math.ceil(12 / Math.max(1, radius / Math.max(1, scale.ticks.length - 1)))
|
|
13830
14931
|
);
|
|
13831
14932
|
for (const [k, t] of scale.ticks.entries()) {
|
|
13832
14933
|
const ring = Array.from({ length: count }, (_, i) => polar(cx, cy, r(t), angle(i))).map(([x, y]) => `${n(x)},${n(y)}`).join(" ");
|
|
13833
|
-
|
|
13834
|
-
|
|
13835
|
-
|
|
13836
|
-
|
|
14934
|
+
if (!model.axes?.value || model.axes.value.source.majorGridlines)
|
|
14935
|
+
out.push(
|
|
14936
|
+
`<polygon points="${ring}" fill="none" stroke="${grid.color}" stroke-width="${n(grid.width)}"/>`
|
|
14937
|
+
);
|
|
14938
|
+
if (chartAxisLabels(model.axes?.value) && model.appearance?.valueAxis?.labelsVisible !== false && k % labelEvery === 0)
|
|
13837
14939
|
out.push(
|
|
13838
|
-
text(
|
|
14940
|
+
text(
|
|
14941
|
+
cx + 3,
|
|
14942
|
+
cy - r(t) + valueSize * 0.3,
|
|
14943
|
+
axisTickText(t, model.axes?.value, scale.percent),
|
|
14944
|
+
valueAttrs
|
|
14945
|
+
)
|
|
13839
14946
|
);
|
|
13840
14947
|
}
|
|
13841
14948
|
model.categories.forEach((c, i) => {
|
|
13842
14949
|
const [x, y] = polar(cx, cy, radius, angle(i));
|
|
13843
|
-
out.push(
|
|
14950
|
+
out.push(axisLine(model, model.axes?.category, "categoryAxis", cx, cy, x, y));
|
|
13844
14951
|
const [lx, ly] = polar(cx, cy, radius + 10, angle(i));
|
|
13845
14952
|
const anchor = Math.abs(lx - cx) < 2 ? "middle" : lx > cx ? "start" : "end";
|
|
13846
|
-
if (model.appearance?.categoryAxis?.labelsVisible !== false)
|
|
14953
|
+
if (chartAxisLabels(model.axes?.category) && model.appearance?.categoryAxis?.labelsVisible !== false)
|
|
13847
14954
|
out.push(
|
|
13848
14955
|
text(lx, ly + categorySize * 0.3, fit(c, area.w / 4, categorySize), {
|
|
13849
14956
|
anchor,
|
|
@@ -13851,12 +14958,22 @@ function radarSvg(model, area) {
|
|
|
13851
14958
|
})
|
|
13852
14959
|
);
|
|
13853
14960
|
});
|
|
14961
|
+
const marks = [];
|
|
13854
14962
|
for (const s of model.series) {
|
|
13855
|
-
const
|
|
14963
|
+
const vertices = s.values.slice(0, count).map((v, i) => polar(cx, cy, r(v ?? scale.min), angle(i)));
|
|
14964
|
+
vertices.forEach(([x, y], i) => {
|
|
14965
|
+
if (s.values[i] === null) return;
|
|
14966
|
+
const markerSeries = s;
|
|
14967
|
+
if (markerSeries.marker || markerSeries.pointMarkers)
|
|
14968
|
+
out.push(chartSeriesMarkerSvg(s, i, x, y));
|
|
14969
|
+
marks.push({ series: s, index: i, x, y, radius: chartMarkerRadius(s, i) });
|
|
14970
|
+
});
|
|
14971
|
+
const points = vertices.map(([x, y]) => `${n(x)},${n(y)}`).join(" ");
|
|
13856
14972
|
out.push(
|
|
13857
14973
|
`<polygon points="${points}" fill="none" stroke="${s.color}" stroke-width="2"${s.shadowFilter ? ` filter="${s.shadowFilter}"` : ""}/>`
|
|
13858
14974
|
);
|
|
13859
14975
|
}
|
|
14976
|
+
pointLabels(model, marks, out);
|
|
13860
14977
|
return out.join("");
|
|
13861
14978
|
}
|
|
13862
14979
|
|
|
@@ -13947,33 +15064,33 @@ var CHART_FONT_FAMILY = "Calibri, Carlito, Arial, sans-serif";
|
|
|
13947
15064
|
function cssFont(attrs) {
|
|
13948
15065
|
return `${attrs.italic ? "italic" : "normal"} ${attrs.weight ?? "normal"} ${attrs.size ?? 10}px ${attrs.family ?? CHART_FONT_FAMILY}`;
|
|
13949
15066
|
}
|
|
13950
|
-
function chartFontMetrics(attrs,
|
|
13951
|
-
const metrics =
|
|
15067
|
+
function chartFontMetrics(attrs, options2) {
|
|
15068
|
+
const metrics = options2.measureFont?.(cssFont(attrs));
|
|
13952
15069
|
return metrics && Number.isFinite(metrics.ascent) && Number.isFinite(metrics.descent) && metrics.ascent >= 0 && metrics.descent >= 0 && metrics.ascent + metrics.descent > 0 ? metrics : void 0;
|
|
13953
15070
|
}
|
|
13954
|
-
function chartTextWidth(content, attrs,
|
|
13955
|
-
const width =
|
|
15071
|
+
function chartTextWidth(content, attrs, options2) {
|
|
15072
|
+
const width = options2.measureText?.(content, cssFont(attrs));
|
|
13956
15073
|
return width !== void 0 && Number.isFinite(width) && width >= 0 ? width : textWidth(content, attrs.size);
|
|
13957
15074
|
}
|
|
13958
|
-
function fitChartText(content, maxWidth, attrs,
|
|
13959
|
-
if (!
|
|
13960
|
-
if (chartTextWidth(content, attrs,
|
|
15075
|
+
function fitChartText(content, maxWidth, attrs, options2) {
|
|
15076
|
+
if (!options2.measureText) return fit(content, maxWidth, attrs.size);
|
|
15077
|
+
if (chartTextWidth(content, attrs, options2) <= maxWidth) return content;
|
|
13961
15078
|
const points = [...content];
|
|
13962
15079
|
let low = 0;
|
|
13963
15080
|
let high = points.length;
|
|
13964
15081
|
while (low < high) {
|
|
13965
15082
|
const mid = Math.ceil((low + high) / 2);
|
|
13966
|
-
if (chartTextWidth(`${points.slice(0, mid).join("")}\u2026`, attrs,
|
|
15083
|
+
if (chartTextWidth(`${points.slice(0, mid).join("")}\u2026`, attrs, options2) <= maxWidth) low = mid;
|
|
13967
15084
|
else high = mid - 1;
|
|
13968
15085
|
}
|
|
13969
15086
|
return `${points.slice(0, low).join("")}\u2026`;
|
|
13970
15087
|
}
|
|
13971
15088
|
|
|
13972
15089
|
// chart/render/chart-svg-legend.ts
|
|
13973
|
-
function chartLegendSvg(model, area, frame2,
|
|
15090
|
+
function chartLegendSvg(model, area, frame2, options2) {
|
|
13974
15091
|
const automatic = [];
|
|
13975
15092
|
const bounds = {};
|
|
13976
|
-
const reserved = automaticLegend(model, area, automatic,
|
|
15093
|
+
const reserved = automaticLegend(model, area, automatic, options2, bounds);
|
|
13977
15094
|
const plot = model.legendOverlay ? area : reserved;
|
|
13978
15095
|
const box = bounds.box;
|
|
13979
15096
|
if (!box) return { plot, markup: "", foreground: false };
|
|
@@ -13987,11 +15104,11 @@ function chartLegendSvg(model, area, frame2, options) {
|
|
|
13987
15104
|
const entries = legendEntries(model);
|
|
13988
15105
|
const attrs = chartTextAttributes(model, "legend");
|
|
13989
15106
|
const size = attrs.size ?? 10;
|
|
13990
|
-
const font = chartFontMetrics(attrs,
|
|
15107
|
+
const font = chartFontMetrics(attrs, options2);
|
|
13991
15108
|
const keySize = size / 2;
|
|
13992
15109
|
const keyGap = size / 4;
|
|
13993
15110
|
const widths = entries.map(
|
|
13994
|
-
(entry) => chartTextWidth(entry.label, attrs,
|
|
15111
|
+
(entry) => chartTextWidth(entry.label, attrs, options2) + keySize + keyGap
|
|
13995
15112
|
);
|
|
13996
15113
|
const horizontal = manual.width > manual.height && widths.reduce((sum, width) => sum + width, 0) + size <= manual.width;
|
|
13997
15114
|
const rowWidth = horizontal ? manual.width / entries.length : manual.width;
|
|
@@ -14006,8 +15123,8 @@ function chartLegendSvg(model, area, frame2, options) {
|
|
|
14006
15123
|
];
|
|
14007
15124
|
const baselineOffset = font ? (font.ascent - font.descent) / 2 : size * 0.35;
|
|
14008
15125
|
entries.forEach((entry, i) => {
|
|
14009
|
-
const available = horizontal ? chartTextWidth(entry.label, attrs,
|
|
14010
|
-
const label = fitChartText(entry.label, available, attrs,
|
|
15126
|
+
const available = horizontal ? chartTextWidth(entry.label, attrs, options2) : Math.max(0, rowWidth - size / 2 - keySize - keyGap);
|
|
15127
|
+
const label = fitChartText(entry.label, available, attrs, options2);
|
|
14011
15128
|
const contentWidth = Math.min(
|
|
14012
15129
|
horizontal ? widths[i] ?? 0 : Math.max(...widths),
|
|
14013
15130
|
rowWidth - size / 2
|
|
@@ -14050,7 +15167,7 @@ function legendEntries(model) {
|
|
|
14050
15167
|
color: s.color
|
|
14051
15168
|
}));
|
|
14052
15169
|
}
|
|
14053
|
-
function automaticLegend(model, area, out,
|
|
15170
|
+
function automaticLegend(model, area, out, options2, bounds) {
|
|
14054
15171
|
const entries = legendEntries(model);
|
|
14055
15172
|
if (!model.showLegend || entries.length === 0) return area;
|
|
14056
15173
|
const pos = model.legendPosition;
|
|
@@ -14059,7 +15176,7 @@ function automaticLegend(model, area, out, options, bounds) {
|
|
|
14059
15176
|
const rowH = Math.max(16, size * 1.4);
|
|
14060
15177
|
if (pos === "t" || pos === "b") {
|
|
14061
15178
|
const widths = entries.map(
|
|
14062
|
-
(e) => Math.min(chartTextWidth(e.label, attrs,
|
|
15179
|
+
(e) => Math.min(chartTextWidth(e.label, attrs, options2) + 20, area.w / 2)
|
|
14063
15180
|
);
|
|
14064
15181
|
const total = widths.reduce((a, b) => a + b, 0);
|
|
14065
15182
|
let x2 = area.x + Math.max(0, (area.w - total) / 2);
|
|
@@ -14076,14 +15193,14 @@ function automaticLegend(model, area, out, options, bounds) {
|
|
|
14076
15193
|
entries.forEach((e, i) => {
|
|
14077
15194
|
const w = widths[i] ?? 0;
|
|
14078
15195
|
out.push(rect2(x2, y, 8, 8, e.color));
|
|
14079
|
-
out.push(text(x2 + 12, y + 8, fitChartText(e.label, w - 16, attrs,
|
|
15196
|
+
out.push(text(x2 + 12, y + 8, fitChartText(e.label, w - 16, attrs, options2), attrs));
|
|
14080
15197
|
x2 += w;
|
|
14081
15198
|
});
|
|
14082
15199
|
return pos === "t" ? { x: area.x, y: area.y + rowH + 4, w: area.w, h: area.h - rowH - 4 } : { x: area.x, y: area.y, w: area.w, h: area.h - rowH - 4 };
|
|
14083
15200
|
}
|
|
14084
15201
|
const width = Math.min(
|
|
14085
15202
|
area.w * 0.35,
|
|
14086
|
-
Math.max(...entries.map((e) => chartTextWidth(e.label, attrs,
|
|
15203
|
+
Math.max(...entries.map((e) => chartTextWidth(e.label, attrs, options2))) + 22
|
|
14087
15204
|
);
|
|
14088
15205
|
const height = entries.length * rowH;
|
|
14089
15206
|
const x = pos === "l" ? area.x + 4 : area.x + area.w - width;
|
|
@@ -14101,24 +15218,24 @@ function automaticLegend(model, area, out, options, bounds) {
|
|
|
14101
15218
|
const y = y0 + i * rowH;
|
|
14102
15219
|
if (y + rowH > area.y + area.h + 2) return;
|
|
14103
15220
|
out.push(rect2(x, y + 3, 8, 8, e.color));
|
|
14104
|
-
out.push(text(x + 12, y + 11, fitChartText(e.label, width - 16, attrs,
|
|
15221
|
+
out.push(text(x + 12, y + 11, fitChartText(e.label, width - 16, attrs, options2), attrs));
|
|
14105
15222
|
});
|
|
14106
15223
|
return pos === "l" ? { x: area.x + width + 8, y: area.y, w: area.w - width - 8, h: area.h } : { x: area.x, y: area.y, w: area.w - width - 8, h: area.h };
|
|
14107
15224
|
}
|
|
14108
15225
|
|
|
14109
15226
|
// text/wrap-styled-runs.ts
|
|
14110
15227
|
var graphemes = new Intl.Segmenter(void 0, { granularity: "grapheme" });
|
|
14111
|
-
function wrapStyledRuns(runs, maxWidth,
|
|
15228
|
+
function wrapStyledRuns(runs, maxWidth, measure2, options2 = {}) {
|
|
14112
15229
|
const groups = [];
|
|
14113
15230
|
for (const [source, run] of runs.entries()) {
|
|
14114
15231
|
for (const token of run.text.split(/(\r\n|[\r\n]|[ \t]+)/u).filter(Boolean)) {
|
|
14115
15232
|
const kind = /^[\r\n]+$/u.test(token) ? "break" : /^[ \t]+$/u.test(token) ? "space" : "word";
|
|
14116
|
-
let
|
|
14117
|
-
if (!
|
|
14118
|
-
|
|
14119
|
-
groups.push(
|
|
15233
|
+
let group2 = groups.at(-1);
|
|
15234
|
+
if (!group2 || group2.kind !== kind || kind === "break") {
|
|
15235
|
+
group2 = { kind, pieces: [] };
|
|
15236
|
+
groups.push(group2);
|
|
14120
15237
|
}
|
|
14121
|
-
if (kind !== "break")
|
|
15238
|
+
if (kind !== "break") group2.pieces.push({ run, source, text: token });
|
|
14122
15239
|
}
|
|
14123
15240
|
}
|
|
14124
15241
|
const merged = (left, right) => {
|
|
@@ -14131,7 +15248,7 @@ function wrapStyledRuns(runs, maxWidth, measure, options = {}) {
|
|
|
14131
15248
|
return result2;
|
|
14132
15249
|
};
|
|
14133
15250
|
const width = (pieces) => pieces.reduce((sum, piece) => {
|
|
14134
|
-
const advance =
|
|
15251
|
+
const advance = measure2(piece.text, piece.run);
|
|
14135
15252
|
return sum + (Number.isFinite(advance) && advance >= 0 ? advance : 0);
|
|
14136
15253
|
}, 0);
|
|
14137
15254
|
const result = [];
|
|
@@ -14142,29 +15259,29 @@ function wrapStyledRuns(runs, maxWidth, measure, options = {}) {
|
|
|
14142
15259
|
line3 = [];
|
|
14143
15260
|
spaces = [];
|
|
14144
15261
|
};
|
|
14145
|
-
for (const
|
|
14146
|
-
if (
|
|
15262
|
+
for (const group2 of groups) {
|
|
15263
|
+
if (group2.kind === "break") {
|
|
14147
15264
|
flush();
|
|
14148
15265
|
continue;
|
|
14149
15266
|
}
|
|
14150
|
-
if (
|
|
14151
|
-
spaces =
|
|
15267
|
+
if (group2.kind === "space") {
|
|
15268
|
+
spaces = group2.pieces;
|
|
14152
15269
|
continue;
|
|
14153
15270
|
}
|
|
14154
15271
|
const separator = line3.length ? spaces : [];
|
|
14155
|
-
const wordWidth = width(
|
|
14156
|
-
if (line3.length && width(merged(line3, [...separator, ...
|
|
15272
|
+
const wordWidth = width(group2.pieces);
|
|
15273
|
+
if (line3.length && width(merged(line3, [...separator, ...group2.pieces])) > maxWidth) flush();
|
|
14157
15274
|
else line3 = merged(line3, separator);
|
|
14158
15275
|
spaces = [];
|
|
14159
|
-
if (
|
|
14160
|
-
for (const piece of
|
|
15276
|
+
if (options2.breakWords && wordWidth > maxWidth) {
|
|
15277
|
+
for (const piece of group2.pieces) {
|
|
14161
15278
|
for (const { segment: segment2 } of graphemes.segment(piece.text)) {
|
|
14162
15279
|
const next = { ...piece, text: segment2 };
|
|
14163
15280
|
if (line3.length && width(merged(line3, [next])) > maxWidth) flush();
|
|
14164
15281
|
line3 = merged(line3, [next]);
|
|
14165
15282
|
}
|
|
14166
15283
|
}
|
|
14167
|
-
} else line3 = merged(line3,
|
|
15284
|
+
} else line3 = merged(line3, group2.pieces);
|
|
14168
15285
|
}
|
|
14169
15286
|
flush();
|
|
14170
15287
|
return result;
|
|
@@ -14174,11 +15291,11 @@ function wrapStyledRuns(runs, maxWidth, measure, options = {}) {
|
|
|
14174
15291
|
function spacing(value, naturalHeight, fallback) {
|
|
14175
15292
|
return value ? value.unit === "points" ? chartPointsToPixels(value.value) : naturalHeight * value.value : fallback;
|
|
14176
15293
|
}
|
|
14177
|
-
function chartRichTitleSvg(model, width,
|
|
15294
|
+
function chartRichTitleSvg(model, width, options2 = {}, frameHeight = 400) {
|
|
14178
15295
|
if (!model.title) return void 0;
|
|
14179
15296
|
const base = chartTextAttributes(model, "title", 14);
|
|
14180
15297
|
const capacity = Math.max(1, width * 0.8 - 8);
|
|
14181
|
-
if (!model.titleText && !hasManualLayoutFields(model.titleLayout) && !model.titleOverlay && !model.title.includes("\n") && chartTextWidth(model.title, base,
|
|
15298
|
+
if (!model.titleText && !hasManualLayoutFields(model.titleLayout) && !model.titleOverlay && !model.title.includes("\n") && chartTextWidth(model.title, base, options2) <= capacity)
|
|
14182
15299
|
return void 0;
|
|
14183
15300
|
const paragraphs = model.titleText?.paragraphs ?? [
|
|
14184
15301
|
{
|
|
@@ -14214,7 +15331,7 @@ function chartRichTitleSvg(model, width, options = {}, frameHeight = 400) {
|
|
|
14214
15331
|
"title",
|
|
14215
15332
|
base.size
|
|
14216
15333
|
),
|
|
14217
|
-
|
|
15334
|
+
options2
|
|
14218
15335
|
),
|
|
14219
15336
|
{ breakWords: true }
|
|
14220
15337
|
);
|
|
@@ -14238,10 +15355,10 @@ function chartRichTitleSvg(model, width, options = {}, frameHeight = 400) {
|
|
|
14238
15355
|
return {
|
|
14239
15356
|
...line3,
|
|
14240
15357
|
runs,
|
|
14241
|
-
width: runs.reduce((sum, run) => sum + chartTextWidth(run.text, run.attrs,
|
|
15358
|
+
width: runs.reduce((sum, run) => sum + chartTextWidth(run.text, run.attrs, options2), 0),
|
|
14242
15359
|
size: runs.length ? Math.max(...runs.map((run) => run.attrs.size ?? 14)) : base.size ?? 14,
|
|
14243
15360
|
fontMetrics: (runs.length ? runs.map((run) => run.attrs) : [base]).map(
|
|
14244
|
-
(attrs) => chartFontMetrics(attrs,
|
|
15361
|
+
(attrs) => chartFontMetrics(attrs, options2)
|
|
14245
15362
|
)
|
|
14246
15363
|
};
|
|
14247
15364
|
});
|
|
@@ -14279,7 +15396,7 @@ function chartRichTitleSvg(model, width, options = {}, frameHeight = 400) {
|
|
|
14279
15396
|
anchor: "start"
|
|
14280
15397
|
}).replace("<text ", '<tspan data-chart-title-run="true" ').replace("</text>", "</tspan>")
|
|
14281
15398
|
);
|
|
14282
|
-
x += chartTextWidth(run.text, run.attrs,
|
|
15399
|
+
x += chartTextWidth(run.text, run.attrs, options2);
|
|
14283
15400
|
}
|
|
14284
15401
|
}
|
|
14285
15402
|
const parent = text(0, 0, "", { ...base, underline: false }).replace(
|
|
@@ -14305,7 +15422,7 @@ function chartRichTitleSvg(model, width, options = {}, frameHeight = 400) {
|
|
|
14305
15422
|
}
|
|
14306
15423
|
|
|
14307
15424
|
// chart/render/chart-svg.ts
|
|
14308
|
-
function renderChartSvg(model, width, height,
|
|
15425
|
+
function renderChartSvg(model, width, height, options2 = {}) {
|
|
14309
15426
|
const paint2 = chartGradientPaint(model, Math.max(1, width), Math.max(1, height));
|
|
14310
15427
|
model = paint2.model;
|
|
14311
15428
|
const w = Math.max(1, width);
|
|
@@ -14319,7 +15436,7 @@ function renderChartSvg(model, width, height, options = {}) {
|
|
|
14319
15436
|
if (paint2.defs) out.push(paint2.defs);
|
|
14320
15437
|
out.push(chartAreaRect(model, "chartArea", { x: 0, y: 0, w, h }));
|
|
14321
15438
|
let area = { x: 8, y: 8, w: w - 16, h: h - 16 };
|
|
14322
|
-
const richTitle = chartRichTitleSvg(model, w,
|
|
15439
|
+
const richTitle = chartRichTitleSvg(model, w, options2, h);
|
|
14323
15440
|
if (richTitle) {
|
|
14324
15441
|
if (model.titleLayout || model.titleOverlay) foregroundTitle = richTitle.markup;
|
|
14325
15442
|
else out.push(richTitle.markup);
|
|
@@ -14328,9 +15445,9 @@ function renderChartSvg(model, width, height, options = {}) {
|
|
|
14328
15445
|
} else if (model.title) {
|
|
14329
15446
|
const attrs = chartTextAttributes(model, "title", 14);
|
|
14330
15447
|
const size = attrs.size ?? 14;
|
|
14331
|
-
const label = fitChartText(model.title, w - 16, attrs,
|
|
14332
|
-
const titleWidth = Math.min(w - 16, chartTextWidth(label, attrs,
|
|
14333
|
-
const font = chartFontMetrics(attrs,
|
|
15448
|
+
const label = fitChartText(model.title, w - 16, attrs, options2);
|
|
15449
|
+
const titleWidth = Math.min(w - 16, chartTextWidth(label, attrs, options2) + 8);
|
|
15450
|
+
const font = chartFontMetrics(attrs, options2);
|
|
14334
15451
|
const titleHeight = Math.max(24, font ? font.ascent + font.descent + 4 : size * 1.4 + 4);
|
|
14335
15452
|
out.push(
|
|
14336
15453
|
chartAreaRect(model, "title", {
|
|
@@ -14358,7 +15475,7 @@ function renderChartSvg(model, width, height, options = {}) {
|
|
|
14358
15475
|
out.push("</svg>");
|
|
14359
15476
|
return out.join("");
|
|
14360
15477
|
}
|
|
14361
|
-
const legend = chartLegendSvg(model, area, { width: w, height: h },
|
|
15478
|
+
const legend = chartLegendSvg(model, area, { width: w, height: h }, options2);
|
|
14362
15479
|
area = legend.plot;
|
|
14363
15480
|
if (!legend.foreground) out.push(legend.markup);
|
|
14364
15481
|
if (area.w > 4 && area.h > 4) {
|
|
@@ -14405,8 +15522,8 @@ function chartSpaceKind(space) {
|
|
|
14405
15522
|
const type = chartSummaryFromSpace(space).chartType;
|
|
14406
15523
|
return { type, drawn: DRAWN_CHART_TYPES.has(type) };
|
|
14407
15524
|
}
|
|
14408
|
-
function renderChartSpaceSvg(space,
|
|
14409
|
-
const { width, height, theme, fonts, formatting, colorPalette, styleDefinition, ...svg } =
|
|
15525
|
+
function renderChartSpaceSvg(space, options2) {
|
|
15526
|
+
const { width, height, theme, fonts, formatting, colorPalette, styleDefinition, ...svg } = options2;
|
|
14410
15527
|
const summary = chartSummaryFromSpace(space, {
|
|
14411
15528
|
...formatting ? { formatting } : {},
|
|
14412
15529
|
...colorPalette !== void 0 ? { colorPalette } : {},
|
|
@@ -14415,8 +15532,8 @@ function renderChartSpaceSvg(space, options) {
|
|
|
14415
15532
|
const view = chartSummaryView(summary, chartThemePalette(theme, fonts));
|
|
14416
15533
|
return renderChartSvg(view, width, height, svg);
|
|
14417
15534
|
}
|
|
14418
|
-
function renderChartSummarySvg(summary,
|
|
14419
|
-
const { width, height, theme, fonts, ...svg } =
|
|
15535
|
+
function renderChartSummarySvg(summary, options2) {
|
|
15536
|
+
const { width, height, theme, fonts, ...svg } = options2;
|
|
14420
15537
|
const view = chartSummaryView(summary, chartThemePalette(theme, fonts));
|
|
14421
15538
|
return renderChartSvg(view, width, height, svg);
|
|
14422
15539
|
}
|
|
@@ -14521,11 +15638,11 @@ function parseDirectParagraphProperties(props) {
|
|
|
14521
15638
|
|
|
14522
15639
|
// docx/numbering-parse.ts
|
|
14523
15640
|
var own = (map, key) => Object.prototype.hasOwnProperty.call(map, key) ? map[key] : void 0;
|
|
14524
|
-
function resolveNumberingLevel(catalog, numId,
|
|
15641
|
+
function resolveNumberingLevel(catalog, numId, level2) {
|
|
14525
15642
|
const num = own(catalog.nums, numId);
|
|
14526
15643
|
if (!num) return void 0;
|
|
14527
|
-
const override = num.levelOverrides?.[
|
|
14528
|
-
const sourceAbstract = own(catalog.abstractNums, num.abstractNumId)?.levels[
|
|
15644
|
+
const override = num.levelOverrides?.[level2];
|
|
15645
|
+
const sourceAbstract = own(catalog.abstractNums, num.abstractNumId)?.levels[level2];
|
|
14529
15646
|
const abstract = sourceAbstract?.startWasOmitted && sourceAbstract.start === 1 ? { ...sourceAbstract, start: 0 } : sourceAbstract;
|
|
14530
15647
|
let base = override?.lvl ?? abstract;
|
|
14531
15648
|
if (!base) return void 0;
|
|
@@ -14924,10 +16041,10 @@ function resolveParagraphNumbering(paragraph, styleCatalog, numberingCatalog) {
|
|
|
14924
16041
|
const inherited = resolveStyleNumbering(paragraph.style, styleCatalog);
|
|
14925
16042
|
if (!inherited || inherited.numId <= 0) return void 0;
|
|
14926
16043
|
if (numberingCatalog && paragraph.style && styleCatalog.styles[paragraph.style]) {
|
|
14927
|
-
for (let
|
|
14928
|
-
const definition = resolveNumberingLevel(numberingCatalog, String(inherited.numId),
|
|
16044
|
+
for (let level2 = 0; level2 < 9; level2++) {
|
|
16045
|
+
const definition = resolveNumberingLevel(numberingCatalog, String(inherited.numId), level2);
|
|
14929
16046
|
if (definition?.paragraphStyleId === paragraph.style)
|
|
14930
|
-
return { numId: inherited.numId, level };
|
|
16047
|
+
return { numId: inherited.numId, level: level2 };
|
|
14931
16048
|
}
|
|
14932
16049
|
}
|
|
14933
16050
|
return inherited;
|
|
@@ -14960,23 +16077,23 @@ var NumberingCounters = class {
|
|
|
14960
16077
|
return started;
|
|
14961
16078
|
}
|
|
14962
16079
|
/** Advances one level and resets deeper counters according to their resolved restart rules. */
|
|
14963
|
-
advance(numId,
|
|
16080
|
+
advance(numId, level2, def, catalog) {
|
|
14964
16081
|
const counts = this.forNum(numId);
|
|
14965
16082
|
const started = this.startedLevels(numId);
|
|
14966
|
-
const next = started.has(
|
|
14967
|
-
counts.set(
|
|
14968
|
-
started.add(
|
|
16083
|
+
const next = started.has(level2) ? (counts.get(level2) ?? def.start) + 1 : def.start;
|
|
16084
|
+
counts.set(level2, next);
|
|
16085
|
+
started.add(level2);
|
|
14969
16086
|
for (const deeper of [...started]) {
|
|
14970
|
-
if (deeper <=
|
|
16087
|
+
if (deeper <= level2) continue;
|
|
14971
16088
|
const deeperDef = resolveNumberingLevel(catalog, numId, deeper);
|
|
14972
16089
|
const restart = deeperDef?.lvlRestart;
|
|
14973
16090
|
if (restart === 0) continue;
|
|
14974
16091
|
const trigger = restart !== void 0 && restart > 0 && restart <= deeper ? restart - 1 : deeper - 1;
|
|
14975
|
-
if (
|
|
16092
|
+
if (level2 > trigger) continue;
|
|
14976
16093
|
counts.delete(deeper);
|
|
14977
16094
|
started.delete(deeper);
|
|
14978
16095
|
}
|
|
14979
|
-
for (let ancestor = 0; ancestor <
|
|
16096
|
+
for (let ancestor = 0; ancestor < level2; ancestor++) {
|
|
14980
16097
|
if (started.has(ancestor)) continue;
|
|
14981
16098
|
const ancestorDef = resolveNumberingLevel(catalog, numId, ancestor);
|
|
14982
16099
|
if (!ancestorDef) continue;
|
|
@@ -14986,14 +16103,14 @@ var NumberingCounters = class {
|
|
|
14986
16103
|
return next;
|
|
14987
16104
|
}
|
|
14988
16105
|
/** Current value for an ancestor placeholder, defaulting to its own start when never instantiated. */
|
|
14989
|
-
current(numId,
|
|
14990
|
-
return this.forNum(numId).get(
|
|
16106
|
+
current(numId, level2, start) {
|
|
16107
|
+
return this.forNum(numId).get(level2) ?? start;
|
|
14991
16108
|
}
|
|
14992
16109
|
};
|
|
14993
|
-
function substituteLvlText(lvlText, numId,
|
|
16110
|
+
function substituteLvlText(lvlText, numId, level2, catalog, counters, forceDecimal) {
|
|
14994
16111
|
return lvlText.replace(/%([1-9])/g, (match, digit) => {
|
|
14995
16112
|
const ancestorLevel = Number(digit) - 1;
|
|
14996
|
-
if (ancestorLevel >
|
|
16113
|
+
if (ancestorLevel > level2) return match;
|
|
14997
16114
|
const ancestorDef = resolveNumberingLevel(catalog, numId, ancestorLevel);
|
|
14998
16115
|
const start = ancestorDef?.start ?? 1;
|
|
14999
16116
|
const value = counters.current(numId, ancestorLevel, start);
|
|
@@ -15010,15 +16127,15 @@ function computeListLabels(model) {
|
|
|
15010
16127
|
const numbering = resolveParagraphNumbering(paragraph, model.paragraphStyles, catalog);
|
|
15011
16128
|
if (!numbering) continue;
|
|
15012
16129
|
const numId = String(numbering.numId);
|
|
15013
|
-
const
|
|
15014
|
-
const def = resolveNumberingLevel(catalog, numId,
|
|
16130
|
+
const level2 = Math.min(8, Math.max(0, numbering.level));
|
|
16131
|
+
const def = resolveNumberingLevel(catalog, numId, level2);
|
|
15015
16132
|
if (!def) continue;
|
|
15016
16133
|
if (def.numFmt === "none") continue;
|
|
15017
|
-
counters.advance(numId,
|
|
15018
|
-
const text2 = def.numFmt === "bullet" ? def.lvlText : substituteLvlText(def.lvlText, numId,
|
|
16134
|
+
counters.advance(numId, level2, def, catalog);
|
|
16135
|
+
const text2 = def.numFmt === "bullet" ? def.lvlText : substituteLvlText(def.lvlText, numId, level2, catalog, counters, Boolean(def.isLgl));
|
|
15019
16136
|
labels.set(paragraph.id, {
|
|
15020
16137
|
numId,
|
|
15021
|
-
level,
|
|
16138
|
+
level: level2,
|
|
15022
16139
|
text: text2,
|
|
15023
16140
|
suffix: def.suffix ?? "tab",
|
|
15024
16141
|
...definedProps({
|
|
@@ -15153,7 +16270,7 @@ function datePicture(instr) {
|
|
|
15153
16270
|
}
|
|
15154
16271
|
var TOKENS = /yyyy|yy|MMMM|MMM|MM|M|dddd|ddd|dd|d|HH|H|hh|h|mm|ss|am\/pm|AM\/PM|'[^']*'/g;
|
|
15155
16272
|
function formatWordDate(date, picture, locale = "en-US") {
|
|
15156
|
-
const name = (
|
|
16273
|
+
const name = (options2) => new Intl.DateTimeFormat(locale, options2).format(date);
|
|
15157
16274
|
const pad = (value) => String(value).padStart(2, "0");
|
|
15158
16275
|
const hours12 = date.getHours() % 12 || 12;
|
|
15159
16276
|
return picture.replace(TOKENS, (token) => {
|
|
@@ -15352,9 +16469,9 @@ function fontMetrics(measurer, font) {
|
|
|
15352
16469
|
const ascent = Math.min(height, measurer.ascentOf?.(font) ?? height * 0.8);
|
|
15353
16470
|
return { ascent, descent: height - ascent };
|
|
15354
16471
|
}
|
|
15355
|
-
function createFakeMeasurer(
|
|
15356
|
-
const charWidthFactor =
|
|
15357
|
-
const lineHeightFactor =
|
|
16472
|
+
function createFakeMeasurer(options2 = {}) {
|
|
16473
|
+
const charWidthFactor = options2.charWidthFactor ?? 0.6;
|
|
16474
|
+
const lineHeightFactor = options2.lineHeightFactor ?? 1.15;
|
|
15358
16475
|
return {
|
|
15359
16476
|
widthOf(text2, font) {
|
|
15360
16477
|
let width = 0;
|
|
@@ -15481,12 +16598,12 @@ function headerFooterSlotForPage(model, page, pageNumber) {
|
|
|
15481
16598
|
return page.pageInSection === 0 && section?.titlePage ? "first" : model.evenAndOddHeaders && pageNumber % 2 === 0 ? "even" : "default";
|
|
15482
16599
|
}
|
|
15483
16600
|
function headerFooterForPage(model, page, pageNumber, kind) {
|
|
15484
|
-
const
|
|
15485
|
-
const section =
|
|
16601
|
+
const sections2 = model.sections ?? [];
|
|
16602
|
+
const section = sections2[page.sectionIndex];
|
|
15486
16603
|
if (!section) return void 0;
|
|
15487
16604
|
const slot = headerFooterSlotForPage(model, page, pageNumber);
|
|
15488
16605
|
for (let index = page.sectionIndex; index >= 0; index--) {
|
|
15489
|
-
const content =
|
|
16606
|
+
const content = sections2[index]?.[kind]?.[slot];
|
|
15490
16607
|
if (content) return content;
|
|
15491
16608
|
}
|
|
15492
16609
|
return void 0;
|
|
@@ -17223,11 +18340,11 @@ function completedNoteStoryMinimum(row2, stories, pendingBlocks, available) {
|
|
|
17223
18340
|
for (const [index, cell] of row2.cells.entries()) {
|
|
17224
18341
|
const groups = /* @__PURE__ */ new Map();
|
|
17225
18342
|
for (const box of cell) {
|
|
17226
|
-
const
|
|
17227
|
-
if (
|
|
17228
|
-
const boxes = groups.get(
|
|
18343
|
+
const group2 = stories.get(box.blockId);
|
|
18344
|
+
if (group2 !== void 0) {
|
|
18345
|
+
const boxes = groups.get(group2) ?? [];
|
|
17229
18346
|
boxes.push(box);
|
|
17230
|
-
groups.set(
|
|
18347
|
+
groups.set(group2, boxes);
|
|
17231
18348
|
}
|
|
17232
18349
|
}
|
|
17233
18350
|
for (const boxes of groups.values()) {
|
|
@@ -17293,8 +18410,8 @@ var TableFootnotes = class {
|
|
|
17293
18410
|
for (const cell of row2.cells) {
|
|
17294
18411
|
for (const paragraph of cellParagraphs(cell))
|
|
17295
18412
|
if (paragraph.footnotes?.length) this.paragraphs.set(paragraph.id, paragraph);
|
|
17296
|
-
for (const [id,
|
|
17297
|
-
this.stories.set(id,
|
|
18413
|
+
for (const [id, group2] of (measured ? independentNoteStories(cell) : void 0) ?? []) {
|
|
18414
|
+
this.stories.set(id, group2);
|
|
17298
18415
|
}
|
|
17299
18416
|
}
|
|
17300
18417
|
}
|
|
@@ -17427,11 +18544,11 @@ var TableFootnotes = class {
|
|
|
17427
18544
|
for (const [index, cell] of row2.cells.entries()) {
|
|
17428
18545
|
const groups = /* @__PURE__ */ new Map();
|
|
17429
18546
|
for (const box of cell) {
|
|
17430
|
-
const
|
|
17431
|
-
if (
|
|
17432
|
-
const boxes = groups.get(
|
|
18547
|
+
const group2 = this.stories.get(box.blockId);
|
|
18548
|
+
if (group2 !== void 0) {
|
|
18549
|
+
const boxes = groups.get(group2) ?? [];
|
|
17433
18550
|
boxes.push(box);
|
|
17434
|
-
groups.set(
|
|
18551
|
+
groups.set(group2, boxes);
|
|
17435
18552
|
}
|
|
17436
18553
|
}
|
|
17437
18554
|
for (const boxes of groups.values()) {
|
|
@@ -19776,8 +20893,8 @@ function sectionBreak(type, note) {
|
|
|
19776
20893
|
return type;
|
|
19777
20894
|
}
|
|
19778
20895
|
function adaptDocumentModel(model, note = () => {
|
|
19779
|
-
},
|
|
19780
|
-
const reviewMode =
|
|
20896
|
+
}, options2 = {}) {
|
|
20897
|
+
const reviewMode = options2.reviewDisplayMode ?? "all";
|
|
19781
20898
|
const visibleModel = visibleReviewModel(model, reviewMode);
|
|
19782
20899
|
const catalog = model.paragraphStyles;
|
|
19783
20900
|
const noted = /* @__PURE__ */ new Set();
|
|
@@ -19955,14 +21072,14 @@ function adaptDocumentModel(model, note = () => {
|
|
|
19955
21072
|
note2.blocks.filter((block) => block.type === "paragraph").map((paragraph) => adaptParagraph(paragraph))
|
|
19956
21073
|
])
|
|
19957
21074
|
) : void 0;
|
|
19958
|
-
const
|
|
21075
|
+
const sections2 = model.sections;
|
|
19959
21076
|
const modernFootnoteSeparator = model.compatibilityMode === 15;
|
|
19960
21077
|
const legacyFootnoteColumns = model.compatibilityMode === 12 || model.compatibilityMode === 14;
|
|
19961
21078
|
if (!modernFootnoteSeparator && !legacyFootnoteColumns && model.sections?.some((section) => section.footnoteColumns !== void 0))
|
|
19962
21079
|
reportOnce(
|
|
19963
21080
|
"Footnote column settings are preserved, but this compatibility mode has not been verified against native Word; Print Layout uses the existing page-wide fallback."
|
|
19964
21081
|
);
|
|
19965
|
-
if (!
|
|
21082
|
+
if (!sections2 || !sections2.length) {
|
|
19966
21083
|
return {
|
|
19967
21084
|
sections: [
|
|
19968
21085
|
{
|
|
@@ -19984,8 +21101,8 @@ function adaptDocumentModel(model, note = () => {
|
|
|
19984
21101
|
}
|
|
19985
21102
|
const indexById = new Map(model.blocks.map((block, index) => [block.id, index]));
|
|
19986
21103
|
let start = 0;
|
|
19987
|
-
const result =
|
|
19988
|
-
const last = index ===
|
|
21104
|
+
const result = sections2.map((section, index) => {
|
|
21105
|
+
const last = index === sections2.length - 1;
|
|
19989
21106
|
const endIndex = last ? blocks.length : (indexById.get(section.endsAtBlockId) ?? start - 1) + 1;
|
|
19990
21107
|
const end = Math.max(start, endIndex);
|
|
19991
21108
|
const slice = blocks.slice(start, end);
|
|
@@ -20170,13 +21287,13 @@ function layoutDocument(input, measurer) {
|
|
|
20170
21287
|
}
|
|
20171
21288
|
return { ...result, approximations: [.../* @__PURE__ */ new Set([...result.approximations, FLOAT_WRAP_NOTE])] };
|
|
20172
21289
|
}
|
|
20173
|
-
function layoutDocumentModel(model, measurer,
|
|
20174
|
-
const projected = reviewDocumentFormatting(model,
|
|
21290
|
+
function layoutDocumentModel(model, measurer, options2 = {}, layout = layoutDocument) {
|
|
21291
|
+
const projected = reviewDocumentFormatting(model, options2.reviewDisplayMode ?? "all");
|
|
20175
21292
|
const approximations = reviewFormattingWarnings(projected.diagnostics);
|
|
20176
21293
|
const input = adaptDocumentModel(
|
|
20177
21294
|
projected.model,
|
|
20178
21295
|
(message) => approximations.push(message),
|
|
20179
|
-
|
|
21296
|
+
options2
|
|
20180
21297
|
);
|
|
20181
21298
|
const result = layout(input, measurer);
|
|
20182
21299
|
return {
|
|
@@ -20359,7 +21476,7 @@ function layoutDocumentIncremental(input, measurer, memory) {
|
|
|
20359
21476
|
}
|
|
20360
21477
|
|
|
20361
21478
|
// docx/layout/layout-session.ts
|
|
20362
|
-
function createLayoutSession(measurer,
|
|
21479
|
+
function createLayoutSession(measurer, options2 = {}) {
|
|
20363
21480
|
const sessionMeasurer = {
|
|
20364
21481
|
widthOf: (text2, font) => measurer.widthOf(text2, font),
|
|
20365
21482
|
lineHeightOf: (font) => measurer.lineHeightOf(font),
|
|
@@ -20367,7 +21484,7 @@ function createLayoutSession(measurer, options = {}) {
|
|
|
20367
21484
|
};
|
|
20368
21485
|
registerParagraphCache(sessionMeasurer);
|
|
20369
21486
|
const memory = {};
|
|
20370
|
-
const paginate =
|
|
21487
|
+
const paginate = options2.incremental ? (input, sessionMeasure) => layoutDocumentIncremental(input, sessionMeasure, memory) : layoutDocument;
|
|
20371
21488
|
return {
|
|
20372
21489
|
layoutDocument: (input) => paginate(input, sessionMeasurer),
|
|
20373
21490
|
layoutDocumentModel: (model, review = {}) => layoutDocumentModel(model, sessionMeasurer, review, paginate),
|