ooxml-core 1.17.0 → 1.18.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.
Files changed (112) hide show
  1. package/dist/{PptxHandler-U6EFO73T.cjs → PptxHandler-4AHDZDA5.cjs} +2 -2
  2. package/dist/{PptxHandler-L3JPWOBN.mjs → PptxHandler-5X4VOWAO.mjs} +1 -1
  3. package/dist/{PptxHandler-K7GMS2ST.mjs → PptxHandler-X6AO6LKJ.mjs} +2 -2
  4. package/dist/{PresentationBuilder-OK526SZ4.mjs → PresentationBuilder-LRX55PXA.mjs} +2 -2
  5. package/dist/{PresentationBuilder-LUR6LGHU.cjs → PresentationBuilder-MJB4LIFS.cjs} +4 -4
  6. package/dist/{PresentationBuilder-XC3F3OPY.mjs → PresentationBuilder-UY3S4YE2.mjs} +1 -1
  7. package/dist/automation/index.cjs +4710 -3016
  8. package/dist/automation/index.mjs +4710 -3016
  9. package/dist/chart/data-label-text.d.ts +70 -0
  10. package/dist/chart/data-label-text.d.ts.map +1 -0
  11. package/dist/chart/formatting-nodes.d.ts +6 -0
  12. package/dist/chart/formatting-nodes.d.ts.map +1 -1
  13. package/dist/chart/index.cjs +690 -375
  14. package/dist/chart/index.d.ts +1 -0
  15. package/dist/chart/index.d.ts.map +1 -1
  16. package/dist/chart/index.mjs +687 -376
  17. package/dist/chart/read-formatting.d.ts.map +1 -1
  18. package/dist/chart/render/chart-svg-bars.d.ts.map +1 -1
  19. package/dist/chart/render/chart-svg-cartesian.d.ts.map +1 -1
  20. package/dist/chart/render/chart-svg-labels.d.ts +42 -0
  21. package/dist/chart/render/chart-svg-labels.d.ts.map +1 -0
  22. package/dist/chart/render/chart-svg-radial.d.ts.map +1 -1
  23. package/dist/chart/render/chart-svg-xy.d.ts.map +1 -1
  24. package/dist/chart/render/chart-view-labels.d.ts +16 -0
  25. package/dist/chart/render/chart-view-labels.d.ts.map +1 -0
  26. package/dist/chart/render/chart-view.d.ts +3 -0
  27. package/dist/chart/render/chart-view.d.ts.map +1 -1
  28. package/dist/chart/render/summary-from-space.d.ts +2 -2
  29. package/dist/chart/render/summary-from-space.d.ts.map +1 -1
  30. package/dist/chart/render/summary-labels.d.ts +9 -0
  31. package/dist/chart/render/summary-labels.d.ts.map +1 -0
  32. package/dist/chart/render/summary.d.ts +23 -0
  33. package/dist/chart/render/summary.d.ts.map +1 -1
  34. package/dist/{chunk-IM5LFEA2.mjs → chunk-7NWQUCGX.mjs} +1 -1
  35. package/dist/{chunk-UFGJNXRG.mjs → chunk-I5ZE3VLI.mjs} +1 -1
  36. package/dist/{chunk-A7S2NYAU.mjs → chunk-LT7RCEHY.mjs} +1 -1
  37. package/dist/{chunk-HLZIALC5.mjs → chunk-U7IDT6VT.mjs} +1 -1
  38. package/dist/{chunk-YS43OMM3.mjs → chunk-Z5Y53IZD.mjs} +4 -4
  39. package/dist/docx/embedded.cjs +15 -0
  40. package/dist/docx/embedded.mjs +15 -0
  41. package/dist/docx/index.cjs +1261 -656
  42. package/dist/docx/index.mjs +1261 -656
  43. package/dist/docx/layout/index.cjs +1129 -539
  44. package/dist/docx/layout/index.mjs +1129 -539
  45. package/dist/docx/load/index.cjs +15 -0
  46. package/dist/docx/load/index.mjs +15 -0
  47. package/dist/docx/ui/index.cjs +1119 -529
  48. package/dist/docx/ui/index.mjs +1119 -529
  49. package/dist/index.cjs +757 -442
  50. package/dist/index.mjs +757 -442
  51. package/dist/pptx/automation/index.cjs +7 -0
  52. package/dist/pptx/automation/index.mjs +5 -5
  53. package/dist/pptx/cli/index.cjs +7 -0
  54. package/dist/pptx/cli/index.mjs +4 -4
  55. package/dist/pptx/converter/index.mjs +2 -2
  56. package/dist/pptx/editor/render/slide-operations.cjs +1 -1
  57. package/dist/pptx/editor/render/slide-operations.mjs +1 -1
  58. package/dist/pptx/index.cjs +7 -0
  59. package/dist/pptx/index.mjs +5 -5
  60. package/dist/teams/index.cjs +145 -49
  61. package/dist/teams/index.mjs +145 -49
  62. package/dist/visio/edit-chart-object-commands.d.ts +36 -0
  63. package/dist/visio/edit-chart-object-commands.d.ts.map +1 -0
  64. package/dist/visio/edit-chart-object.d.ts +7 -0
  65. package/dist/visio/edit-chart-object.d.ts.map +1 -0
  66. package/dist/visio/edit-commands.d.ts +2 -1
  67. package/dist/visio/edit-commands.d.ts.map +1 -1
  68. package/dist/visio/edit-foreign-frame.d.ts +8 -0
  69. package/dist/visio/edit-foreign-frame.d.ts.map +1 -0
  70. package/dist/visio/edit-metadata-commands.d.ts +7 -0
  71. package/dist/visio/edit-metadata-commands.d.ts.map +1 -1
  72. package/dist/visio/edit-picture.d.ts +8 -0
  73. package/dist/visio/edit-picture.d.ts.map +1 -1
  74. package/dist/visio/edit.d.ts.map +1 -1
  75. package/dist/visio/emf-bitmap.d.ts +8 -0
  76. package/dist/visio/emf-bitmap.d.ts.map +1 -0
  77. package/dist/visio/index.cjs +17093 -6136
  78. package/dist/visio/index.d.ts +2 -0
  79. package/dist/visio/index.d.ts.map +1 -1
  80. package/dist/visio/index.mjs +17091 -6137
  81. package/dist/visio/model.d.ts +18 -0
  82. package/dist/visio/model.d.ts.map +1 -1
  83. package/dist/visio/prepare-embedded.d.ts +10 -0
  84. package/dist/visio/prepare-embedded.d.ts.map +1 -0
  85. package/dist/visio/prepare-images.d.ts.map +1 -1
  86. package/dist/visio/shapes.d.ts.map +1 -1
  87. package/dist/visio/sheet.d.ts +2 -1
  88. package/dist/visio/sheet.d.ts.map +1 -1
  89. package/dist/visio/ui/edit-commands.d.ts.map +1 -1
  90. package/dist/visio/ui/index.cjs +33320 -22884
  91. package/dist/visio/ui/index.mjs +33318 -22884
  92. package/dist/visio/ui/insert.d.ts +11 -0
  93. package/dist/visio/ui/insert.d.ts.map +1 -1
  94. package/dist/xlsx/index.cjs +1175 -564
  95. package/dist/xlsx/index.mjs +1175 -564
  96. package/dist/xlsx/load/index.cjs +136 -50
  97. package/dist/xlsx/load/index.mjs +136 -50
  98. package/dist/xlsx/model.d.ts +5 -0
  99. package/dist/xlsx/model.d.ts.map +1 -1
  100. package/dist/xlsx/read/load.d.ts.map +1 -1
  101. package/dist/xlsx/read/workbook-part.d.ts +2 -0
  102. package/dist/xlsx/read/workbook-part.d.ts.map +1 -1
  103. package/dist/xlsx/ui/dialogs/grid-chart.d.ts +22 -1
  104. package/dist/xlsx/ui/dialogs/grid-chart.d.ts.map +1 -1
  105. package/dist/xlsx/ui/index.cjs +16820 -4239
  106. package/dist/xlsx/ui/index.mjs +16810 -4237
  107. package/dist/xlsx/write/workbook-part.d.ts.map +1 -1
  108. package/package.json +1 -1
  109. package/dist/visio/edit-foreign-bitmap.d.ts +0 -7
  110. package/dist/visio/edit-foreign-bitmap.d.ts.map +0 -1
  111. /package/dist/{chunk-KU3SMBFU.mjs → chunk-C363NN2C.mjs} +0 -0
  112. /package/dist/{chunk-UWWS6VVJ.cjs → chunk-R4BCOQHB.cjs} +0 -0
@@ -57,8 +57,8 @@ function parseXml(xml, options = {}) {
57
57
  let parsed;
58
58
  try {
59
59
  parsed = new DOMParser({
60
- onError: (level, message) => {
61
- if (level !== "warning") parseError = message;
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 level of levels) {
732
- const value = level[key];
731
+ for (const level2 of levels) {
732
+ const value = level2[key];
733
733
  if (value !== void 0) result[key] = value;
734
734
  }
735
735
  }
@@ -11339,6 +11339,287 @@ 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
+
11577
+ // chart/data-label-text.ts
11578
+ var DATA_LABEL_SEPARATOR = ", ";
11579
+ var DATA_LABEL_CATEGORY_PERCENT_SEPARATOR = "\n";
11580
+ var FLAG_KEYS = [
11581
+ "showValue",
11582
+ "showCategory",
11583
+ "showSeriesName",
11584
+ "showPercent",
11585
+ "showBubbleSize"
11586
+ ];
11587
+ function resolveDataLabelFlags(levels) {
11588
+ const { point, series, chart } = levels;
11589
+ const picked = {};
11590
+ for (const key of FLAG_KEYS) picked[key] = point?.[key] ?? series?.[key] ?? chart?.[key];
11591
+ const anyDeclared = FLAG_KEYS.some((key) => picked[key] !== void 0);
11592
+ return {
11593
+ showValue: anyDeclared ? picked.showValue === true : levels.siblingOwnsLabels !== true,
11594
+ showCategory: picked.showCategory === true,
11595
+ showSeriesName: picked.showSeriesName === true,
11596
+ showPercent: picked.showPercent === true,
11597
+ showBubbleSize: picked.showBubbleSize === true,
11598
+ separator: point?.separator ?? series?.separator ?? chart?.separator ?? (picked.showCategory === true && picked.showPercent === true ? DATA_LABEL_CATEGORY_PERCENT_SEPARATOR : DATA_LABEL_SEPARATOR)
11599
+ };
11600
+ }
11601
+ function composeDataLabelText(input) {
11602
+ const { flags, value, numberFormat } = input;
11603
+ const parts = [];
11604
+ let valueColor;
11605
+ if (flags.showSeriesName && input.seriesName) parts.push(input.seriesName);
11606
+ if (flags.showCategory && input.category) parts.push(input.category);
11607
+ if (flags.showValue) {
11608
+ const formatted = formatChartNumberWithColor(value, numberFormat);
11609
+ parts.push(formatted?.text ?? (input.formatValue ?? String)(value, numberFormat));
11610
+ valueColor = formatted?.color;
11611
+ }
11612
+ if (flags.showPercent) {
11613
+ const base = input.percentBase;
11614
+ parts.push(base > 0 ? `${Math.round(Math.abs(value) / base * 100)}%` : "0%");
11615
+ }
11616
+ if (flags.showBubbleSize && input.bubbleSize !== void 0)
11617
+ parts.push((input.formatBubbleSize ?? String)(input.bubbleSize));
11618
+ const text2 = parts.join(flags.separator);
11619
+ if (text2.length === 0) return void 0;
11620
+ return { text: text2, color: parts.length === 1 && flags.showValue ? valueColor : void 0 };
11621
+ }
11622
+
11342
11623
  // chart/bubble-radius.ts
11343
11624
  function computeBubbleRadius(sizeVal, maxBubble, medianRadius, options) {
11344
11625
  const scale = (options?.bubbleScale ?? 100) / 100;
@@ -11451,10 +11732,10 @@ function squarify(nodes, box) {
11451
11732
 
11452
11733
  // chart/hierarchy.ts
11453
11734
  function normalizeLevels(levels, pointCount) {
11454
- return levels.map((level) => {
11735
+ return levels.map((level2) => {
11455
11736
  let previous = "";
11456
11737
  return Array.from({ length: pointCount }, (_, index) => {
11457
- const label = level[index]?.trim() ?? "";
11738
+ const label = level2[index]?.trim() ?? "";
11458
11739
  if (label) previous = label;
11459
11740
  return label || previous;
11460
11741
  });
@@ -11612,12 +11893,12 @@ function computeSunburstArcs(series, cx, cy, maxR) {
11612
11893
  });
11613
11894
  return out;
11614
11895
  }
11615
- function hierarchyKey(levels, level, index) {
11616
- return levels.slice(level).map((labels) => labels[index] ?? "").join("\0");
11896
+ function hierarchyKey(levels, level2, index) {
11897
+ return levels.slice(level2).map((labels) => labels[index] ?? "").join("\0");
11617
11898
  }
11618
11899
  function computeHierarchicalSunburstArcs(categoryLevels, values, cx, cy, maxR) {
11619
- const levels = categoryLevels.filter((level) => level.length > 0);
11620
- const leafCount = Math.max(values.length, ...levels.map((level) => level.length), 0);
11900
+ const levels = categoryLevels.filter((level2) => level2.length > 0);
11901
+ const leafCount = Math.max(values.length, ...levels.map((level2) => level2.length), 0);
11621
11902
  if (levels.length === 0 || leafCount === 0) return [];
11622
11903
  const rawWeights = Array.from({ length: leafCount }, (_, index) => Math.abs(values[index] ?? 0));
11623
11904
  const weights = rawWeights.some((value) => value !== 0) ? rawWeights : rawWeights.map(() => 1);
@@ -11628,15 +11909,15 @@ function computeHierarchicalSunburstArcs(categoryLevels, values, cx, cy, maxR) {
11628
11909
  const rootLabels = levels[levels.length - 1] ?? [];
11629
11910
  const rootColors = /* @__PURE__ */ new Map();
11630
11911
  const out = [];
11631
- for (let level = levels.length - 1; level >= 0; level--) {
11632
- const ringIndex = levels.length - 1 - level;
11912
+ for (let level2 = levels.length - 1; level2 >= 0; level2--) {
11913
+ const ringIndex = levels.length - 1 - level2;
11633
11914
  const innerRadius = ringWidth * (ringIndex + 0.5);
11634
11915
  const outerRadius = ringWidth * (ringIndex + 1.5);
11635
11916
  let start = 0;
11636
11917
  while (start < leafCount) {
11637
- const key = hierarchyKey(levels, level, start);
11918
+ const key = hierarchyKey(levels, level2, start);
11638
11919
  let end = start + 1;
11639
- while (end < leafCount && hierarchyKey(levels, level, end) === key) end++;
11920
+ while (end < leafCount && hierarchyKey(levels, level2, end) === key) end++;
11640
11921
  const startAngle = -Math.PI / 2 + (prefix2[start] ?? 0) / total * Math.PI * 2;
11641
11922
  const endAngle = -Math.PI / 2 + (prefix2[end] ?? 0) / total * Math.PI * 2;
11642
11923
  const rootLabel = rootLabels[start] ?? "";
@@ -11646,8 +11927,8 @@ function computeHierarchicalSunburstArcs(categoryLevels, values, cx, cy, maxR) {
11646
11927
  colorIndex: rootColors.get(rootLabel) ?? start,
11647
11928
  opacity: Math.max(0.1, 0.9 - ringIndex * 0.1),
11648
11929
  level: ringIndex,
11649
- label: levels[level]?.[start] ?? "",
11650
- ...level === 0 && end === start + 1 ? { pointIndex: start } : {},
11930
+ label: levels[level2]?.[start] ?? "",
11931
+ ...level2 === 0 && end === start + 1 ? { pointIndex: start } : {},
11651
11932
  ...arcLabelPlacement(cx, cy, (innerRadius + outerRadius) / 2, startAngle, endAngle)
11652
11933
  });
11653
11934
  start = end;
@@ -11935,6 +12216,65 @@ function chartErrorBarAmount(options, values, displayIndex, sourceIndex, side) {
11935
12216
  }
11936
12217
  }
11937
12218
 
12219
+ // chart/pie-best-fit.ts
12220
+ var PX_PER_PT = 4 / 3;
12221
+ var BEST_FIT_RIM_INSET = 4 * PX_PER_PT;
12222
+ var BEST_FIT_EDGE_TOLERANCE = 1.5 * PX_PER_PT;
12223
+ var BEST_FIT_OUTSIDE_GAP = 2 * PX_PER_PT;
12224
+ function farCorner(x, y, w, h) {
12225
+ return Math.hypot(Math.abs(x) + w / 2, Math.abs(y) + h / 2);
12226
+ }
12227
+ function insideDistance(ux, uy, w, h, limit) {
12228
+ if (farCorner(0, 0, w, h) > limit) {
12229
+ return void 0;
12230
+ }
12231
+ let lo = 0;
12232
+ let hi = limit;
12233
+ for (let i = 0; i < 40; i++) {
12234
+ const mid = (lo + hi) / 2;
12235
+ if (farCorner(mid * ux, mid * uy, w, h) > limit) {
12236
+ hi = mid;
12237
+ } else {
12238
+ lo = mid;
12239
+ }
12240
+ }
12241
+ return lo;
12242
+ }
12243
+ function edgeOverhang(x, y, w, h, slice) {
12244
+ let worst = Number.NEGATIVE_INFINITY;
12245
+ const corners = [
12246
+ [-w / 2, -h / 2],
12247
+ [w / 2, -h / 2],
12248
+ [-w / 2, h / 2],
12249
+ [w / 2, h / 2]
12250
+ ];
12251
+ for (const [dx, dy] of corners) {
12252
+ const px = x + dx;
12253
+ const py = y + dy;
12254
+ const fromStart = Math.cos(slice.startAngle) * py - Math.sin(slice.startAngle) * px;
12255
+ const fromEnd = Math.sin(slice.endAngle) * px - Math.cos(slice.endAngle) * py;
12256
+ worst = Math.max(worst, -fromStart, -fromEnd);
12257
+ }
12258
+ return worst;
12259
+ }
12260
+ function placeBestFitLabel(slice, w, h) {
12261
+ const mid = (slice.startAngle + slice.endAngle) / 2;
12262
+ const ux = Math.cos(mid);
12263
+ const uy = Math.sin(mid);
12264
+ const distance = insideDistance(ux, uy, w, h, slice.outerR - BEST_FIT_RIM_INSET);
12265
+ if (distance !== void 0) {
12266
+ const x = distance * ux;
12267
+ const y = distance * uy;
12268
+ const reflex = slice.endAngle - slice.startAngle >= Math.PI;
12269
+ if (reflex || edgeOverhang(x, y, w, h, slice) <= BEST_FIT_EDGE_TOLERANCE) {
12270
+ return { x: slice.cx + x, y: slice.cy + y, inside: true };
12271
+ }
12272
+ }
12273
+ const extent = Math.abs(ux) * w / 2 + Math.abs(uy) * h / 2;
12274
+ const outside = slice.outerR + BEST_FIT_OUTSIDE_GAP + extent;
12275
+ return { x: slice.cx + outside * ux, y: slice.cy + outside * uy, inside: false };
12276
+ }
12277
+
11938
12278
  // chart/color-palettes.ts
11939
12279
  var COLORFUL_VARIATIONS = [
11940
12280
  {},
@@ -12288,6 +12628,41 @@ function summaryAnalysis(series) {
12288
12628
  };
12289
12629
  }
12290
12630
 
12631
+ // chart/render/summary-labels.ts
12632
+ function level(options, custom) {
12633
+ const out = {};
12634
+ if (options.deleted !== void 0) out.deleted = options.deleted;
12635
+ if (options.showValue !== void 0) out.showValue = options.showValue;
12636
+ if (options.showCategoryName !== void 0) out.showCategory = options.showCategoryName;
12637
+ if (options.showSeriesName !== void 0) out.showSeriesName = options.showSeriesName;
12638
+ if (options.showPercent !== void 0) out.showPercent = options.showPercent;
12639
+ if (options.showBubbleSize !== void 0) out.showBubbleSize = options.showBubbleSize;
12640
+ if (options.separator !== void 0) out.separator = options.separator;
12641
+ if (options.position) out.position = options.position;
12642
+ if (options.numberFormat?.formatCode) out.numberFormat = options.numberFormat.formatCode;
12643
+ if (custom?.text !== void 0) out.text = custom.text;
12644
+ return out;
12645
+ }
12646
+ function shows(levels, point) {
12647
+ const flags = resolveDataLabelFlags({ ...levels, ...point ? { point } : {} });
12648
+ return point?.text !== void 0 || Object.values(flags).some((value) => value === true);
12649
+ }
12650
+ function summaryDataLabels(series, group2) {
12651
+ const own2 = series.dataLabels;
12652
+ if (!own2 && !group2) return void 0;
12653
+ const out = {};
12654
+ if (group2) out.chart = level(group2);
12655
+ if (own2) out.series = level(own2);
12656
+ const points = {};
12657
+ for (const labels of [group2, own2])
12658
+ for (const label of labels?.labels ?? [])
12659
+ if (label.index !== void 0)
12660
+ points[label.index] = { ...points[label.index], ...level(label, label.tx) };
12661
+ if (Object.keys(points).length) out.points = points;
12662
+ if (!shows(out) && !Object.values(points).some((point) => shows(out, point))) return void 0;
12663
+ return out;
12664
+ }
12665
+
12291
12666
  // chart/render/summary-from-space.ts
12292
12667
  var solidColor = (fill) => fill?.kind === "solid" ? fill.color : void 0;
12293
12668
  var isSolidFill = (fill) => fill?.kind === "solid" || fill?.kind === "unsupported" && fill.element === "solidFill";
@@ -12305,7 +12680,7 @@ var GROUP_TYPES = {
12305
12680
  surface: "surface"
12306
12681
  };
12307
12682
  var GROUPINGS = /* @__PURE__ */ new Set(["clustered", "stacked", "percentStacked", "standard"]);
12308
- function chartSummarySeries(source, chartType) {
12683
+ function chartSummarySeries(source, chartType, groupLabels) {
12309
12684
  const categories = source.categories ?? source.xValues;
12310
12685
  const values = source.values ?? source.yValues;
12311
12686
  const numeric = (v) => typeof v === "number" ? v : v === "" ? null : Number.isFinite(Number(v)) ? Number(v) : null;
@@ -12313,6 +12688,7 @@ function chartSummarySeries(source, chartType) {
12313
12688
  categories: chartSourceValues(categories),
12314
12689
  values: chartSourceValues(values).map(numeric)
12315
12690
  };
12691
+ if (values?.cache?.formatCode !== void 0) out.numberFormat = values.cache.formatCode;
12316
12692
  if (source.bubbleSizes) {
12317
12693
  out.bubbleSizes = chartSourceValues(source.bubbleSizes).map(numeric);
12318
12694
  if (source.bubbleSizes.formula) out.bubbleSizesRef = source.bubbleSizes.formula;
@@ -12341,6 +12717,8 @@ function chartSummarySeries(source, chartType) {
12341
12717
  }
12342
12718
  if (Object.keys(points).length) out.pointColors = points;
12343
12719
  if (Object.keys(pointFills).length) out.pointFills = pointFills;
12720
+ const dataLabels = summaryDataLabels(source, groupLabels);
12721
+ if (dataLabels) out.dataLabels = dataLabels;
12344
12722
  Object.assign(out, summaryAnalysis(source));
12345
12723
  return out;
12346
12724
  }
@@ -12349,12 +12727,12 @@ function valueAxisId(chartSpace, axisIds) {
12349
12727
  (id) => chartSpace.plotArea.axes.some((a) => a.id === id && a.kind === "val")
12350
12728
  );
12351
12729
  }
12352
- function stockStyle(group) {
12730
+ function stockStyle(group2) {
12353
12731
  return {
12354
- ...group.hiLowLinesSpPr ? { hiLowLines: group.hiLowLinesSpPr } : {},
12355
- ...group.upBars?.spPr ? { upBars: group.upBars.spPr } : {},
12356
- ...group.downBars?.spPr ? { downBars: group.downBars.spPr } : {},
12357
- ...group.upDownBarsGapWidth === void 0 ? {} : { gapWidth: group.upDownBarsGapWidth }
12732
+ ...group2.hiLowLinesSpPr ? { hiLowLines: group2.hiLowLinesSpPr } : {},
12733
+ ...group2.upBars?.spPr ? { upBars: group2.upBars.spPr } : {},
12734
+ ...group2.downBars?.spPr ? { downBars: group2.downBars.spPr } : {},
12735
+ ...group2.upDownBarsGapWidth === void 0 ? {} : { gapWidth: group2.upDownBarsGapWidth }
12358
12736
  };
12359
12737
  }
12360
12738
  function extraGroups(chartSpace, firstType) {
@@ -12362,31 +12740,33 @@ function extraGroups(chartSpace, firstType) {
12362
12740
  if (!first3 || !["column", "line", "area"].includes(firstType)) return [];
12363
12741
  const primary = valueAxisId(chartSpace, first3.axisIds);
12364
12742
  const out = [];
12365
- for (const group of rest) {
12366
- const stockOverColumns = group.kind === "stock" && firstType === "column";
12367
- if (group.is3D || !(["bar", "line", "area"].includes(group.kind) || stockOverColumns)) continue;
12368
- const type = group.kind === "bar" ? "column" : group.kind;
12743
+ for (const group2 of rest) {
12744
+ const stockOverColumns = group2.kind === "stock" && firstType === "column";
12745
+ if (group2.is3D || !(["bar", "line", "area"].includes(group2.kind) || stockOverColumns)) continue;
12746
+ const type = group2.kind === "bar" ? "column" : group2.kind;
12369
12747
  const entry = {
12370
12748
  chartType: type,
12371
- series: group.series.map((source) => chartSummarySeries(source, type)),
12372
- secondary: valueAxisId(chartSpace, group.axisIds) !== primary
12749
+ series: group2.series.map((source) => chartSummarySeries(source, type, group2.dataLabels)),
12750
+ secondary: valueAxisId(chartSpace, group2.axisIds) !== primary
12373
12751
  };
12374
- if (group.grouping && GROUPINGS.has(group.grouping))
12375
- entry.grouping = group.grouping;
12376
- if (type === "stock") entry.stock = stockStyle(group);
12752
+ if (group2.grouping && GROUPINGS.has(group2.grouping))
12753
+ entry.grouping = group2.grouping;
12754
+ if (type === "stock") entry.stock = stockStyle(group2);
12377
12755
  if (type === "column") {
12378
- if (group.gapWidth !== void 0) entry.barGapWidth = group.gapWidth;
12379
- if (group.overlap !== void 0) entry.barOverlap = group.overlap;
12756
+ if (group2.gapWidth !== void 0) entry.barGapWidth = group2.gapWidth;
12757
+ if (group2.overlap !== void 0) entry.barOverlap = group2.overlap;
12380
12758
  }
12381
12759
  if (entry.series.length) out.push(entry);
12382
12760
  }
12383
12761
  return out;
12384
12762
  }
12385
12763
  function chartSummaryFromSpace(chartSpace, extras = {}) {
12386
- const group = chartSpace.plotArea.groups[0];
12387
- let chartType = group ? GROUP_TYPES[group.kind] : "column";
12388
- if (chartType === "bar" && group?.barDirection !== "bar") chartType = "column";
12389
- const series = (group?.series ?? []).map((source) => chartSummarySeries(source, chartType));
12764
+ const group2 = chartSpace.plotArea.groups[0];
12765
+ let chartType = group2 ? GROUP_TYPES[group2.kind] : "column";
12766
+ if (chartType === "bar" && group2?.barDirection !== "bar") chartType = "column";
12767
+ const series = (group2?.series ?? []).map(
12768
+ (source) => chartSummarySeries(source, chartType, group2?.dataLabels)
12769
+ );
12390
12770
  const summary = {
12391
12771
  chartType,
12392
12772
  series,
@@ -12394,22 +12774,22 @@ function chartSummaryFromSpace(chartSpace, extras = {}) {
12394
12774
  };
12395
12775
  const combined = extraGroups(chartSpace, chartType);
12396
12776
  if (combined.length) summary.extraGroups = combined;
12397
- if (chartType === "stock" && group) summary.stock = stockStyle(group);
12398
- if (chartType === "bubble" && group) {
12399
- const sizeRepresents = group.sizeRepresents === "w" ? "w" : "area";
12777
+ if (chartType === "stock" && group2) summary.stock = stockStyle(group2);
12778
+ if (chartType === "bubble" && group2) {
12779
+ const sizeRepresents = group2.sizeRepresents === "w" ? "w" : "area";
12400
12780
  summary.bubble = {
12401
12781
  sizeRepresents,
12402
- ...group.bubbleScale === void 0 ? {} : { bubbleScale: group.bubbleScale },
12403
- showNegativeBubbles: group.showNegativeBubbles === true
12782
+ ...group2.bubbleScale === void 0 ? {} : { bubbleScale: group2.bubbleScale },
12783
+ showNegativeBubbles: group2.showNegativeBubbles === true
12404
12784
  };
12405
12785
  }
12406
- const grouping = group?.grouping;
12786
+ const grouping = group2?.grouping;
12407
12787
  if (grouping && GROUPINGS.has(grouping))
12408
12788
  summary.grouping = grouping;
12409
12789
  if (chartType === "bar" || chartType === "column") {
12410
12790
  for (const [value, field, fallback, min, max] of [
12411
- [group?.gapWidth, "barGapWidth", 150, 0, 500],
12412
- [group?.overlap, "barOverlap", 0, -100, 100]
12791
+ [group2?.gapWidth, "barGapWidth", 150, 0, 500],
12792
+ [group2?.overlap, "barOverlap", 0, -100, 100]
12413
12793
  ]) {
12414
12794
  const resolved = value ?? fallback;
12415
12795
  if (Number.isInteger(resolved) && resolved >= min && resolved <= max)
@@ -12471,268 +12851,56 @@ function chartBarSpacing(chart) {
12471
12851
  };
12472
12852
  }
12473
12853
 
12474
- // chart/render/chart-svg-bars.ts
12475
- function barLayout(model, frame2) {
12476
- const count = Math.max(1, model.series.length);
12477
- const geometry = clusteredBarGeometry(frame2.bandSize, count, chartBarSpacing(model));
12478
- const barSize = geometry.singleBarWidth;
12479
- const offset = (si) => model.horizontal ? geometry.clusterWidth / 2 - barSize - si * geometry.step : -geometry.clusterWidth / 2 + si * geometry.step;
12480
- return { barSize, offset };
12481
- }
12482
- function bars(model, frame2, out, values) {
12483
- const stacked = model.grouping === "stacked" || model.grouping === "percentStacked";
12484
- const { barSize, offset: barOffset } = barLayout(model, frame2);
12485
- const base = frame2.value(0);
12486
- const pos = new Array(model.categories.length).fill(0);
12487
- const neg = new Array(model.categories.length).fill(0);
12488
- model.series.forEach((s, si) => {
12489
- values[si]?.forEach((v, i) => {
12490
- if (v === null || i >= model.categories.length) return;
12491
- let from = 0;
12492
- let to = v;
12493
- if (stacked) {
12494
- const acc = v >= 0 ? pos : neg;
12495
- from = acc[i] ?? 0;
12496
- to = from + v;
12497
- acc[i] = to;
12498
- }
12499
- const a = stacked ? frame2.value(from) : base;
12500
- const b = frame2.value(to);
12501
- const offset = barOffset(si);
12502
- const center = frame2.band(i);
12503
- const width = model.horizontal ? Math.abs(b - a) : barSize;
12504
- const height = model.horizontal ? barSize : Math.abs(b - a);
12505
- let color = s.pointColors?.[i] ?? s.color;
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
- });
12854
+ // chart/render/theme-palette.ts
12855
+ var THEME_SLOTS = [
12856
+ "lt1",
12857
+ "dk1",
12858
+ "lt2",
12859
+ "dk2",
12860
+ "accent1",
12861
+ "accent2",
12862
+ "accent3",
12863
+ "accent4",
12864
+ "accent5",
12865
+ "accent6",
12866
+ "hlink",
12867
+ "folHlink"
12868
+ ];
12869
+ var DEFAULT_THEME_COLORS = [
12870
+ "FFFFFF",
12871
+ "000000",
12872
+ "E7E6E6",
12873
+ "44546A",
12874
+ "4472C4",
12875
+ "ED7D31",
12876
+ "A5A5A5",
12877
+ "FFC000",
12878
+ "5B9BD5",
12879
+ "70AD47",
12880
+ "0563C1",
12881
+ "954F72"
12882
+ ];
12883
+ function themeColor(theme, index) {
12884
+ const hex = theme.colors[index] ?? DEFAULT_THEME_COLORS[index];
12885
+ return hex && parseArgbHex(hex) ? hex.replace(/^#/, "") : void 0;
12532
12886
  }
12533
12887
 
12534
- // chart/render/chart-svg-analysis.ts
12535
- var DASHES = {
12536
- dot: [1, 3],
12537
- dash: [4, 3],
12538
- lgDash: [8, 3],
12539
- dashDot: [4, 3, 1, 3],
12540
- lgDashDot: [8, 3, 1, 3],
12541
- lgDashDotDot: [8, 3, 1, 3, 1, 3],
12542
- sysDash: [3, 1],
12543
- sysDot: [1, 1],
12544
- sysDashDot: [3, 1, 1, 1],
12545
- sysDashDotDot: [3, 1, 1, 1, 1, 1]
12546
- };
12547
- var CAP = 4;
12548
- function strokeAttributes(stroke) {
12549
- const pattern = stroke.dash ? DASHES[stroke.dash] : void 0;
12550
- const dash = pattern ? ` stroke-dasharray="${pattern.map((step) => n(step * stroke.width)).join(" ")}"` : "";
12551
- return `stroke="${esc(stroke.color)}" stroke-width="${n(stroke.width)}"${dash}`;
12552
- }
12553
- var segment = (x1, y1, x2, y2, stroke) => `<line x1="${n(x1)}" y1="${n(y1)}" x2="${n(x2)}" y2="${n(y2)}" ${stroke}/>`;
12554
- function trendlines(series, si, xs, ys, plane, out) {
12555
- for (const trendline of series.trendlines ?? []) {
12556
- const fit2 = fitChartTrendline(trendline.fit, xs, ys);
12557
- if (fit2.points.length < 2) continue;
12558
- const points = fit2.points.map(({ x, y }) => plane(x, y).map(n).join(",")).join(" ");
12559
- out.push(
12560
- `<polyline points="${points}" fill="none" ${strokeAttributes(trendline.stroke)} data-chart-part="trendline" data-chart-series="${si}"/>`
12561
- );
12562
- }
12888
+ // chart/render/chart-colors.ts
12889
+ function chartColorScheme(theme) {
12890
+ const slots = Object.fromEntries(
12891
+ THEME_SLOTS.map((slot, index) => [slot, `#${themeColor(theme, index) ?? "000000"}`])
12892
+ );
12893
+ return {
12894
+ ...slots,
12895
+ bg1: slots.lt1,
12896
+ tx1: slots.dk1,
12897
+ bg2: slots.lt2,
12898
+ tx2: slots.dk2
12899
+ };
12563
12900
  }
12564
- function errorBar(bars2, at, values, plane, out) {
12565
- const stroke = strokeAttributes(bars2.stroke);
12566
- for (const side of ["plus", "minus"]) {
12567
- if (bars2.barType !== side && bars2.barType !== "both") continue;
12568
- const amount = chartErrorBarAmount(bars2.amount, values, at.displayIndex, at.sourceIndex, side);
12569
- const sign = side === "plus" ? 1 : -1;
12570
- const [x1, y1] = plane(at.x, at.y);
12571
- const [x2, y2] = bars2.direction === "x" ? plane(at.x + sign * amount, at.y) : plane(at.x, at.y + sign * amount);
12572
- out.push(segment(x1, y1, x2, y2, stroke));
12573
- if (!bars2.endCap) continue;
12574
- if (x1 === x2) out.push(segment(x2 - CAP, y2, x2 + CAP, y2, stroke));
12575
- else out.push(segment(x2, y2 - CAP, x2, y2 + CAP, stroke));
12576
- }
12577
- }
12578
- function plottedPoints(series, xOf) {
12579
- return series.values.flatMap((y, index) => {
12580
- const x = xOf(index);
12581
- return y === null || x === null ? [] : [{ x, y, index }];
12582
- });
12583
- }
12584
- function seriesAnalysis(series, si, xOf, plane, barPlane, categoryAxis, out) {
12585
- const points = plottedPoints(series, xOf);
12586
- const xs = points.map((p) => p.x);
12587
- const ys = points.map((p) => p.y);
12588
- trendlines(series, si, xs, ys, plane, out);
12589
- for (const bars2 of series.errorBars ?? []) {
12590
- if (categoryAxis && bars2.direction === "x") continue;
12591
- const values = bars2.direction === "x" ? xs : ys;
12592
- points.forEach(
12593
- (p, displayIndex) => errorBar(bars2, { x: p.x, y: p.y, displayIndex, sourceIndex: p.index }, values, barPlane, out)
12594
- );
12595
- }
12596
- }
12597
- function categoryAnalysis(model, frame2, out) {
12598
- if (model.grouping === "stacked" || model.grouping === "percentStacked") return;
12599
- const plane = (x, y) => model.horizontal ? [frame2.value(y), frame2.band(x - 1)] : [frame2.band(x - 1), frame2.value(y)];
12600
- const barred = model.type === "bar" || model.type === "column";
12601
- const layout = barred ? barLayout(model, frame2) : void 0;
12602
- model.series.forEach((series, si) => {
12603
- if (!series.trendlines && !series.errorBars) return;
12604
- const shift = layout ? layout.offset(si) + layout.barSize / 2 : 0;
12605
- const barPlane = (x, y) => {
12606
- const [px, py] = plane(x, y);
12607
- return model.horizontal ? [px, py + shift] : [px + shift, py];
12608
- };
12609
- seriesAnalysis(series, si, (i) => i + 1, plane, barPlane, true, out);
12610
- });
12611
- }
12612
- function scatterAnalysis(model, px, py, out) {
12613
- const plane = (x, y) => [px(x), py(y)];
12614
- model.series.forEach((series, si) => {
12615
- if (!series.trendlines && !series.errorBars) return;
12616
- seriesAnalysis(series, si, (i) => series.xValues?.[i] ?? null, plane, plane, false, out);
12617
- });
12618
- }
12619
-
12620
- // chart/render/chart-scale.ts
12621
- var clean = (n2) => Number(n2.toPrecision(12));
12622
- function* units(raw) {
12623
- let exp = Math.floor(Math.log10(raw)) - 1;
12624
- for (; ; ) {
12625
- const base = 10 ** exp;
12626
- for (const m of [1, 2, 5]) yield clean(m * base);
12627
- exp++;
12628
- }
12629
- }
12630
- function niceScale(dataMin, dataMax, options = {}) {
12631
- const maxIntervals = Math.max(1, options.maxIntervals ?? 10);
12632
- let lo = Number.isFinite(dataMin) ? dataMin : 0;
12633
- let hi = Number.isFinite(dataMax) ? dataMax : 0;
12634
- if (lo > hi) [lo, hi] = [hi, lo];
12635
- if (lo === hi) {
12636
- if (lo === 0) hi = 1;
12637
- else if (options.noZero) {
12638
- const pad = Math.abs(lo) * 0.1 || 1;
12639
- lo -= pad;
12640
- hi += pad;
12641
- } else if (lo > 0) lo = 0;
12642
- else hi = 0;
12643
- }
12644
- let fixedLo = false;
12645
- let fixedHi = false;
12646
- if (!options.noZero) {
12647
- if (lo >= 0 && hi - lo >= hi / 6) {
12648
- lo = 0;
12649
- fixedLo = true;
12650
- } else if (hi <= 0 && hi - lo >= -lo / 6) {
12651
- hi = 0;
12652
- fixedHi = true;
12653
- }
12654
- }
12655
- const range = hi - lo;
12656
- const top = fixedHi ? hi : hi + range * 0.05;
12657
- const bottom = fixedLo ? lo : lo - range * 0.05;
12658
- for (const unit of units(range / maxIntervals)) {
12659
- const min = fixedLo ? lo : Math.floor(clean(bottom / unit)) * unit;
12660
- const max = fixedHi ? hi : Math.ceil(clean(top / unit)) * unit;
12661
- const intervals = Math.round((max - min) / unit);
12662
- if (intervals <= maxIntervals && intervals > 0) {
12663
- const ticks = [];
12664
- for (let i = 0; i <= intervals; i++) ticks.push(clean(min + i * unit));
12665
- return { min: clean(min), max: clean(max), majorUnit: unit, ticks };
12666
- }
12667
- }
12668
- return { min: lo, max: hi, majorUnit: range, ticks: [lo, hi] };
12669
- }
12670
- var PERCENT_SCALE = {
12671
- min: 0,
12672
- max: 1,
12673
- majorUnit: 0.1,
12674
- ticks: [0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1]
12675
- };
12676
- function formatAxisValue(value, percent = false) {
12677
- if (percent) return `${clean(value * 100)}%`;
12678
- const v = clean(value);
12679
- if (Math.abs(v) >= 1e15 || v !== 0 && Math.abs(v) < 1e-6)
12680
- return v.toExponential(2).replace("e+", "E+").replace("e-", "E-");
12681
- const [int = "0", frac] = String(Math.abs(v)).split(".");
12682
- const grouped = int.replace(/\B(?=(\d{3})+(?!\d))/g, ",");
12683
- return `${v < 0 ? "-" : ""}${grouped}${frac ? `.${frac}` : ""}`;
12684
- }
12685
-
12686
- // chart/render/theme-palette.ts
12687
- var THEME_SLOTS = [
12688
- "lt1",
12689
- "dk1",
12690
- "lt2",
12691
- "dk2",
12692
- "accent1",
12693
- "accent2",
12694
- "accent3",
12695
- "accent4",
12696
- "accent5",
12697
- "accent6",
12698
- "hlink",
12699
- "folHlink"
12700
- ];
12701
- var DEFAULT_THEME_COLORS = [
12702
- "FFFFFF",
12703
- "000000",
12704
- "E7E6E6",
12705
- "44546A",
12706
- "4472C4",
12707
- "ED7D31",
12708
- "A5A5A5",
12709
- "FFC000",
12710
- "5B9BD5",
12711
- "70AD47",
12712
- "0563C1",
12713
- "954F72"
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;
12718
- }
12719
-
12720
- // chart/render/chart-colors.ts
12721
- function chartColorScheme(theme) {
12722
- const slots = Object.fromEntries(
12723
- THEME_SLOTS.map((slot, index) => [slot, `#${themeColor(theme, index) ?? "000000"}`])
12724
- );
12725
- return {
12726
- ...slots,
12727
- bg1: slots.lt1,
12728
- tx1: slots.dk1,
12729
- bg2: slots.lt2,
12730
- tx2: slots.dk2
12731
- };
12732
- }
12733
- function autoSeriesColor(theme, index) {
12734
- const i = Math.max(0, Math.floor(index));
12735
- return chartPaletteSeriesColor(findChartColorPalette(10), i, i + 1, chartColorScheme(theme));
12901
+ function autoSeriesColor(theme, index) {
12902
+ const i = Math.max(0, Math.floor(index));
12903
+ return chartPaletteSeriesColor(findChartColorPalette(10), i, i + 1, chartColorScheme(theme));
12736
12904
  }
12737
12905
 
12738
12906
  // chart/text-inheritance.ts
@@ -12761,66 +12929,504 @@ function inheritChartText(part, entry, builtIn, root) {
12761
12929
  const value = root[key] ?? builtIn?.[key];
12762
12930
  if (value !== void 0) Object.assign(out, { [key]: value });
12763
12931
  }
12764
- if (part === "title" && root.fontSize !== void 0) out.fontSize = root.fontSize * 1.2;
12765
- if (root.textEffectsXml !== void 0) out.textEffectsXml = root.textEffectsXml;
12766
- return out;
12932
+ if (part === "title" && root.fontSize !== void 0) out.fontSize = root.fontSize * 1.2;
12933
+ if (root.textEffectsXml !== void 0) out.textEffectsXml = root.textEffectsXml;
12934
+ return out;
12935
+ }
12936
+
12937
+ // chart/render/chart-appearance.ts
12938
+ var chartPointsToPixels = (points) => points * EMU_PER_POINT / EMU_PER_PIXEL;
12939
+ function typeface(entry, theme) {
12940
+ const name = entry.typeface;
12941
+ if (name?.startsWith("+mj-")) return theme.majorFont;
12942
+ if (name?.startsWith("+mn-")) return theme.minorFont;
12943
+ return name ?? (entry.fontRef?.index === "major" ? theme.majorFont : entry.fontRef?.index === "minor" ? theme.minorFont : void 0);
12944
+ }
12945
+ function chartAppearance(chart, theme) {
12946
+ const defaults = builtInChartTextStyle(effectiveBuiltInChartStyle(chart.formatting));
12947
+ const entries = {};
12948
+ for (const part of CHART_STYLE_PARTS) {
12949
+ const base = chart.styleDefinition?.entries[part];
12950
+ const direct = chart.formatting?.entries[part];
12951
+ if (!defaults[part] && !base && !direct) continue;
12952
+ const entry = {
12953
+ ...inheritChartText(
12954
+ part,
12955
+ { ...defaults[part], ...base, sourceXml: base?.sourceXml ?? "" },
12956
+ defaults[part],
12957
+ chart.formatting?.textDefaults
12958
+ ),
12959
+ ...direct,
12960
+ sourceXml: direct?.sourceXml ?? base?.sourceXml ?? ""
12961
+ };
12962
+ if (base?.line || direct?.line) entry.line = { ...base?.line, ...direct?.line };
12963
+ entries[part] = entry;
12964
+ }
12965
+ const scheme = chartColorScheme(theme);
12966
+ const resolve = (color) => resolveDrawingColor(
12967
+ color,
12968
+ { scheme: (name) => scheme[name] },
12969
+ { hslRounding: "halfDown", transformOrder: "document" }
12970
+ );
12971
+ const out = resolveChartStyleDefinition(
12972
+ { entries},
12973
+ (color) => drawingColorCss(resolve(color))
12974
+ ) ?? {};
12975
+ for (const part of CHART_STYLE_PARTS) {
12976
+ const entry = entries[part];
12977
+ if (!entry) continue;
12978
+ const family = typeface(entry, theme);
12979
+ const shadow = resolveDrawingShadowXml(entry.textEffectsXml, {
12980
+ scheme: (name) => scheme[name]
12981
+ });
12982
+ if (shadow) (out[part] ??= {}).textShadow = shadow;
12983
+ if (family) (out[part] ??= {}).typeface = family;
12984
+ if (entry.axisVisible !== void 0) (out[part] ??= {}).axisVisible = entry.axisVisible;
12985
+ if (entry.labelsVisible !== void 0) (out[part] ??= {}).labelsVisible = entry.labelsVisible;
12986
+ if (entry.line?.widthEmu === 0) (out[part] ??= {}).lineWidth = 0;
12987
+ if (entry.fill?.kind === "gradient") {
12988
+ (out[part] ??= {}).gradient = resolveChartGradient(entry.fill, resolve);
12989
+ }
12990
+ }
12991
+ return out;
12992
+ }
12993
+
12994
+ // text/css-font-family.ts
12995
+ var FALLBACKS = {
12996
+ calibri: '"Calibri", "Carlito", "Segoe UI", Arial, sans-serif',
12997
+ "calibri light": '"Calibri Light", "Calibri", "Carlito", "Segoe UI", Arial, sans-serif',
12998
+ cambria: '"Cambria", "Caladea", Georgia, serif',
12999
+ arial: 'Arial, "Liberation Sans", Helvetica, sans-serif',
13000
+ "times new roman": '"Times New Roman", "Liberation Serif", Times, serif',
13001
+ "courier new": '"Courier New", "Liberation Mono", monospace',
13002
+ aptos: '"Aptos", "Calibri", "Carlito", "Segoe UI", sans-serif'
13003
+ };
13004
+ function cssFontFamily(name) {
13005
+ const known = FALLBACKS[name.toLowerCase()];
13006
+ if (known) return known;
13007
+ const quoted = `"${name.replace(/["\\]/g, "")}"`;
13008
+ return `${quoted}, "Calibri", "Carlito", "Segoe UI", sans-serif`;
13009
+ }
13010
+
13011
+ // chart/render/chart-svg-appearance.ts
13012
+ var nextPaintId = 0;
13013
+ function chartGradientPaint(model, width = 1024, height = 768) {
13014
+ const prefix2 = `xlsx-chart-${++nextPaintId}`;
13015
+ const appearance = { ...model.appearance };
13016
+ const defs = [];
13017
+ const shadowPaint = (shadow, suffix) => {
13018
+ const id = `${prefix2}-${suffix}`;
13019
+ const pad = Math.max(4, shadow.blur * 3 + Math.abs(shadow.dx) + Math.abs(shadow.dy));
13020
+ defs.push(
13021
+ `<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>`
13022
+ );
13023
+ return `url(#${id})`;
13024
+ };
13025
+ for (const [part, entry] of Object.entries(appearance)) {
13026
+ if (entry?.textShadow)
13027
+ appearance[part] = {
13028
+ ...entry,
13029
+ textShadowFilter: shadowPaint(entry.textShadow, `${part}-text-shadow`)
13030
+ };
13031
+ }
13032
+ const paint2 = (gradient, suffix, bounds) => {
13033
+ const def = buildChartGradientDef(`${prefix2}-${suffix}`, gradient, bounds);
13034
+ defs.push(chartGradientMarkup(def));
13035
+ return `url(#${def.id})`;
13036
+ };
13037
+ for (const part of ["chartArea", "plotArea"]) {
13038
+ const entry = appearance[part];
13039
+ if (!entry?.gradient) continue;
13040
+ if (part === "plotArea" && ["circle", "shape"].includes(entry.gradient.path ?? "")) continue;
13041
+ appearance[part] = {
13042
+ ...entry,
13043
+ fillColor: paint2(entry.gradient, part, { width, height, shape: "rect" })
13044
+ };
13045
+ }
13046
+ const series = model.series.map((source, index) => {
13047
+ const view = { ...source };
13048
+ if (source.shadow) view.shadowFilter = shadowPaint(source.shadow, `s${index}-shadow`);
13049
+ const bounds = model.type === "bar" || model.type === "column" ? { width: 1, height: 1, shape: "rect" } : void 0;
13050
+ if (source.gradient) view.color = paint2(source.gradient, `s${index}`, bounds);
13051
+ if (source.pointGradients) {
13052
+ view.pointColors = [...source.pointColors ?? []];
13053
+ for (const [key, gradient] of Object.entries(source.pointGradients))
13054
+ view.pointColors[Number(key)] = paint2(gradient, `s${index}-p${key}`, bounds);
13055
+ }
13056
+ return view;
13057
+ });
13058
+ return defs.length ? { model: { ...model, appearance, series }, defs: `<defs>${defs.join("")}</defs>` } : { model, defs: "" };
13059
+ }
13060
+ function chartTextAttributes(model, part, fallbackSize = FONT_SIZE) {
13061
+ const entry = model.appearance?.[part];
13062
+ return {
13063
+ size: entry?.fontSize === void 0 ? fallbackSize : chartPointsToPixels(entry.fontSize),
13064
+ ...entry?.color === void 0 ? {} : { fill: entry.color },
13065
+ ...entry?.bold === void 0 ? {} : { weight: entry.bold ? "bold" : "normal" },
13066
+ ...entry?.italic === void 0 ? {} : { italic: entry.italic },
13067
+ ...entry?.underline === void 0 ? {} : { underline: entry.underline },
13068
+ ...entry?.typeface === void 0 ? {} : { family: cssFontFamily(entry.typeface) },
13069
+ ...entry?.textShadowFilter === void 0 ? {} : { filter: entry.textShadowFilter }
13070
+ };
13071
+ }
13072
+ function chartStroke(model, part) {
13073
+ const entry = model.appearance?.[part];
13074
+ return {
13075
+ color: entry?.axisVisible === false ? "none" : entry?.lineColor ?? (part === "gridlineMajor" ? GRID_COLOR : AXIS_COLOR),
13076
+ width: entry?.lineWidth === void 0 ? 1 : chartPointsToPixels(entry.lineWidth)
13077
+ };
13078
+ }
13079
+ function chartAreaRect(model, part, area) {
13080
+ if (area.w <= 0 || area.h <= 0) return "";
13081
+ const entry = model.appearance?.[part];
13082
+ let fill = entry?.fillColor ?? (part === "chartArea" ? "#FFFFFF" : "none");
13083
+ let defs = "";
13084
+ if (part !== "chartArea" && entry?.gradient && (part !== "plotArea" || ["circle", "shape"].includes(entry.gradient.path ?? ""))) {
13085
+ const def = buildChartGradientDef(`xlsx-chart-${++nextPaintId}-${part}`, entry.gradient, {
13086
+ width: area.w,
13087
+ height: area.h,
13088
+ shape: "rect"
13089
+ });
13090
+ defs = `<defs>${chartGradientMarkup(def)}</defs>`;
13091
+ fill = `url(#${def.id})`;
13092
+ }
13093
+ const stroke = entry?.lineColor ?? "none";
13094
+ if (fill === "none" && stroke === "none") return "";
13095
+ const width = entry?.lineWidth === void 0 ? 1 : chartPointsToPixels(entry.lineWidth);
13096
+ 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}"/>`;
13097
+ }
13098
+
13099
+ // chart/render/chart-svg-labels.ts
13100
+ var GAP = 3;
13101
+ var LINE = 1.2;
13102
+ var NAMED_COLORS = /^(black|blue|cyan|green|magenta|red|white|yellow)$/iu;
13103
+ function measure(model, label) {
13104
+ const attrs = chartTextAttributes(model, "dataLabel", 10);
13105
+ const size = attrs.size ?? 10;
13106
+ const lines = label.text.split("\n");
13107
+ return {
13108
+ lines,
13109
+ size,
13110
+ w: Math.max(...lines.map((l) => textWidth(l, size))),
13111
+ h: lines.length * size * LINE,
13112
+ attrs
13113
+ };
13114
+ }
13115
+ function draw(m, label, x, y, anchor, out) {
13116
+ const fill = label.color && NAMED_COLORS.test(label.color) ? label.color.toLowerCase() : void 0;
13117
+ m.lines.forEach((line3, k) => {
13118
+ const lineY = y - m.h / 2 + (k + 0.5) * m.size * LINE + m.size * 0.35;
13119
+ out.push(text(x, lineY, line3, { ...m.attrs, ...fill ? { fill } : {}, anchor }));
13120
+ });
13121
+ }
13122
+ function barLabels(model, marks, out) {
13123
+ const stacked = model.grouping === "stacked" || model.grouping === "percentStacked";
13124
+ for (const mark of marks) {
13125
+ const label = mark.series.labels?.[mark.index];
13126
+ if (!label) continue;
13127
+ const m = measure(model, label);
13128
+ let position = label.position ?? (stacked ? "ctr" : "outEnd");
13129
+ if (stacked && position === "outEnd") position = "ctr";
13130
+ const cx = mark.x + mark.w / 2;
13131
+ const cy = mark.y + mark.h / 2;
13132
+ if (model.horizontal) {
13133
+ const end = mark.negative ? mark.x : mark.x + mark.w;
13134
+ const base = mark.negative ? mark.x + mark.w : mark.x;
13135
+ const dir2 = mark.negative ? -1 : 1;
13136
+ const side = (at, outward) => [
13137
+ at + (outward ? dir2 : -dir2) * GAP,
13138
+ (outward ? dir2 : -dir2) > 0 ? "start" : "end"
13139
+ ];
13140
+ const [x, anchor] = position === "ctr" ? [cx, "middle"] : position === "inEnd" ? side(end, false) : position === "inBase" ? side(base, true) : side(end, true);
13141
+ draw(m, label, x, cy, anchor, out);
13142
+ continue;
13143
+ }
13144
+ const top = mark.negative ? mark.y + mark.h : mark.y;
13145
+ const bottom = mark.negative ? mark.y : mark.y + mark.h;
13146
+ const dir = mark.negative ? 1 : -1;
13147
+ 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);
13148
+ draw(m, label, cx, y, "middle", out);
13149
+ }
13150
+ }
13151
+ function pointLabels(model, marks, out) {
13152
+ for (const mark of marks) {
13153
+ const label = mark.series.labels?.[mark.index];
13154
+ if (!label) continue;
13155
+ const m = measure(model, label);
13156
+ const reach = mark.radius + GAP;
13157
+ switch (model.type === "area" ? "ctr" : label.position ?? "r") {
13158
+ case "ctr":
13159
+ draw(m, label, mark.x, mark.y, "middle", out);
13160
+ break;
13161
+ case "t":
13162
+ draw(m, label, mark.x, mark.y - reach - m.h / 2, "middle", out);
13163
+ break;
13164
+ case "b":
13165
+ draw(m, label, mark.x, mark.y + reach + m.h / 2, "middle", out);
13166
+ break;
13167
+ case "l":
13168
+ draw(m, label, mark.x - reach, mark.y, "end", out);
13169
+ break;
13170
+ default:
13171
+ draw(m, label, mark.x + reach, mark.y, "start", out);
13172
+ }
13173
+ }
13174
+ }
13175
+ function sliceLabels(model, marks, out) {
13176
+ for (const mark of marks) {
13177
+ const label = mark.series.labels?.[mark.index];
13178
+ if (!label) continue;
13179
+ const m = measure(model, label);
13180
+ const mid = (mark.start + mark.end) / 2;
13181
+ const ux = Math.sin(mid);
13182
+ const uy = -Math.cos(mid);
13183
+ const place2 = (radius) => [
13184
+ mark.cx + radius * ux,
13185
+ mark.cy + radius * uy
13186
+ ];
13187
+ const position = model.type === "doughnut" ? "ctr" : label.position ?? "bestFit";
13188
+ let x;
13189
+ let y;
13190
+ if (position === "ctr") [x, y] = place2(mark.inner + (mark.outer - mark.inner) / 2);
13191
+ else if (position === "inEnd") {
13192
+ const extent = Math.abs(ux) * m.w / 2 + Math.abs(uy) * m.h / 2;
13193
+ [x, y] = place2(Math.max(0, mark.outer - GAP - extent));
13194
+ } else if (position === "outEnd") {
13195
+ const extent = Math.abs(ux) * m.w / 2 + Math.abs(uy) * m.h / 2;
13196
+ [x, y] = place2(mark.outer + GAP + extent);
13197
+ } else {
13198
+ const placed2 = placeBestFitLabel(
13199
+ {
13200
+ cx: mark.cx,
13201
+ cy: mark.cy,
13202
+ outerR: mark.outer,
13203
+ startAngle: mark.start - Math.PI / 2,
13204
+ endAngle: mark.end - Math.PI / 2
13205
+ },
13206
+ m.w,
13207
+ m.h
13208
+ );
13209
+ x = placed2.x;
13210
+ y = placed2.y;
13211
+ }
13212
+ draw(m, label, x, y, "middle", out);
13213
+ }
13214
+ }
13215
+ function hasOutsideLabels(model) {
13216
+ return model.series.some(
13217
+ (s) => s.labels?.some(
13218
+ (l) => l !== void 0 && ["bestFit", "outEnd"].includes(l.position ?? "bestFit")
13219
+ )
13220
+ );
13221
+ }
13222
+
13223
+ // chart/render/chart-svg-bars.ts
13224
+ function barLayout(model, frame2) {
13225
+ const count = Math.max(1, model.series.length);
13226
+ const geometry = clusteredBarGeometry(frame2.bandSize, count, chartBarSpacing(model));
13227
+ const barSize = geometry.singleBarWidth;
13228
+ const offset = (si) => model.horizontal ? geometry.clusterWidth / 2 - barSize - si * geometry.step : -geometry.clusterWidth / 2 + si * geometry.step;
13229
+ return { barSize, offset };
13230
+ }
13231
+ function bars(model, frame2, out, values) {
13232
+ const stacked = model.grouping === "stacked" || model.grouping === "percentStacked";
13233
+ const { barSize, offset: barOffset } = barLayout(model, frame2);
13234
+ const base = frame2.value(0);
13235
+ const pos = new Array(model.categories.length).fill(0);
13236
+ const neg = new Array(model.categories.length).fill(0);
13237
+ const marks = [];
13238
+ model.series.forEach((s, si) => {
13239
+ values[si]?.forEach((v, i) => {
13240
+ if (v === null || i >= model.categories.length) return;
13241
+ let from = 0;
13242
+ let to = v;
13243
+ if (stacked) {
13244
+ const acc = v >= 0 ? pos : neg;
13245
+ from = acc[i] ?? 0;
13246
+ to = from + v;
13247
+ acc[i] = to;
13248
+ }
13249
+ const a = stacked ? frame2.value(from) : base;
13250
+ const b = frame2.value(to);
13251
+ const offset = barOffset(si);
13252
+ const center = frame2.band(i);
13253
+ const width = model.horizontal ? Math.abs(b - a) : barSize;
13254
+ const height = model.horizontal ? barSize : Math.abs(b - a);
13255
+ let color = s.pointColors?.[i] ?? s.color;
13256
+ const gradient = s.pointGradients?.[i] ?? (s.pointColors?.[i] === void 0 ? s.gradient : void 0);
13257
+ if (gradient && (gradient.path === "circle" || gradient.path === "shape")) {
13258
+ const baseId = color.match(/^url\(#(.+)\)$/)?.[1];
13259
+ if (baseId) {
13260
+ const id = baseId.replace(/(-s\d+(?:-p\d+)?)$/, `-mark${i}$1`);
13261
+ const def = buildChartGradientDef(id, gradient, {
13262
+ width: Number(n(width)),
13263
+ height: Number(n(height)),
13264
+ shape: "rect"
13265
+ });
13266
+ out.push(`<defs>${chartGradientMarkup(def)}</defs>`);
13267
+ color = `url(#${id})`;
13268
+ }
13269
+ }
13270
+ out.push(`<g data-chart-series="${si}" data-chart-point="${i}">`);
13271
+ 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) };
13272
+ out.push(rect2(box.x, box.y, box.w, box.h, color, s.shadowFilter));
13273
+ out.push("</g>");
13274
+ marks.push({ series: s, index: i, ...box, negative: v < 0 });
13275
+ });
13276
+ });
13277
+ barLabels(model, marks, out);
13278
+ }
13279
+
13280
+ // chart/render/chart-svg-analysis.ts
13281
+ var DASHES = {
13282
+ dot: [1, 3],
13283
+ dash: [4, 3],
13284
+ lgDash: [8, 3],
13285
+ dashDot: [4, 3, 1, 3],
13286
+ lgDashDot: [8, 3, 1, 3],
13287
+ lgDashDotDot: [8, 3, 1, 3, 1, 3],
13288
+ sysDash: [3, 1],
13289
+ sysDot: [1, 1],
13290
+ sysDashDot: [3, 1, 1, 1],
13291
+ sysDashDotDot: [3, 1, 1, 1, 1, 1]
13292
+ };
13293
+ var CAP = 4;
13294
+ function strokeAttributes(stroke) {
13295
+ const pattern = stroke.dash ? DASHES[stroke.dash] : void 0;
13296
+ const dash = pattern ? ` stroke-dasharray="${pattern.map((step) => n(step * stroke.width)).join(" ")}"` : "";
13297
+ return `stroke="${esc(stroke.color)}" stroke-width="${n(stroke.width)}"${dash}`;
13298
+ }
13299
+ var segment = (x1, y1, x2, y2, stroke) => `<line x1="${n(x1)}" y1="${n(y1)}" x2="${n(x2)}" y2="${n(y2)}" ${stroke}/>`;
13300
+ function trendlines(series, si, xs, ys, plane, out) {
13301
+ for (const trendline of series.trendlines ?? []) {
13302
+ const fit2 = fitChartTrendline(trendline.fit, xs, ys);
13303
+ if (fit2.points.length < 2) continue;
13304
+ const points = fit2.points.map(({ x, y }) => plane(x, y).map(n).join(",")).join(" ");
13305
+ out.push(
13306
+ `<polyline points="${points}" fill="none" ${strokeAttributes(trendline.stroke)} data-chart-part="trendline" data-chart-series="${si}"/>`
13307
+ );
13308
+ }
13309
+ }
13310
+ function errorBar(bars2, at, values, plane, out) {
13311
+ const stroke = strokeAttributes(bars2.stroke);
13312
+ for (const side of ["plus", "minus"]) {
13313
+ if (bars2.barType !== side && bars2.barType !== "both") continue;
13314
+ const amount = chartErrorBarAmount(bars2.amount, values, at.displayIndex, at.sourceIndex, side);
13315
+ const sign = side === "plus" ? 1 : -1;
13316
+ const [x1, y1] = plane(at.x, at.y);
13317
+ const [x2, y2] = bars2.direction === "x" ? plane(at.x + sign * amount, at.y) : plane(at.x, at.y + sign * amount);
13318
+ out.push(segment(x1, y1, x2, y2, stroke));
13319
+ if (!bars2.endCap) continue;
13320
+ if (x1 === x2) out.push(segment(x2 - CAP, y2, x2 + CAP, y2, stroke));
13321
+ else out.push(segment(x2, y2 - CAP, x2, y2 + CAP, stroke));
13322
+ }
13323
+ }
13324
+ function plottedPoints(series, xOf) {
13325
+ return series.values.flatMap((y, index) => {
13326
+ const x = xOf(index);
13327
+ return y === null || x === null ? [] : [{ x, y, index }];
13328
+ });
13329
+ }
13330
+ function seriesAnalysis(series, si, xOf, plane, barPlane, categoryAxis, out) {
13331
+ const points = plottedPoints(series, xOf);
13332
+ const xs = points.map((p) => p.x);
13333
+ const ys = points.map((p) => p.y);
13334
+ trendlines(series, si, xs, ys, plane, out);
13335
+ for (const bars2 of series.errorBars ?? []) {
13336
+ if (categoryAxis && bars2.direction === "x") continue;
13337
+ const values = bars2.direction === "x" ? xs : ys;
13338
+ points.forEach(
13339
+ (p, displayIndex) => errorBar(bars2, { x: p.x, y: p.y, displayIndex, sourceIndex: p.index }, values, barPlane, out)
13340
+ );
13341
+ }
13342
+ }
13343
+ function categoryAnalysis(model, frame2, out) {
13344
+ if (model.grouping === "stacked" || model.grouping === "percentStacked") return;
13345
+ const plane = (x, y) => model.horizontal ? [frame2.value(y), frame2.band(x - 1)] : [frame2.band(x - 1), frame2.value(y)];
13346
+ const barred = model.type === "bar" || model.type === "column";
13347
+ const layout = barred ? barLayout(model, frame2) : void 0;
13348
+ model.series.forEach((series, si) => {
13349
+ if (!series.trendlines && !series.errorBars) return;
13350
+ const shift = layout ? layout.offset(si) + layout.barSize / 2 : 0;
13351
+ const barPlane = (x, y) => {
13352
+ const [px, py] = plane(x, y);
13353
+ return model.horizontal ? [px, py + shift] : [px + shift, py];
13354
+ };
13355
+ seriesAnalysis(series, si, (i) => i + 1, plane, barPlane, true, out);
13356
+ });
13357
+ }
13358
+ function scatterAnalysis(model, px, py, out) {
13359
+ const plane = (x, y) => [px(x), py(y)];
13360
+ model.series.forEach((series, si) => {
13361
+ if (!series.trendlines && !series.errorBars) return;
13362
+ seriesAnalysis(series, si, (i) => series.xValues?.[i] ?? null, plane, plane, false, out);
13363
+ });
12767
13364
  }
12768
13365
 
12769
- // chart/render/chart-appearance.ts
12770
- var chartPointsToPixels = (points) => points * EMU_PER_POINT / EMU_PER_PIXEL;
12771
- function typeface(entry, theme) {
12772
- const name = entry.typeface;
12773
- if (name?.startsWith("+mj-")) return theme.majorFont;
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);
13366
+ // chart/render/chart-scale.ts
13367
+ var clean = (n2) => Number(n2.toPrecision(12));
13368
+ function* units(raw) {
13369
+ let exp = Math.floor(Math.log10(raw)) - 1;
13370
+ for (; ; ) {
13371
+ const base = 10 ** exp;
13372
+ for (const m of [1, 2, 5]) yield clean(m * base);
13373
+ exp++;
13374
+ }
12776
13375
  }
12777
- function chartAppearance(chart, theme) {
12778
- const defaults = builtInChartTextStyle(effectiveBuiltInChartStyle(chart.formatting));
12779
- const entries = {};
12780
- for (const part of CHART_STYLE_PARTS) {
12781
- const base = chart.styleDefinition?.entries[part];
12782
- const direct = chart.formatting?.entries[part];
12783
- if (!defaults[part] && !base && !direct) continue;
12784
- const entry = {
12785
- ...inheritChartText(
12786
- part,
12787
- { ...defaults[part], ...base, sourceXml: base?.sourceXml ?? "" },
12788
- defaults[part],
12789
- chart.formatting?.textDefaults
12790
- ),
12791
- ...direct,
12792
- sourceXml: direct?.sourceXml ?? base?.sourceXml ?? ""
12793
- };
12794
- if (base?.line || direct?.line) entry.line = { ...base?.line, ...direct?.line };
12795
- entries[part] = entry;
13376
+ function niceScale(dataMin, dataMax, options = {}) {
13377
+ const maxIntervals = Math.max(1, options.maxIntervals ?? 10);
13378
+ let lo = Number.isFinite(dataMin) ? dataMin : 0;
13379
+ let hi = Number.isFinite(dataMax) ? dataMax : 0;
13380
+ if (lo > hi) [lo, hi] = [hi, lo];
13381
+ if (lo === hi) {
13382
+ if (lo === 0) hi = 1;
13383
+ else if (options.noZero) {
13384
+ const pad = Math.abs(lo) * 0.1 || 1;
13385
+ lo -= pad;
13386
+ hi += pad;
13387
+ } else if (lo > 0) lo = 0;
13388
+ else hi = 0;
12796
13389
  }
12797
- const scheme = chartColorScheme(theme);
12798
- const resolve = (color) => resolveDrawingColor(
12799
- color,
12800
- { scheme: (name) => scheme[name] },
12801
- { hslRounding: "halfDown", transformOrder: "document" }
12802
- );
12803
- const out = resolveChartStyleDefinition(
12804
- { entries},
12805
- (color) => drawingColorCss(resolve(color))
12806
- ) ?? {};
12807
- for (const part of CHART_STYLE_PARTS) {
12808
- const entry = entries[part];
12809
- if (!entry) continue;
12810
- const family = typeface(entry, theme);
12811
- const shadow = resolveDrawingShadowXml(entry.textEffectsXml, {
12812
- scheme: (name) => scheme[name]
12813
- });
12814
- if (shadow) (out[part] ??= {}).textShadow = shadow;
12815
- if (family) (out[part] ??= {}).typeface = family;
12816
- if (entry.axisVisible !== void 0) (out[part] ??= {}).axisVisible = entry.axisVisible;
12817
- if (entry.labelsVisible !== void 0) (out[part] ??= {}).labelsVisible = entry.labelsVisible;
12818
- if (entry.line?.widthEmu === 0) (out[part] ??= {}).lineWidth = 0;
12819
- if (entry.fill?.kind === "gradient") {
12820
- (out[part] ??= {}).gradient = resolveChartGradient(entry.fill, resolve);
13390
+ let fixedLo = false;
13391
+ let fixedHi = false;
13392
+ if (!options.noZero) {
13393
+ if (lo >= 0 && hi - lo >= hi / 6) {
13394
+ lo = 0;
13395
+ fixedLo = true;
13396
+ } else if (hi <= 0 && hi - lo >= -lo / 6) {
13397
+ hi = 0;
13398
+ fixedHi = true;
12821
13399
  }
12822
13400
  }
12823
- return out;
13401
+ const range = hi - lo;
13402
+ const top = fixedHi ? hi : hi + range * 0.05;
13403
+ const bottom = fixedLo ? lo : lo - range * 0.05;
13404
+ for (const unit of units(range / maxIntervals)) {
13405
+ const min = fixedLo ? lo : Math.floor(clean(bottom / unit)) * unit;
13406
+ const max = fixedHi ? hi : Math.ceil(clean(top / unit)) * unit;
13407
+ const intervals = Math.round((max - min) / unit);
13408
+ if (intervals <= maxIntervals && intervals > 0) {
13409
+ const ticks = [];
13410
+ for (let i = 0; i <= intervals; i++) ticks.push(clean(min + i * unit));
13411
+ return { min: clean(min), max: clean(max), majorUnit: unit, ticks };
13412
+ }
13413
+ }
13414
+ return { min: lo, max: hi, majorUnit: range, ticks: [lo, hi] };
13415
+ }
13416
+ var PERCENT_SCALE = {
13417
+ min: 0,
13418
+ max: 1,
13419
+ majorUnit: 0.1,
13420
+ ticks: [0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1]
13421
+ };
13422
+ function formatAxisValue(value, percent = false) {
13423
+ if (percent) return `${clean(value * 100)}%`;
13424
+ const v = clean(value);
13425
+ if (Math.abs(v) >= 1e15 || v !== 0 && Math.abs(v) < 1e-6)
13426
+ return v.toExponential(2).replace("e+", "E+").replace("e-", "E-");
13427
+ const [int = "0", frac] = String(Math.abs(v)).split(".");
13428
+ const grouped = int.replace(/\B(?=(\d{3})+(?!\d))/g, ",");
13429
+ return `${v < 0 ? "-" : ""}${grouped}${frac ? `.${frac}` : ""}`;
12824
13430
  }
12825
13431
 
12826
13432
  // chart/render/chart-view-analysis.ts
@@ -13079,12 +13685,70 @@ function chartTitleText(chart, theme) {
13079
13685
  };
13080
13686
  }
13081
13687
 
13688
+ // chart/render/chart-view-labels.ts
13689
+ function labelsOf(source, view, categories, numberFormat) {
13690
+ const { chart, series, points } = source;
13691
+ if ((series?.deleted ?? chart?.deleted) === true) return void 0;
13692
+ const percentBase = view.values.reduce(
13693
+ (sum, v) => sum + (v === null ? 0 : Math.abs(v)),
13694
+ 0
13695
+ );
13696
+ const out = [];
13697
+ let any = false;
13698
+ view.values.forEach((value, i) => {
13699
+ const point = points?.[i];
13700
+ if (value === null || point?.deleted === true) return;
13701
+ const position = point?.position ?? series?.position ?? chart?.position;
13702
+ const x = view.xValues?.[i];
13703
+ const category = x === void 0 || x === null ? categories[i] : formatAxisValue(x);
13704
+ let built;
13705
+ if (point?.text !== void 0) built = { text: point.text };
13706
+ else {
13707
+ const flags = resolveDataLabelFlags({
13708
+ ...point ? { point } : {},
13709
+ ...series ? { series } : {},
13710
+ ...chart ? { chart } : {}
13711
+ });
13712
+ built = composeDataLabelText({
13713
+ flags,
13714
+ seriesName: view.name,
13715
+ category,
13716
+ value,
13717
+ numberFormat: point?.numberFormat ?? series?.numberFormat ?? chart?.numberFormat ?? numberFormat,
13718
+ percentBase,
13719
+ bubbleSize: view.sizes?.[i] ?? void 0,
13720
+ formatValue: (v) => formatAxisValue(v),
13721
+ formatBubbleSize: (size) => formatAxisValue(size)
13722
+ });
13723
+ }
13724
+ if (!built) return;
13725
+ any = true;
13726
+ out[i] = {
13727
+ text: built.text,
13728
+ ...position ? { position } : {},
13729
+ ...built.color ? { color: built.color } : {}
13730
+ };
13731
+ });
13732
+ return any ? out : void 0;
13733
+ }
13734
+ function applyDataLabels(model, sources, extra) {
13735
+ const apply = (source, view) => {
13736
+ if (!source?.dataLabels) return;
13737
+ const labels = labelsOf(source.dataLabels, view, model.categories, source.numberFormat);
13738
+ if (labels) view.labels = labels;
13739
+ };
13740
+ model.series.forEach((view, i) => apply(sources[i], view));
13741
+ model.extraGroups?.forEach(
13742
+ (group2, g) => group2.series.forEach((view, i) => apply(extra[g]?.series[i], view))
13743
+ );
13744
+ }
13745
+
13082
13746
  // chart/render/chart-view-ex.ts
13083
13747
  function groupsAxis(groups, categories) {
13084
13748
  let min = Infinity;
13085
13749
  let max = -Infinity;
13086
- for (const group of groups) {
13087
- const extent = valueExtent(group.type, group.grouping, group.series, categories);
13750
+ for (const group2 of groups) {
13751
+ const extent = valueExtent(group2.type, group2.grouping, group2.series, categories);
13088
13752
  min = Math.min(min, extent.min);
13089
13753
  max = Math.max(max, extent.max);
13090
13754
  }
@@ -13093,17 +13757,17 @@ function groupsAxis(groups, categories) {
13093
13757
  function chartExtraView(chart, model, ctx, total, categoriesOf) {
13094
13758
  let index = chart.series.length;
13095
13759
  const groups = [];
13096
- for (const group of chart.extraGroups ?? []) {
13097
- const series = group.series.map((s) => seriesView(ctx, s, index++, total, categoriesOf));
13760
+ for (const group2 of chart.extraGroups ?? []) {
13761
+ const series = group2.series.map((s) => seriesView(ctx, s, index++, total, categoriesOf));
13098
13762
  const view = {
13099
- type: group.chartType,
13100
- grouping: group.grouping ?? (group.chartType === "column" ? "clustered" : "standard"),
13763
+ type: group2.chartType,
13764
+ grouping: group2.grouping ?? (group2.chartType === "column" ? "clustered" : "standard"),
13101
13765
  series,
13102
- secondary: group.secondary
13766
+ secondary: group2.secondary
13103
13767
  };
13104
- if (group.chartType === "stock") view.stock = stockView(group.stock, ctx);
13105
- if (group.barGapWidth !== void 0) view.barGapWidth = group.barGapWidth;
13106
- if (group.barOverlap !== void 0) view.barOverlap = group.barOverlap;
13768
+ if (group2.chartType === "stock") view.stock = stockView(group2.stock, ctx);
13769
+ if (group2.barGapWidth !== void 0) view.barGapWidth = group2.barGapWidth;
13770
+ if (group2.barOverlap !== void 0) view.barOverlap = group2.barOverlap;
13107
13771
  groups.push(view);
13108
13772
  }
13109
13773
  if (!groups.length) return;
@@ -13120,8 +13784,8 @@ function chartExtraAxes(model) {
13120
13784
  const own2 = valueExtent(model.type, model.grouping, model.series, count);
13121
13785
  let min = own2.min;
13122
13786
  let max = own2.max;
13123
- for (const group of shared) {
13124
- const extent = valueExtent(group.type, group.grouping, group.series, count);
13787
+ for (const group2 of shared) {
13788
+ const extent = valueExtent(group2.type, group2.grouping, group2.series, count);
13125
13789
  min = Math.min(min, extent.min);
13126
13790
  max = Math.max(max, extent.max);
13127
13791
  }
@@ -13264,115 +13928,11 @@ function chartSummaryView(chart, theme, options = {}) {
13264
13928
  chartExtraView(chart, model, ctx, total, collect);
13265
13929
  if (type === "waterfall") waterfallView(chart, model, ctx);
13266
13930
  else if (!byPoint) model.valueAxis = valueAxis(model);
13931
+ applyDataLabels(model, chart.series, extra);
13267
13932
  chartExtraAxes(model);
13268
13933
  return model;
13269
13934
  }
13270
13935
 
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
13936
  // chart/render/chart-svg-cartesian.ts
13377
13937
  function cartesianAxes(model, area, out) {
13378
13938
  const scale = model.valueAxis;
@@ -13491,6 +14051,7 @@ function linesAndAreas(model, frame2, out) {
13491
14051
  const stacked = model.grouping === "stacked" || model.grouping === "percentStacked";
13492
14052
  const acc = new Array(model.categories.length).fill(0);
13493
14053
  const area = model.type === "area";
14054
+ const marks = [];
13494
14055
  const layers = [];
13495
14056
  model.series.forEach((s, si) => {
13496
14057
  const points = [];
@@ -13505,6 +14066,13 @@ function linesAndAreas(model, frame2, out) {
13505
14066
  const top = below2 + (v ?? 0);
13506
14067
  if (stacked) acc[i] = top;
13507
14068
  points.push([frame2.band(i), frame2.value(top)]);
14069
+ marks.push({
14070
+ series: s,
14071
+ index: i,
14072
+ x: frame2.band(i),
14073
+ y: frame2.value(top),
14074
+ radius: area ? 0 : 3
14075
+ });
13508
14076
  lower.push([frame2.band(i), frame2.value(below2)]);
13509
14077
  });
13510
14078
  layers.push({
@@ -13537,6 +14105,7 @@ function linesAndAreas(model, frame2, out) {
13537
14105
  if (!Number.isNaN(x))
13538
14106
  out.push(`<circle cx="${n(x)}" cy="${n(y)}" r="2.5" fill="${color}"${filter}/>`);
13539
14107
  }
14108
+ pointLabels(model, marks, out);
13540
14109
  }
13541
14110
 
13542
14111
  // chart/render/chart-svg-xy.ts
@@ -13606,6 +14175,7 @@ function scatter(model, area, out) {
13606
14175
  line2(plot.x, plot.y + plot.h, plot.x + plot.w, plot.y + plot.h, xAxis.color, xAxis.width)
13607
14176
  );
13608
14177
  out.push(line2(plot.x, plot.y, plot.x, plot.y + plot.h, yAxis.color, yAxis.width));
14178
+ const marks = [];
13609
14179
  for (const [si, s] of model.series.entries())
13610
14180
  s.values.forEach((v, i) => {
13611
14181
  const x = s.xValues?.[i] ?? null;
@@ -13614,14 +14184,17 @@ function scatter(model, area, out) {
13614
14184
  const fill = s.pointColors?.[i] ?? s.color;
13615
14185
  if (!bubble) {
13616
14186
  out.push(`<circle cx="${n(px(x))}" cy="${n(py(v))}" r="3" fill="${fill}"${filter}/>`);
14187
+ marks.push({ series: s, index: i, x: px(x), y: py(v), radius: 3 });
13617
14188
  return;
13618
14189
  }
13619
14190
  const r = radiusOf(s.sizes?.[i] ?? void 0);
13620
14191
  if (r === void 0) return;
14192
+ marks.push({ series: s, index: i, x: px(x), y: py(v), radius: r });
13621
14193
  out.push(
13622
14194
  `<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
14195
  );
13624
14196
  });
14197
+ pointLabels(model, marks, out);
13625
14198
  scatterAnalysis(model, px, py, out);
13626
14199
  }
13627
14200
 
@@ -13738,21 +14311,21 @@ function cartesianSvg(model, area) {
13738
14311
  return out.join("");
13739
14312
  }
13740
14313
  const layers = [{ model, frame: frame2 }];
13741
- for (const group of model.extraGroups ?? []) {
14314
+ for (const group2 of model.extraGroups ?? []) {
13742
14315
  const grouped = {
13743
14316
  ...model,
13744
- type: group.type,
13745
- grouping: group.grouping,
13746
- series: group.series,
14317
+ type: group2.type,
14318
+ grouping: group2.grouping,
14319
+ series: group2.series,
13747
14320
  horizontal: false
13748
14321
  };
13749
- if (group.stock) grouped.stock = group.stock;
14322
+ if (group2.stock) grouped.stock = group2.stock;
13750
14323
  else delete grouped.stock;
13751
- if (group.barGapWidth !== void 0) grouped.barGapWidth = group.barGapWidth;
14324
+ if (group2.barGapWidth !== void 0) grouped.barGapWidth = group2.barGapWidth;
13752
14325
  else delete grouped.barGapWidth;
13753
- if (group.barOverlap !== void 0) grouped.barOverlap = group.barOverlap;
14326
+ if (group2.barOverlap !== void 0) grouped.barOverlap = group2.barOverlap;
13754
14327
  else delete grouped.barOverlap;
13755
- const value = group.secondary && frame2.secondary ? frame2.secondary : frame2.value;
14328
+ const value = group2.secondary && frame2.secondary ? frame2.secondary : frame2.value;
13756
14329
  layers.push({ model: grouped, frame: { ...frame2, value } });
13757
14330
  }
13758
14331
  layers.map((layer, order) => ({ layer, order })).sort(
@@ -13786,7 +14359,9 @@ function pieSvg(model, area) {
13786
14359
  const out = [chartAreaRect(model, "plotArea", area)];
13787
14360
  const cx = area.x + area.w / 2;
13788
14361
  const cy = area.y + area.h / 2;
13789
- const radius = Math.max(1, Math.min(area.w, area.h) / 2 - 4);
14362
+ const margin = hasOutsideLabels(model) ? Math.min(area.w, area.h) * 0.12 : 0;
14363
+ const radius = Math.max(1, Math.min(area.w, area.h) / 2 - 4 - margin);
14364
+ const slices = [];
13790
14365
  const rings = model.type === "doughnut" ? model.series : model.series.slice(0, 1);
13791
14366
  const hole = model.type === "doughnut" ? radius * 0.5 : 0;
13792
14367
  const ringSize = (radius - hole) / Math.max(1, rings.length);
@@ -13803,9 +14378,20 @@ function pieSvg(model, area) {
13803
14378
  out.push(
13804
14379
  `<path d="${slicePath(cx, cy, outer, inner, angle, angle + sweep)}" fill="${color}" stroke="#FFFFFF" stroke-width="1"${s.shadowFilter ? ` filter="${s.shadowFilter}"` : ""}/>`
13805
14380
  );
14381
+ slices.push({
14382
+ series: s,
14383
+ index: i,
14384
+ cx,
14385
+ cy,
14386
+ outer,
14387
+ inner,
14388
+ start: angle,
14389
+ end: angle + sweep
14390
+ });
13806
14391
  angle += sweep;
13807
14392
  });
13808
14393
  });
14394
+ sliceLabels(model, slices, out);
13809
14395
  return out.join("");
13810
14396
  }
13811
14397
  function radarSvg(model, area) {
@@ -13851,12 +14437,16 @@ function radarSvg(model, area) {
13851
14437
  })
13852
14438
  );
13853
14439
  });
14440
+ const marks = [];
13854
14441
  for (const s of model.series) {
13855
- const points = s.values.slice(0, count).map((v, i) => polar(cx, cy, r(v ?? scale.min), angle(i))).map(([x, y]) => `${n(x)},${n(y)}`).join(" ");
14442
+ const vertices = s.values.slice(0, count).map((v, i) => polar(cx, cy, r(v ?? scale.min), angle(i)));
14443
+ vertices.forEach(([x, y], i) => marks.push({ series: s, index: i, x, y, radius: 3 }));
14444
+ const points = vertices.map(([x, y]) => `${n(x)},${n(y)}`).join(" ");
13856
14445
  out.push(
13857
14446
  `<polygon points="${points}" fill="none" stroke="${s.color}" stroke-width="2"${s.shadowFilter ? ` filter="${s.shadowFilter}"` : ""}/>`
13858
14447
  );
13859
14448
  }
14449
+ pointLabels(model, marks, out);
13860
14450
  return out.join("");
13861
14451
  }
13862
14452
 
@@ -14108,17 +14698,17 @@ function automaticLegend(model, area, out, options, bounds) {
14108
14698
 
14109
14699
  // text/wrap-styled-runs.ts
14110
14700
  var graphemes = new Intl.Segmenter(void 0, { granularity: "grapheme" });
14111
- function wrapStyledRuns(runs, maxWidth, measure, options = {}) {
14701
+ function wrapStyledRuns(runs, maxWidth, measure2, options = {}) {
14112
14702
  const groups = [];
14113
14703
  for (const [source, run] of runs.entries()) {
14114
14704
  for (const token of run.text.split(/(\r\n|[\r\n]|[ \t]+)/u).filter(Boolean)) {
14115
14705
  const kind = /^[\r\n]+$/u.test(token) ? "break" : /^[ \t]+$/u.test(token) ? "space" : "word";
14116
- let group = groups.at(-1);
14117
- if (!group || group.kind !== kind || kind === "break") {
14118
- group = { kind, pieces: [] };
14119
- groups.push(group);
14706
+ let group2 = groups.at(-1);
14707
+ if (!group2 || group2.kind !== kind || kind === "break") {
14708
+ group2 = { kind, pieces: [] };
14709
+ groups.push(group2);
14120
14710
  }
14121
- if (kind !== "break") group.pieces.push({ run, source, text: token });
14711
+ if (kind !== "break") group2.pieces.push({ run, source, text: token });
14122
14712
  }
14123
14713
  }
14124
14714
  const merged = (left, right) => {
@@ -14131,7 +14721,7 @@ function wrapStyledRuns(runs, maxWidth, measure, options = {}) {
14131
14721
  return result2;
14132
14722
  };
14133
14723
  const width = (pieces) => pieces.reduce((sum, piece) => {
14134
- const advance = measure(piece.text, piece.run);
14724
+ const advance = measure2(piece.text, piece.run);
14135
14725
  return sum + (Number.isFinite(advance) && advance >= 0 ? advance : 0);
14136
14726
  }, 0);
14137
14727
  const result = [];
@@ -14142,29 +14732,29 @@ function wrapStyledRuns(runs, maxWidth, measure, options = {}) {
14142
14732
  line3 = [];
14143
14733
  spaces = [];
14144
14734
  };
14145
- for (const group of groups) {
14146
- if (group.kind === "break") {
14735
+ for (const group2 of groups) {
14736
+ if (group2.kind === "break") {
14147
14737
  flush();
14148
14738
  continue;
14149
14739
  }
14150
- if (group.kind === "space") {
14151
- spaces = group.pieces;
14740
+ if (group2.kind === "space") {
14741
+ spaces = group2.pieces;
14152
14742
  continue;
14153
14743
  }
14154
14744
  const separator = line3.length ? spaces : [];
14155
- const wordWidth = width(group.pieces);
14156
- if (line3.length && width(merged(line3, [...separator, ...group.pieces])) > maxWidth) flush();
14745
+ const wordWidth = width(group2.pieces);
14746
+ if (line3.length && width(merged(line3, [...separator, ...group2.pieces])) > maxWidth) flush();
14157
14747
  else line3 = merged(line3, separator);
14158
14748
  spaces = [];
14159
14749
  if (options.breakWords && wordWidth > maxWidth) {
14160
- for (const piece of group.pieces) {
14750
+ for (const piece of group2.pieces) {
14161
14751
  for (const { segment: segment2 } of graphemes.segment(piece.text)) {
14162
14752
  const next = { ...piece, text: segment2 };
14163
14753
  if (line3.length && width(merged(line3, [next])) > maxWidth) flush();
14164
14754
  line3 = merged(line3, [next]);
14165
14755
  }
14166
14756
  }
14167
- } else line3 = merged(line3, group.pieces);
14757
+ } else line3 = merged(line3, group2.pieces);
14168
14758
  }
14169
14759
  flush();
14170
14760
  return result;
@@ -14521,11 +15111,11 @@ function parseDirectParagraphProperties(props) {
14521
15111
 
14522
15112
  // docx/numbering-parse.ts
14523
15113
  var own = (map, key) => Object.prototype.hasOwnProperty.call(map, key) ? map[key] : void 0;
14524
- function resolveNumberingLevel(catalog, numId, level) {
15114
+ function resolveNumberingLevel(catalog, numId, level2) {
14525
15115
  const num = own(catalog.nums, numId);
14526
15116
  if (!num) return void 0;
14527
- const override = num.levelOverrides?.[level];
14528
- const sourceAbstract = own(catalog.abstractNums, num.abstractNumId)?.levels[level];
15117
+ const override = num.levelOverrides?.[level2];
15118
+ const sourceAbstract = own(catalog.abstractNums, num.abstractNumId)?.levels[level2];
14529
15119
  const abstract = sourceAbstract?.startWasOmitted && sourceAbstract.start === 1 ? { ...sourceAbstract, start: 0 } : sourceAbstract;
14530
15120
  let base = override?.lvl ?? abstract;
14531
15121
  if (!base) return void 0;
@@ -14924,10 +15514,10 @@ function resolveParagraphNumbering(paragraph, styleCatalog, numberingCatalog) {
14924
15514
  const inherited = resolveStyleNumbering(paragraph.style, styleCatalog);
14925
15515
  if (!inherited || inherited.numId <= 0) return void 0;
14926
15516
  if (numberingCatalog && paragraph.style && styleCatalog.styles[paragraph.style]) {
14927
- for (let level = 0; level < 9; level++) {
14928
- const definition = resolveNumberingLevel(numberingCatalog, String(inherited.numId), level);
15517
+ for (let level2 = 0; level2 < 9; level2++) {
15518
+ const definition = resolveNumberingLevel(numberingCatalog, String(inherited.numId), level2);
14929
15519
  if (definition?.paragraphStyleId === paragraph.style)
14930
- return { numId: inherited.numId, level };
15520
+ return { numId: inherited.numId, level: level2 };
14931
15521
  }
14932
15522
  }
14933
15523
  return inherited;
@@ -14960,23 +15550,23 @@ var NumberingCounters = class {
14960
15550
  return started;
14961
15551
  }
14962
15552
  /** Advances one level and resets deeper counters according to their resolved restart rules. */
14963
- advance(numId, level, def, catalog) {
15553
+ advance(numId, level2, def, catalog) {
14964
15554
  const counts = this.forNum(numId);
14965
15555
  const started = this.startedLevels(numId);
14966
- const next = started.has(level) ? (counts.get(level) ?? def.start) + 1 : def.start;
14967
- counts.set(level, next);
14968
- started.add(level);
15556
+ const next = started.has(level2) ? (counts.get(level2) ?? def.start) + 1 : def.start;
15557
+ counts.set(level2, next);
15558
+ started.add(level2);
14969
15559
  for (const deeper of [...started]) {
14970
- if (deeper <= level) continue;
15560
+ if (deeper <= level2) continue;
14971
15561
  const deeperDef = resolveNumberingLevel(catalog, numId, deeper);
14972
15562
  const restart = deeperDef?.lvlRestart;
14973
15563
  if (restart === 0) continue;
14974
15564
  const trigger = restart !== void 0 && restart > 0 && restart <= deeper ? restart - 1 : deeper - 1;
14975
- if (level > trigger) continue;
15565
+ if (level2 > trigger) continue;
14976
15566
  counts.delete(deeper);
14977
15567
  started.delete(deeper);
14978
15568
  }
14979
- for (let ancestor = 0; ancestor < level; ancestor++) {
15569
+ for (let ancestor = 0; ancestor < level2; ancestor++) {
14980
15570
  if (started.has(ancestor)) continue;
14981
15571
  const ancestorDef = resolveNumberingLevel(catalog, numId, ancestor);
14982
15572
  if (!ancestorDef) continue;
@@ -14986,14 +15576,14 @@ var NumberingCounters = class {
14986
15576
  return next;
14987
15577
  }
14988
15578
  /** Current value for an ancestor placeholder, defaulting to its own start when never instantiated. */
14989
- current(numId, level, start) {
14990
- return this.forNum(numId).get(level) ?? start;
15579
+ current(numId, level2, start) {
15580
+ return this.forNum(numId).get(level2) ?? start;
14991
15581
  }
14992
15582
  };
14993
- function substituteLvlText(lvlText, numId, level, catalog, counters, forceDecimal) {
15583
+ function substituteLvlText(lvlText, numId, level2, catalog, counters, forceDecimal) {
14994
15584
  return lvlText.replace(/%([1-9])/g, (match, digit) => {
14995
15585
  const ancestorLevel = Number(digit) - 1;
14996
- if (ancestorLevel > level) return match;
15586
+ if (ancestorLevel > level2) return match;
14997
15587
  const ancestorDef = resolveNumberingLevel(catalog, numId, ancestorLevel);
14998
15588
  const start = ancestorDef?.start ?? 1;
14999
15589
  const value = counters.current(numId, ancestorLevel, start);
@@ -15010,15 +15600,15 @@ function computeListLabels(model) {
15010
15600
  const numbering = resolveParagraphNumbering(paragraph, model.paragraphStyles, catalog);
15011
15601
  if (!numbering) continue;
15012
15602
  const numId = String(numbering.numId);
15013
- const level = Math.min(8, Math.max(0, numbering.level));
15014
- const def = resolveNumberingLevel(catalog, numId, level);
15603
+ const level2 = Math.min(8, Math.max(0, numbering.level));
15604
+ const def = resolveNumberingLevel(catalog, numId, level2);
15015
15605
  if (!def) continue;
15016
15606
  if (def.numFmt === "none") continue;
15017
- counters.advance(numId, level, def, catalog);
15018
- const text2 = def.numFmt === "bullet" ? def.lvlText : substituteLvlText(def.lvlText, numId, level, catalog, counters, Boolean(def.isLgl));
15607
+ counters.advance(numId, level2, def, catalog);
15608
+ const text2 = def.numFmt === "bullet" ? def.lvlText : substituteLvlText(def.lvlText, numId, level2, catalog, counters, Boolean(def.isLgl));
15019
15609
  labels.set(paragraph.id, {
15020
15610
  numId,
15021
- level,
15611
+ level: level2,
15022
15612
  text: text2,
15023
15613
  suffix: def.suffix ?? "tab",
15024
15614
  ...definedProps({
@@ -15481,12 +16071,12 @@ function headerFooterSlotForPage(model, page, pageNumber) {
15481
16071
  return page.pageInSection === 0 && section?.titlePage ? "first" : model.evenAndOddHeaders && pageNumber % 2 === 0 ? "even" : "default";
15482
16072
  }
15483
16073
  function headerFooterForPage(model, page, pageNumber, kind) {
15484
- const sections = model.sections ?? [];
15485
- const section = sections[page.sectionIndex];
16074
+ const sections2 = model.sections ?? [];
16075
+ const section = sections2[page.sectionIndex];
15486
16076
  if (!section) return void 0;
15487
16077
  const slot = headerFooterSlotForPage(model, page, pageNumber);
15488
16078
  for (let index = page.sectionIndex; index >= 0; index--) {
15489
- const content = sections[index]?.[kind]?.[slot];
16079
+ const content = sections2[index]?.[kind]?.[slot];
15490
16080
  if (content) return content;
15491
16081
  }
15492
16082
  return void 0;
@@ -17223,11 +17813,11 @@ function completedNoteStoryMinimum(row2, stories, pendingBlocks, available) {
17223
17813
  for (const [index, cell] of row2.cells.entries()) {
17224
17814
  const groups = /* @__PURE__ */ new Map();
17225
17815
  for (const box of cell) {
17226
- const group = stories.get(box.blockId);
17227
- if (group !== void 0) {
17228
- const boxes = groups.get(group) ?? [];
17816
+ const group2 = stories.get(box.blockId);
17817
+ if (group2 !== void 0) {
17818
+ const boxes = groups.get(group2) ?? [];
17229
17819
  boxes.push(box);
17230
- groups.set(group, boxes);
17820
+ groups.set(group2, boxes);
17231
17821
  }
17232
17822
  }
17233
17823
  for (const boxes of groups.values()) {
@@ -17293,8 +17883,8 @@ var TableFootnotes = class {
17293
17883
  for (const cell of row2.cells) {
17294
17884
  for (const paragraph of cellParagraphs(cell))
17295
17885
  if (paragraph.footnotes?.length) this.paragraphs.set(paragraph.id, paragraph);
17296
- for (const [id, group] of (measured ? independentNoteStories(cell) : void 0) ?? []) {
17297
- this.stories.set(id, group);
17886
+ for (const [id, group2] of (measured ? independentNoteStories(cell) : void 0) ?? []) {
17887
+ this.stories.set(id, group2);
17298
17888
  }
17299
17889
  }
17300
17890
  }
@@ -17427,11 +18017,11 @@ var TableFootnotes = class {
17427
18017
  for (const [index, cell] of row2.cells.entries()) {
17428
18018
  const groups = /* @__PURE__ */ new Map();
17429
18019
  for (const box of cell) {
17430
- const group = this.stories.get(box.blockId);
17431
- if (group !== void 0) {
17432
- const boxes = groups.get(group) ?? [];
18020
+ const group2 = this.stories.get(box.blockId);
18021
+ if (group2 !== void 0) {
18022
+ const boxes = groups.get(group2) ?? [];
17433
18023
  boxes.push(box);
17434
- groups.set(group, boxes);
18024
+ groups.set(group2, boxes);
17435
18025
  }
17436
18026
  }
17437
18027
  for (const boxes of groups.values()) {
@@ -19955,14 +20545,14 @@ function adaptDocumentModel(model, note = () => {
19955
20545
  note2.blocks.filter((block) => block.type === "paragraph").map((paragraph) => adaptParagraph(paragraph))
19956
20546
  ])
19957
20547
  ) : void 0;
19958
- const sections = model.sections;
20548
+ const sections2 = model.sections;
19959
20549
  const modernFootnoteSeparator = model.compatibilityMode === 15;
19960
20550
  const legacyFootnoteColumns = model.compatibilityMode === 12 || model.compatibilityMode === 14;
19961
20551
  if (!modernFootnoteSeparator && !legacyFootnoteColumns && model.sections?.some((section) => section.footnoteColumns !== void 0))
19962
20552
  reportOnce(
19963
20553
  "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
20554
  );
19965
- if (!sections || !sections.length) {
20555
+ if (!sections2 || !sections2.length) {
19966
20556
  return {
19967
20557
  sections: [
19968
20558
  {
@@ -19984,8 +20574,8 @@ function adaptDocumentModel(model, note = () => {
19984
20574
  }
19985
20575
  const indexById = new Map(model.blocks.map((block, index) => [block.id, index]));
19986
20576
  let start = 0;
19987
- const result = sections.map((section, index) => {
19988
- const last = index === sections.length - 1;
20577
+ const result = sections2.map((section, index) => {
20578
+ const last = index === sections2.length - 1;
19989
20579
  const endIndex = last ? blocks.length : (indexById.get(section.endsAtBlockId) ?? start - 1) + 1;
19990
20580
  const end = Math.max(start, endIndex);
19991
20581
  const slice = blocks.slice(start, end);