pptx-react-viewer 1.18.0 → 1.19.1

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 (99) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/dist/{Model3DScene-GVWQ6SOM.js → Model3DScene-3RYDRQOD.js} +3 -3
  3. package/dist/Model3DScene-3RYDRQOD.js.br +0 -0
  4. package/dist/Model3DScene-3RYDRQOD.js.gz +0 -0
  5. package/dist/{Model3DScene-JGVLIDLD.mjs → Model3DScene-SLGODOXT.mjs} +2 -2
  6. package/dist/Model3DScene-SLGODOXT.mjs.br +0 -0
  7. package/dist/Model3DScene-SLGODOXT.mjs.gz +0 -0
  8. package/dist/PowerPointViewer-C4d7SKZf.d.ts.map +1 -1
  9. package/dist/{SurfaceChart3DScene-ZOTOHOIE.js → SurfaceChart3DScene-3UZ5HZ2W.js} +3 -3
  10. package/dist/SurfaceChart3DScene-3UZ5HZ2W.js.br +0 -0
  11. package/dist/SurfaceChart3DScene-3UZ5HZ2W.js.gz +0 -0
  12. package/dist/{SurfaceChart3DScene-DBWSDSKI.mjs → SurfaceChart3DScene-YL4QD3O5.mjs} +2 -2
  13. package/dist/SurfaceChart3DScene-YL4QD3O5.mjs.br +0 -0
  14. package/dist/SurfaceChart3DScene-YL4QD3O5.mjs.gz +0 -0
  15. package/dist/{chunk-Z4MDCPAY.mjs → chunk-3TRQKGBU.mjs} +26 -731
  16. package/dist/chunk-3TRQKGBU.mjs.br +0 -0
  17. package/dist/chunk-3TRQKGBU.mjs.gz +0 -0
  18. package/dist/{chunk-SBNTEQUA.mjs → chunk-3ZGCM6RC.mjs} +20269 -12232
  19. package/dist/chunk-3ZGCM6RC.mjs.br +0 -0
  20. package/dist/chunk-3ZGCM6RC.mjs.gz +0 -0
  21. package/dist/{chunk-73ST7AC6.js → chunk-7JYQRDRI.js} +6962 -6661
  22. package/dist/chunk-7JYQRDRI.js.br +0 -0
  23. package/dist/chunk-7JYQRDRI.js.gz +0 -0
  24. package/dist/{chunk-EXDUEXTO.js → chunk-AD3EAEY6.js} +20282 -12231
  25. package/dist/chunk-AD3EAEY6.js.br +0 -0
  26. package/dist/chunk-AD3EAEY6.js.gz +0 -0
  27. package/dist/{chunk-HBXPK572.js → chunk-G5GATDE4.js} +2969 -746
  28. package/dist/chunk-G5GATDE4.js.br +0 -0
  29. package/dist/chunk-G5GATDE4.js.gz +0 -0
  30. package/dist/{chunk-JDRC3PSY.js → chunk-H5V24JVW.js} +470 -1186
  31. package/dist/chunk-H5V24JVW.js.br +0 -0
  32. package/dist/chunk-H5V24JVW.js.gz +0 -0
  33. package/dist/{chunk-KMLIWCNL.mjs → chunk-TG2ZYU7Y.mjs} +5782 -5480
  34. package/dist/chunk-TG2ZYU7Y.mjs.br +0 -0
  35. package/dist/chunk-TG2ZYU7Y.mjs.gz +0 -0
  36. package/dist/{chunk-HHTZQHKZ.mjs → chunk-VOU7OCQM.mjs} +2922 -722
  37. package/dist/chunk-VOU7OCQM.mjs.br +0 -0
  38. package/dist/chunk-VOU7OCQM.mjs.gz +0 -0
  39. package/dist/dist-3YRZ26TL.mjs +2 -0
  40. package/dist/dist-3YRZ26TL.mjs.br +0 -0
  41. package/dist/dist-3YRZ26TL.mjs.gz +0 -0
  42. package/dist/{dist-KRRXYUGI.js → dist-M2P6HBG4.js} +602 -546
  43. package/dist/dist-M2P6HBG4.js.br +0 -0
  44. package/dist/dist-M2P6HBG4.js.gz +0 -0
  45. package/dist/hooks-unstable.d.ts +523 -49
  46. package/dist/hooks-unstable.d.ts.map +1 -1
  47. package/dist/hooks-unstable.js +77 -77
  48. package/dist/hooks-unstable.js.br +0 -0
  49. package/dist/hooks-unstable.js.gz +0 -0
  50. package/dist/hooks-unstable.mjs +3 -3
  51. package/dist/hooks-unstable.mjs.br +0 -0
  52. package/dist/hooks-unstable.mjs.gz +0 -0
  53. package/dist/index.d.ts +417 -21
  54. package/dist/index.js +18 -18
  55. package/dist/index.js.br +0 -0
  56. package/dist/index.js.gz +0 -0
  57. package/dist/index.mjs +4 -4
  58. package/dist/index.mjs.br +0 -0
  59. package/dist/index.mjs.gz +0 -0
  60. package/dist/pptx-viewer.css +2 -2
  61. package/dist/pptx-viewer.css.br +0 -0
  62. package/dist/pptx-viewer.css.gz +0 -0
  63. package/dist/viewer/index.d.ts +509 -27
  64. package/dist/viewer/index.js +20 -20
  65. package/dist/viewer/index.js.br +0 -0
  66. package/dist/viewer/index.js.gz +0 -0
  67. package/dist/viewer/index.mjs +4 -4
  68. package/dist/viewer/index.mjs.br +0 -0
  69. package/dist/viewer/index.mjs.gz +0 -0
  70. package/package.json +12 -12
  71. package/dist/Model3DScene-GVWQ6SOM.js.br +0 -0
  72. package/dist/Model3DScene-GVWQ6SOM.js.gz +0 -0
  73. package/dist/Model3DScene-JGVLIDLD.mjs.br +0 -0
  74. package/dist/Model3DScene-JGVLIDLD.mjs.gz +0 -0
  75. package/dist/SurfaceChart3DScene-DBWSDSKI.mjs.br +0 -0
  76. package/dist/SurfaceChart3DScene-DBWSDSKI.mjs.gz +0 -0
  77. package/dist/SurfaceChart3DScene-ZOTOHOIE.js.br +0 -0
  78. package/dist/SurfaceChart3DScene-ZOTOHOIE.js.gz +0 -0
  79. package/dist/chunk-73ST7AC6.js.br +0 -0
  80. package/dist/chunk-73ST7AC6.js.gz +0 -0
  81. package/dist/chunk-EXDUEXTO.js.br +0 -0
  82. package/dist/chunk-EXDUEXTO.js.gz +0 -0
  83. package/dist/chunk-HBXPK572.js.br +0 -0
  84. package/dist/chunk-HBXPK572.js.gz +0 -0
  85. package/dist/chunk-HHTZQHKZ.mjs.br +0 -0
  86. package/dist/chunk-HHTZQHKZ.mjs.gz +0 -0
  87. package/dist/chunk-JDRC3PSY.js.br +0 -0
  88. package/dist/chunk-JDRC3PSY.js.gz +0 -0
  89. package/dist/chunk-KMLIWCNL.mjs.br +0 -0
  90. package/dist/chunk-KMLIWCNL.mjs.gz +0 -0
  91. package/dist/chunk-SBNTEQUA.mjs.br +0 -0
  92. package/dist/chunk-SBNTEQUA.mjs.gz +0 -0
  93. package/dist/chunk-Z4MDCPAY.mjs.br +0 -0
  94. package/dist/chunk-Z4MDCPAY.mjs.gz +0 -0
  95. package/dist/dist-KRRXYUGI.js.br +0 -0
  96. package/dist/dist-KRRXYUGI.js.gz +0 -0
  97. package/dist/dist-N6PAPXK6.mjs +0 -2
  98. package/dist/dist-N6PAPXK6.mjs.br +0 -0
  99. package/dist/dist-N6PAPXK6.mjs.gz +0 -0
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var chunkEXDUEXTO_js = require('./chunk-EXDUEXTO.js');
3
+ var chunkAD3EAEY6_js = require('./chunk-AD3EAEY6.js');
4
4
  var DOMPurify = require('dompurify');
5
5
 
6
6
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
@@ -202,6 +202,18 @@ function collectImagePaths(slides) {
202
202
  });
203
203
  }
204
204
  }
205
+ if (el.type === "model3d") {
206
+ const model = el;
207
+ if (model.modelPath && !model.modelData && !isExternalUrl(model.modelPath)) {
208
+ paths.add(model.modelPath);
209
+ refs.push({ element: el, field: "modelData", path: model.modelPath });
210
+ }
211
+ const posterNeedsResolution = model.posterImage ? !isExternalUrl(model.posterImage) : !model.imageData;
212
+ if (model.imagePath && posterNeedsResolution && !isExternalUrl(model.imagePath)) {
213
+ paths.add(model.imagePath);
214
+ refs.push({ element: el, field: "posterImage", path: model.imagePath });
215
+ }
216
+ }
205
217
  if (el.type === "group" && el.children?.length) {
206
218
  walkElements(el.children);
207
219
  }
@@ -222,7 +234,7 @@ function buildInitialGuides(presentationGuides, firstSlideGuides) {
222
234
  guides.push({
223
235
  id: g.id,
224
236
  axis: g.orientation === "horz" ? "h" : "v",
225
- position: chunkEXDUEXTO_js.guideEmuToPx(g.positionEmu)
237
+ position: chunkAD3EAEY6_js.guideEmuToPx(g.positionEmu)
226
238
  });
227
239
  }
228
240
  }
@@ -231,7 +243,7 @@ function buildInitialGuides(presentationGuides, firstSlideGuides) {
231
243
  guides.push({
232
244
  id: g.id,
233
245
  axis: g.orientation === "horz" ? "h" : "v",
234
- position: chunkEXDUEXTO_js.guideEmuToPx(g.positionEmu)
246
+ position: chunkAD3EAEY6_js.guideEmuToPx(g.positionEmu)
235
247
  });
236
248
  }
237
249
  }
@@ -244,23 +256,23 @@ function getResolvedShapeClipPathFor(shapeType, width, height, adjustments) {
244
256
  return void 0;
245
257
  }
246
258
  if (!Number.isFinite(width) || !Number.isFinite(height) || width <= 0 || height <= 0) {
247
- return chunkEXDUEXTO_js.getShapeClipPath(shapeType);
259
+ return chunkAD3EAEY6_js.getShapeClipPath(shapeType);
248
260
  }
249
261
  if (adjustments && Object.keys(adjustments).length > 0) {
250
- const adjusted = chunkEXDUEXTO_js.getAdjustmentAwareShapeClipPath(shapeType, width, height, adjustments);
262
+ const adjusted = chunkAD3EAEY6_js.getAdjustmentAwareShapeClipPath(shapeType, width, height, adjustments);
251
263
  if (adjusted !== void 0) {
252
264
  return adjusted;
253
265
  }
254
266
  }
255
- const fromPreset = chunkEXDUEXTO_js.getShapeClipPathFromPreset(shapeType, width, height, adjustments);
267
+ const fromPreset = chunkAD3EAEY6_js.getShapeClipPathFromPreset(shapeType, width, height, adjustments);
256
268
  if (fromPreset !== void 0) {
257
269
  return fromPreset;
258
270
  }
259
- const cloud = chunkEXDUEXTO_js.getCloudPathForRendering(shapeType, width, height);
271
+ const cloud = chunkAD3EAEY6_js.getCloudPathForRendering(shapeType, width, height);
260
272
  if (cloud !== void 0) {
261
273
  return cloud;
262
274
  }
263
- return chunkEXDUEXTO_js.getShapeClipPath(shapeType);
275
+ return chunkAD3EAEY6_js.getShapeClipPath(shapeType);
264
276
  }
265
277
  function getResolvedShapeClipPath(element, width, height) {
266
278
  const shapeType = element.shapeType;
@@ -453,7 +465,7 @@ function getPatternSvg(preset, fg, bg) {
453
465
  const svg = (w, h, inner) => `<svg xmlns="${xmlns}" width="${w}" height="${h}">${inner}</svg>`;
454
466
  const rect = (x, y, w, h, fill) => `<rect x="${x}" y="${y}" width="${w}" height="${h}" fill="${fill}"/>`;
455
467
  const bgRect = (w, h) => rect(0, 0, w, h, bg);
456
- const line = (x1, y1, x2, y2, stroke, sw, extra = "") => `<line x1="${x1}" y1="${y1}" x2="${x2}" y2="${y2}" stroke="${stroke}" stroke-width="${sw}"${extra}/>`;
468
+ const line2 = (x1, y1, x2, y2, stroke, sw, extra = "") => `<line x1="${x1}" y1="${y1}" x2="${x2}" y2="${y2}" stroke="${stroke}" stroke-width="${sw}"${extra}/>`;
457
469
  const circle = (cx, cy, r, fill) => `<circle cx="${cx}" cy="${cy}" r="${r}" fill="${fill}"/>`;
458
470
  switch (preset) {
459
471
  // ── Percentage fills ──────────────────────────────────────────────
@@ -532,61 +544,61 @@ function getPatternSvg(preset, fg, bg) {
532
544
  return svg(
533
545
  s,
534
546
  s,
535
- bgRect(s, s) + line(0, 0, s, s, fg, 2) + line(-s, 0, 0, s, fg, 2) + line(s, 0, s * 2, s, fg, 2)
547
+ bgRect(s, s) + line2(0, 0, s, s, fg, 2) + line2(-s, 0, 0, s, fg, 2) + line2(s, 0, s * 2, s, fg, 2)
536
548
  );
537
549
  case "ltDnDiag":
538
550
  return svg(
539
551
  s,
540
552
  s,
541
- bgRect(s, s) + line(0, 0, s, s, fg, 1) + line(-s, 0, 0, s, fg, 1) + line(s, 0, s * 2, s, fg, 1)
553
+ bgRect(s, s) + line2(0, 0, s, s, fg, 1) + line2(-s, 0, 0, s, fg, 1) + line2(s, 0, s * 2, s, fg, 1)
542
554
  );
543
555
  case "dkDnDiag":
544
556
  return svg(
545
557
  s,
546
558
  s,
547
- bgRect(s, s) + line(0, 0, s, s, fg, 3) + line(-s, 0, 0, s, fg, 3) + line(s, 0, s * 2, s, fg, 3)
559
+ bgRect(s, s) + line2(0, 0, s, s, fg, 3) + line2(-s, 0, 0, s, fg, 3) + line2(s, 0, s * 2, s, fg, 3)
548
560
  );
549
561
  case "wdDnDiag":
550
562
  return svg(
551
563
  12,
552
564
  12,
553
- bgRect(12, 12) + line(0, 0, 12, 12, fg, 4) + line(-12, 0, 0, 12, fg, 4) + line(12, 0, 24, 12, fg, 4)
565
+ bgRect(12, 12) + line2(0, 0, 12, 12, fg, 4) + line2(-12, 0, 0, 12, fg, 4) + line2(12, 0, 24, 12, fg, 4)
554
566
  );
555
567
  case "dashDnDiag":
556
- return svg(s, s, bgRect(s, s) + line(0, 0, s, s, fg, 1, ' stroke-dasharray="4,4"'));
568
+ return svg(s, s, bgRect(s, s) + line2(0, 0, s, s, fg, 1, ' stroke-dasharray="4,4"'));
557
569
  // ── Diagonal lines (up) ──────────────────────────────────────────
558
570
  case "upDiag":
559
571
  return svg(
560
572
  s,
561
573
  s,
562
- bgRect(s, s) + line(0, s, s, 0, fg, 2) + line(-s, s, 0, 0, fg, 2) + line(s, s, s * 2, 0, fg, 2)
574
+ bgRect(s, s) + line2(0, s, s, 0, fg, 2) + line2(-s, s, 0, 0, fg, 2) + line2(s, s, s * 2, 0, fg, 2)
563
575
  );
564
576
  case "ltUpDiag":
565
577
  return svg(
566
578
  s,
567
579
  s,
568
- bgRect(s, s) + line(0, s, s, 0, fg, 1) + line(-s, s, 0, 0, fg, 1) + line(s, s, s * 2, 0, fg, 1)
580
+ bgRect(s, s) + line2(0, s, s, 0, fg, 1) + line2(-s, s, 0, 0, fg, 1) + line2(s, s, s * 2, 0, fg, 1)
569
581
  );
570
582
  case "dkUpDiag":
571
583
  return svg(
572
584
  s,
573
585
  s,
574
- bgRect(s, s) + line(0, s, s, 0, fg, 3) + line(-s, s, 0, 0, fg, 3) + line(s, s, s * 2, 0, fg, 3)
586
+ bgRect(s, s) + line2(0, s, s, 0, fg, 3) + line2(-s, s, 0, 0, fg, 3) + line2(s, s, s * 2, 0, fg, 3)
575
587
  );
576
588
  case "wdUpDiag":
577
589
  return svg(
578
590
  12,
579
591
  12,
580
- bgRect(12, 12) + line(0, 12, 12, 0, fg, 4) + line(-12, 12, 0, 0, fg, 4) + line(12, 12, 24, 0, fg, 4)
592
+ bgRect(12, 12) + line2(0, 12, 12, 0, fg, 4) + line2(-12, 12, 0, 0, fg, 4) + line2(12, 12, 24, 0, fg, 4)
581
593
  );
582
594
  case "dashUpDiag":
583
- return svg(s, s, bgRect(s, s) + line(0, s, s, 0, fg, 1, ' stroke-dasharray="4,4"'));
595
+ return svg(s, s, bgRect(s, s) + line2(0, s, s, 0, fg, 1, ' stroke-dasharray="4,4"'));
584
596
  // ── Diagonal cross ───────────────────────────────────────────────
585
597
  case "diagCross":
586
598
  return svg(
587
599
  s,
588
600
  s,
589
- bgRect(s, s) + line(0, 0, s, s, fg, 1) + line(-s, 0, 0, s, fg, 1) + line(s, 0, s * 2, s, fg, 1) + line(0, s, s, 0, fg, 1) + line(-s, s, 0, 0, fg, 1) + line(s, s, s * 2, 0, fg, 1)
601
+ bgRect(s, s) + line2(0, 0, s, s, fg, 1) + line2(-s, 0, 0, s, fg, 1) + line2(s, 0, s * 2, s, fg, 1) + line2(0, s, s, 0, fg, 1) + line2(-s, s, 0, 0, fg, 1) + line2(s, s, s * 2, 0, fg, 1)
590
602
  );
591
603
  // ── Checkerboard ─────────────────────────────────────────────────
592
604
  case "smCheck":
@@ -628,7 +640,7 @@ function getPatternSvg(preset, fg, bg) {
628
640
  return svg(
629
641
  s,
630
642
  s,
631
- bgRect(s, s) + line(0, 4, 4, 0, fg, 1) + line(4, s, s, 4, fg, 1) + line(0, s, s, 0, fg, 1)
643
+ bgRect(s, s) + line2(0, 4, 4, 0, fg, 1) + line2(4, s, s, 4, fg, 1) + line2(0, s, s, 0, fg, 1)
632
644
  );
633
645
  // ── Diamond ──────────────────────────────────────────────────────
634
646
  case "solidDmnd":
@@ -637,7 +649,7 @@ function getPatternSvg(preset, fg, bg) {
637
649
  return svg(
638
650
  s,
639
651
  s,
640
- bgRect(s, s) + line(4, 0, s, 4, fg, 1) + line(s, 4, 4, s, fg, 1) + line(4, s, 0, 4, fg, 1) + line(0, 4, 4, 0, fg, 1)
652
+ bgRect(s, s) + line2(4, 0, s, 4, fg, 1) + line2(s, 4, 4, s, fg, 1) + line2(4, s, 0, 4, fg, 1) + line2(0, 4, 4, 0, fg, 1)
641
653
  );
642
654
  case "dotDmnd":
643
655
  return svg(
@@ -662,21 +674,21 @@ function getPatternSvg(preset, fg, bg) {
662
674
  return svg(
663
675
  s,
664
676
  s,
665
- bgRect(s, s) + line(0, 0, 4, 4, fg, 1.5) + line(4, 4, 0, s, fg, 1.5) + line(s, 0, 4, 4, fg, 1.5) + line(4, 4, s, s, fg, 1.5) + line(4, 0, s, 4, fg, 1.5) + line(0, 4, 4, s, fg, 1.5)
677
+ bgRect(s, s) + line2(0, 0, 4, 4, fg, 1.5) + line2(4, 4, 0, s, fg, 1.5) + line2(s, 0, 4, 4, fg, 1.5) + line2(4, 4, s, s, fg, 1.5) + line2(4, 0, s, 4, fg, 1.5) + line2(0, 4, 4, s, fg, 1.5)
666
678
  );
667
679
  // ── Divot ────────────────────────────────────────────────────────
668
680
  case "divot":
669
681
  return svg(
670
682
  s,
671
683
  s,
672
- bgRect(s, s) + line(2, 1, 2, 3, fg, 1) + line(1, 2, 3, 2, fg, 1) + line(6, 5, 6, 7, fg, 1) + line(5, 6, 7, 6, fg, 1)
684
+ bgRect(s, s) + line2(2, 1, 2, 3, fg, 1) + line2(1, 2, 3, 2, fg, 1) + line2(6, 5, 6, 7, fg, 1) + line2(5, 6, 7, 6, fg, 1)
673
685
  );
674
686
  // ── Shingle ──────────────────────────────────────────────────────
675
687
  case "shingle":
676
688
  return svg(
677
689
  s,
678
690
  s,
679
- bgRect(s, s) + line(0, 0, s, s, fg, 1) + line(0, s, 4, 4, fg, 1) + rect(0, 7, s, 1, fg)
691
+ bgRect(s, s) + line2(0, 0, s, s, fg, 1) + line2(0, s, 4, 4, fg, 1) + rect(0, 7, s, 1, fg)
680
692
  );
681
693
  // ── Wave ─────────────────────────────────────────────────────────
682
694
  case "wave":
@@ -975,7 +987,7 @@ var DEFAULT_SCHEME_COLOR_MAP = {
975
987
  phclr: "#4472C4"
976
988
  };
977
989
  function applyDrawingColorTransforms2(baseColor, colorNode) {
978
- return chunkEXDUEXTO_js.applyDrawingColorTransforms(baseColor, colorNode);
990
+ return chunkAD3EAEY6_js.applyDrawingColorTransforms(baseColor, colorNode);
979
991
  }
980
992
  function parseDrawingColorChoice(colorNode, schemeColorOverrides) {
981
993
  if (!colorNode) {
@@ -1027,7 +1039,7 @@ function parseDrawingColorChoice(colorNode, schemeColorOverrides) {
1027
1039
  const h = hueRaw / 6e4;
1028
1040
  const s = clampUnitInterval(satRaw / 1e5);
1029
1041
  const l = clampUnitInterval(lumRaw / 1e5);
1030
- const rgb = chunkEXDUEXTO_js.hslToRgb(h, s, l);
1042
+ const rgb = chunkAD3EAEY6_js.hslToRgb(h, s, l);
1031
1043
  const toHex = (value) => Math.min(255, Math.max(0, Math.round(value))).toString(16).padStart(2, "0").toUpperCase();
1032
1044
  const base = `#${toHex(rgb.r)}${toHex(rgb.g)}${toHex(rgb.b)}`;
1033
1045
  return applyDrawingColorTransforms2(base, hslNode);
@@ -1037,7 +1049,7 @@ function parseDrawingColorChoice(colorNode, schemeColorOverrides) {
1037
1049
  const preset = String(
1038
1050
  colorNode["a:prstClr"]?.["@_val"] || ""
1039
1051
  ).toLowerCase();
1040
- const mapped = chunkEXDUEXTO_js.PRESET_COLOR_MAP[preset];
1052
+ const mapped = chunkAD3EAEY6_js.PRESET_COLOR_MAP[preset];
1041
1053
  if (!mapped) {
1042
1054
  return void 0;
1043
1055
  }
@@ -1363,14 +1375,36 @@ function buildReflectionCssValue(distance, startOpacity, endOpacity, fadeLength,
1363
1375
  function getDuotoneFilterId(elementId) {
1364
1376
  return `dag-duotone-${elementId}`;
1365
1377
  }
1366
- function clamp(v, lo, hi) {
1378
+ function clamp(value, minimum, maximum) {
1379
+ return Math.min(maximum, Math.max(minimum, value));
1380
+ }
1381
+ function buildImageBiLevelTable(threshold) {
1382
+ const cutoff = clamp(threshold, 0, 100);
1383
+ return Array.from({ length: 101 }, (_, index) => index >= cutoff ? "1" : "0").join(" ");
1384
+ }
1385
+ function buildImageLuminanceTransfer(amount) {
1386
+ const normalized = clamp(amount / 100, -1, 1);
1387
+ return normalized >= 0 ? { slope: 1 - normalized, intercept: normalized } : { slope: 1 + normalized, intercept: 0 };
1388
+ }
1389
+ function clamp2(v, lo, hi) {
1367
1390
  return v < lo ? lo : v > hi ? hi : v;
1368
1391
  }
1369
1392
  function normalizeRadius01(radius) {
1370
- return clamp(radius / 100, 0, 1);
1393
+ return clamp2(radius / 100, 0, 1);
1394
+ }
1395
+ function hexToRgbUnit2(hex) {
1396
+ const clean = hex.replace(/^#/u, "");
1397
+ const r = parseInt(clean.substring(0, 2), 16) / 255;
1398
+ const g = parseInt(clean.substring(2, 4), 16) / 255;
1399
+ const b = parseInt(clean.substring(4, 6), 16) / 255;
1400
+ return {
1401
+ r: Number.isFinite(r) ? r : 0,
1402
+ g: Number.isFinite(g) ? g : 0,
1403
+ b: Number.isFinite(b) ? b : 0
1404
+ };
1371
1405
  }
1372
1406
  function getEffects(element) {
1373
- if (!chunkEXDUEXTO_js.isImageLikeElement(element)) {
1407
+ if (!chunkAD3EAEY6_js.isImageLikeElement(element)) {
1374
1408
  return void 0;
1375
1409
  }
1376
1410
  return element.imageEffects;
@@ -1458,10 +1492,6 @@ function getImageFilterCss(element, options) {
1458
1492
  filters.push(buildSimpleArtisticCss(effects.artisticEffect, radius));
1459
1493
  }
1460
1494
  }
1461
- if (typeof effects.biLevel === "number") {
1462
- const thresh = clamp(effects.biLevel, 0, 100);
1463
- filters.push(`grayscale(100%) contrast(1000%) brightness(${thresh}%)`);
1464
- }
1465
1495
  return filters.length > 0 ? filters.join(" ") : void 0;
1466
1496
  }
1467
1497
  var getImageEffectsFilter = getImageFilterCss;
@@ -1532,10 +1562,257 @@ function getImageEffectsOpacity(element) {
1532
1562
  return void 0;
1533
1563
  }
1534
1564
  if (typeof effects.alphaModFix === "number") {
1535
- return clamp(effects.alphaModFix / 100, 0, 1);
1565
+ return clamp2(effects.alphaModFix / 100, 0, 1);
1536
1566
  }
1537
1567
  return void 0;
1538
1568
  }
1569
+ var GRAYSCALE_LUMINANCE_MATRIX = [
1570
+ 0.2126,
1571
+ 0.7152,
1572
+ 0.0722,
1573
+ 0,
1574
+ 0,
1575
+ 0.2126,
1576
+ 0.7152,
1577
+ 0.0722,
1578
+ 0,
1579
+ 0,
1580
+ 0.2126,
1581
+ 0.7152,
1582
+ 0.0722,
1583
+ 0,
1584
+ 0,
1585
+ 0,
1586
+ 0,
1587
+ 0,
1588
+ 1,
1589
+ 0
1590
+ ].join(" ");
1591
+ function buildDuotoneFilterMarkup(color1, color2) {
1592
+ const c1 = hexToRgbUnit2(color1);
1593
+ const c2 = hexToRgbUnit2(color2);
1594
+ return `<feColorMatrix type="matrix" values="${GRAYSCALE_LUMINANCE_MATRIX}"/><feComponentTransfer><feFuncR type="linear" slope="${c2.r - c1.r}" intercept="${c1.r}"/><feFuncG type="linear" slope="${c2.g - c1.g}" intercept="${c1.g}"/><feFuncB type="linear" slope="${c2.b - c1.b}" intercept="${c1.b}"/></feComponentTransfer>`;
1595
+ }
1596
+ function getDuotoneImageFilter(element, elementId = chunkAD3EAEY6_js.isImageLikeElement(element) ? element.id : "") {
1597
+ const effects = getEffects(element);
1598
+ if (!effects?.duotone) {
1599
+ return void 0;
1600
+ }
1601
+ const id = getImageDuotoneFilterId(elementId);
1602
+ return {
1603
+ id,
1604
+ cssReference: `url(#${id})`,
1605
+ filterMarkup: buildDuotoneFilterMarkup(effects.duotone.color1, effects.duotone.color2)
1606
+ };
1607
+ }
1608
+ function buildImageAlphaFilterMarkup(effects) {
1609
+ const parts = [];
1610
+ let resultIdx = 0;
1611
+ let inputRef = "SourceGraphic";
1612
+ const next = (build) => {
1613
+ const output = `r${resultIdx++}`;
1614
+ parts.push(build(inputRef, output));
1615
+ inputRef = output;
1616
+ };
1617
+ if (typeof effects.alphaModFix === "number") {
1618
+ const mul = clamp2(effects.alphaModFix / 100, 0, 1);
1619
+ next(
1620
+ (inp, out) => `<feColorMatrix in="${inp}" result="${out}" type="matrix" values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 ${mul} 0"/>`
1621
+ );
1622
+ }
1623
+ if (effects.alphaInv) {
1624
+ next(
1625
+ (inp, out) => `<feComponentTransfer in="${inp}" result="${out}"><feFuncA type="linear" slope="-1" intercept="1"/></feComponentTransfer>`
1626
+ );
1627
+ }
1628
+ if (effects.alphaCeiling) {
1629
+ next(
1630
+ (inp, out) => `<feComponentTransfer in="${inp}" result="${out}"><feFuncA type="discrete" tableValues="0 1 1 1 1 1 1 1 1 1"/></feComponentTransfer>`
1631
+ );
1632
+ }
1633
+ if (effects.alphaFloor) {
1634
+ next(
1635
+ (inp, out) => `<feComponentTransfer in="${inp}" result="${out}"><feFuncA type="discrete" tableValues="0 0 0 0 0 0 0 0 0 1"/></feComponentTransfer>`
1636
+ );
1637
+ }
1638
+ if (typeof effects.alphaRepl === "number") {
1639
+ const a = clamp2(effects.alphaRepl / 100, 0, 1);
1640
+ next(
1641
+ (inp, out) => `<feComponentTransfer in="${inp}" result="${out}"><feFuncA type="linear" slope="0" intercept="${a}"/></feComponentTransfer>`
1642
+ );
1643
+ }
1644
+ if (typeof effects.alphaBiLevel === "number") {
1645
+ const t = clamp2(effects.alphaBiLevel / 100, 0, 1);
1646
+ const table = Array.from({ length: 10 }, (_, i) => i / 10 >= t ? "1" : "0").join(" ");
1647
+ next(
1648
+ (inp, out) => `<feComponentTransfer in="${inp}" result="${out}"><feFuncA type="discrete" tableValues="${table}"/></feComponentTransfer>`
1649
+ );
1650
+ }
1651
+ if (typeof effects.biLevel === "number") {
1652
+ next((inp, out) => `<feColorMatrix in="${inp}" result="${out}" type="saturate" values="0"/>`);
1653
+ const tbl = buildImageBiLevelTable(effects.biLevel);
1654
+ next(
1655
+ (inp, out) => `<feComponentTransfer in="${inp}" result="${out}"><feFuncR type="discrete" tableValues="${tbl}"/><feFuncG type="discrete" tableValues="${tbl}"/><feFuncB type="discrete" tableValues="${tbl}"/></feComponentTransfer>`
1656
+ );
1657
+ }
1658
+ if (effects.lum && (typeof effects.lum.bright === "number" || typeof effects.lum.contrast === "number")) {
1659
+ const b = (effects.lum.bright ?? 0) / 100;
1660
+ const c = 1 + (effects.lum.contrast ?? 0) / 100;
1661
+ const slope = c;
1662
+ const intercept = b + (1 - c) / 2;
1663
+ next(
1664
+ (inp, out) => `<feComponentTransfer in="${inp}" result="${out}"><feFuncR type="linear" slope="${slope}" intercept="${intercept}"/><feFuncG type="linear" slope="${slope}" intercept="${intercept}"/><feFuncB type="linear" slope="${slope}" intercept="${intercept}"/></feComponentTransfer>`
1665
+ );
1666
+ }
1667
+ if (effects.hsl && typeof effects.hsl.sat === "number") {
1668
+ const v = clamp2(1 + effects.hsl.sat / 100, 0, 2);
1669
+ next(
1670
+ (inp, out) => `<feColorMatrix in="${inp}" result="${out}" type="saturate" values="${v}"/>`
1671
+ );
1672
+ }
1673
+ if (effects.hsl && typeof effects.hsl.lum === "number") {
1674
+ const { slope, intercept } = buildImageLuminanceTransfer(effects.hsl.lum);
1675
+ next(
1676
+ (inp, out) => `<feComponentTransfer in="${inp}" result="${out}"><feFuncR type="linear" slope="${slope}" intercept="${intercept}"/><feFuncG type="linear" slope="${slope}" intercept="${intercept}"/><feFuncB type="linear" slope="${slope}" intercept="${intercept}"/></feComponentTransfer>`
1677
+ );
1678
+ }
1679
+ if (effects.tint && typeof effects.tint.hue === "number") {
1680
+ next(
1681
+ (inp, out) => `<feColorMatrix in="${inp}" result="${out}" type="hueRotate" values="${effects.tint.hue}"/>`
1682
+ );
1683
+ }
1684
+ if (effects.tint && typeof effects.tint.amt === "number") {
1685
+ const { slope, intercept } = buildImageLuminanceTransfer(effects.tint.amt);
1686
+ next(
1687
+ (inp, out) => `<feComponentTransfer in="${inp}" result="${out}"><feFuncR type="linear" slope="${slope}" intercept="${intercept}"/><feFuncG type="linear" slope="${slope}" intercept="${intercept}"/><feFuncB type="linear" slope="${slope}" intercept="${intercept}"/></feComponentTransfer>`
1688
+ );
1689
+ }
1690
+ if (effects.clrRepl) {
1691
+ const c = hexToRgbUnit2(effects.clrRepl.color);
1692
+ next(
1693
+ (inp, out) => `<feColorMatrix in="${inp}" result="${out}" type="matrix" values="0 0 0 0 ${c.r} 0 0 0 0 ${c.g} 0 0 0 0 ${c.b} 0 0 0 1 0"/>`
1694
+ );
1695
+ }
1696
+ return parts.length > 0 ? parts.join("") : void 0;
1697
+ }
1698
+ function getImageAlphaFilter(element, elementId = chunkAD3EAEY6_js.isImageLikeElement(element) ? element.id : "") {
1699
+ const effects = getEffects(element);
1700
+ if (!effects || !hasAdvancedImageAlphaEffects(element)) {
1701
+ return void 0;
1702
+ }
1703
+ const markup = buildImageAlphaFilterMarkup(effects);
1704
+ if (!markup) {
1705
+ return void 0;
1706
+ }
1707
+ const id = getImageAlphaFilterId(elementId);
1708
+ return { id, cssReference: `url(#${id})`, filterMarkup: markup };
1709
+ }
1710
+ function buildDiscreteTable(steps) {
1711
+ const values = [];
1712
+ for (let i = 0; i < steps; i++) {
1713
+ const v = Math.round(i / (steps - 1) * 100) / 100;
1714
+ const count = Math.ceil(256 / steps);
1715
+ for (let j = 0; j < count; j++) {
1716
+ values.push(v);
1717
+ }
1718
+ }
1719
+ return values.slice(0, 256).join(" ");
1720
+ }
1721
+ function buildArtisticFilterMarkup(effectName, radius) {
1722
+ const normalizedRadius = clamp2(radius, 0, 100) / 100;
1723
+ switch (effectName) {
1724
+ case "artisticFilmGrain":
1725
+ case "filmGrain": {
1726
+ const freq = 0.5 + normalizedRadius * 0.5;
1727
+ const opacity = 0.15 + normalizedRadius * 0.25;
1728
+ return `<feTurbulence type="fractalNoise" baseFrequency="${freq}" numOctaves="4" seed="1" stitchTiles="stitch" result="grain"/><feColorMatrix in="grain" type="saturate" values="0" result="grainGray"/><feBlend in="SourceGraphic" in2="grainGray" mode="overlay"/><feComponentTransfer><feFuncR type="linear" slope="${1 + opacity * 0.3}" intercept="${opacity * 0.02}"/><feFuncG type="linear" slope="${1 + opacity * 0.3}" intercept="${opacity * 0.02}"/><feFuncB type="linear" slope="${1 + opacity * 0.3}" intercept="${opacity * 0.02}"/></feComponentTransfer>`;
1729
+ }
1730
+ case "artisticCutout":
1731
+ case "cutout": {
1732
+ const steps = Math.max(2, Math.round(4 + normalizedRadius * 4));
1733
+ const tableValues = buildDiscreteTable(steps);
1734
+ return `<feComponentTransfer><feFuncR type="discrete" tableValues="${tableValues}"/><feFuncG type="discrete" tableValues="${tableValues}"/><feFuncB type="discrete" tableValues="${tableValues}"/></feComponentTransfer>`;
1735
+ }
1736
+ case "artisticCement":
1737
+ case "cement": {
1738
+ const freq = 1.5 + normalizedRadius * 2.5;
1739
+ const desat = Math.max(0, 0.4 - normalizedRadius * 0.3);
1740
+ return `<feColorMatrix type="saturate" values="${desat}" result="desat"/><feTurbulence type="fractalNoise" baseFrequency="${freq}" numOctaves="5" seed="2" stitchTiles="stitch" result="cementNoise"/><feColorMatrix in="cementNoise" type="saturate" values="0" result="cementGray"/><feBlend in="desat" in2="cementGray" mode="multiply"/><feComponentTransfer><feFuncR type="linear" slope="1.2" intercept="0"/><feFuncG type="linear" slope="1.2" intercept="0"/><feFuncB type="linear" slope="1.2" intercept="0"/></feComponentTransfer>`;
1741
+ }
1742
+ case "artisticTexturizer":
1743
+ case "texturizer": {
1744
+ const freq = 2 + normalizedRadius * 3;
1745
+ return `<feTurbulence type="fractalNoise" baseFrequency="${freq}" numOctaves="3" seed="3" stitchTiles="stitch" result="texNoise"/><feColorMatrix in="texNoise" type="saturate" values="0" result="texGray"/><feBlend in="SourceGraphic" in2="texGray" mode="overlay"/><feComponentTransfer><feFuncR type="linear" slope="1.1" intercept="0.02"/><feFuncG type="linear" slope="1.1" intercept="0.02"/><feFuncB type="linear" slope="1.1" intercept="0.02"/></feComponentTransfer>`;
1746
+ }
1747
+ case "artisticCrisscrossEtching":
1748
+ case "crisscrossEtching": {
1749
+ const freq = 0.08 + normalizedRadius * 0.12;
1750
+ return `<feColorMatrix type="saturate" values="0" result="gray"/><feTurbulence type="turbulence" baseFrequency="${freq} ${freq * 3}" numOctaves="1" seed="7" result="lines"/><feColorMatrix in="lines" type="saturate" values="0" result="linesGray"/><feBlend in="gray" in2="linesGray" mode="multiply"/><feComponentTransfer><feFuncR type="linear" slope="1.3" intercept="-0.05"/><feFuncG type="linear" slope="1.3" intercept="-0.05"/><feFuncB type="linear" slope="1.3" intercept="-0.05"/></feComponentTransfer>`;
1751
+ }
1752
+ case "artisticMosaic":
1753
+ case "artisticMosaicBubbles":
1754
+ case "mosaicBubbles":
1755
+ case "mosaic": {
1756
+ const blurAmount = Math.max(2, Math.round(radius * 0.8));
1757
+ const freq = 0.02 + normalizedRadius * 0.03;
1758
+ return `<feGaussianBlur in="SourceGraphic" stdDeviation="${blurAmount}" result="blurred"/><feTurbulence type="turbulence" baseFrequency="${freq}" numOctaves="1" seed="4" result="cells"/><feDisplacementMap in="blurred" in2="cells" scale="${blurAmount * 0.5}" xChannelSelector="R" yChannelSelector="G" result="mosaic"/><feComponentTransfer in="mosaic"><feFuncR type="linear" slope="1.05" intercept="0"/><feFuncG type="linear" slope="1.05" intercept="0"/><feFuncB type="linear" slope="1.05" intercept="0"/></feComponentTransfer>`;
1759
+ }
1760
+ case "artisticGlowEdges":
1761
+ case "glowEdges":
1762
+ case "glow_edges": {
1763
+ const edgeBlur = Math.max(1, Math.round(normalizedRadius * 3));
1764
+ return `<feColorMatrix type="matrix" values="-1 0 0 0 1 0 -1 0 0 1 0 0 -1 0 1 0 0 0 1 0" result="inverted"/><feGaussianBlur in="inverted" stdDeviation="${edgeBlur}" result="blurredInv"/><feBlend in="SourceGraphic" in2="blurredInv" mode="screen"/><feComponentTransfer><feFuncR type="linear" slope="2" intercept="-0.3"/><feFuncG type="linear" slope="2" intercept="-0.3"/><feFuncB type="linear" slope="2" intercept="-0.3"/></feComponentTransfer>`;
1765
+ }
1766
+ case "artisticChalkSketch":
1767
+ case "chalkSketch":
1768
+ case "chalk": {
1769
+ const freq = 1 + normalizedRadius * 2;
1770
+ const desat = Math.max(0, 0.2 - normalizedRadius * 0.2);
1771
+ return `<feColorMatrix type="saturate" values="${desat}" result="gray"/><feTurbulence type="fractalNoise" baseFrequency="${freq}" numOctaves="4" seed="5" stitchTiles="stitch" result="chalkTex"/><feColorMatrix in="chalkTex" type="saturate" values="0" result="chalkGray"/><feBlend in="gray" in2="chalkGray" mode="overlay"/><feComponentTransfer><feFuncR type="linear" slope="1.5" intercept="0.05"/><feFuncG type="linear" slope="1.5" intercept="0.05"/><feFuncB type="linear" slope="1.5" intercept="0.05"/></feComponentTransfer>`;
1772
+ }
1773
+ case "artisticPencilSketch":
1774
+ case "pencilSketch": {
1775
+ const blurAmt = Math.max(3, Math.round(4 + normalizedRadius * 8));
1776
+ return `<feColorMatrix type="saturate" values="0" result="gray"/><feColorMatrix in="gray" type="matrix" values="-1 0 0 0 1 0 -1 0 0 1 0 0 -1 0 1 0 0 0 1 0" result="invGray"/><feGaussianBlur in="invGray" stdDeviation="${blurAmt}" result="blurInv"/><feBlend in="blurInv" in2="gray" mode="screen" result="sketch"/><feComponentTransfer in="sketch"><feFuncR type="linear" slope="1.6" intercept="-0.15"/><feFuncG type="linear" slope="1.6" intercept="-0.15"/><feFuncB type="linear" slope="1.6" intercept="-0.15"/></feComponentTransfer>`;
1777
+ }
1778
+ case "artisticPencilGrayscale":
1779
+ case "pencilGrayscale":
1780
+ case "grayPencil": {
1781
+ const sharpenBlur = Math.max(0.5, 1 + normalizedRadius * 2);
1782
+ return `<feColorMatrix type="saturate" values="0" result="gray"/><feGaussianBlur in="gray" stdDeviation="${sharpenBlur}" result="grayBlur"/><feComposite in="gray" in2="grayBlur" operator="arithmetic" k1="0" k2="1.5" k3="-0.5" k4="0"/>`;
1783
+ }
1784
+ default:
1785
+ return void 0;
1786
+ }
1787
+ }
1788
+ function getArtisticImageFilter(element, elementId = chunkAD3EAEY6_js.isImageLikeElement(element) ? element.id : "") {
1789
+ const effects = getEffects(element);
1790
+ if (!effects?.artisticEffect || !needsSvgArtisticFilter(effects.artisticEffect)) {
1791
+ return void 0;
1792
+ }
1793
+ const markup = buildArtisticFilterMarkup(effects.artisticEffect, effects.artisticRadius ?? 5);
1794
+ if (!markup) {
1795
+ return void 0;
1796
+ }
1797
+ const id = getArtisticFilterId(elementId);
1798
+ return { id, cssReference: `url(#${id})`, filterMarkup: markup };
1799
+ }
1800
+ function getImageSvgFilters(element) {
1801
+ const defs = [];
1802
+ const duotone = getDuotoneImageFilter(element);
1803
+ if (duotone) {
1804
+ defs.push({ id: duotone.id, markup: duotone.filterMarkup });
1805
+ }
1806
+ const alpha = getImageAlphaFilter(element);
1807
+ if (alpha) {
1808
+ defs.push({ id: alpha.id, markup: alpha.filterMarkup });
1809
+ }
1810
+ const artistic = getArtisticImageFilter(element);
1811
+ if (artistic) {
1812
+ defs.push({ id: artistic.id, markup: artistic.filterMarkup });
1813
+ }
1814
+ return defs;
1815
+ }
1539
1816
  var NONE_PRESETS = /* @__PURE__ */ new Set(["textNoShape", "textPlain"]);
1540
1817
  var PATH_PRESETS = /* @__PURE__ */ new Set([
1541
1818
  "textArchUp",
@@ -3290,8 +3567,8 @@ function hexToRgb(hex) {
3290
3567
  ];
3291
3568
  }
3292
3569
  function rgbToHex(r, g, b) {
3293
- const clamp3 = (v) => Math.max(0, Math.min(255, Math.round(v)));
3294
- return `#${clamp3(r).toString(16).padStart(2, "0")}${clamp3(g).toString(16).padStart(2, "0")}${clamp3(b).toString(16).padStart(2, "0")}`;
3570
+ const clamp7 = (v) => Math.max(0, Math.min(255, Math.round(v)));
3571
+ return `#${clamp7(r).toString(16).padStart(2, "0")}${clamp7(g).toString(16).padStart(2, "0")}${clamp7(b).toString(16).padStart(2, "0")}`;
3295
3572
  }
3296
3573
  function tint(hex, amount) {
3297
3574
  const [r, g, b] = hexToRgb(hex);
@@ -3403,14 +3680,17 @@ function computeValueRange(series) {
3403
3680
  }
3404
3681
  function valueToY(val2, range, topY, bottomY) {
3405
3682
  const usable = bottomY - topY;
3683
+ let ratio;
3406
3684
  if (range.logScale && range.logBase) {
3407
3685
  const base = range.logBase;
3408
3686
  const clampedVal = Math.max(val2, range.min);
3409
3687
  const logVal = Math.log(clampedVal) / Math.log(base);
3410
3688
  const logMin = Math.log(range.min) / Math.log(base);
3411
- return bottomY - (logVal - logMin) / range.span * usable;
3689
+ ratio = (logVal - logMin) / range.span;
3690
+ } else {
3691
+ ratio = (val2 - range.min) / range.span;
3412
3692
  }
3413
- return bottomY - (val2 - range.min) / range.span * usable;
3693
+ return range.reverseOrder ? topY + ratio * usable : bottomY - ratio * usable;
3414
3694
  }
3415
3695
  function formatAxisValue(val2) {
3416
3696
  if (Math.abs(val2) >= 1e6) {
@@ -3468,8 +3748,9 @@ function computeLayout(elementWidth, elementHeight, style, hasAxes, legendPos, o
3468
3748
  svgHeight
3469
3749
  };
3470
3750
  }
3751
+ var LOG_EXPONENT_TOLERANCE = 1e-12;
3471
3752
  function computeLogValueRange(series, logBase) {
3472
- const allValues = series.flatMap((s) => s.values).filter((v) => v > 0);
3753
+ const allValues = series.flatMap((item) => item.values).filter((value) => value > 0);
3473
3754
  if (allValues.length === 0) {
3474
3755
  return { min: 1, max: logBase, span: 1, logScale: true, logBase };
3475
3756
  }
@@ -3479,15 +3760,34 @@ function computeLogValueRange(series, logBase) {
3479
3760
  const logMax = Math.ceil(Math.log(dataMax) / Math.log(logBase));
3480
3761
  const min = logBase ** logMin;
3481
3762
  const max = logBase ** Math.max(logMax, logMin + 1);
3482
- const logSpan = Math.log(max) / Math.log(logBase) - Math.log(min) / Math.log(logBase);
3483
3763
  return {
3484
3764
  min,
3485
3765
  max,
3486
- span: Math.max(logSpan, 1),
3766
+ span: Math.max(Math.log(max) / Math.log(logBase) - Math.log(min) / Math.log(logBase), 1),
3487
3767
  logScale: true,
3488
3768
  logBase
3489
3769
  };
3490
3770
  }
3771
+ function computeValueRangeForAxis(series, axis) {
3772
+ const requestedLogBase = axis?.logBase ?? 10;
3773
+ const logBase = axis?.logScale && Number.isFinite(requestedLogBase) && requestedLogBase > 1 ? requestedLogBase : axis?.logScale ? 10 : void 0;
3774
+ const automatic = logBase ? computeLogValueRange(series, logBase) : computeValueRange(series);
3775
+ const validMin = typeof axis?.min === "number" && Number.isFinite(axis.min) && (!logBase || axis.min > 0) ? axis.min : void 0;
3776
+ const validMax = typeof axis?.max === "number" && Number.isFinite(axis.max) && (!logBase || axis.max > 0) ? axis.max : void 0;
3777
+ const min = validMin ?? automatic.min;
3778
+ let max = validMax ?? automatic.max;
3779
+ if (max <= min) {
3780
+ max = logBase ? min * logBase : min + 1;
3781
+ }
3782
+ const span = logBase ? Math.log(max) / Math.log(logBase) - Math.log(min) / Math.log(logBase) : max - min;
3783
+ return {
3784
+ min,
3785
+ max,
3786
+ span: Math.max(span, Number.EPSILON),
3787
+ ...logBase ? { logScale: true, logBase } : {},
3788
+ ...axis?.orientation === "maxMin" ? { reverseOrder: true } : {}
3789
+ };
3790
+ }
3491
3791
  function generateLogTicks(range) {
3492
3792
  if (!range.logScale || !range.logBase) {
3493
3793
  return [];
@@ -3495,21 +3795,56 @@ function generateLogTicks(range) {
3495
3795
  const base = range.logBase;
3496
3796
  const logMin = Math.log(range.min) / Math.log(base);
3497
3797
  const logMax = Math.log(range.max) / Math.log(base);
3498
- const ticks = [];
3499
- for (let exp = Math.round(logMin); exp <= Math.round(logMax); exp++) {
3500
- ticks.push(base ** exp);
3798
+ const firstExponent = Math.ceil(logMin - LOG_EXPONENT_TOLERANCE);
3799
+ const lastExponent = Math.floor(logMax + LOG_EXPONENT_TOLERANCE);
3800
+ if (lastExponent < firstExponent) {
3801
+ return range.min === range.max ? [range.min] : [range.min, range.max];
3501
3802
  }
3502
- return ticks;
3803
+ return Array.from(
3804
+ { length: lastExponent - firstExponent + 1 },
3805
+ (_unused, index) => base ** (firstExponent + index)
3806
+ );
3503
3807
  }
3504
- function findLogAxis(axes) {
3505
- return axes?.find((a) => a.axisType === "valAx" && a.logScale);
3808
+ function generateIntervalTicks(range, unit) {
3809
+ if (!Number.isFinite(unit) || unit <= 0 || range.logScale) {
3810
+ return [];
3811
+ }
3812
+ const tolerance = Math.max(1, Math.abs(range.min), Math.abs(range.max)) * 1e-12;
3813
+ const first = Math.ceil((range.min - tolerance) / unit);
3814
+ const last = Math.floor((range.max + tolerance) / unit);
3815
+ const count = Math.min(Math.max(last - first + 1, 0), 2e3);
3816
+ return Array.from({ length: count }, (_, index) => (first + index) * unit);
3506
3817
  }
3507
- function computeValueRangeForChart(series, axes) {
3508
- const logAxis = findLogAxis(axes);
3509
- if (logAxis?.logBase) {
3510
- return computeLogValueRange(series, logAxis.logBase);
3818
+ function generateAxisTicks(range, axis, defaultIntervals) {
3819
+ if (range.logScale && range.logBase) {
3820
+ return generateLogTicks(range);
3821
+ }
3822
+ const explicit = generateIntervalTicks(range, axis?.majorUnit ?? 0);
3823
+ if (explicit.length > 0) {
3824
+ return explicit;
3825
+ }
3826
+ return Array.from(
3827
+ { length: defaultIntervals + 1 },
3828
+ (_, index) => range.min + range.span / defaultIntervals * index
3829
+ );
3830
+ }
3831
+ function generateMinorAxisTicks(range, axis) {
3832
+ const minor = generateIntervalTicks(range, axis?.minorUnit ?? 0);
3833
+ if (minor.length === 0) {
3834
+ return [];
3511
3835
  }
3512
- return computeValueRange(series);
3836
+ const majorUnit = axis?.majorUnit;
3837
+ if (!majorUnit || !Number.isFinite(majorUnit) || majorUnit <= 0) {
3838
+ return minor;
3839
+ }
3840
+ const tolerance = Math.max(1, Math.abs(range.min), Math.abs(range.max)) * 1e-10;
3841
+ return minor.filter(
3842
+ (value) => Math.abs(value / majorUnit - Math.round(value / majorUnit)) > tolerance
3843
+ );
3844
+ }
3845
+ function computeValueRangeForChart(series, axes) {
3846
+ const primaryAxis = axes?.find((axis) => axis.axisType === "valAx" && axis.axPos === "l") ?? axes?.find((axis) => axis.axisType === "valAx" && axis.axPos !== "r");
3847
+ return computeValueRangeForAxis(series, primaryAxis);
3513
3848
  }
3514
3849
  var DISPLAY_UNIT_DIVISORS = {
3515
3850
  hundreds: 100,
@@ -3595,6 +3930,13 @@ function getSecondaryValueAxisId(axes) {
3595
3930
  const ax = getSecondaryValueAxis(axes);
3596
3931
  return ax?.axisId;
3597
3932
  }
3933
+ function getPrimaryValueAxisId(axes) {
3934
+ if (!axes) {
3935
+ return void 0;
3936
+ }
3937
+ const primary = axes.find((a) => a.axisType === "valAx" && a.axPos === "l");
3938
+ return primary?.axisId ?? axes.find((a) => a.axisType === "valAx")?.axisId;
3939
+ }
3598
3940
  function isSeriesOnSecondaryAxis(series, axes) {
3599
3941
  if (!axes) {
3600
3942
  return false;
@@ -3620,41 +3962,199 @@ function splitSeriesByAxis(series, axes) {
3620
3962
  }
3621
3963
  return { primary, secondary };
3622
3964
  }
3965
+ function clamp3(value, min, max) {
3966
+ return Math.min(Math.max(value, min), max);
3967
+ }
3968
+ function horizontalAxisY(valueAxis, range, layout, fallback) {
3969
+ if (valueAxis?.crosses === "max") {
3970
+ return layout.plotTop;
3971
+ }
3972
+ if (valueAxis?.crosses === "min") {
3973
+ return layout.plotBottom;
3974
+ }
3975
+ const crossingValue = valueAxis?.crossesAt ?? 0;
3976
+ if (valueAxis?.crossesAt !== void 0 || valueAxis?.crosses === "autoZero") {
3977
+ return valueToY2(
3978
+ clamp3(crossingValue, range.min, range.max),
3979
+ range,
3980
+ layout.plotTop,
3981
+ layout.plotBottom
3982
+ );
3983
+ }
3984
+ return fallback === "top" ? layout.plotTop : layout.plotBottom;
3985
+ }
3986
+ function verticalAxisX(categoryAxis, categoryCount, layout, fallback, dateValues) {
3987
+ if (categoryAxis?.crosses === "max") {
3988
+ return layout.plotRight;
3989
+ }
3990
+ if (categoryAxis?.crosses === "min") {
3991
+ return layout.plotLeft;
3992
+ }
3993
+ if (categoryAxis?.crossesAt !== void 0) {
3994
+ if (categoryAxis.axisType === "dateAx" && dateValues?.length) {
3995
+ const min = categoryAxis.min ?? Math.min(...dateValues);
3996
+ const max = categoryAxis.max ?? Math.max(...dateValues);
3997
+ const ratio2 = max === min ? 0.5 : (clamp3(categoryAxis.crossesAt, min, max) - min) / (max - min);
3998
+ return layout.plotLeft + ratio2 * layout.plotWidth;
3999
+ }
4000
+ const index = clamp3(categoryAxis.crossesAt - 1, 0, Math.max(categoryCount - 1, 0));
4001
+ const ratio = categoryCount <= 1 ? 0.5 : index / (categoryCount - 1);
4002
+ return layout.plotLeft + ratio * layout.plotWidth;
4003
+ }
4004
+ return fallback === "right" ? layout.plotRight : layout.plotLeft;
4005
+ }
4006
+ var DEFAULT_COLOR2 = "#64748b";
4007
+ function dashArray(style, width) {
4008
+ if (!style || style === "solid") {
4009
+ return void 0;
4010
+ }
4011
+ const unit = Math.max(width, 1);
4012
+ if (style === "dot" || style === "sysDot") {
4013
+ return `${unit} ${unit * 2}`;
4014
+ }
4015
+ if (style === "lgDash") {
4016
+ return `${unit * 6} ${unit * 3}`;
4017
+ }
4018
+ return `${unit * 3} ${unit * 2}`;
4019
+ }
4020
+ function chartAxisTextStyle(axis, defaultFontSize = 8) {
4021
+ return {
4022
+ fontSize: axis?.fontSize ?? defaultFontSize,
4023
+ fill: axis?.fontColor ?? DEFAULT_COLOR2,
4024
+ ...axis?.fontBold !== void 0 ? { fontWeight: axis.fontBold ? "bold" : "normal" } : {},
4025
+ ...axis?.fontFamily ? { fontFamily: axis.fontFamily } : {}
4026
+ };
4027
+ }
4028
+ function chartLineStyle(shape, fallbackColor = DEFAULT_COLOR2, fallbackWidth = 1) {
4029
+ const strokeWidth = shape?.strokeWidth ?? fallbackWidth;
4030
+ return {
4031
+ stroke: shape?.strokeColor ?? fallbackColor,
4032
+ strokeWidth,
4033
+ ...dashArray(shape?.strokeDashStyle, strokeWidth) ? { dashArray: dashArray(shape?.strokeDashStyle, strokeWidth) } : {}
4034
+ };
4035
+ }
4036
+ function buildVerticalTickMark(axisX, y, placement, side, length, shape) {
4037
+ if (!placement || placement === "none") {
4038
+ return void 0;
4039
+ }
4040
+ const inward = side === "left" ? 1 : -1;
4041
+ const startOffset = placement === "cross" ? -inward * length : 0;
4042
+ const endOffset = placement === "out" ? -inward * length : inward * length;
4043
+ return {
4044
+ kind: "line",
4045
+ x1: axisX + startOffset,
4046
+ y1: y,
4047
+ x2: axisX + endOffset,
4048
+ y2: y,
4049
+ ...chartLineStyle(shape)
4050
+ };
4051
+ }
4052
+ function buildVerticalAxisLine(axis, axisX, layout) {
4053
+ return axis?.spPr ? {
4054
+ kind: "line",
4055
+ x1: axisX,
4056
+ y1: layout.plotTop,
4057
+ x2: axisX,
4058
+ y2: layout.plotBottom,
4059
+ ...chartLineStyle(axis.spPr)
4060
+ } : void 0;
4061
+ }
4062
+ function buildStyledGridline(y, layout, shape, fallbackColor, fallbackWidth, fallbackDash, opacity) {
4063
+ const style = chartLineStyle(shape, fallbackColor, fallbackWidth);
4064
+ return {
4065
+ kind: "line",
4066
+ x1: layout.plotLeft,
4067
+ y1: y,
4068
+ x2: layout.plotRight,
4069
+ y2: y,
4070
+ ...style,
4071
+ ...(shape ? style.dashArray : fallbackDash) ? { dashArray: shape ? style.dashArray : fallbackDash } : {},
4072
+ ...opacity !== void 0 ? { opacity } : {}
4073
+ };
4074
+ }
3623
4075
  var GRIDLINE_COLOR = "#e2e8f0";
3624
- var AXIS_LABEL_COLOR = "#64748b";
3625
4076
  var SECONDARY_GRID_COLOR = "#e2e8f0";
3626
4077
  var TICK_COUNT = 5;
4078
+ var MAJOR_TICK_LENGTH = 4;
4079
+ var MINOR_TICK_LENGTH = 2.5;
4080
+ function valueAxisLabelPlacement(layout, position, defaultSide, axisX) {
4081
+ if (!position || position === "nextTo") {
4082
+ return defaultSide === "left" ? { x: axisX - 4, textAnchor: "end" } : { x: axisX + 4, textAnchor: "start" };
4083
+ }
4084
+ const side = position === "high" ? "right" : position === "low" ? "left" : defaultSide;
4085
+ return side === "left" ? { x: layout.plotLeft - 4, textAnchor: "end" } : { x: layout.plotRight + 4, textAnchor: "start" };
4086
+ }
3627
4087
  function formatTick(val2, axis) {
3628
4088
  if (axis?.displayUnits) {
3629
4089
  return formatAxisValueWithUnits(val2, axis);
3630
4090
  }
3631
4091
  return formatAxisValue2(val2);
3632
4092
  }
3633
- function buildPrimaryAxis(range, layout, axis) {
4093
+ function buildPrimaryAxis(range, layout, axis, axisX = layout.plotLeft) {
3634
4094
  const gridlines = [];
3635
4095
  const axisLabels = [];
3636
- const tickVals = range.logScale && range.logBase ? generateLogTicks(range) : Array.from({ length: TICK_COUNT + 1 }, (_, i) => range.min + range.span / TICK_COUNT * i);
4096
+ const tickVals = generateAxisTicks(range, axis, TICK_COUNT);
4097
+ const minorTickVals = generateMinorAxisTicks(range, axis);
4098
+ const axisLine = buildVerticalAxisLine(axis, axisX, layout);
4099
+ if (axisLine) {
4100
+ gridlines.push(axisLine);
4101
+ }
4102
+ if (axis?.minorGridlines) {
4103
+ for (const val2 of minorTickVals) {
4104
+ const y = valueToY2(val2, range, layout.plotTop, layout.plotBottom);
4105
+ gridlines.push(
4106
+ buildStyledGridline(y, layout, axis.minorGridlinesSpPr, GRIDLINE_COLOR, 0.5, "1 2", 0.5)
4107
+ );
4108
+ }
4109
+ }
4110
+ for (const val2 of minorTickVals) {
4111
+ const y = valueToY2(val2, range, layout.plotTop, layout.plotBottom);
4112
+ const tick = buildVerticalTickMark(
4113
+ axisX,
4114
+ y,
4115
+ axis?.minorTickMark,
4116
+ "left",
4117
+ MINOR_TICK_LENGTH,
4118
+ axis?.spPr
4119
+ );
4120
+ if (tick) {
4121
+ gridlines.push(tick);
4122
+ }
4123
+ }
3637
4124
  for (const val2 of tickVals) {
3638
4125
  const y = valueToY2(val2, range, layout.plotTop, layout.plotBottom);
3639
- gridlines.push({
3640
- kind: "line",
3641
- x1: layout.plotLeft,
3642
- y1: y,
3643
- x2: layout.plotRight,
3644
- y2: y,
3645
- stroke: GRIDLINE_COLOR,
3646
- strokeWidth: 1
3647
- });
3648
- axisLabels.push({
3649
- kind: "text",
3650
- x: layout.plotLeft - 4,
4126
+ gridlines.push(
4127
+ buildStyledGridline(
4128
+ y,
4129
+ layout,
4130
+ axis?.majorGridlinesSpPr,
4131
+ GRIDLINE_COLOR,
4132
+ 1,
4133
+ void 0,
4134
+ void 0
4135
+ )
4136
+ );
4137
+ const tick = buildVerticalTickMark(
4138
+ axisX,
3651
4139
  y,
3652
- text: formatTick(val2, axis),
3653
- fontSize: 8,
3654
- fill: AXIS_LABEL_COLOR,
3655
- textAnchor: "end",
3656
- dominantBaseline: "central"
3657
- });
4140
+ axis?.majorTickMark,
4141
+ "left",
4142
+ MAJOR_TICK_LENGTH,
4143
+ axis?.spPr
4144
+ );
4145
+ if (tick) {
4146
+ gridlines.push(tick);
4147
+ }
4148
+ if (axis?.tickLblPos !== "none") {
4149
+ axisLabels.push({
4150
+ kind: "text",
4151
+ ...valueAxisLabelPlacement(layout, axis?.tickLblPos, "left", axisX),
4152
+ y,
4153
+ text: formatTick(val2, axis),
4154
+ ...chartAxisTextStyle(axis),
4155
+ dominantBaseline: "central"
4156
+ });
4157
+ }
3658
4158
  }
3659
4159
  if (axis?.displayUnits) {
3660
4160
  const unitLabel = getDisplayUnitLabel(axis.displayUnits, axis.displayUnitsLabel);
@@ -3666,8 +4166,7 @@ function buildPrimaryAxis(range, layout, axis) {
3666
4166
  x: labelX,
3667
4167
  y: midY,
3668
4168
  text: unitLabel,
3669
- fontSize: 9,
3670
- fill: AXIS_LABEL_COLOR,
4169
+ ...chartAxisTextStyle(axis, 9),
3671
4170
  textAnchor: "middle",
3672
4171
  transform: `rotate(-90, ${labelX}, ${midY})`
3673
4172
  });
@@ -3675,37 +4174,81 @@ function buildPrimaryAxis(range, layout, axis) {
3675
4174
  }
3676
4175
  return { gridlines, axisLabels };
3677
4176
  }
3678
- function buildSecondaryAxis(range, layout, axis) {
4177
+ function buildSecondaryAxis(range, layout, axis, axisX = layout.plotRight) {
3679
4178
  const gridlines = [];
3680
4179
  const axisLabels = [];
3681
- const fontSize = axis?.fontSize ?? 8;
3682
- const fontColor = axis?.fontColor ?? AXIS_LABEL_COLOR;
3683
- const fontWeight = axis?.fontBold ? "bold" : "normal";
3684
- for (let i = 0; i <= TICK_COUNT - 1; i++) {
3685
- const val2 = range.min + range.span / (TICK_COUNT - 1) * i;
4180
+ const textStyle = chartAxisTextStyle(axis);
4181
+ const captionStyle = chartAxisTextStyle(axis, 9);
4182
+ const axisLine = buildVerticalAxisLine(axis, axisX, layout);
4183
+ if (axisLine) {
4184
+ gridlines.push(axisLine);
4185
+ }
4186
+ const tickValues = generateAxisTicks(range, axis, TICK_COUNT - 1);
4187
+ const minorTickValues = generateMinorAxisTicks(range, axis);
4188
+ if (axis?.minorGridlines) {
4189
+ for (const val2 of minorTickValues) {
4190
+ const y = valueToY2(val2, range, layout.plotTop, layout.plotBottom);
4191
+ gridlines.push(
4192
+ buildStyledGridline(
4193
+ y,
4194
+ layout,
4195
+ axis.minorGridlinesSpPr,
4196
+ SECONDARY_GRID_COLOR,
4197
+ 0.5,
4198
+ "1 2",
4199
+ 0.35
4200
+ )
4201
+ );
4202
+ }
4203
+ }
4204
+ for (const val2 of minorTickValues) {
3686
4205
  const y = valueToY2(val2, range, layout.plotTop, layout.plotBottom);
3687
- gridlines.push({
3688
- kind: "line",
3689
- x1: layout.plotLeft,
3690
- y1: y,
3691
- x2: layout.plotRight,
3692
- y2: y,
3693
- stroke: SECONDARY_GRID_COLOR,
3694
- strokeWidth: 0.5,
3695
- dashArray: "2 3",
3696
- opacity: 0.5
3697
- });
3698
- axisLabels.push({
3699
- kind: "text",
3700
- x: layout.plotRight + 4,
4206
+ const tick = buildVerticalTickMark(
4207
+ axisX,
3701
4208
  y,
3702
- text: formatTick(val2, axis),
3703
- fontSize,
3704
- fill: fontColor,
3705
- textAnchor: "start",
3706
- fontWeight,
3707
- dominantBaseline: "central"
3708
- });
4209
+ axis?.minorTickMark,
4210
+ "right",
4211
+ MINOR_TICK_LENGTH,
4212
+ axis?.spPr
4213
+ );
4214
+ if (tick) {
4215
+ gridlines.push(tick);
4216
+ }
4217
+ }
4218
+ for (const val2 of tickValues) {
4219
+ const y = valueToY2(val2, range, layout.plotTop, layout.plotBottom);
4220
+ gridlines.push(
4221
+ buildStyledGridline(
4222
+ y,
4223
+ layout,
4224
+ axis?.majorGridlinesSpPr,
4225
+ SECONDARY_GRID_COLOR,
4226
+ 0.5,
4227
+ "2 3",
4228
+ 0.5
4229
+ )
4230
+ );
4231
+ const tick = buildVerticalTickMark(
4232
+ axisX,
4233
+ y,
4234
+ axis?.majorTickMark,
4235
+ "right",
4236
+ MAJOR_TICK_LENGTH,
4237
+ axis?.spPr
4238
+ );
4239
+ if (tick) {
4240
+ gridlines.push(tick);
4241
+ }
4242
+ if (axis?.tickLblPos !== "none") {
4243
+ axisLabels.push({
4244
+ kind: "text",
4245
+ ...valueAxisLabelPlacement(layout, axis?.tickLblPos, "right", axisX),
4246
+ y,
4247
+ text: formatTick(val2, axis),
4248
+ ...textStyle,
4249
+ dominantBaseline: "central"
4250
+ });
4251
+ }
3709
4252
  }
3710
4253
  if (axis?.titleText) {
3711
4254
  const titleX = layout.plotRight + 36;
@@ -3715,8 +4258,7 @@ function buildSecondaryAxis(range, layout, axis) {
3715
4258
  x: titleX,
3716
4259
  y: midY,
3717
4260
  text: axis.titleText,
3718
- fontSize: 9,
3719
- fill: fontColor,
4261
+ ...captionStyle,
3720
4262
  textAnchor: "middle",
3721
4263
  transform: `rotate(-90, ${titleX}, ${midY})`
3722
4264
  });
@@ -3731,8 +4273,7 @@ function buildSecondaryAxis(range, layout, axis) {
3731
4273
  x: labelX,
3732
4274
  y: midY,
3733
4275
  text: unitLabel,
3734
- fontSize: 9,
3735
- fill: fontColor,
4276
+ ...captionStyle,
3736
4277
  textAnchor: "middle",
3737
4278
  transform: `rotate(-90, ${labelX}, ${midY})`
3738
4279
  });
@@ -3740,13 +4281,60 @@ function buildSecondaryAxis(range, layout, axis) {
3740
4281
  }
3741
4282
  return { gridlines, axisLabels };
3742
4283
  }
4284
+ function hasRicherAxisFeatures(chartData) {
4285
+ return Boolean(
4286
+ chartData.dataTable || chartData.axes?.some(
4287
+ (axis) => axis.crosses !== void 0 || axis.crossesAt !== void 0 || axis.crossBetween !== void 0 || axis.axisType === "valAx" && Boolean(
4288
+ axis.logScale || axis.displayUnits || axis.axPos === "r" || axis.orientation === "maxMin" || axis.majorUnit !== void 0 || axis.minorUnit !== void 0 || axis.minorGridlines || axis.majorTickMark !== void 0 || axis.minorTickMark !== void 0 || axis.tickLblPos !== void 0
4289
+ )
4290
+ )
4291
+ );
4292
+ }
4293
+ function buildCartesianAxes(chartData, layout, primaryRange, secondaryRange, categoryCount) {
4294
+ if (!hasRicherAxisFeatures(chartData)) {
4295
+ const { gridlines, axisLabels } = buildGridlinesAndLabels(primaryRange, layout);
4296
+ return { gridlines, axisLabels, secondaryGridlines: void 0, secondaryAxisLabels: void 0 };
4297
+ }
4298
+ const primaryAxis = chartData.axes?.find((axis) => axis.axisType === "valAx" && axis.axPos !== "r") ?? chartData.axes?.find((axis) => axis.axisType === "valAx");
4299
+ const categoryAxisFor = (axisId) => chartData.axes?.find(
4300
+ (axis) => (axis.axisType === "catAx" || axis.axisType === "dateAx") && axis.axisId === axisId
4301
+ );
4302
+ const axisX = (axisId, fallback) => verticalAxisX(
4303
+ categoryAxisFor(axisId),
4304
+ categoryCount,
4305
+ layout,
4306
+ fallback,
4307
+ chartData.dateCategories?.values
4308
+ );
4309
+ const primary = buildPrimaryAxis(
4310
+ primaryRange,
4311
+ layout,
4312
+ primaryAxis,
4313
+ axisX(primaryAxis?.crossAxisId, "left")
4314
+ );
4315
+ if (!secondaryRange) {
4316
+ return { ...primary, secondaryGridlines: void 0, secondaryAxisLabels: void 0 };
4317
+ }
4318
+ const secondaryAxis = getSecondaryValueAxis(chartData.axes);
4319
+ const secondary = buildSecondaryAxis(
4320
+ secondaryRange,
4321
+ layout,
4322
+ secondaryAxis,
4323
+ axisX(secondaryAxis?.crossAxisId, "right")
4324
+ );
4325
+ return {
4326
+ ...primary,
4327
+ secondaryGridlines: secondary.gridlines,
4328
+ secondaryAxisLabels: secondary.axisLabels
4329
+ };
4330
+ }
3743
4331
  function categoryTotals(series, catCount) {
3744
4332
  return Array.from(
3745
4333
  { length: catCount },
3746
4334
  (_, ci) => series.reduce((sum, s) => sum + Math.abs(s.values[ci] ?? 0), 0)
3747
4335
  );
3748
4336
  }
3749
- function buildBars(chartData, catCount, layout, primaryRange, secondaryRange, secondaryIdx, grouping) {
4337
+ function buildBars(chartData, catCount, layout, primaryRange, secondaryRange, secondaryIdx, grouping, sourceIndices2) {
3750
4338
  const primitives = [];
3751
4339
  const dataLabels = [];
3752
4340
  const series = chartData.series;
@@ -3757,10 +4345,11 @@ function buildBars(chartData, catCount, layout, primaryRange, secondaryRange, se
3757
4345
  const barGroupWidth2 = layout.plotWidth / Math.max(catCount, 1);
3758
4346
  const singleBarWidth = barGroupWidth2 * 0.7 / seriesCount;
3759
4347
  const groupOffset = (barGroupWidth2 - singleBarWidth * seriesCount) / 2;
3760
- for (let ci = 0; ci < catCount; ci++) {
4348
+ for (let displayIndex = 0; displayIndex < catCount; displayIndex++) {
4349
+ const sourceIndex = sourceIndices2[displayIndex] ?? displayIndex;
3761
4350
  for (let si = 0; si < series.length; si++) {
3762
- const val2 = series[si].values[ci] ?? 0;
3763
- const x = layout.plotLeft + barGroupWidth2 * ci + groupOffset + singleBarWidth * si;
4351
+ const val2 = series[si].values[sourceIndex] ?? 0;
4352
+ const x = layout.plotLeft + barGroupWidth2 * displayIndex + groupOffset + singleBarWidth * si;
3764
4353
  const activeRange = secondaryIdx.has(si) && secondaryRange ? secondaryRange : primaryRange;
3765
4354
  const zeroY = valueToY2(0, activeRange, layout.plotTop, layout.plotBottom);
3766
4355
  const valY = valueToY2(val2, activeRange, layout.plotTop, layout.plotBottom);
@@ -3774,7 +4363,7 @@ function buildBars(chartData, catCount, layout, primaryRange, secondaryRange, se
3774
4363
  h,
3775
4364
  fill: seriesColor2(series[si], si, palette),
3776
4365
  rx: 1,
3777
- part: { role: "dataPoint", seriesIndex: si, pointIndex: ci }
4366
+ part: { role: "dataPoint", seriesIndex: si, pointIndex: sourceIndex }
3778
4367
  });
3779
4368
  if (showLabels) {
3780
4369
  dataLabels.push({
@@ -3792,7 +4381,11 @@ function buildBars(chartData, catCount, layout, primaryRange, secondaryRange, se
3792
4381
  return { primitives, dataLabels };
3793
4382
  }
3794
4383
  if (grouping === "stacked") {
3795
- const rects = computeStackedBarRects(series, catCount, layout, primaryRange, palette);
4384
+ const displaySeries2 = series.map((entry) => ({
4385
+ ...entry,
4386
+ values: sourceIndices2.map((sourceIndex) => entry.values[sourceIndex] ?? 0)
4387
+ }));
4388
+ const rects = computeStackedBarRects(displaySeries2, catCount, layout, primaryRange, palette);
3796
4389
  for (const r of rects) {
3797
4390
  primitives.push({
3798
4391
  kind: "rect",
@@ -3802,24 +4395,33 @@ function buildBars(chartData, catCount, layout, primaryRange, secondaryRange, se
3802
4395
  h: r.h,
3803
4396
  fill: r.fill,
3804
4397
  rx: 1,
3805
- part: r.seriesIndex !== void 0 && r.pointIndex !== void 0 ? { role: "dataPoint", seriesIndex: r.seriesIndex, pointIndex: r.pointIndex } : void 0
4398
+ part: r.seriesIndex !== void 0 && r.pointIndex !== void 0 ? {
4399
+ role: "dataPoint",
4400
+ seriesIndex: r.seriesIndex,
4401
+ pointIndex: sourceIndices2[r.pointIndex] ?? r.pointIndex
4402
+ } : void 0
3806
4403
  });
3807
4404
  }
3808
4405
  if (showLabels) {
3809
- pushClusteredStackedLabels(series, catCount, layout, primaryRange, dataLabels);
4406
+ pushClusteredStackedLabels(series, sourceIndices2, catCount, layout, primaryRange, dataLabels);
3810
4407
  }
3811
4408
  return { primitives, dataLabels };
3812
4409
  }
3813
4410
  const barGroupWidth = layout.plotWidth / Math.max(catCount, 1);
3814
4411
  const barW = barGroupWidth * 0.6;
3815
4412
  const barOffset = (barGroupWidth - barW) / 2;
3816
- const totals = categoryTotals(series, catCount);
4413
+ const displaySeries = series.map((entry) => ({
4414
+ ...entry,
4415
+ values: sourceIndices2.map((sourceIndex) => entry.values[sourceIndex] ?? 0)
4416
+ }));
4417
+ const totals = categoryTotals(displaySeries, catCount);
3817
4418
  for (let ci = 0; ci < catCount; ci++) {
3818
4419
  let posRunning = 0;
3819
4420
  let negRunning = 0;
3820
4421
  const catTotal = totals[ci] || 1;
3821
4422
  for (let si = 0; si < series.length; si++) {
3822
- const rawVal = series[si].values[ci] ?? 0;
4423
+ const sourceIndex = sourceIndices2[ci] ?? ci;
4424
+ const rawVal = series[si].values[sourceIndex] ?? 0;
3823
4425
  const val2 = catTotal > 0 ? rawVal / catTotal * 100 : 0;
3824
4426
  const isNeg = val2 < 0;
3825
4427
  const base = isNeg ? negRunning : posRunning;
@@ -3836,7 +4438,7 @@ function buildBars(chartData, catCount, layout, primaryRange, secondaryRange, se
3836
4438
  w: barW,
3837
4439
  h,
3838
4440
  fill: seriesColor2(series[si], si, palette),
3839
- part: { role: "dataPoint", seriesIndex: si, pointIndex: ci }
4441
+ part: { role: "dataPoint", seriesIndex: si, pointIndex: sourceIndex }
3840
4442
  });
3841
4443
  if (showLabels && Math.abs(val2) > 0) {
3842
4444
  dataLabels.push({
@@ -3859,14 +4461,15 @@ function buildBars(chartData, catCount, layout, primaryRange, secondaryRange, se
3859
4461
  }
3860
4462
  return { primitives, dataLabels };
3861
4463
  }
3862
- function pushClusteredStackedLabels(series, catCount, layout, range, dataLabels) {
4464
+ function pushClusteredStackedLabels(series, sourceIndices2, catCount, layout, range, dataLabels) {
3863
4465
  const barGroupWidth = layout.plotWidth / catCount;
3864
4466
  const seriesCount = Math.max(series.length, 1);
3865
4467
  const singleBarWidth = barGroupWidth * 0.7 / seriesCount;
3866
4468
  const groupOffset = (barGroupWidth - singleBarWidth * seriesCount) / 2;
3867
4469
  for (let ci = 0; ci < catCount; ci++) {
4470
+ const sourceIndex = sourceIndices2[ci] ?? ci;
3868
4471
  for (let si = 0; si < series.length; si++) {
3869
- const val2 = series[si].values[ci] ?? 0;
4472
+ const val2 = series[si].values[sourceIndex] ?? 0;
3870
4473
  const x = layout.plotLeft + barGroupWidth * ci + groupOffset + singleBarWidth * si + singleBarWidth / 2;
3871
4474
  const zeroY = valueToY2(0, range, layout.plotTop, layout.plotBottom);
3872
4475
  const valY = valueToY2(val2, range, layout.plotTop, layout.plotBottom);
@@ -3883,7 +4486,7 @@ function pushClusteredStackedLabels(series, catCount, layout, range, dataLabels)
3883
4486
  }
3884
4487
  }
3885
4488
  }
3886
- function buildLines(chartData, catCount, layout, primaryRange, secondaryRange, secondaryIdx) {
4489
+ function buildLines(chartData, catCount, layout, primaryRange, secondaryRange, secondaryIdx, sourceIndices2, xPositions) {
3887
4490
  const primitives = [];
3888
4491
  const dataLabels = [];
3889
4492
  const showLabels = chartData.style?.hasDataLabels;
@@ -3893,7 +4496,13 @@ function buildLines(chartData, catCount, layout, primaryRange, secondaryRange, s
3893
4496
  continue;
3894
4497
  }
3895
4498
  const activeRange = secondaryIdx.has(si) && secondaryRange ? secondaryRange : primaryRange;
3896
- const pts = computeLinePoints(series.values, catCount, layout, activeRange);
4499
+ const displayValues = sourceIndices2.map((sourceIndex) => series.values[sourceIndex] ?? 0);
4500
+ const pts = computeLinePoints(displayValues, catCount, layout, activeRange).map(
4501
+ (point, index) => ({
4502
+ ...point,
4503
+ x: xPositions?.[index] ?? point.x
4504
+ })
4505
+ );
3897
4506
  const c = seriesColor2(series, si, chartData.colorPalette);
3898
4507
  primitives.push({
3899
4508
  kind: "polyline",
@@ -3903,19 +4512,20 @@ function buildLines(chartData, catCount, layout, primaryRange, secondaryRange, s
3903
4512
  fill: "none",
3904
4513
  part: { role: "series", seriesIndex: si }
3905
4514
  });
3906
- pts.forEach((pt, vi) => {
4515
+ pts.forEach((pt, displayIndex) => {
4516
+ const sourceIndex = sourceIndices2[displayIndex] ?? displayIndex;
3907
4517
  primitives.push({
3908
4518
  kind: "circle",
3909
4519
  cx: pt.x,
3910
4520
  cy: pt.y,
3911
4521
  r: 2.5,
3912
4522
  fill: c,
3913
- part: { role: "dataPoint", seriesIndex: si, pointIndex: vi }
4523
+ part: { role: "dataPoint", seriesIndex: si, pointIndex: sourceIndex }
3914
4524
  });
3915
4525
  });
3916
4526
  if (showLabels) {
3917
- series.values.forEach((val2, vi) => {
3918
- const pt = pts[vi];
4527
+ displayValues.forEach((val2, displayIndex) => {
4528
+ const pt = pts[displayIndex];
3919
4529
  if (!pt) {
3920
4530
  return;
3921
4531
  }
@@ -3933,7 +4543,7 @@ function buildLines(chartData, catCount, layout, primaryRange, secondaryRange, s
3933
4543
  }
3934
4544
  return { primitives, dataLabels };
3935
4545
  }
3936
- function buildAreas(chartData, catCount, layout, range) {
4546
+ function buildAreas(chartData, catCount, layout, range, sourceIndices2, xPositions) {
3937
4547
  const primitives = [];
3938
4548
  const dataLabels = [];
3939
4549
  const showLabels = chartData.style?.hasDataLabels;
@@ -3943,7 +4553,11 @@ function buildAreas(chartData, catCount, layout, range) {
3943
4553
  if (series.values.length === 0) {
3944
4554
  continue;
3945
4555
  }
3946
- const pts = computeLinePoints(series.values, catCount, layout, range);
4556
+ const displayValues = sourceIndices2.map((sourceIndex) => series.values[sourceIndex] ?? 0);
4557
+ const pts = computeLinePoints(displayValues, catCount, layout, range).map((point, index) => ({
4558
+ ...point,
4559
+ x: xPositions?.[index] ?? point.x
4560
+ }));
3947
4561
  const c = seriesColor2(series, si, chartData.colorPalette);
3948
4562
  const lineStr = linePointsToSvgString(pts);
3949
4563
  const firstPt = pts[0];
@@ -3951,7 +4565,7 @@ function buildAreas(chartData, catCount, layout, range) {
3951
4565
  if (firstPt && lastPt) {
3952
4566
  primitives.push({
3953
4567
  kind: "polyline",
3954
- points: `${layout.plotLeft.toFixed(2)},${baselineY.toFixed(2)} ${lineStr} ${lastPt.x.toFixed(2)},${baselineY.toFixed(2)}`,
4568
+ points: `${firstPt.x.toFixed(2)},${baselineY.toFixed(2)} ${lineStr} ${lastPt.x.toFixed(2)},${baselineY.toFixed(2)}`,
3955
4569
  stroke: "none",
3956
4570
  strokeWidth: 0,
3957
4571
  fill: c,
@@ -3967,9 +4581,23 @@ function buildAreas(chartData, catCount, layout, range) {
3967
4581
  fill: "none",
3968
4582
  part: { role: "series", seriesIndex: si }
3969
4583
  });
4584
+ pts.forEach((pt, displayIndex) => {
4585
+ primitives.push({
4586
+ kind: "circle",
4587
+ cx: pt.x,
4588
+ cy: pt.y,
4589
+ r: 2,
4590
+ fill: c,
4591
+ part: {
4592
+ role: "dataPoint",
4593
+ seriesIndex: si,
4594
+ pointIndex: sourceIndices2[displayIndex] ?? displayIndex
4595
+ }
4596
+ });
4597
+ });
3970
4598
  if (showLabels) {
3971
- series.values.forEach((val2, vi) => {
3972
- const pt = pts[vi];
4599
+ displayValues.forEach((val2, displayIndex) => {
4600
+ const pt = pts[displayIndex];
3973
4601
  if (!pt) {
3974
4602
  return;
3975
4603
  }
@@ -3993,10 +4621,11 @@ function buildScatter(chartData, layout, range) {
3993
4621
  const showLabels = chartData.style?.hasDataLabels;
3994
4622
  const allIndices = chartData.series.flatMap((s) => s.values.map((_, i) => i));
3995
4623
  const maxXIndex = Math.max(1, ...allIndices);
4624
+ const xValues = chartData.categories.map(Number);
3996
4625
  for (let si = 0; si < chartData.series.length; si++) {
3997
4626
  const series = chartData.series[si];
3998
4627
  const c = seriesColor2(series, si, chartData.colorPalette);
3999
- const dots = computeScatterDots(series.values, maxXIndex, layout, range);
4628
+ const dots = computeScatterDots(series.values, maxXIndex, layout, range, xValues);
4000
4629
  dots.forEach((dot, vi) => {
4001
4630
  primitives.push({
4002
4631
  kind: "circle",
@@ -4034,6 +4663,7 @@ function buildBubbles(chartData, layout, range) {
4034
4663
  const showLabels = chartData.style?.hasDataLabels;
4035
4664
  const allIndices = chartData.series.flatMap((s) => s.values.map((_, i) => i));
4036
4665
  const maxXIndex = Math.max(1, ...allIndices);
4666
+ const xValues = chartData.categories.map(Number);
4037
4667
  const sizeSeries = chartData.series.length >= 3 ? chartData.series[2] : void 0;
4038
4668
  const maxBubble = sizeSeries ? Math.max(1, ...sizeSeries.values.map((v) => Math.abs(v))) : 1;
4039
4669
  const medianRadius = Math.min(layout.plotWidth, layout.plotHeight) * 0.04;
@@ -4041,7 +4671,7 @@ function buildBubbles(chartData, layout, range) {
4041
4671
  for (let si = 0; si < pointSeries.length; si++) {
4042
4672
  const series = pointSeries[si];
4043
4673
  const c = seriesColor2(series, si, chartData.colorPalette);
4044
- const dots = computeScatterDots(series.values, maxXIndex, layout, range);
4674
+ const dots = computeScatterDots(series.values, maxXIndex, layout, range, xValues);
4045
4675
  dots.forEach((dot, vi) => {
4046
4676
  const r = computeBubbleRadius(sizeSeries?.values[vi], maxBubble, medianRadius);
4047
4677
  primitives.push({
@@ -4074,12 +4704,527 @@ function buildBubbles(chartData, layout, range) {
4074
4704
  }
4075
4705
  return { primitives, dataLabels };
4076
4706
  }
4077
- function xToPixel2(xVal, catCount, layout, mode) {
4078
- if (mode === "bar") {
4079
- const slotWidth = layout.plotWidth / Math.max(catCount, 1);
4080
- return layout.plotLeft + slotWidth * xVal + slotWidth / 2;
4707
+ function categoryX(displayIndex, count, layout, spacing) {
4708
+ if (spacing === "bar") {
4709
+ return layout.plotLeft + layout.plotWidth / Math.max(count, 1) * (displayIndex + 0.5);
4081
4710
  }
4082
- const maxIdx = Math.max(catCount - 1, 1);
4711
+ return count > 1 ? layout.plotLeft + layout.plotWidth / (count - 1) * displayIndex : layout.plotLeft + layout.plotWidth / 2;
4712
+ }
4713
+ function groupedLabels(values) {
4714
+ const groups = [];
4715
+ values.forEach((text, index) => {
4716
+ const previous = groups[groups.length - 1];
4717
+ if (previous?.text === text) {
4718
+ previous.end = index;
4719
+ } else {
4720
+ groups.push({ text, start: index, end: index });
4721
+ }
4722
+ });
4723
+ return groups;
4724
+ }
4725
+ function buildMultiLevelCategoryLabels(categoryLabels, categoryLevels, sourceIndices2, layout, spacing, axis, labelY, labelsAbove, offset) {
4726
+ const sourceLevels = categoryLevels?.length ? categoryLevels : [categoryLabels];
4727
+ const levels = axis?.noMultiLevelLabels ? sourceLevels.slice(0, 1) : sourceLevels;
4728
+ const skip = Math.max(1, axis?.tickLabelSkip ?? 1);
4729
+ const textAnchor = axis?.labelAlignment === "l" ? "start" : axis?.labelAlignment === "r" ? "end" : "middle";
4730
+ const direction = labelsAbove ? -1 : 1;
4731
+ const bandHeight = Math.max(axis?.fontSize ?? 8, 8) + 4;
4732
+ return levels.flatMap((level, levelIndex) => {
4733
+ const values = sourceIndices2.map((sourceIndex) => level[sourceIndex] ?? "");
4734
+ return groupedLabels(values).flatMap((group) => {
4735
+ if (!group.text || group.start % skip !== 0) {
4736
+ return [];
4737
+ }
4738
+ const startX = categoryX(group.start, sourceIndices2.length, layout, spacing);
4739
+ const endX = categoryX(group.end, sourceIndices2.length, layout, spacing);
4740
+ return [
4741
+ {
4742
+ kind: "text",
4743
+ x: (startX + endX) / 2,
4744
+ y: labelY + direction * (offset + levelIndex * bandHeight),
4745
+ text: group.text,
4746
+ textAnchor,
4747
+ ...chartAxisTextStyle(axis)
4748
+ }
4749
+ ];
4750
+ });
4751
+ });
4752
+ }
4753
+ function primaryCategoryAxis(axes) {
4754
+ const categoryAxes = axes?.filter(
4755
+ (axis) => axis.axisType === "catAx" || axis.axisType === "dateAx"
4756
+ );
4757
+ return categoryAxes?.find((axis) => axis.axPos !== "t") ?? categoryAxes?.[0];
4758
+ }
4759
+ function tickLine(x, y, placement, topAxis, length, axis) {
4760
+ if (!placement || placement === "none") {
4761
+ return void 0;
4762
+ }
4763
+ const inward = topAxis ? length : -length;
4764
+ const outward = -inward;
4765
+ const [start, end] = placement === "cross" ? [-length, length] : placement === "in" ? [0, inward] : [0, outward];
4766
+ return {
4767
+ kind: "line",
4768
+ x1: x,
4769
+ y1: y + start,
4770
+ x2: x,
4771
+ y2: y + end,
4772
+ ...chartLineStyle(axis.spPr)
4773
+ };
4774
+ }
4775
+ function buildTickMarks(axis, sourceCount, layout, spacing, axisY) {
4776
+ if (!axis || axis.deleted) {
4777
+ return [];
4778
+ }
4779
+ const result = [];
4780
+ const topAxis = axis.axPos === "t";
4781
+ const y = axisY ?? (topAxis ? layout.plotTop : layout.plotBottom);
4782
+ if (axis.spPr) {
4783
+ result.push({
4784
+ kind: "line",
4785
+ x1: layout.plotLeft,
4786
+ y1: y,
4787
+ x2: layout.plotRight,
4788
+ y2: y,
4789
+ ...chartLineStyle(axis.spPr)
4790
+ });
4791
+ }
4792
+ const majorSkip = Math.max(1, axis.tickMarkSkip ?? 1);
4793
+ for (let displayIndex = 0; displayIndex < sourceCount; displayIndex += majorSkip) {
4794
+ const x = categoryX(displayIndex, sourceCount, layout, spacing);
4795
+ const major = tickLine(x, y, axis.majorTickMark, topAxis, 4, axis);
4796
+ if (major) {
4797
+ result.push(major);
4798
+ }
4799
+ if (axis.minorTickMark !== void 0 && displayIndex + majorSkip < sourceCount) {
4800
+ const nextX = categoryX(displayIndex + majorSkip, sourceCount, layout, spacing);
4801
+ const minor = tickLine((x + nextX) / 2, y, axis.minorTickMark, topAxis, 2.5, axis);
4802
+ if (minor) {
4803
+ result.push(minor);
4804
+ }
4805
+ }
4806
+ }
4807
+ return result;
4808
+ }
4809
+ function buildCategoryAxisPlan(categoryLabels, layout, spacing, axes, selectedAxis, axisY, categoryLevels) {
4810
+ const axis = selectedAxis ?? primaryCategoryAxis(axes);
4811
+ const sourceIndices2 = categoryLabels.map((_label, index) => index);
4812
+ if (axis?.orientation === "maxMin") {
4813
+ sourceIndices2.reverse();
4814
+ }
4815
+ if (axis?.deleted || axis?.tickLblPos === "none") {
4816
+ return {
4817
+ axis,
4818
+ sourceIndices: sourceIndices2,
4819
+ labels: [],
4820
+ tickMarks: buildTickMarks(axis, sourceIndices2.length, layout, spacing, axisY)
4821
+ };
4822
+ }
4823
+ const topAxis = axis?.axPos === "t";
4824
+ const high = axis?.tickLblPos === "high";
4825
+ const low = axis?.tickLblPos === "low";
4826
+ const labelsAbove = high || !low && topAxis;
4827
+ const offset = 4 + 8 * ((axis?.labelOffset ?? 100) / 100);
4828
+ const labelY = high ? layout.plotTop : low ? layout.plotBottom : axisY ?? (topAxis ? layout.plotTop : layout.plotBottom);
4829
+ const labels = buildMultiLevelCategoryLabels(
4830
+ categoryLabels,
4831
+ categoryLevels,
4832
+ sourceIndices2,
4833
+ layout,
4834
+ spacing,
4835
+ axis,
4836
+ labelY,
4837
+ labelsAbove,
4838
+ offset
4839
+ );
4840
+ return {
4841
+ axis,
4842
+ sourceIndices: sourceIndices2,
4843
+ labels,
4844
+ tickMarks: buildTickMarks(axis, sourceIndices2.length, layout, spacing, axisY)
4845
+ };
4846
+ }
4847
+ function chartDataInCategoryOrder(chartData, sourceIndices2) {
4848
+ if (sourceIndices2.every((sourceIndex, displayIndex) => sourceIndex === displayIndex)) {
4849
+ return chartData;
4850
+ }
4851
+ return {
4852
+ ...chartData,
4853
+ categories: sourceIndices2.map((sourceIndex) => chartData.categories[sourceIndex] ?? ""),
4854
+ categoryLevels: chartData.categoryLevels?.map(
4855
+ (level) => sourceIndices2.map((sourceIndex) => level[sourceIndex] ?? "")
4856
+ ),
4857
+ series: chartData.series.map((series) => ({
4858
+ ...series,
4859
+ values: sourceIndices2.map((sourceIndex) => series.values[sourceIndex] ?? 0),
4860
+ errBars: series.errBars?.map((errorBars) => ({
4861
+ ...errorBars,
4862
+ customPlus: errorBars.customPlus ? sourceIndices2.map((sourceIndex) => errorBars.customPlus?.[sourceIndex] ?? 0) : void 0,
4863
+ customMinus: errorBars.customMinus ? sourceIndices2.map((sourceIndex) => errorBars.customMinus?.[sourceIndex] ?? 0) : void 0
4864
+ }))
4865
+ }))
4866
+ };
4867
+ }
4868
+ var DAY_MS = 864e5;
4869
+ function excelSerialToDate(serial, date1904 = false) {
4870
+ const epoch = date1904 ? Date.UTC(1904, 0, 1) : Date.UTC(1899, 11, serial < 60 ? 31 : 30);
4871
+ return new Date(epoch + serial * DAY_MS);
4872
+ }
4873
+ function primaryDateAxis(chartData) {
4874
+ return chartData.axes?.find((axis) => axis.axisType === "dateAx" && axis.axPos !== "t") ?? chartData.axes?.find((axis) => axis.axisType === "dateAx");
4875
+ }
4876
+ function serialToX(serial, min, max, layout) {
4877
+ const ratio = max === min ? 0.5 : (serial - min) / (max - min);
4878
+ return layout.plotLeft + ratio * layout.plotWidth;
4879
+ }
4880
+ function addUnit(date, amount, unit) {
4881
+ const next = new Date(date);
4882
+ if (unit === "days") {
4883
+ next.setUTCDate(next.getUTCDate() + amount);
4884
+ } else if (unit === "months") {
4885
+ next.setUTCMonth(next.getUTCMonth() + amount);
4886
+ } else {
4887
+ next.setUTCFullYear(next.getUTCFullYear() + amount);
4888
+ }
4889
+ return next;
4890
+ }
4891
+ function formatDate(date, unit, format) {
4892
+ const month = date.toLocaleString("en-US", { month: "short", timeZone: "UTC" });
4893
+ const year = String(date.getUTCFullYear());
4894
+ const day = String(date.getUTCDate());
4895
+ if (format?.toLowerCase().includes("yyyy")) {
4896
+ return format.toLowerCase().includes("d") ? `${day} ${month} ${year}` : `${month} ${year}`;
4897
+ }
4898
+ if (unit === "years") {
4899
+ return year;
4900
+ }
4901
+ if (unit === "months") {
4902
+ return `${month} ${year}`;
4903
+ }
4904
+ return `${day} ${month}`;
4905
+ }
4906
+ function tickLine2(x, y, axis, minor) {
4907
+ const placement = minor ? axis.minorTickMark : axis.majorTickMark;
4908
+ if (!placement || placement === "none") {
4909
+ return void 0;
4910
+ }
4911
+ const length = minor ? 2.5 : 4;
4912
+ const direction = axis.axPos === "t" ? 1 : -1;
4913
+ const inward = direction * length;
4914
+ const outward = -inward;
4915
+ const [start, end] = placement === "cross" ? [-length, length] : placement === "in" ? [0, inward] : [0, outward];
4916
+ return {
4917
+ kind: "line",
4918
+ x1: x,
4919
+ y1: y + start,
4920
+ x2: x,
4921
+ y2: y + end,
4922
+ ...chartLineStyle(axis.spPr)
4923
+ };
4924
+ }
4925
+ function calendarTicks(min, max, date1904, unit, step) {
4926
+ const result = [];
4927
+ let date = excelSerialToDate(min, date1904);
4928
+ for (let guard = 0; guard < 1e3 && date.getTime() <= excelSerialToDate(max, date1904).getTime(); guard++) {
4929
+ result.push(min + (date.getTime() - excelSerialToDate(min, date1904).getTime()) / DAY_MS);
4930
+ date = addUnit(date, step, unit);
4931
+ }
4932
+ return result;
4933
+ }
4934
+ function buildDateAxisPlan(chartData, layout, selectedAxis, axisY) {
4935
+ const dates = chartData.dateCategories;
4936
+ const axis = selectedAxis ?? primaryDateAxis(chartData);
4937
+ if (!dates || !axis || dates.values.length === 0) {
4938
+ return void 0;
4939
+ }
4940
+ const indexed = dates.values.map((value, index) => ({ value, index })).sort((a, b) => a.value - b.value);
4941
+ const dataMin = indexed[0]?.value ?? 0;
4942
+ const dataMax = indexed[indexed.length - 1]?.value ?? dataMin;
4943
+ const min = axis.min ?? dataMin;
4944
+ const max = axis.max ?? dataMax;
4945
+ const visible = indexed.filter(({ value }) => value >= min && value <= max);
4946
+ if (axis.orientation === "maxMin") {
4947
+ visible.reverse();
4948
+ }
4949
+ const sourceIndices2 = visible.map(({ index }) => index);
4950
+ const xPositions = visible.map(({ value }) => {
4951
+ const x = serialToX(value, min, max, layout);
4952
+ return axis.orientation === "maxMin" ? layout.plotLeft + layout.plotWidth - (x - layout.plotLeft) : x;
4953
+ });
4954
+ const unit = axis.majorTimeUnit ?? axis.baseTimeUnit ?? "days";
4955
+ const ticks = calendarTicks(
4956
+ min,
4957
+ max,
4958
+ dates.date1904 ?? false,
4959
+ unit,
4960
+ Math.max(1, axis.majorUnit ?? 1)
4961
+ );
4962
+ const y = axisY ?? (axis.axPos === "t" ? layout.plotTop : layout.plotBottom);
4963
+ const offset = 4 + 8 * ((axis.labelOffset ?? 100) / 100);
4964
+ const labelsAbove = axis.tickLblPos === "high" || axis.tickLblPos !== "low" && axis.axPos === "t";
4965
+ const labelY = axis.tickLblPos === "high" ? layout.plotTop : axis.tickLblPos === "low" ? layout.plotBottom : y;
4966
+ const labelSkip = Math.max(1, axis.tickLabelSkip ?? 1);
4967
+ const labels = axis.deleted || axis.tickLblPos === "none" ? [] : ticks.flatMap((serial, index) => {
4968
+ if (index % labelSkip !== 0) {
4969
+ return [];
4970
+ }
4971
+ let x = serialToX(serial, min, max, layout);
4972
+ if (axis.orientation === "maxMin") {
4973
+ x = layout.plotLeft + layout.plotWidth - (x - layout.plotLeft);
4974
+ }
4975
+ return [
4976
+ {
4977
+ kind: "text",
4978
+ x,
4979
+ y: labelsAbove ? labelY - offset : labelY + offset,
4980
+ text: formatDate(
4981
+ excelSerialToDate(serial, dates.date1904),
4982
+ unit,
4983
+ axis.numFmt?.formatCode ?? dates.formatCode
4984
+ ),
4985
+ ...chartAxisTextStyle(axis),
4986
+ textAnchor: "middle"
4987
+ }
4988
+ ];
4989
+ });
4990
+ const tickMarks = axis.deleted ? [] : ticks.flatMap((serial, index) => {
4991
+ if (index % Math.max(1, axis.tickMarkSkip ?? 1) !== 0) {
4992
+ return [];
4993
+ }
4994
+ let x = serialToX(serial, min, max, layout);
4995
+ if (axis.orientation === "maxMin") {
4996
+ x = layout.plotLeft + layout.plotWidth - (x - layout.plotLeft);
4997
+ }
4998
+ const line2 = tickLine2(x, y, axis, false);
4999
+ return line2 ? [line2] : [];
5000
+ });
5001
+ if (!axis.deleted && axis.spPr) {
5002
+ tickMarks.unshift({
5003
+ kind: "line",
5004
+ x1: layout.plotLeft,
5005
+ y1: y,
5006
+ x2: layout.plotRight,
5007
+ y2: y,
5008
+ ...chartLineStyle(axis.spPr)
5009
+ });
5010
+ }
5011
+ if (!axis.deleted && axis.minorTickMark && axis.minorTickMark !== "none") {
5012
+ const minorUnit = axis.minorTimeUnit ?? axis.baseTimeUnit ?? unit;
5013
+ for (const serial of calendarTicks(
5014
+ min,
5015
+ max,
5016
+ dates.date1904 ?? false,
5017
+ minorUnit,
5018
+ Math.max(1, axis.minorUnit ?? 1)
5019
+ )) {
5020
+ let x = serialToX(serial, min, max, layout);
5021
+ if (axis.orientation === "maxMin") {
5022
+ x = layout.plotLeft + layout.plotWidth - (x - layout.plotLeft);
5023
+ }
5024
+ const line2 = tickLine2(x, y, axis, true);
5025
+ if (line2) {
5026
+ tickMarks.push(line2);
5027
+ }
5028
+ }
5029
+ }
5030
+ return { sourceIndices: sourceIndices2, xPositions, labels, tickMarks };
5031
+ }
5032
+ function buildCartesianHorizontalAxis(chartData, categoryLabels, layout, kind, primaryRange, secondaryRange) {
5033
+ let catAxisStyle = kind === "line" || kind === "area" || kind === "scatter" || kind === "bubble" ? "line" : "bar";
5034
+ const horizontalAxes = chartData.axes?.filter(
5035
+ (axis) => axis.axisType === "catAx" || axis.axisType === "dateAx"
5036
+ );
5037
+ const primaryAxis = horizontalAxes?.find((axis) => axis.axPos !== "t") ?? horizontalAxes?.[0];
5038
+ const secondaryAxis = horizontalAxes?.find((axis) => axis.axPos === "t" && axis !== primaryAxis);
5039
+ const linkedValueAxis = (axis) => chartData.axes?.find(
5040
+ (candidate) => candidate.axisType === "valAx" && candidate.axisId === axis?.crossAxisId
5041
+ );
5042
+ const primaryValueAxis = linkedValueAxis(primaryAxis);
5043
+ if (primaryValueAxis?.crossBetween === "between") {
5044
+ catAxisStyle = "bar";
5045
+ } else if (primaryValueAxis?.crossBetween === "midCat") {
5046
+ catAxisStyle = "line";
5047
+ }
5048
+ const rangeAndY = (axis) => {
5049
+ const valueAxis = linkedValueAxis(axis);
5050
+ const range = valueAxis?.axPos === "r" && secondaryRange ? secondaryRange : primaryRange;
5051
+ return horizontalAxisY(valueAxis, range, layout, axis?.axPos === "t" ? "top" : "bottom");
5052
+ };
5053
+ const supportsDateScale = kind === "line" || kind === "area" || kind === "combo" || kind === "stock";
5054
+ const datePlan = supportsDateScale && primaryAxis?.axisType === "dateAx" ? buildDateAxisPlan(chartData, layout, primaryAxis, rangeAndY(primaryAxis)) : void 0;
5055
+ const categoryPlan = kind === "scatter" || kind === "bubble" || datePlan ? void 0 : buildCategoryAxisPlan(
5056
+ categoryLabels,
5057
+ layout,
5058
+ catAxisStyle,
5059
+ chartData.axes,
5060
+ primaryAxis,
5061
+ rangeAndY(primaryAxis),
5062
+ chartData.categoryLevels
5063
+ );
5064
+ const secondaryPlan = secondaryAxis ? secondaryAxis.axisType === "dateAx" ? buildDateAxisPlan(chartData, layout, secondaryAxis, rangeAndY(secondaryAxis)) : buildCategoryAxisPlan(
5065
+ categoryLabels,
5066
+ layout,
5067
+ linkedValueAxis(secondaryAxis)?.crossBetween === "between" ? "bar" : "line",
5068
+ chartData.axes,
5069
+ secondaryAxis,
5070
+ rangeAndY(secondaryAxis),
5071
+ chartData.categoryLevels
5072
+ ) : void 0;
5073
+ const sourceIndices2 = datePlan?.sourceIndices ?? categoryPlan?.sourceIndices ?? categoryLabels.map((_label, index) => index);
5074
+ return {
5075
+ catAxisStyle,
5076
+ sourceIndices: sourceIndices2,
5077
+ xPositions: datePlan?.xPositions ?? categoryPlan?.sourceIndices.map(
5078
+ (_sourceIndex, displayIndex) => categoryX(displayIndex, categoryPlan.sourceIndices.length, layout, catAxisStyle)
5079
+ ),
5080
+ labels: [
5081
+ ...datePlan?.labels ?? categoryPlan?.labels ?? buildCategoryLabels(categoryLabels, layout, catAxisStyle),
5082
+ ...secondaryPlan?.labels ?? []
5083
+ ],
5084
+ tickMarks: [
5085
+ ...datePlan?.tickMarks ?? categoryPlan?.tickMarks ?? [],
5086
+ ...secondaryPlan?.tickMarks ?? []
5087
+ ],
5088
+ displayChartData: datePlan || categoryPlan ? chartDataInCategoryOrder(chartData, sourceIndices2) : chartData
5089
+ };
5090
+ }
5091
+ var DEFAULT_COLOR3 = "#334155";
5092
+ var CAP_HALF_WIDTH = 4;
5093
+ function categoryX2(value, count, layout, mode) {
5094
+ if (mode === "bar") {
5095
+ const slot = layout.plotWidth / Math.max(count, 1);
5096
+ return layout.plotLeft + slot * value + slot / 2;
5097
+ }
5098
+ return layout.plotLeft + value / Math.max(count - 1, 1) * layout.plotWidth;
5099
+ }
5100
+ function positionedCategoryX(value, positions, fallback) {
5101
+ if (!positions || positions.length === 0) {
5102
+ return fallback(value);
5103
+ }
5104
+ const lower = Math.floor(value);
5105
+ const upper = Math.ceil(value);
5106
+ const at = (index) => {
5107
+ if (positions[index] !== void 0) {
5108
+ return positions[index];
5109
+ }
5110
+ const lastIndex = positions.length - 1;
5111
+ const last = positions[lastIndex] ?? 0;
5112
+ const beforeLast = lastIndex > 0 ? positions[lastIndex - 1] ?? positions[0] ?? 0 : positions[0] ?? 0;
5113
+ const gap = last - beforeLast;
5114
+ return last + gap * (index - positions.length + 1);
5115
+ };
5116
+ return at(lower) + (at(upper) - at(lower)) * (value - lower);
5117
+ }
5118
+ function numericX(value, range, layout) {
5119
+ return layout.plotLeft + (value - range.min) / Math.max(range.span, 1e-9) * layout.plotWidth;
5120
+ }
5121
+ function xValuesForSeries(chartData, series, indexes) {
5122
+ const seriesType = series.seriesChartType ?? chartData.chartType;
5123
+ const numeric = seriesType === "scatter" || seriesType === "bubble";
5124
+ if (!numeric) {
5125
+ return { values: indexes.map((_index, displayIndex) => displayIndex), numeric: false };
5126
+ }
5127
+ return {
5128
+ values: indexes.map((index) => {
5129
+ const parsed = Number(chartData.categories[index]);
5130
+ return Number.isFinite(parsed) ? parsed : index;
5131
+ }),
5132
+ numeric: true
5133
+ };
5134
+ }
5135
+ function numericXRange(values) {
5136
+ const min = Math.min(...values);
5137
+ const max = Math.max(...values);
5138
+ return { min, max, span: Math.max(max - min, 1) };
5139
+ }
5140
+ function errorValue(errBars, values, displayIndex, sourceIndex, direction) {
5141
+ switch (errBars.valType) {
5142
+ case "fixedVal":
5143
+ return errBars.val ?? 0;
5144
+ case "percentage":
5145
+ return Math.abs(values[displayIndex] ?? 0) * ((errBars.val ?? 0) / 100);
5146
+ case "stdDev": {
5147
+ const mean = values.reduce((sum, value) => sum + value, 0) / Math.max(values.length, 1);
5148
+ const variance = values.reduce((sum, value) => sum + (value - mean) ** 2, 0) / Math.max(values.length, 1);
5149
+ return Math.sqrt(variance) * (errBars.val ?? 1);
5150
+ }
5151
+ case "stdErr": {
5152
+ const count = Math.max(values.length, 1);
5153
+ const mean = values.reduce((sum, value) => sum + value, 0) / count;
5154
+ const variance = values.reduce((sum, value) => sum + (value - mean) ** 2, 0) / count;
5155
+ return Math.sqrt(variance / count);
5156
+ }
5157
+ case "cust":
5158
+ return direction === "plus" ? errBars.customPlus?.[sourceIndex] ?? 0 : errBars.customMinus?.[sourceIndex] ?? 0;
5159
+ }
5160
+ }
5161
+ function line(x1, y1, x2, y2, color) {
5162
+ return { kind: "line", x1, y1, x2, y2, stroke: color, strokeWidth: 1 };
5163
+ }
5164
+ function appendYBar(out, errBars, x, baseValue, error, direction, range, layout) {
5165
+ const color = errBars.color ?? DEFAULT_COLOR3;
5166
+ const baseY = valueToY2(baseValue, range, layout.plotTop, layout.plotBottom);
5167
+ const endValue = direction === "plus" ? baseValue + error : baseValue - error;
5168
+ const endY = valueToY2(endValue, range, layout.plotTop, layout.plotBottom);
5169
+ out.push(line(x, baseY, x, endY, color));
5170
+ if (!errBars.noEndCap) {
5171
+ out.push(line(x - CAP_HALF_WIDTH, endY, x + CAP_HALF_WIDTH, endY, color));
5172
+ }
5173
+ }
5174
+ function appendXBar(out, errBars, baseXValue, error, direction, y, toPixel) {
5175
+ const color = errBars.color ?? DEFAULT_COLOR3;
5176
+ const baseX = toPixel(baseXValue);
5177
+ const endValue = direction === "plus" ? baseXValue + error : baseXValue - error;
5178
+ const endX = toPixel(endValue);
5179
+ out.push(line(baseX, y, endX, y, color));
5180
+ if (!errBars.noEndCap) {
5181
+ out.push(line(endX, y - CAP_HALF_WIDTH, endX, y + CAP_HALF_WIDTH, color));
5182
+ }
5183
+ }
5184
+ function computeErrorBarPrimitives(chartData, catCount, layout, range, mode = "line", options = {}) {
5185
+ const out = [];
5186
+ chartData.series.forEach((series, seriesIndex) => {
5187
+ const indexes = options.sourceIndices ?? series.values.map((_value, index) => index);
5188
+ const yValues = indexes.map((index) => series.values[index] ?? 0);
5189
+ const xValues = xValuesForSeries(chartData, series, indexes);
5190
+ const xRange = xValues.numeric ? numericXRange(xValues.values) : void 0;
5191
+ const seriesMode = options.seriesModes?.[seriesIndex] ?? mode;
5192
+ const yRange = options.seriesRanges?.[seriesIndex] ?? range;
5193
+ series.errBars?.forEach((errBars) => {
5194
+ indexes.forEach((sourceIndex, displayIndex) => {
5195
+ const yValue = yValues[displayIndex] ?? 0;
5196
+ const baseXValue = xValues.values[displayIndex] ?? displayIndex;
5197
+ const categoryMapper = (value) => positionedCategoryX(
5198
+ value,
5199
+ options.xPositions,
5200
+ (index) => categoryX2(index, indexes.length || catCount, layout, seriesMode)
5201
+ );
5202
+ const toPixel = xValues.numeric ? (value) => numericX(value, xRange, layout) : categoryMapper;
5203
+ const x = toPixel(baseXValue);
5204
+ const y = valueToY2(yValue, yRange, layout.plotTop, layout.plotBottom);
5205
+ for (const direction of ["plus", "minus"]) {
5206
+ if (errBars.barType !== direction && errBars.barType !== "both") {
5207
+ continue;
5208
+ }
5209
+ const values = errBars.direction === "x" ? xValues.values : yValues;
5210
+ const error = errorValue(errBars, values, displayIndex, sourceIndex, direction);
5211
+ if (errBars.direction === "x") {
5212
+ appendXBar(out, errBars, baseXValue, error, direction, y, toPixel);
5213
+ } else {
5214
+ appendYBar(out, errBars, x, yValue, error, direction, yRange, layout);
5215
+ }
5216
+ }
5217
+ });
5218
+ });
5219
+ });
5220
+ return out;
5221
+ }
5222
+ function xToPixel2(xVal, catCount, layout, mode) {
5223
+ if (mode === "bar") {
5224
+ const slotWidth = layout.plotWidth / Math.max(catCount, 1);
5225
+ return layout.plotLeft + slotWidth * xVal + slotWidth / 2;
5226
+ }
5227
+ const maxIdx = Math.max(catCount - 1, 1);
4083
5228
  return layout.plotLeft + xVal / maxIdx * layout.plotWidth;
4084
5229
  }
4085
5230
  function computeLinearRegression2(xVals, yVals) {
@@ -4328,102 +5473,6 @@ function computeTrendlinePrimitives(chartData, catCount, layout, range, mode = "
4328
5473
  });
4329
5474
  return out;
4330
5475
  }
4331
- function computeErrorValue(errBars, values, pointIndex, direction) {
4332
- switch (errBars.valType) {
4333
- case "fixedVal":
4334
- return errBars.val ?? 0;
4335
- case "percentage":
4336
- return Math.abs(values[pointIndex]) * ((errBars.val ?? 0) / 100);
4337
- case "stdDev": {
4338
- const n = values.length;
4339
- if (n === 0) {
4340
- return 0;
4341
- }
4342
- const mean = values.reduce((s, v) => s + v, 0) / n;
4343
- const variance = values.reduce((s, v) => s + (v - mean) ** 2, 0) / n;
4344
- return Math.sqrt(variance) * (errBars.val ?? 1);
4345
- }
4346
- case "stdErr": {
4347
- const n2 = values.length;
4348
- if (n2 === 0) {
4349
- return 0;
4350
- }
4351
- const mean2 = values.reduce((s, v) => s + v, 0) / n2;
4352
- const variance2 = values.reduce((s, v) => s + (v - mean2) ** 2, 0) / n2;
4353
- return Math.sqrt(variance2 / n2);
4354
- }
4355
- case "cust":
4356
- return direction === "plus" ? errBars.customPlus?.[pointIndex] ?? 0 : errBars.customMinus?.[pointIndex] ?? 0;
4357
- default:
4358
- return 0;
4359
- }
4360
- }
4361
- var ERROR_BAR_COLOR = "#334155";
4362
- function computeErrorBarPrimitives(chartData, catCount, layout, range, mode = "line") {
4363
- const out = [];
4364
- const capW = 4;
4365
- chartData.series.forEach((series) => {
4366
- if (!series.errBars || series.errBars.length === 0) {
4367
- return;
4368
- }
4369
- series.errBars.forEach((eb) => {
4370
- if (eb.direction !== "y") {
4371
- return;
4372
- }
4373
- series.values.forEach((val2, vi) => {
4374
- const cx = xToPixel2(vi, catCount, layout, mode);
4375
- const baseY = valueToY2(val2, range, layout.plotTop, layout.plotBottom);
4376
- if (eb.barType === "plus" || eb.barType === "both") {
4377
- const plusErr = computeErrorValue(eb, series.values, vi, "plus");
4378
- const topY = valueToY2(val2 + plusErr, range, layout.plotTop, layout.plotBottom);
4379
- const stem = {
4380
- kind: "line",
4381
- x1: cx,
4382
- y1: baseY,
4383
- x2: cx,
4384
- y2: topY,
4385
- stroke: ERROR_BAR_COLOR,
4386
- strokeWidth: 1
4387
- };
4388
- const cap = {
4389
- kind: "line",
4390
- x1: cx - capW,
4391
- y1: topY,
4392
- x2: cx + capW,
4393
- y2: topY,
4394
- stroke: ERROR_BAR_COLOR,
4395
- strokeWidth: 1
4396
- };
4397
- out.push(stem, cap);
4398
- }
4399
- if (eb.barType === "minus" || eb.barType === "both") {
4400
- const minusErr = computeErrorValue(eb, series.values, vi, "minus");
4401
- const botY = valueToY2(val2 - minusErr, range, layout.plotTop, layout.plotBottom);
4402
- const stem = {
4403
- kind: "line",
4404
- x1: cx,
4405
- y1: baseY,
4406
- x2: cx,
4407
- y2: botY,
4408
- stroke: ERROR_BAR_COLOR,
4409
- strokeWidth: 1
4410
- };
4411
- const cap = {
4412
- kind: "line",
4413
- x1: cx - capW,
4414
- y1: botY,
4415
- x2: cx + capW,
4416
- y2: botY,
4417
- stroke: ERROR_BAR_COLOR,
4418
- strokeWidth: 1
4419
- };
4420
- out.push(stem, cap);
4421
- }
4422
- });
4423
- });
4424
- });
4425
- return out;
4426
- }
4427
5476
  var AXIS_TITLE_COLOR = "#475569";
4428
5477
  function computeAxisTitlePrimitives(chartData, layout) {
4429
5478
  const out = [];
@@ -4633,42 +5682,6 @@ function computeDataTablePrimitives(chartData, layout, colorPalette) {
4633
5682
  });
4634
5683
  return out;
4635
5684
  }
4636
- function hasRicherAxisFeatures(chartData) {
4637
- const axes = chartData.axes;
4638
- if (axes && axes.length > 0) {
4639
- for (const a of axes) {
4640
- if (a.axisType === "valAx" && (a.logScale || a.displayUnits || a.axPos === "r")) {
4641
- return true;
4642
- }
4643
- }
4644
- }
4645
- return Boolean(chartData.dataTable);
4646
- }
4647
- function findPrimaryValueAxis(chartData) {
4648
- const axes = chartData.axes;
4649
- if (!axes) {
4650
- return void 0;
4651
- }
4652
- return axes.find((a) => a.axisType === "valAx" && a.axPos !== "r") ?? axes.find((a) => a.axisType === "valAx");
4653
- }
4654
- function buildAxes(chartData, layout, primaryRange, secondaryRange) {
4655
- const richer = hasRicherAxisFeatures(chartData);
4656
- if (!richer) {
4657
- const { gridlines: gridlines2, axisLabels: axisLabels2 } = buildGridlinesAndLabels(primaryRange, layout);
4658
- return { gridlines: gridlines2, axisLabels: axisLabels2, secondaryGridlines: void 0, secondaryAxisLabels: void 0 };
4659
- }
4660
- const primaryAxis = findPrimaryValueAxis(chartData);
4661
- const { gridlines, axisLabels } = buildPrimaryAxis(primaryRange, layout, primaryAxis);
4662
- let secondaryGridlines;
4663
- let secondaryAxisLabels;
4664
- if (secondaryRange) {
4665
- const secAxis = getSecondaryValueAxis(chartData.axes);
4666
- const sec = buildSecondaryAxis(secondaryRange, layout, secAxis);
4667
- secondaryGridlines = sec.gridlines;
4668
- secondaryAxisLabels = sec.axisLabels;
4669
- }
4670
- return { gridlines, axisLabels, secondaryGridlines, secondaryAxisLabels };
4671
- }
4672
5685
  function stackedRange(chartData, catCount, isPercent) {
4673
5686
  if (isPercent) {
4674
5687
  return { min: 0, max: 100, span: 100 };
@@ -4687,15 +5700,31 @@ function buildCartesianViewModel(element, chartData, categoryLabels, kind) {
4687
5700
  const useSecondary = !isStacked && secondaryIdx.size > 0;
4688
5701
  const primaryPlotSeries = useSecondary ? chartData.series.filter((_s, i) => !secondaryIdx.has(i)) : chartData.series;
4689
5702
  const secondaryPlotSeries = useSecondary ? chartData.series.filter((_s, i) => secondaryIdx.has(i)) : [];
4690
- const primaryRange = isStacked ? stackedRange(chartData, catCount, isPercent) : computeValueRangeForChart(
5703
+ const primaryAxis = chartData.axes?.find(
5704
+ (axis) => axis.axisType === "valAx" && axis.axPos !== "r"
5705
+ );
5706
+ const primaryRange = isStacked ? {
5707
+ ...stackedRange(chartData, catCount, isPercent),
5708
+ ...primaryAxis?.orientation === "maxMin" ? { reverseOrder: true } : {}
5709
+ } : computeValueRangeForChart(
4691
5710
  primaryPlotSeries.length > 0 ? primaryPlotSeries : chartData.series,
4692
5711
  chartData.axes
4693
5712
  );
4694
- const secondaryRange = useSecondary && secondaryPlotSeries.length > 0 ? computeValueRange2(secondaryPlotSeries) : void 0;
4695
- const axisRes = buildAxes(chartData, layout, primaryRange, secondaryRange);
5713
+ const secondaryRange = useSecondary && secondaryPlotSeries.length > 0 ? computeValueRangeForAxis(
5714
+ secondaryPlotSeries,
5715
+ chartData.axes?.find((axis) => axis.axisType === "valAx" && axis.axPos === "r")
5716
+ ) : void 0;
5717
+ const axisRes = buildCartesianAxes(chartData, layout, primaryRange, secondaryRange, catCount);
4696
5718
  const zeroLine = primaryRange.logScale ? void 0 : buildZeroLine(primaryRange, layout);
4697
- const catAxisStyle = kind === "line" || kind === "area" || kind === "scatter" || kind === "bubble" ? "line" : "bar";
4698
- const catLabels = buildCategoryLabels(categoryLabels, layout, catAxisStyle);
5719
+ const horizontalAxis = buildCartesianHorizontalAxis(
5720
+ chartData,
5721
+ categoryLabels,
5722
+ layout,
5723
+ kind,
5724
+ primaryRange,
5725
+ secondaryRange
5726
+ );
5727
+ const { catAxisStyle, sourceIndices: sourceIndices2, displayChartData } = horizontalAxis;
4699
5728
  const legendPos = chartData.style?.legendPosition ?? "b";
4700
5729
  const { legend, legendX, legendY, legendAnchor } = buildLegend(
4701
5730
  chartData.series,
@@ -4714,31 +5743,52 @@ function buildCartesianViewModel(element, chartData, categoryLabels, kind) {
4714
5743
  primaryRange,
4715
5744
  secondaryRange,
4716
5745
  secondaryIdx,
4717
- isStacked ? isPercent ? "percentStacked" : "stacked" : "clustered"
5746
+ isStacked ? isPercent ? "percentStacked" : "stacked" : "clustered",
5747
+ sourceIndices2
4718
5748
  );
4719
5749
  } else if (kind === "line") {
4720
- plot = buildLines(chartData, catCount, layout, primaryRange, secondaryRange, secondaryIdx);
5750
+ plot = buildLines(
5751
+ chartData,
5752
+ catCount,
5753
+ layout,
5754
+ primaryRange,
5755
+ secondaryRange,
5756
+ secondaryIdx,
5757
+ sourceIndices2,
5758
+ horizontalAxis.xPositions
5759
+ );
4721
5760
  } else if (kind === "area") {
4722
- plot = buildAreas(chartData, catCount, layout, primaryRange);
5761
+ plot = buildAreas(
5762
+ chartData,
5763
+ catCount,
5764
+ layout,
5765
+ primaryRange,
5766
+ sourceIndices2,
5767
+ horizontalAxis.xPositions
5768
+ );
4723
5769
  } else if (kind === "scatter") {
4724
5770
  plot = buildScatter(chartData, layout, primaryRange);
4725
5771
  } else {
4726
5772
  plot = buildBubbles(chartData, layout, primaryRange);
4727
5773
  }
4728
- const primitives = [...plot.primitives];
5774
+ const primitives = [...plot.primitives, ...horizontalAxis.tickMarks];
4729
5775
  const overlays = [
4730
5776
  ...computeTrendlinePrimitives(
4731
- chartData,
5777
+ displayChartData,
4732
5778
  catCount,
4733
5779
  layout,
4734
5780
  primaryRange,
4735
5781
  catAxisStyle,
4736
5782
  chartData.colorPalette
4737
5783
  ),
4738
- ...computeErrorBarPrimitives(chartData, catCount, layout, primaryRange, catAxisStyle),
5784
+ ...computeErrorBarPrimitives(displayChartData, catCount, layout, primaryRange, catAxisStyle),
4739
5785
  ...computeAxisTitlePrimitives(chartData, layout)
4740
5786
  ];
4741
- const dataTablePrims = computeDataTablePrimitives(chartData, layout, chartData.colorPalette);
5787
+ const dataTablePrims = computeDataTablePrimitives(
5788
+ displayChartData,
5789
+ layout,
5790
+ chartData.colorPalette
5791
+ );
4742
5792
  primitives.push(...overlays, ...dataTablePrims);
4743
5793
  const title = chartData.style?.hasTitle && chartData.title ? chartData.title : void 0;
4744
5794
  const valueDrag = isStacked ? void 0 : {
@@ -4757,7 +5807,7 @@ function buildCartesianViewModel(element, chartData, categoryLabels, kind) {
4757
5807
  gridlines: axisRes.gridlines,
4758
5808
  axisLabels: axisRes.axisLabels,
4759
5809
  zeroLine,
4760
- categoryLabels: catLabels,
5810
+ categoryLabels: horizontalAxis.labels,
4761
5811
  primitives,
4762
5812
  dataLabels: plot.dataLabels,
4763
5813
  legend: chartData.style?.hasLegend ? legend : [],
@@ -4771,135 +5821,255 @@ function buildCartesianViewModel(element, chartData, categoryLabels, kind) {
4771
5821
  valueDrag
4772
5822
  };
4773
5823
  }
4774
- var CANDLE_UP_FILL = "#22c55e";
4775
- var CANDLE_DOWN_FILL = "#ef4444";
4776
- var CANDLE_WICK_COLOR = "#334155";
5824
+ function rangeForSeries(index, primaryRange, secondaryRange, secondaryIndexes) {
5825
+ return secondaryRange && secondaryIndexes.has(index) ? secondaryRange : primaryRange;
5826
+ }
4777
5827
  function buildComboViewModel(element, chartData, categoryLabels) {
4778
- const layout = computePlotLayout(element.width, element.height, chartData, true);
4779
- const catCount = Math.max(categoryLabels.length, 1);
4780
- const range = computeValueRange2(chartData.series);
4781
- const { gridlines, axisLabels } = buildGridlinesAndLabels(range, layout);
4782
- const zeroLine = buildZeroLine(range, layout);
4783
- const catLabels = buildCategoryLabels(categoryLabels, layout, "bar");
4784
- const legendPos = chartData.style?.legendPosition ?? "b";
4785
- const { legend, legendX, legendY, legendAnchor } = buildLegend(
4786
- chartData.series,
4787
- chartData.colorPalette,
4788
- layout.svgWidth,
4789
- legendPos,
4790
- layout.svgHeight,
4791
- layout.plotTop
5828
+ const layoutOptions = computeLayoutOptions(
5829
+ chartData.axes,
5830
+ chartData.dataTable,
5831
+ chartData.series.length
4792
5832
  );
4793
- const primitives = [];
4794
- const dataLabels = [];
4795
- const barSeries = chartData.series.slice(0, 1);
4796
- if (barSeries.length > 0) {
4797
- const barRects = computeBarRects(barSeries, catCount, layout, range, chartData.colorPalette);
4798
- for (const r of barRects) {
4799
- primitives.push({
4800
- kind: "rect",
4801
- x: r.x,
4802
- y: r.y,
4803
- w: r.w,
4804
- h: r.h,
4805
- fill: r.fill,
4806
- rx: 1
4807
- });
4808
- }
4809
- if (chartData.style?.hasDataLabels && barSeries[0]) {
4810
- const barGroupWidth2 = layout.plotWidth / catCount;
4811
- const singleBarWidth = barGroupWidth2 * 0.7;
4812
- const groupOffset = (barGroupWidth2 - singleBarWidth) / 2;
4813
- barSeries[0].values.forEach((val2, vi) => {
4814
- const x = layout.plotLeft + barGroupWidth2 * vi + groupOffset + singleBarWidth / 2;
4815
- const zeroY = valueToY2(0, range, layout.plotTop, layout.plotBottom);
4816
- const valY = valueToY2(val2, range, layout.plotTop, layout.plotBottom);
4817
- const labelY = val2 >= 0 ? Math.min(zeroY, valY) - 4 : Math.max(zeroY, valY) + 10;
4818
- dataLabels.push({
4819
- kind: "text",
4820
- x,
4821
- y: labelY,
4822
- text: formatAxisValue2(val2),
4823
- fontSize: 7,
4824
- fill: "#334155",
4825
- textAnchor: "middle"
4826
- });
4827
- });
4828
- }
5833
+ const layout = computePlotLayout(
5834
+ element.width,
5835
+ element.height,
5836
+ chartData,
5837
+ true,
5838
+ layoutOptions
5839
+ );
5840
+ const catCount = Math.max(categoryLabels.length, 1);
5841
+ const { primary, secondary } = splitSeriesByAxis(chartData.series, chartData.axes);
5842
+ const secondaryIndexes = new Set(secondary.map((entry) => entry.index));
5843
+ const primarySeries = primary.length > 0 ? primary.map((entry) => entry.series) : chartData.series;
5844
+ const primaryAxisId = getPrimaryValueAxisId(chartData.axes);
5845
+ const primaryAxis = chartData.axes?.find((axis) => axis.axisId === primaryAxisId);
5846
+ const secondaryAxisFormatting = getSecondaryValueAxis(chartData.axes);
5847
+ const primaryRange = computeValueRangeForAxis(primarySeries, primaryAxis);
5848
+ const secondaryRange = secondary.length > 0 ? computeValueRangeForAxis(
5849
+ secondary.map((entry) => entry.series),
5850
+ secondaryAxisFormatting
5851
+ ) : void 0;
5852
+ const primaryCategoryAxis2 = chartData.axes?.find(
5853
+ (axis) => (axis.axisType === "catAx" || axis.axisType === "dateAx") && axis.axisId === primaryAxis?.crossAxisId
5854
+ );
5855
+ const primaryAxisX = verticalAxisX(
5856
+ primaryCategoryAxis2,
5857
+ catCount,
5858
+ layout,
5859
+ "left",
5860
+ chartData.dateCategories?.values
5861
+ );
5862
+ const primaryRendered = primaryCategoryAxis2?.crosses !== void 0 || primaryCategoryAxis2?.crossesAt !== void 0 ? buildPrimaryAxis(primaryRange, layout, primaryAxis, primaryAxisX) : buildGridlinesAndLabels(primaryRange, layout);
5863
+ const { gridlines, axisLabels } = primaryRendered;
5864
+ const secondaryCategoryAxis = chartData.axes?.find(
5865
+ (axis) => (axis.axisType === "catAx" || axis.axisType === "dateAx") && axis.axisId === secondaryAxisFormatting?.crossAxisId
5866
+ );
5867
+ const secondaryAxis = secondaryRange ? buildSecondaryAxis(
5868
+ secondaryRange,
5869
+ layout,
5870
+ secondaryAxisFormatting,
5871
+ verticalAxisX(
5872
+ secondaryCategoryAxis,
5873
+ catCount,
5874
+ layout,
5875
+ "right",
5876
+ chartData.dateCategories?.values
5877
+ )
5878
+ ) : void 0;
5879
+ const zeroLine = primaryRange.logScale ? void 0 : buildZeroLine(primaryRange, layout);
5880
+ const horizontalAxis = buildCartesianHorizontalAxis(
5881
+ chartData,
5882
+ categoryLabels,
5883
+ layout,
5884
+ "combo",
5885
+ primaryRange,
5886
+ secondaryRange
5887
+ );
5888
+ const sourceIndices2 = horizontalAxis.sourceIndices;
5889
+ const legendPos = chartData.style?.legendPosition ?? "b";
5890
+ const { legend, legendX, legendY, legendAnchor } = buildLegend(
5891
+ chartData.series,
5892
+ chartData.colorPalette,
5893
+ layout.svgWidth,
5894
+ legendPos,
5895
+ layout.svgHeight,
5896
+ layout.plotTop
5897
+ );
5898
+ const primitives = [];
5899
+ const dataLabels = [];
5900
+ const barSeries = chartData.series.slice(0, 1);
5901
+ if (barSeries[0]) {
5902
+ const barRange = rangeForSeries(0, primaryRange, secondaryRange, secondaryIndexes);
5903
+ const displayBarSeries = [
5904
+ { ...barSeries[0], values: sourceIndices2.map((index) => barSeries[0].values[index] ?? 0) }
5905
+ ];
5906
+ primitives.push(
5907
+ ...computeBarRects(displayBarSeries, catCount, layout, barRange, chartData.colorPalette).map(
5908
+ (rect, displayIndex) => ({
5909
+ kind: "rect",
5910
+ x: horizontalAxis.xPositions ? (horizontalAxis.xPositions[displayIndex] ?? rect.x) - rect.w / 2 : rect.x,
5911
+ y: rect.y,
5912
+ w: rect.w,
5913
+ h: rect.h,
5914
+ fill: rect.fill,
5915
+ rx: 1,
5916
+ part: {
5917
+ role: "dataPoint",
5918
+ seriesIndex: 0,
5919
+ pointIndex: sourceIndices2[displayIndex] ?? displayIndex
5920
+ }
5921
+ })
5922
+ )
5923
+ );
5924
+ appendBarLabels(
5925
+ barSeries[0],
5926
+ chartData,
5927
+ layout,
5928
+ catCount,
5929
+ barRange,
5930
+ sourceIndices2,
5931
+ dataLabels,
5932
+ horizontalAxis.xPositions
5933
+ );
4829
5934
  }
4830
5935
  const barGroupWidth = layout.plotWidth / catCount;
4831
- const lineSeries = chartData.series.slice(1);
4832
- lineSeries.forEach((series, si) => {
5936
+ chartData.series.slice(1).forEach((series, offset) => {
5937
+ const seriesIndex = offset + 1;
4833
5938
  if (series.values.length === 0) {
4834
5939
  return;
4835
5940
  }
4836
- const seriesIdx = si + 1;
4837
- const c = seriesColor2(series, seriesIdx, chartData.colorPalette);
4838
- const pts = series.values.map((val2, vi) => ({
4839
- x: layout.plotLeft + barGroupWidth * vi + barGroupWidth / 2,
4840
- y: valueToY2(val2, range, layout.plotTop, layout.plotBottom)
4841
- }));
4842
- const pointsStr = pts.map((p) => `${p.x.toFixed(2)},${p.y.toFixed(2)}`).join(" ");
5941
+ const range = rangeForSeries(seriesIndex, primaryRange, secondaryRange, secondaryIndexes);
5942
+ const fill = seriesColor2(series, seriesIndex, chartData.colorPalette);
5943
+ const points = sourceIndices2.map((sourceIndex, displayIndex) => {
5944
+ const value = series.values[sourceIndex] ?? 0;
5945
+ return {
5946
+ x: horizontalAxis.xPositions?.[displayIndex] ?? layout.plotLeft + barGroupWidth * displayIndex + barGroupWidth / 2,
5947
+ y: valueToY2(value, range, layout.plotTop, layout.plotBottom),
5948
+ sourceIndex,
5949
+ value
5950
+ };
5951
+ });
4843
5952
  primitives.push({
4844
5953
  kind: "polyline",
4845
- points: pointsStr,
4846
- stroke: c,
5954
+ points: points.map((point) => `${point.x.toFixed(2)},${point.y.toFixed(2)}`).join(" "),
5955
+ stroke: fill,
4847
5956
  strokeWidth: 2.4,
4848
5957
  fill: "none"
4849
5958
  });
4850
- for (const pt of pts) {
4851
- primitives.push({
4852
- kind: "circle",
4853
- cx: pt.x,
4854
- cy: pt.y,
4855
- r: 2.5,
4856
- fill: c
4857
- });
4858
- }
5959
+ primitives.push(
5960
+ ...points.map(
5961
+ (point) => ({
5962
+ kind: "circle",
5963
+ cx: point.x,
5964
+ cy: point.y,
5965
+ r: 2.5,
5966
+ fill,
5967
+ part: { role: "dataPoint", seriesIndex, pointIndex: point.sourceIndex }
5968
+ })
5969
+ )
5970
+ );
4859
5971
  if (chartData.style?.hasDataLabels) {
4860
- series.values.forEach((val2, vi) => {
4861
- const pt = pts[vi];
4862
- if (!pt) {
4863
- return;
5972
+ points.forEach((point) => {
5973
+ if (point) {
5974
+ dataLabels.push({
5975
+ kind: "text",
5976
+ x: point.x,
5977
+ y: point.y - 7,
5978
+ text: formatAxisValue2(point.value),
5979
+ fontSize: 7,
5980
+ fill: "#334155",
5981
+ textAnchor: "middle"
5982
+ });
4864
5983
  }
4865
- dataLabels.push({
4866
- kind: "text",
4867
- x: pt.x,
4868
- y: pt.y - 7,
4869
- text: formatAxisValue2(val2),
4870
- fontSize: 7,
4871
- fill: "#334155",
4872
- textAnchor: "middle"
4873
- });
4874
5984
  });
4875
5985
  }
4876
5986
  });
4877
- const title = chartData.style?.hasTitle && chartData.title ? chartData.title : void 0;
5987
+ primitives.push(...horizontalAxis.tickMarks);
5988
+ const displayChartData = horizontalAxis.displayChartData;
5989
+ primitives.push(
5990
+ ...computeErrorBarPrimitives(displayChartData, catCount, layout, primaryRange, "line", {
5991
+ xPositions: horizontalAxis.xPositions,
5992
+ seriesRanges: chartData.series.map(
5993
+ (_series, index) => rangeForSeries(index, primaryRange, secondaryRange, secondaryIndexes)
5994
+ ),
5995
+ seriesModes: chartData.series.map((_series, index) => index === 0 ? "bar" : "line")
5996
+ })
5997
+ );
4878
5998
  return {
4879
5999
  svgWidth: layout.svgWidth,
4880
6000
  svgHeight: layout.svgHeight,
4881
- title,
6001
+ title: chartData.style?.hasTitle && chartData.title ? chartData.title : void 0,
4882
6002
  titleX: layout.svgWidth / 2,
4883
6003
  titleY: 12,
4884
6004
  gridlines,
4885
6005
  axisLabels,
4886
6006
  zeroLine,
4887
- categoryLabels: catLabels,
6007
+ categoryLabels: horizontalAxis.labels,
4888
6008
  primitives,
4889
6009
  dataLabels,
4890
6010
  legend: chartData.style?.hasLegend ? legend : [],
4891
6011
  legendX,
4892
6012
  legendY,
4893
- legendAnchor
6013
+ legendAnchor,
6014
+ secondaryGridlines: secondaryAxis?.gridlines,
6015
+ secondaryAxisLabels: secondaryAxis?.axisLabels
4894
6016
  };
4895
6017
  }
6018
+ function appendBarLabels(series, chartData, layout, catCount, range, sourceIndices2, labels, xPositions) {
6019
+ if (!chartData.style?.hasDataLabels) {
6020
+ return;
6021
+ }
6022
+ const groupWidth = layout.plotWidth / catCount;
6023
+ const barWidth = groupWidth * 0.7;
6024
+ const offset = (groupWidth - barWidth) / 2;
6025
+ sourceIndices2.forEach((sourceIndex, displayIndex) => {
6026
+ const value = series.values[sourceIndex] ?? 0;
6027
+ const zeroY = valueToY2(0, range, layout.plotTop, layout.plotBottom);
6028
+ const valueY = valueToY2(value, range, layout.plotTop, layout.plotBottom);
6029
+ labels.push({
6030
+ kind: "text",
6031
+ x: xPositions?.[displayIndex] ?? layout.plotLeft + groupWidth * displayIndex + offset + barWidth / 2,
6032
+ y: value >= 0 ? Math.min(zeroY, valueY) - 4 : Math.max(zeroY, valueY) + 10,
6033
+ text: formatAxisValue2(value),
6034
+ fontSize: 7,
6035
+ fill: "#334155",
6036
+ textAnchor: "middle"
6037
+ });
6038
+ });
6039
+ }
6040
+ var CANDLE_UP_FILL = "#22c55e";
6041
+ var CANDLE_DOWN_FILL = "#ef4444";
6042
+ var CANDLE_WICK_COLOR = "#334155";
4896
6043
  function buildStockViewModel(element, chartData, categoryLabels) {
4897
- const layout = computePlotLayout(element.width, element.height, chartData, true);
6044
+ const layout = computePlotLayout(
6045
+ element.width,
6046
+ element.height,
6047
+ chartData,
6048
+ true,
6049
+ computeLayoutOptions(chartData.axes, chartData.dataTable, chartData.series.length)
6050
+ );
4898
6051
  const catCount = Math.max(categoryLabels.length, 1);
4899
6052
  const range = computeValueRange2(chartData.series);
4900
- const { gridlines, axisLabels } = buildGridlinesAndLabels(range, layout);
6053
+ const valueAxis = chartData.axes?.find((axis) => axis.axisType === "valAx" && axis.axPos !== "r");
6054
+ const categoryAxis = chartData.axes?.find(
6055
+ (axis) => (axis.axisType === "catAx" || axis.axisType === "dateAx") && axis.axisId === valueAxis?.crossAxisId
6056
+ );
6057
+ const renderedAxis = categoryAxis?.crosses !== void 0 || categoryAxis?.crossesAt !== void 0 ? buildPrimaryAxis(
6058
+ range,
6059
+ layout,
6060
+ valueAxis,
6061
+ verticalAxisX(categoryAxis, catCount, layout, "left", chartData.dateCategories?.values)
6062
+ ) : buildGridlinesAndLabels(range, layout);
6063
+ const { gridlines, axisLabels } = renderedAxis;
4901
6064
  const zeroLine = buildZeroLine(range, layout);
4902
- const catLabels = buildCategoryLabels(categoryLabels, layout, "bar");
6065
+ const horizontalAxis = buildCartesianHorizontalAxis(
6066
+ chartData,
6067
+ categoryLabels,
6068
+ layout,
6069
+ "stock",
6070
+ range
6071
+ );
6072
+ const sourceIndices2 = horizontalAxis.sourceIndices;
4903
6073
  const legendPos = chartData.style?.legendPosition ?? "b";
4904
6074
  const { legend, legendX, legendY, legendAnchor } = buildLegend(
4905
6075
  chartData.series,
@@ -4919,13 +6089,14 @@ function buildStockViewModel(element, chartData, categoryLabels) {
4919
6089
  if (highSeries && lowSeries && closeSeries) {
4920
6090
  const barGroupWidth = layout.plotWidth / catCount;
4921
6091
  const candleWidth = barGroupWidth * 0.5;
4922
- for (let ci = 0; ci < catCount; ci++) {
4923
- const high = highSeries.values[ci] ?? 0;
4924
- const low = lowSeries.values[ci] ?? 0;
4925
- const open = openSeries ? openSeries.values[ci] ?? low : low;
4926
- const close = closeSeries.values[ci] ?? high;
6092
+ for (let displayIndex = 0; displayIndex < catCount; displayIndex++) {
6093
+ const sourceIndex = sourceIndices2[displayIndex] ?? displayIndex;
6094
+ const high = highSeries.values[sourceIndex] ?? 0;
6095
+ const low = lowSeries.values[sourceIndex] ?? 0;
6096
+ const open = openSeries ? openSeries.values[sourceIndex] ?? low : low;
6097
+ const close = closeSeries.values[sourceIndex] ?? high;
4927
6098
  const isUp = close >= open;
4928
- const cx = layout.plotLeft + barGroupWidth * ci + barGroupWidth / 2;
6099
+ const cx = horizontalAxis.xPositions?.[displayIndex] ?? layout.plotLeft + barGroupWidth * displayIndex + barGroupWidth / 2;
4929
6100
  const highY = valueToY2(high, range, layout.plotTop, layout.plotBottom);
4930
6101
  const lowY = valueToY2(low, range, layout.plotTop, layout.plotBottom);
4931
6102
  const openY = valueToY2(open, range, layout.plotTop, layout.plotBottom);
@@ -4948,7 +6119,12 @@ function buildStockViewModel(element, chartData, categoryLabels) {
4948
6119
  w: candleWidth,
4949
6120
  h: bodyHeight,
4950
6121
  fill: isUp ? CANDLE_UP_FILL : CANDLE_DOWN_FILL,
4951
- rx: 1
6122
+ rx: 1,
6123
+ part: {
6124
+ role: "dataPoint",
6125
+ seriesIndex: hasFour ? 3 : 2,
6126
+ pointIndex: sourceIndex
6127
+ }
4952
6128
  });
4953
6129
  if (chartData.style?.hasDataLabels) {
4954
6130
  dataLabels.push({
@@ -4963,6 +6139,7 @@ function buildStockViewModel(element, chartData, categoryLabels) {
4963
6139
  }
4964
6140
  }
4965
6141
  }
6142
+ primitives.push(...horizontalAxis.tickMarks);
4966
6143
  const title = chartData.style?.hasTitle && chartData.title ? chartData.title : void 0;
4967
6144
  return {
4968
6145
  svgWidth: layout.svgWidth,
@@ -4973,7 +6150,7 @@ function buildStockViewModel(element, chartData, categoryLabels) {
4973
6150
  gridlines,
4974
6151
  axisLabels,
4975
6152
  zeroLine,
4976
- categoryLabels: catLabels,
6153
+ categoryLabels: horizontalAxis.labels,
4977
6154
  primitives,
4978
6155
  dataLabels,
4979
6156
  legend: chartData.style?.hasLegend ? legend : [],
@@ -4982,255 +6159,544 @@ function buildStockViewModel(element, chartData, categoryLabels) {
4982
6159
  legendAnchor
4983
6160
  };
4984
6161
  }
4985
- var WHISKER_COLOR = "#64748b";
4986
- var MEDIAN_COLOR = "#1e293b";
4987
- var DATA_LABEL_COLOR = "#334155";
6162
+ function percentile(sorted, p, method) {
6163
+ const rank = method === "inclusive" ? (sorted.length - 1) * p : (sorted.length + 1) * p - 1;
6164
+ const clamped = Math.max(0, Math.min(rank, sorted.length - 1));
6165
+ const lower = Math.floor(clamped);
6166
+ const upper = Math.ceil(clamped);
6167
+ const fraction = clamped - lower;
6168
+ return sorted[lower] + (sorted[upper] - sorted[lower]) * fraction;
6169
+ }
6170
+ function computeBoxStats(values, method) {
6171
+ if (values.length < 2) {
6172
+ return void 0;
6173
+ }
6174
+ const sorted = [...values].sort((a, b) => a - b);
6175
+ if (!method) {
6176
+ return {
6177
+ min: sorted[0],
6178
+ q1: sorted[Math.floor(sorted.length * 0.25)],
6179
+ median: sorted[Math.floor(sorted.length * 0.5)],
6180
+ q3: sorted[Math.floor(sorted.length * 0.75)],
6181
+ max: sorted[sorted.length - 1]
6182
+ };
6183
+ }
6184
+ return {
6185
+ min: sorted[0],
6186
+ q1: percentile(sorted, 0.25, method),
6187
+ median: percentile(sorted, 0.5, method),
6188
+ q3: percentile(sorted, 0.75, method),
6189
+ max: sorted[sorted.length - 1]
6190
+ };
6191
+ }
4988
6192
  function distributionRange(series) {
4989
- const all = series.flatMap((s) => s.values);
6193
+ const all = series.flatMap((item) => item.values);
4990
6194
  const min = Math.min(...all, 0);
4991
6195
  const max = Math.max(...all, 1);
4992
6196
  return { min, max, span: Math.max(max - min, 1) };
4993
6197
  }
6198
+ var WHISKER_COLOR = "#64748b";
6199
+ var MEDIAN_COLOR = "#1e293b";
6200
+ function computeBoxWhiskerGeometry(chartData, catCount, layout, range, colorPalette) {
6201
+ const groupWidth = layout.plotWidth / catCount;
6202
+ const boxW = groupWidth * 0.5;
6203
+ const options = chartData.series.find((series) => series.boxWhiskerOptions)?.boxWhiskerOptions;
6204
+ const method = options ? options.quartileMethod ?? "exclusive" : void 0;
6205
+ const output = [];
6206
+ for (let categoryIndex = 0; categoryIndex < catCount; categoryIndex++) {
6207
+ const observations = chartData.series.map((series, seriesIndex) => ({ value: series.values[categoryIndex], seriesIndex })).filter((item) => item.value !== void 0);
6208
+ const stats = computeBoxStats(
6209
+ observations.map((item) => item.value),
6210
+ method
6211
+ );
6212
+ if (!stats) {
6213
+ continue;
6214
+ }
6215
+ const iqr = stats.q3 - stats.q1;
6216
+ const lowerFence = stats.q1 - 1.5 * iqr;
6217
+ const upperFence = stats.q3 + 1.5 * iqr;
6218
+ const inliers = observations.filter(
6219
+ (item) => !options || item.value >= lowerFence && item.value <= upperFence
6220
+ );
6221
+ const whiskerMin = Math.min(...inliers.map((item) => item.value));
6222
+ const whiskerMax = Math.max(...inliers.map((item) => item.value));
6223
+ const boxX = layout.plotLeft + groupWidth * categoryIndex + (groupWidth - boxW) / 2;
6224
+ const mean = observations.reduce((sum, item) => sum + item.value, 0) / observations.length;
6225
+ output.push({
6226
+ stats,
6227
+ boxX,
6228
+ boxW,
6229
+ xMid: boxX + boxW / 2,
6230
+ yMin: valueToY2(whiskerMin, range, layout.plotTop, layout.plotBottom),
6231
+ yMax: valueToY2(whiskerMax, range, layout.plotTop, layout.plotBottom),
6232
+ yQ1: valueToY2(stats.q1, range, layout.plotTop, layout.plotBottom),
6233
+ yQ3: valueToY2(stats.q3, range, layout.plotTop, layout.plotBottom),
6234
+ yMed: valueToY2(stats.median, range, layout.plotTop, layout.plotBottom),
6235
+ yMean: valueToY2(mean, range, layout.plotTop, layout.plotBottom),
6236
+ fill: paletteColor2(categoryIndex, colorPalette),
6237
+ points: observations.map((item, index) => ({
6238
+ x: boxX + boxW * (0.2 + 0.6 * (index + 1) / (observations.length + 1)),
6239
+ y: valueToY2(item.value, range, layout.plotTop, layout.plotBottom),
6240
+ seriesIndex: item.seriesIndex,
6241
+ outlier: item.value < whiskerMin || item.value > whiskerMax
6242
+ }))
6243
+ });
6244
+ }
6245
+ return output;
6246
+ }
6247
+ function whiskerPrimitives(geometry) {
6248
+ const g = geometry;
6249
+ return [
6250
+ {
6251
+ kind: "line",
6252
+ x1: g.xMid,
6253
+ y1: g.yMax,
6254
+ x2: g.xMid,
6255
+ y2: g.yQ3,
6256
+ stroke: WHISKER_COLOR,
6257
+ strokeWidth: 1
6258
+ },
6259
+ {
6260
+ kind: "line",
6261
+ x1: g.xMid,
6262
+ y1: g.yQ1,
6263
+ x2: g.xMid,
6264
+ y2: g.yMin,
6265
+ stroke: WHISKER_COLOR,
6266
+ strokeWidth: 1
6267
+ },
6268
+ {
6269
+ kind: "line",
6270
+ x1: g.boxX + g.boxW * 0.25,
6271
+ y1: g.yMax,
6272
+ x2: g.boxX + g.boxW * 0.75,
6273
+ y2: g.yMax,
6274
+ stroke: WHISKER_COLOR,
6275
+ strokeWidth: 1
6276
+ },
6277
+ {
6278
+ kind: "line",
6279
+ x1: g.boxX + g.boxW * 0.25,
6280
+ y1: g.yMin,
6281
+ x2: g.boxX + g.boxW * 0.75,
6282
+ y2: g.yMin,
6283
+ stroke: WHISKER_COLOR,
6284
+ strokeWidth: 1
6285
+ },
6286
+ {
6287
+ kind: "rect",
6288
+ x: g.boxX,
6289
+ y: Math.min(g.yQ1, g.yQ3),
6290
+ w: g.boxW,
6291
+ h: Math.abs(g.yQ1 - g.yQ3),
6292
+ fill: g.fill,
6293
+ rx: 1,
6294
+ opacity: 0.8
6295
+ },
6296
+ {
6297
+ kind: "line",
6298
+ x1: g.boxX,
6299
+ y1: g.yMed,
6300
+ x2: g.boxX + g.boxW,
6301
+ y2: g.yMed,
6302
+ stroke: MEDIAN_COLOR,
6303
+ strokeWidth: 2
6304
+ }
6305
+ ];
6306
+ }
6307
+ function optionPrimitives(geometry, options, categoryIndex) {
6308
+ if (!options) {
6309
+ return [];
6310
+ }
6311
+ const output = [];
6312
+ if (options.showMeanLine) {
6313
+ output.push({
6314
+ kind: "line",
6315
+ x1: geometry.boxX,
6316
+ y1: geometry.yMean,
6317
+ x2: geometry.boxX + geometry.boxW,
6318
+ y2: geometry.yMean,
6319
+ stroke: "#0f766e",
6320
+ strokeWidth: 1.5
6321
+ });
6322
+ }
6323
+ if (options.showMeanMarker) {
6324
+ output.push({
6325
+ kind: "circle",
6326
+ cx: geometry.xMid,
6327
+ cy: geometry.yMean,
6328
+ r: 3,
6329
+ fill: "#0f766e"
6330
+ });
6331
+ }
6332
+ for (const point of geometry.points) {
6333
+ if (point.outlier && !options.showOutlierPoints || !point.outlier && !options.showInnerPoints) {
6334
+ continue;
6335
+ }
6336
+ output.push({
6337
+ kind: "circle",
6338
+ cx: point.x,
6339
+ cy: point.y,
6340
+ r: 2.25,
6341
+ fill: point.outlier ? "#dc2626" : MEDIAN_COLOR,
6342
+ part: { role: "dataPoint", seriesIndex: point.seriesIndex, pointIndex: categoryIndex }
6343
+ });
6344
+ }
6345
+ return output;
6346
+ }
6347
+ function buildBoxWhiskerViewModel(element, chartData, categoryLabels) {
6348
+ const layout = computePlotLayout(element.width, element.height, chartData, true);
6349
+ const range = distributionRange(chartData.series);
6350
+ const options = chartData.series.find((series) => series.boxWhiskerOptions)?.boxWhiskerOptions;
6351
+ const geometries = computeBoxWhiskerGeometry(
6352
+ chartData,
6353
+ Math.max(categoryLabels.length, 1),
6354
+ layout,
6355
+ range,
6356
+ chartData.colorPalette
6357
+ );
6358
+ const primitives = geometries.flatMap((geometry, index) => [
6359
+ ...whiskerPrimitives(geometry),
6360
+ ...optionPrimitives(geometry, options, index)
6361
+ ]);
6362
+ const { gridlines, axisLabels } = buildGridlinesAndLabels(range, layout);
6363
+ const { legend, legendX, legendY, legendAnchor } = buildLegend(
6364
+ chartData.series,
6365
+ chartData.colorPalette,
6366
+ layout.svgWidth,
6367
+ chartData.style?.legendPosition ?? "b",
6368
+ layout.svgHeight,
6369
+ layout.plotTop
6370
+ );
6371
+ const categoryLegend = categoryLabels.map((label, index) => ({
6372
+ color: paletteColor2(index, chartData.colorPalette),
6373
+ label
6374
+ }));
6375
+ return {
6376
+ svgWidth: layout.svgWidth,
6377
+ svgHeight: layout.svgHeight,
6378
+ title: chartData.style?.hasTitle ? chartData.title : void 0,
6379
+ titleX: layout.svgWidth / 2,
6380
+ titleY: 12,
6381
+ gridlines,
6382
+ axisLabels,
6383
+ zeroLine: buildZeroLine(range, layout),
6384
+ categoryLabels: buildCategoryLabels(categoryLabels, layout, "bar"),
6385
+ primitives,
6386
+ dataLabels: [],
6387
+ legend: chartData.style?.hasLegend ? categoryLegend.length ? categoryLegend : legend : [],
6388
+ legendX,
6389
+ legendY,
6390
+ legendAnchor
6391
+ };
6392
+ }
6393
+ function orderParetoEntries(entries) {
6394
+ return [...entries].sort(
6395
+ (left, right) => Math.max(right.value, 0) - Math.max(left.value, 0) || left.sourcePointIndex - right.sourcePointIndex
6396
+ );
6397
+ }
6398
+ function buildParetoPrimitives(entries, layout, series, seriesIndex) {
6399
+ const total = entries.reduce((sum, entry) => sum + Math.max(entry.value, 0), 0);
6400
+ if (total <= 0) {
6401
+ return [];
6402
+ }
6403
+ let cumulative = 0;
6404
+ const points = entries.map((entry, displayIndex) => {
6405
+ cumulative += Math.max(entry.value, 0);
6406
+ const percentage = displayIndex === entries.length - 1 ? 100 : cumulative / total * 100;
6407
+ return {
6408
+ x: layout.plotLeft + layout.plotWidth * (displayIndex + 0.5) / entries.length,
6409
+ y: layout.plotBottom - layout.plotHeight * percentage / 100,
6410
+ pointIndex: entry.sourcePointIndex
6411
+ };
6412
+ });
6413
+ const color = series.color ?? "#ED7D31";
6414
+ return [
6415
+ {
6416
+ kind: "polyline",
6417
+ points: points.map((point) => `${point.x},${point.y}`).join(" "),
6418
+ stroke: color,
6419
+ strokeWidth: 2,
6420
+ fill: "none",
6421
+ part: { role: "series", seriesIndex }
6422
+ },
6423
+ ...points.map(
6424
+ (point) => ({
6425
+ kind: "circle",
6426
+ cx: point.x,
6427
+ cy: point.y,
6428
+ r: 2.5,
6429
+ fill: color,
6430
+ part: { role: "dataPoint", seriesIndex, pointIndex: point.pointIndex }
6431
+ })
6432
+ )
6433
+ ];
6434
+ }
6435
+ function buildParetoAxis(layout) {
6436
+ const axis = buildSecondaryAxis({ min: 0, max: 100, span: 100 }, layout, {
6437
+ majorUnit: 20,
6438
+ majorTickMark: "out"
6439
+ });
6440
+ return {
6441
+ secondaryGridlines: axis.gridlines,
6442
+ secondaryAxisLabels: axis.axisLabels.map((label) => ({
6443
+ ...label,
6444
+ text: `${label.text}%`
6445
+ }))
6446
+ };
6447
+ }
6448
+ var DATA_LABEL_COLOR = "#334155";
6449
+ function binLabel(lower, upper, closed) {
6450
+ return closed === "r" ? `(${formatAxisValue2(lower)}, ${formatAxisValue2(upper)}]` : `[${formatAxisValue2(lower)}, ${formatAxisValue2(upper)})`;
6451
+ }
6452
+ function computeHistogramBins(values, options) {
6453
+ const closed = options.intervalClosed ?? "l";
6454
+ const finite = values.map((value, sourceIndex) => ({ value, sourceIndex })).filter((item) => Number.isFinite(item.value));
6455
+ if (finite.length === 0) {
6456
+ return [];
6457
+ }
6458
+ const underflow = typeof options.underflow === "number" ? options.underflow : void 0;
6459
+ const overflow = typeof options.overflow === "number" ? options.overflow : void 0;
6460
+ const under = underflow === void 0 ? [] : finite.filter(
6461
+ (item) => closed === "r" ? item.value <= underflow : item.value < underflow
6462
+ );
6463
+ const over = overflow === void 0 ? [] : finite.filter((item) => closed === "l" ? item.value >= overflow : item.value > overflow);
6464
+ const regular = finite.filter((item) => !under.includes(item) && !over.includes(item));
6465
+ const result = [];
6466
+ if (underflow !== void 0) {
6467
+ result.push({
6468
+ value: under.length,
6469
+ label: `${closed === "r" ? "\u2264" : "<"} ${formatAxisValue2(underflow)}`,
6470
+ sourceIndices: under.map((item) => item.sourceIndex)
6471
+ });
6472
+ }
6473
+ if (regular.length > 0) {
6474
+ const min = Math.min(...regular.map((item) => item.value));
6475
+ const max = Math.max(...regular.map((item) => item.value));
6476
+ const requestedSize = options.binSize && options.binSize > 0 ? options.binSize : void 0;
6477
+ const requestedCount = options.binCount && options.binCount > 0 ? options.binCount : void 0;
6478
+ const start = requestedSize ? Math.floor(min / requestedSize) * requestedSize : min;
6479
+ const count = requestedSize ? Math.max(
6480
+ closed === "l" ? Math.floor((max - start) / requestedSize) + 1 : Math.ceil((max - start) / requestedSize),
6481
+ 1
6482
+ ) : Math.max(requestedCount ?? Math.ceil(Math.sqrt(regular.length)), 1);
6483
+ const width = requestedSize ?? Math.max((max - start) / count, 1);
6484
+ const bins = Array.from({ length: count }, (_, index) => ({
6485
+ value: 0,
6486
+ label: binLabel(start + index * width, start + (index + 1) * width, closed),
6487
+ sourceIndices: []
6488
+ }));
6489
+ for (const item of regular) {
6490
+ const rawIndex = closed === "r" ? Math.ceil((item.value - start) / width) - 1 : Math.floor((item.value - start) / width);
6491
+ const index = Math.max(0, Math.min(rawIndex, bins.length - 1));
6492
+ bins[index].value += 1;
6493
+ bins[index].sourceIndices.push(item.sourceIndex);
6494
+ }
6495
+ result.push(...bins);
6496
+ }
6497
+ if (overflow !== void 0) {
6498
+ result.push({
6499
+ value: over.length,
6500
+ label: `${closed === "l" ? "\u2265" : ">"} ${formatAxisValue2(overflow)}`,
6501
+ sourceIndices: over.map((item) => item.sourceIndex)
6502
+ });
6503
+ }
6504
+ return result;
6505
+ }
4994
6506
  function computeHistogramBars(values, catCount, layout, range, seriesColorOverride, colorPalette) {
4995
6507
  const count = Math.max(catCount, values.length, 1);
4996
6508
  const barWidth = layout.plotWidth / count;
4997
- return values.map((val2, i) => {
4998
- const x = layout.plotLeft + barWidth * i;
6509
+ return values.map((val2, pointIndex) => {
4999
6510
  const zeroY = valueToY2(0, range, layout.plotTop, layout.plotBottom);
5000
6511
  const valY = valueToY2(val2, range, layout.plotTop, layout.plotBottom);
5001
- const y = Math.min(zeroY, valY);
5002
- const h = Math.max(Math.abs(zeroY - valY), 1);
5003
6512
  return {
5004
- x,
5005
- y,
6513
+ x: layout.plotLeft + barWidth * pointIndex,
6514
+ y: Math.min(zeroY, valY),
5006
6515
  w: Math.max(barWidth - 0.5, 1),
5007
- h,
5008
- fill: seriesColorOverride ?? paletteColor2(i, colorPalette)
6516
+ h: Math.max(Math.abs(zeroY - valY), 1),
6517
+ fill: seriesColorOverride ?? paletteColor2(pointIndex, colorPalette),
6518
+ pointIndex
5009
6519
  };
5010
6520
  });
5011
6521
  }
5012
6522
  function buildHistogramViewModel(element, chartData, categoryLabels) {
5013
- const layout = computePlotLayout(element.width, element.height, chartData, true);
5014
- const range = distributionRange(chartData.series);
5015
- const values = chartData.series[0]?.values ?? [];
5016
- const catCount = Math.max(categoryLabels.length, values.length, 1);
5017
- const barWidth = layout.plotWidth / catCount;
6523
+ const paretoIndex = chartData.series.findIndex(
6524
+ (item) => item.histogramOptions?.layout === "pareto"
6525
+ );
6526
+ const layout = computePlotLayout(element.width, element.height, chartData, true, {
6527
+ hasSecondaryValueAxis: paretoIndex >= 0
6528
+ });
6529
+ const histogramIndex = Math.max(
6530
+ chartData.series.findIndex((series2) => series2.histogramOptions?.layout !== "pareto"),
6531
+ 0
6532
+ );
6533
+ const series = chartData.series[histogramIndex];
6534
+ const options = series?.histogramOptions;
6535
+ const bins = options?.layout === "histogram" ? computeHistogramBins(series?.values ?? [], options) : void 0;
6536
+ const baseEntries = (bins?.map((bin) => ({ value: bin.value, label: bin.label })) ?? (series?.values ?? []).map((value, index) => ({
6537
+ value,
6538
+ label: categoryLabels[index] ?? ""
6539
+ }))).map((entry, sourcePointIndex) => ({ ...entry, sourcePointIndex }));
6540
+ const entries = paretoIndex >= 0 ? orderParetoEntries(baseEntries) : baseEntries;
6541
+ const values = entries.map((entry) => entry.value);
6542
+ const labels = entries.map((entry) => entry.label);
6543
+ const range = distributionRange([{ name: series?.name ?? "", values }]);
5018
6544
  const bars = computeHistogramBars(
5019
6545
  values,
5020
- categoryLabels.length,
6546
+ labels.length,
5021
6547
  layout,
5022
6548
  range,
5023
- chartData.series[0]?.color,
6549
+ series?.color,
5024
6550
  chartData.colorPalette
5025
6551
  );
5026
6552
  const primitives = bars.map(
5027
- (b) => ({
6553
+ (bar, displayIndex) => ({
5028
6554
  kind: "rect",
5029
- x: b.x,
5030
- y: b.y,
5031
- w: b.w,
5032
- h: b.h,
5033
- fill: b.fill,
5034
- opacity: 0.85
6555
+ x: bar.x,
6556
+ y: bar.y,
6557
+ w: bar.w,
6558
+ h: bar.h,
6559
+ fill: bar.fill,
6560
+ opacity: 0.85,
6561
+ ...bins ? {} : {
6562
+ part: {
6563
+ role: "dataPoint",
6564
+ seriesIndex: histogramIndex,
6565
+ pointIndex: entries[displayIndex]?.sourcePointIndex ?? displayIndex
6566
+ }
6567
+ }
5035
6568
  })
5036
6569
  );
5037
- const dataLabels = [];
5038
- if (chartData.style?.hasDataLabels) {
5039
- bars.forEach((b, i) => {
5040
- const val2 = values[i];
5041
- if (val2 === void 0) {
5042
- return;
5043
- }
5044
- dataLabels.push({
5045
- kind: "text",
5046
- x: b.x + barWidth / 2,
5047
- y: b.y - 4,
5048
- text: formatAxisValue2(val2),
5049
- fontSize: 7,
5050
- fill: DATA_LABEL_COLOR,
5051
- textAnchor: "middle"
5052
- });
5053
- });
6570
+ if (paretoIndex >= 0) {
6571
+ primitives.push(
6572
+ ...buildParetoPrimitives(entries, layout, chartData.series[paretoIndex], paretoIndex)
6573
+ );
5054
6574
  }
6575
+ const dataLabels = chartData.style?.hasDataLabels ? bars.map((bar, index) => ({
6576
+ kind: "text",
6577
+ x: bar.x + bar.w / 2,
6578
+ y: bar.y - 4,
6579
+ text: formatAxisValue2(values[index]),
6580
+ fontSize: 7,
6581
+ fill: DATA_LABEL_COLOR,
6582
+ textAnchor: "middle"
6583
+ })) : [];
5055
6584
  const { gridlines, axisLabels } = buildGridlinesAndLabels(range, layout);
5056
- const zeroLine = buildZeroLine(range, layout);
5057
- const catLabels = buildCategoryLabels(categoryLabels, layout, "bar");
5058
- const legendPos = chartData.style?.legendPosition ?? "b";
6585
+ const paretoAxis = paretoIndex >= 0 ? buildParetoAxis(layout) : void 0;
5059
6586
  const { legend, legendX, legendY, legendAnchor } = buildLegend(
5060
6587
  chartData.series,
5061
6588
  chartData.colorPalette,
5062
6589
  layout.svgWidth,
5063
- legendPos,
6590
+ chartData.style?.legendPosition ?? "b",
5064
6591
  layout.svgHeight,
5065
6592
  layout.plotTop
5066
6593
  );
5067
- const title = chartData.style?.hasTitle && chartData.title ? chartData.title : void 0;
5068
6594
  return {
5069
6595
  svgWidth: layout.svgWidth,
5070
6596
  svgHeight: layout.svgHeight,
5071
- title,
6597
+ title: chartData.style?.hasTitle ? chartData.title : void 0,
5072
6598
  titleX: layout.svgWidth / 2,
5073
6599
  titleY: 12,
5074
6600
  gridlines,
5075
6601
  axisLabels,
5076
- zeroLine,
5077
- categoryLabels: catLabels,
6602
+ zeroLine: buildZeroLine(range, layout),
6603
+ categoryLabels: buildCategoryLabels(labels, layout, "bar"),
5078
6604
  primitives,
5079
6605
  dataLabels,
5080
6606
  legend: chartData.style?.hasLegend ? legend : [],
5081
6607
  legendX,
5082
6608
  legendY,
5083
- legendAnchor
6609
+ legendAnchor,
6610
+ secondaryGridlines: paretoAxis?.secondaryGridlines,
6611
+ secondaryAxisLabels: paretoAxis?.secondaryAxisLabels
5084
6612
  };
5085
6613
  }
5086
- function computeBoxStats(values) {
5087
- if (values.length < 2) {
5088
- return void 0;
5089
- }
5090
- const sorted = [...values].sort((a, b) => a - b);
5091
- const n = sorted.length;
5092
- return {
5093
- min: sorted[0],
5094
- q1: sorted[Math.floor(n * 0.25)],
5095
- median: sorted[Math.floor(n * 0.5)],
5096
- q3: sorted[Math.floor(n * 0.75)],
5097
- max: sorted[n - 1]
5098
- };
6614
+ function arcPath(cx, cy, innerRadius, outerRadius, startAngle, endAngle) {
6615
+ const sweep = endAngle - startAngle;
6616
+ const largeArc = sweep > Math.PI ? 1 : 0;
6617
+ const x1 = cx + outerRadius * Math.cos(startAngle);
6618
+ const y1 = cy + outerRadius * Math.sin(startAngle);
6619
+ const x2 = cx + outerRadius * Math.cos(endAngle);
6620
+ const y2 = cy + outerRadius * Math.sin(endAngle);
6621
+ const x3 = cx + innerRadius * Math.cos(endAngle);
6622
+ const y3 = cy + innerRadius * Math.sin(endAngle);
6623
+ const x4 = cx + innerRadius * Math.cos(startAngle);
6624
+ const y4 = cy + innerRadius * Math.sin(startAngle);
6625
+ return `M ${x1} ${y1} A ${outerRadius} ${outerRadius} 0 ${largeArc} 1 ${x2} ${y2} L ${x3} ${y3} A ${innerRadius} ${innerRadius} 0 ${largeArc} 0 ${x4} ${y4} Z`;
5099
6626
  }
5100
- function computeBoxWhiskerGeometry(chartData, catCount, layout, range, colorPalette) {
5101
- const boxGroupW = layout.plotWidth / catCount;
5102
- const boxW = boxGroupW * 0.5;
5103
- const boxOffset = (boxGroupW - boxW) / 2;
6627
+ function computeSunburstArcs(series, cx, cy, maxR, colorPalette) {
6628
+ const seriesCount = Math.max(series.length, 1);
6629
+ const ringWidth = maxR / (seriesCount + 0.5);
5104
6630
  const out = [];
5105
- for (let ci = 0; ci < catCount; ci++) {
5106
- const catVals = chartData.series.map((s) => s.values[ci] ?? 0);
5107
- const stats = computeBoxStats(catVals);
5108
- if (!stats) {
5109
- continue;
6631
+ for (let si = 0; si < series.length; si++) {
6632
+ const values = series[si].values;
6633
+ const innerRadius = ringWidth * (si + 0.5);
6634
+ const outerRadius = ringWidth * (si + 1.5);
6635
+ const total = values.reduce((acc, value) => acc + Math.abs(value), 0) || 1;
6636
+ let startAngle = -Math.PI / 2;
6637
+ for (let pointIndex = 0; pointIndex < values.length; pointIndex++) {
6638
+ const endAngle = startAngle + Math.abs(values[pointIndex]) / total * Math.PI * 2;
6639
+ out.push({
6640
+ d: arcPath(cx, cy, innerRadius, outerRadius, startAngle, endAngle),
6641
+ fill: paletteColor2(pointIndex, colorPalette),
6642
+ opacity: Math.max(0.1, 0.9 - si * 0.1),
6643
+ pointIndex,
6644
+ level: si
6645
+ });
6646
+ startAngle = endAngle;
5110
6647
  }
5111
- const boxX = layout.plotLeft + boxGroupW * ci + boxOffset;
5112
- out.push({
5113
- stats,
5114
- boxX,
5115
- boxW,
5116
- xMid: boxX + boxW / 2,
5117
- yMin: valueToY2(stats.min, range, layout.plotTop, layout.plotBottom),
5118
- yMax: valueToY2(stats.max, range, layout.plotTop, layout.plotBottom),
5119
- yQ1: valueToY2(stats.q1, range, layout.plotTop, layout.plotBottom),
5120
- yQ3: valueToY2(stats.q3, range, layout.plotTop, layout.plotBottom),
5121
- yMed: valueToY2(stats.median, range, layout.plotTop, layout.plotBottom),
5122
- fill: paletteColor2(ci, colorPalette)
5123
- });
5124
6648
  }
5125
6649
  return out;
5126
6650
  }
5127
- function buildBoxWhiskerViewModel(element, chartData, categoryLabels) {
5128
- const layout = computePlotLayout(element.width, element.height, chartData, true);
5129
- const range = distributionRange(chartData.series);
5130
- const catCount = Math.max(categoryLabels.length, 1);
5131
- const geometries = computeBoxWhiskerGeometry(
5132
- chartData,
5133
- catCount,
5134
- layout,
5135
- range,
5136
- chartData.colorPalette
5137
- );
5138
- const primitives = [];
5139
- for (const g of geometries) {
5140
- primitives.push(
5141
- {
5142
- kind: "line",
5143
- x1: g.xMid,
5144
- y1: g.yMax,
5145
- x2: g.xMid,
5146
- y2: g.yQ3,
5147
- stroke: WHISKER_COLOR,
5148
- strokeWidth: 1
5149
- },
5150
- {
5151
- kind: "line",
5152
- x1: g.xMid,
5153
- y1: g.yQ1,
5154
- x2: g.xMid,
5155
- y2: g.yMin,
5156
- stroke: WHISKER_COLOR,
5157
- strokeWidth: 1
6651
+ function hierarchyKey(levels, level, index) {
6652
+ return levels.slice(level).map((labels) => labels[index] ?? "").join("\0");
6653
+ }
6654
+ function computeHierarchicalSunburstArcs(categoryLevels, values, cx, cy, maxR, colorPalette) {
6655
+ const levels = categoryLevels.filter((level) => level.length > 0);
6656
+ const leafCount = Math.max(values.length, ...levels.map((level) => level.length), 0);
6657
+ if (levels.length === 0 || leafCount === 0) {
6658
+ return [];
6659
+ }
6660
+ const rawWeights = Array.from({ length: leafCount }, (_, index) => Math.abs(values[index] ?? 0));
6661
+ const weights = rawWeights.some((value) => value !== 0) ? rawWeights : rawWeights.map(() => 1);
6662
+ const total = weights.reduce((sum, value) => sum + value, 0);
6663
+ const prefix = [0];
6664
+ for (const weight of weights) {
6665
+ prefix.push((prefix[prefix.length - 1] ?? 0) + weight);
6666
+ }
6667
+ const ringWidth = maxR / (levels.length + 0.5);
6668
+ const rootLabels = levels[levels.length - 1] ?? [];
6669
+ const rootColors = /* @__PURE__ */ new Map();
6670
+ const out = [];
6671
+ for (let level = levels.length - 1; level >= 0; level--) {
6672
+ const ringIndex = levels.length - 1 - level;
6673
+ const innerRadius = ringWidth * (ringIndex + 0.5);
6674
+ const outerRadius = ringWidth * (ringIndex + 1.5);
6675
+ let start = 0;
6676
+ while (start < leafCount) {
6677
+ const key = hierarchyKey(levels, level, start);
6678
+ let end = start + 1;
6679
+ while (end < leafCount && hierarchyKey(levels, level, end) === key) {
6680
+ end++;
5158
6681
  }
5159
- );
5160
- primitives.push(
5161
- {
5162
- kind: "line",
5163
- x1: g.boxX + g.boxW * 0.25,
5164
- y1: g.yMax,
5165
- x2: g.boxX + g.boxW * 0.75,
5166
- y2: g.yMax,
5167
- stroke: WHISKER_COLOR,
5168
- strokeWidth: 1
5169
- },
5170
- {
5171
- kind: "line",
5172
- x1: g.boxX + g.boxW * 0.25,
5173
- y1: g.yMin,
5174
- x2: g.boxX + g.boxW * 0.75,
5175
- y2: g.yMin,
5176
- stroke: WHISKER_COLOR,
5177
- strokeWidth: 1
6682
+ const startAngle = -Math.PI / 2 + prefix[start] / total * Math.PI * 2;
6683
+ const endAngle = -Math.PI / 2 + prefix[end] / total * Math.PI * 2;
6684
+ const rootLabel = rootLabels[start] ?? "";
6685
+ if (!rootColors.has(rootLabel)) {
6686
+ rootColors.set(rootLabel, rootColors.size);
5178
6687
  }
5179
- );
5180
- primitives.push({
5181
- kind: "rect",
5182
- x: g.boxX,
5183
- y: Math.min(g.yQ1, g.yQ3),
5184
- w: g.boxW,
5185
- h: Math.abs(g.yQ1 - g.yQ3),
5186
- fill: g.fill,
5187
- rx: 1,
5188
- opacity: 0.8
5189
- });
5190
- primitives.push({
5191
- kind: "line",
5192
- x1: g.boxX,
5193
- y1: g.yMed,
5194
- x2: g.boxX + g.boxW,
5195
- y2: g.yMed,
5196
- stroke: MEDIAN_COLOR,
5197
- strokeWidth: 2
5198
- });
6688
+ out.push({
6689
+ d: arcPath(cx, cy, innerRadius, outerRadius, startAngle, endAngle),
6690
+ fill: paletteColor2(rootColors.get(rootLabel) ?? start, colorPalette),
6691
+ opacity: Math.max(0.1, 0.9 - ringIndex * 0.1),
6692
+ level: ringIndex,
6693
+ label: levels[level][start] ?? "",
6694
+ ...level === 0 && end === start + 1 ? { pointIndex: start } : {}
6695
+ });
6696
+ start = end;
6697
+ }
5199
6698
  }
5200
- const { gridlines, axisLabels } = buildGridlinesAndLabels(range, layout);
5201
- const zeroLine = buildZeroLine(range, layout);
5202
- const catLabels = buildCategoryLabels(categoryLabels, layout, "bar");
5203
- const legendPos = chartData.style?.legendPosition ?? "b";
5204
- const { legend, legendX, legendY, legendAnchor } = buildLegend(
5205
- chartData.series,
5206
- chartData.colorPalette,
5207
- layout.svgWidth,
5208
- legendPos,
5209
- layout.svgHeight,
5210
- layout.plotTop
5211
- );
5212
- const catLegend = categoryLabels.map((label, i) => ({
5213
- color: paletteColor2(i, chartData.colorPalette),
5214
- label
5215
- }));
5216
- const title = chartData.style?.hasTitle && chartData.title ? chartData.title : void 0;
5217
- return {
5218
- svgWidth: layout.svgWidth,
5219
- svgHeight: layout.svgHeight,
5220
- title,
5221
- titleX: layout.svgWidth / 2,
5222
- titleY: 12,
5223
- gridlines,
5224
- axisLabels,
5225
- zeroLine,
5226
- categoryLabels: catLabels,
5227
- primitives,
5228
- dataLabels: [],
5229
- legend: chartData.style?.hasLegend ? catLegend.length > 0 ? catLegend : legend : [],
5230
- legendX,
5231
- legendY,
5232
- legendAnchor
5233
- };
6699
+ return out;
5234
6700
  }
5235
6701
  function emptyChrome() {
5236
6702
  return {
@@ -5327,45 +6793,20 @@ function buildFunnelViewModel(element, chartData, categoryLabels) {
5327
6793
  legendAnchor: "middle"
5328
6794
  };
5329
6795
  }
5330
- function computeSunburstArcs(series, cx, cy, maxR, colorPalette) {
5331
- const seriesCount = Math.max(series.length, 1);
5332
- const ringWidth = maxR / (seriesCount + 0.5);
5333
- const out = [];
5334
- for (let si = 0; si < series.length; si++) {
5335
- const s = series[si];
5336
- const iR = ringWidth * (si + 0.5);
5337
- const oR = ringWidth * (si + 1.5);
5338
- const total = s.values.reduce((acc, v) => acc + Math.abs(v), 0) || 1;
5339
- let startAngle = -Math.PI / 2;
5340
- for (let vi = 0; vi < s.values.length; vi++) {
5341
- const val2 = s.values[vi];
5342
- const sweep = Math.abs(val2) / total * Math.PI * 2;
5343
- const endAngle = startAngle + sweep;
5344
- const largeArc = sweep > Math.PI ? 1 : 0;
5345
- const x1 = cx + oR * Math.cos(startAngle);
5346
- const y1 = cy + oR * Math.sin(startAngle);
5347
- const x2 = cx + oR * Math.cos(endAngle);
5348
- const y2 = cy + oR * Math.sin(endAngle);
5349
- const x3 = cx + iR * Math.cos(endAngle);
5350
- const y3 = cy + iR * Math.sin(endAngle);
5351
- const x4 = cx + iR * Math.cos(startAngle);
5352
- const y4 = cy + iR * Math.sin(startAngle);
5353
- out.push({
5354
- d: `M ${x1} ${y1} A ${oR} ${oR} 0 ${largeArc} 1 ${x2} ${y2} L ${x3} ${y3} A ${iR} ${iR} 0 ${largeArc} 0 ${x4} ${y4} Z`,
5355
- fill: paletteColor2(vi, colorPalette),
5356
- opacity: Math.max(0.1, 0.9 - si * 0.1)
5357
- });
5358
- startAngle = endAngle;
5359
- }
5360
- }
5361
- return out;
5362
- }
5363
6796
  function buildSunburstViewModel(element, chartData, categoryLabels) {
5364
6797
  const layout = computePlotLayout(element.width, element.height, chartData, false);
5365
6798
  const cx = layout.plotLeft + layout.plotWidth / 2;
5366
6799
  const cy = layout.plotTop + layout.plotHeight / 2;
5367
6800
  const maxR = Math.min(layout.plotWidth, layout.plotHeight) / 2 - 4;
5368
- const arcs = computeSunburstArcs(chartData.series, cx, cy, maxR, chartData.colorPalette);
6801
+ const categoryLevels = chartData.categoryLevels;
6802
+ const arcs = categoryLevels?.length ? computeHierarchicalSunburstArcs(
6803
+ categoryLevels,
6804
+ chartData.series[0]?.values ?? [],
6805
+ cx,
6806
+ cy,
6807
+ maxR,
6808
+ chartData.colorPalette
6809
+ ) : computeSunburstArcs(chartData.series, cx, cy, maxR, chartData.colorPalette);
5369
6810
  const primitives = arcs.map(
5370
6811
  (arc) => ({
5371
6812
  kind: "path",
@@ -5373,10 +6814,12 @@ function buildSunburstViewModel(element, chartData, categoryLabels) {
5373
6814
  fill: arc.fill,
5374
6815
  stroke: "#ffffff",
5375
6816
  strokeWidth: 1,
5376
- opacity: arc.opacity
6817
+ opacity: arc.opacity,
6818
+ part: arc.pointIndex === void 0 ? void 0 : { role: "dataPoint", seriesIndex: 0, pointIndex: arc.pointIndex }
5377
6819
  })
5378
6820
  );
5379
- const legend = chartData.style?.hasLegend ? categoryLabels.map((label, i) => ({ color: paletteColor2(i, chartData.colorPalette), label })) : [];
6821
+ const legendLabels = categoryLevels?.length ? [...new Set(categoryLevels[categoryLevels.length - 1]?.filter(Boolean) ?? categoryLabels)] : categoryLabels;
6822
+ const legend = chartData.style?.hasLegend ? legendLabels.map((label, i) => ({ color: paletteColor2(i, chartData.colorPalette), label })) : [];
5380
6823
  const title = chartData.style?.hasTitle && chartData.title ? chartData.title : void 0;
5381
6824
  return {
5382
6825
  svgWidth: layout.svgWidth,
@@ -5393,6 +6836,176 @@ function buildSunburstViewModel(element, chartData, categoryLabels) {
5393
6836
  legendAnchor: "middle"
5394
6837
  };
5395
6838
  }
6839
+ function normalizedLevels(levels, pointCount) {
6840
+ return levels.map((level) => {
6841
+ let previous = "";
6842
+ return Array.from({ length: pointCount }, (_, index) => {
6843
+ const label = level[index]?.trim() ?? "";
6844
+ if (label) {
6845
+ previous = label;
6846
+ }
6847
+ return label || previous;
6848
+ });
6849
+ });
6850
+ }
6851
+ function findOrAddParent(children, label, colorIndex, parentLabelLayout) {
6852
+ const existing = children.find((child2) => child2.children && child2.label === label);
6853
+ if (existing) {
6854
+ return existing;
6855
+ }
6856
+ const parent = {
6857
+ label,
6858
+ weight: 0,
6859
+ children: [],
6860
+ colorIndex,
6861
+ parentLabelLayout
6862
+ };
6863
+ children.push(parent);
6864
+ return parent;
6865
+ }
6866
+ function buildSeriesHierarchy(series, seriesIndex, categoryLabels, categoryLevels, colorStride) {
6867
+ const pointCount = series.values.length;
6868
+ const levels = normalizedLevels(categoryLevels ?? [], pointCount);
6869
+ const layout = series.treemapOptions?.parentLabelLayout ?? "banner";
6870
+ const roots = [];
6871
+ for (let pointIndex = 0; pointIndex < pointCount; pointIndex++) {
6872
+ let children = roots;
6873
+ for (let levelIndex = levels.length - 1; levelIndex >= 1; levelIndex--) {
6874
+ const label = levels[levelIndex][pointIndex] || `Group ${levelIndex}`;
6875
+ children = findOrAddParent(children, label, pointIndex, layout).children;
6876
+ }
6877
+ children.push({
6878
+ label: levels[0]?.[pointIndex] || categoryLabels[pointIndex] || String(pointIndex + 1),
6879
+ weight: Math.abs(series.values[pointIndex] ?? 0),
6880
+ seriesIndex,
6881
+ pointIndex,
6882
+ colorIndex: seriesIndex * colorStride + pointIndex,
6883
+ parentLabelLayout: layout
6884
+ });
6885
+ }
6886
+ return roots;
6887
+ }
6888
+ function aggregate(node) {
6889
+ if (node.children) {
6890
+ node.weight = node.children.reduce((sum, child2) => sum + aggregate(child2), 0);
6891
+ }
6892
+ return node.weight;
6893
+ }
6894
+ function splitNodes(nodes, box) {
6895
+ const sorted = [...nodes].sort((a, b) => b.weight - a.weight);
6896
+ const total = sorted.reduce((sum, node) => sum + node.weight, 0);
6897
+ const fallback = total === 0 ? sorted.length : total;
6898
+ let remaining = fallback;
6899
+ let current = { ...box };
6900
+ return sorted.map((node) => {
6901
+ const weight = total === 0 ? 1 : node.weight;
6902
+ const fraction = remaining > 0 ? weight / remaining : 0;
6903
+ const splitWidth = current.w >= current.h;
6904
+ const allocated = splitWidth ? { ...current, w: current.w * fraction } : { ...current, h: current.h * fraction };
6905
+ if (splitWidth) {
6906
+ current = { ...current, x: current.x + allocated.w, w: current.w - allocated.w };
6907
+ } else {
6908
+ current = { ...current, y: current.y + allocated.h, h: current.h - allocated.h };
6909
+ }
6910
+ remaining -= weight;
6911
+ return [node, allocated];
6912
+ });
6913
+ }
6914
+ function renderNodes(nodes, box, colorPalette, primitives) {
6915
+ for (const [node, allocation] of splitNodes(nodes, box)) {
6916
+ const cell = {
6917
+ x: allocation.x + 1,
6918
+ y: allocation.y + 1,
6919
+ w: Math.max(allocation.w - 2, 1),
6920
+ h: Math.max(allocation.h - 2, 1)
6921
+ };
6922
+ if (node.children) {
6923
+ const showParent = node.parentLabelLayout !== "none" && cell.w > 28 && cell.h > 16;
6924
+ if (showParent) {
6925
+ primitives.push({
6926
+ kind: "text",
6927
+ x: cell.x + 4,
6928
+ y: cell.y + 11,
6929
+ text: node.label,
6930
+ fontSize: 10,
6931
+ fill: "#303030",
6932
+ textAnchor: "start",
6933
+ fontWeight: "bold"
6934
+ });
6935
+ }
6936
+ const bannerHeight = showParent && node.parentLabelLayout === "banner" ? 16 : 0;
6937
+ renderNodes(
6938
+ node.children,
6939
+ { ...cell, y: cell.y + bannerHeight, h: Math.max(cell.h - bannerHeight, 1) },
6940
+ colorPalette,
6941
+ primitives
6942
+ );
6943
+ continue;
6944
+ }
6945
+ primitives.push({
6946
+ kind: "rect",
6947
+ ...cell,
6948
+ fill: paletteColor2(node.colorIndex, colorPalette),
6949
+ rx: 2,
6950
+ opacity: 0.85,
6951
+ part: {
6952
+ role: "dataPoint",
6953
+ seriesIndex: node.seriesIndex,
6954
+ pointIndex: node.pointIndex
6955
+ }
6956
+ });
6957
+ if (cell.w > 30 && cell.h > 14) {
6958
+ primitives.push({
6959
+ kind: "text",
6960
+ x: cell.x + cell.w / 2,
6961
+ y: cell.y + cell.h / 2,
6962
+ text: node.label,
6963
+ fontSize: Math.min(10, cell.h * 0.3),
6964
+ fill: "#ffffff",
6965
+ textAnchor: "middle",
6966
+ fontWeight: "bold",
6967
+ dominantBaseline: "central"
6968
+ });
6969
+ }
6970
+ }
6971
+ }
6972
+ function buildHierarchicalTreemapPrimitives(chartData, categoryLabels, box) {
6973
+ const colorStride = Math.max(
6974
+ categoryLabels.length,
6975
+ ...chartData.series.map((s) => s.values.length),
6976
+ 1
6977
+ );
6978
+ let roots = chartData.series.flatMap(
6979
+ (series, seriesIndex) => buildSeriesHierarchy(
6980
+ series,
6981
+ seriesIndex,
6982
+ categoryLabels,
6983
+ chartData.categoryLevels,
6984
+ colorStride
6985
+ )
6986
+ );
6987
+ if (chartData.series.length > 1) {
6988
+ roots = chartData.series.map((series, seriesIndex) => ({
6989
+ label: series.name,
6990
+ weight: 0,
6991
+ children: buildSeriesHierarchy(
6992
+ series,
6993
+ seriesIndex,
6994
+ categoryLabels,
6995
+ chartData.categoryLevels,
6996
+ colorStride
6997
+ ),
6998
+ colorIndex: seriesIndex * colorStride,
6999
+ parentLabelLayout: series.treemapOptions?.parentLabelLayout ?? "banner"
7000
+ }));
7001
+ }
7002
+ for (const root of roots) {
7003
+ aggregate(root);
7004
+ }
7005
+ const primitives = [];
7006
+ renderNodes(roots, box, chartData.colorPalette, primitives);
7007
+ return primitives;
7008
+ }
5396
7009
  var ISO_COS30 = Math.cos(Math.PI / 6);
5397
7010
  var ISO_SIN30 = Math.sin(Math.PI / 6);
5398
7011
  function isoProject(x, y, z) {
@@ -5562,67 +7175,24 @@ function buildFlatSurfaceViewModel(element, chartData, categoryLabels) {
5562
7175
  legendX,
5563
7176
  legendY,
5564
7177
  legendAnchor
5565
- };
5566
- }
5567
- function buildSurfaceViewModel(element, chartData, categoryLabels) {
5568
- const catCount = Math.max(categoryLabels.length, 1);
5569
- const seriesCount = chartData.series.length;
5570
- if (seriesCount >= 2 && catCount >= 2) {
5571
- return buildIsometricSurfaceViewModel(element, chartData, categoryLabels);
5572
- }
5573
- return buildFlatSurfaceViewModel(element, chartData, categoryLabels);
5574
- }
5575
- function buildTreemapViewModel(element, chartData, categoryLabels) {
5576
- const layout = computePlotLayout(element.width, element.height, chartData, false);
5577
- const allValues = chartData.series.flatMap((s) => s.values);
5578
- const totalAbs = allValues.reduce((sum, v) => sum + Math.abs(v), 0) || 1;
5579
- const primitives = [];
5580
- let curX = layout.plotLeft;
5581
- let curY = layout.plotTop;
5582
- let remainW = layout.plotWidth;
5583
- let remainH = layout.plotHeight;
5584
- let remainTotal = totalAbs;
5585
- const items = allValues.map((v, i) => ({ value: Math.abs(v), index: i })).sort((a, b) => b.value - a.value);
5586
- for (const item of items) {
5587
- const fraction = remainTotal > 0 ? item.value / remainTotal : 0;
5588
- const useWidth = remainW >= remainH;
5589
- const w = useWidth ? remainW * fraction : remainW;
5590
- const h = useWidth ? remainH : remainH * fraction;
5591
- const rw = Math.max(w - 1, 1);
5592
- const rh = Math.max(h - 1, 1);
5593
- primitives.push({
5594
- kind: "rect",
5595
- x: curX,
5596
- y: curY,
5597
- w: rw,
5598
- h: rh,
5599
- fill: paletteColor2(item.index, chartData.colorPalette),
5600
- rx: 2,
5601
- opacity: 0.85
5602
- });
5603
- const label = categoryLabels[item.index] ?? String(item.index + 1);
5604
- if (rw > 30 && rh > 14) {
5605
- primitives.push({
5606
- kind: "text",
5607
- x: curX + rw / 2,
5608
- y: curY + rh / 2,
5609
- text: label,
5610
- fontSize: Math.min(10, rh * 0.3),
5611
- fill: "#ffffff",
5612
- textAnchor: "middle",
5613
- fontWeight: "bold",
5614
- dominantBaseline: "central"
5615
- });
5616
- }
5617
- if (useWidth) {
5618
- curX += w;
5619
- remainW -= w;
5620
- } else {
5621
- curY += h;
5622
- remainH -= h;
5623
- }
5624
- remainTotal -= item.value;
7178
+ };
7179
+ }
7180
+ function buildSurfaceViewModel(element, chartData, categoryLabels) {
7181
+ const catCount = Math.max(categoryLabels.length, 1);
7182
+ const seriesCount = chartData.series.length;
7183
+ if (seriesCount >= 2 && catCount >= 2) {
7184
+ return buildIsometricSurfaceViewModel(element, chartData, categoryLabels);
5625
7185
  }
7186
+ return buildFlatSurfaceViewModel(element, chartData, categoryLabels);
7187
+ }
7188
+ function buildTreemapViewModel(element, chartData, categoryLabels) {
7189
+ const layout = computePlotLayout(element.width, element.height, chartData, false);
7190
+ const primitives = buildHierarchicalTreemapPrimitives(chartData, categoryLabels, {
7191
+ x: layout.plotLeft,
7192
+ y: layout.plotTop,
7193
+ w: layout.plotWidth,
7194
+ h: layout.plotHeight
7195
+ });
5626
7196
  const legendPos = chartData.style?.legendPosition ?? "b";
5627
7197
  const { legend, legendX, legendY, legendAnchor } = buildLegend(
5628
7198
  chartData.series,
@@ -5652,31 +7222,144 @@ function buildTreemapViewModel(element, chartData, categoryLabels) {
5652
7222
  legendAnchor
5653
7223
  };
5654
7224
  }
7225
+ function sourceIndices(indices, length) {
7226
+ return Array.from({ length }, (_, position) => indices?.[position] ?? position);
7227
+ }
7228
+ function valueAtSource(values, indices, sourceIndex) {
7229
+ const position = indices.indexOf(sourceIndex);
7230
+ return position >= 0 ? values[position] : void 0;
7231
+ }
7232
+ function cachedEntityName(cache, entityId) {
7233
+ if (!cache || typeof cache !== "object") {
7234
+ return void 0;
7235
+ }
7236
+ const record = cache;
7237
+ if (String(record["@_entityId"] ?? "") === entityId && record["@_entityName"] !== void 0) {
7238
+ return String(record["@_entityName"]);
7239
+ }
7240
+ for (const value of Object.values(record)) {
7241
+ if (Array.isArray(value)) {
7242
+ for (const item of value) {
7243
+ const name = cachedEntityName(item, entityId);
7244
+ if (name) {
7245
+ return name;
7246
+ }
7247
+ }
7248
+ } else {
7249
+ const name = cachedEntityName(value, entityId);
7250
+ if (name) {
7251
+ return name;
7252
+ }
7253
+ }
7254
+ }
7255
+ return void 0;
7256
+ }
7257
+ function resolveRegionEntityCode(entityId, options, resolveCode) {
7258
+ if (!entityId) {
7259
+ return void 0;
7260
+ }
7261
+ const direct = resolveCode(entityId);
7262
+ if (direct) {
7263
+ return direct;
7264
+ }
7265
+ const tokens = entityId.split(/[:/|._-]+/u).filter(Boolean);
7266
+ for (let index = tokens.length - 1; index >= 0; index--) {
7267
+ const resolved = resolveCode(tokens[index] ?? "");
7268
+ if (resolved) {
7269
+ return resolved;
7270
+ }
7271
+ }
7272
+ const cachedName = cachedEntityName(options?.geographyCache, entityId);
7273
+ return cachedName ? resolveCode(cachedName) : void 0;
7274
+ }
7275
+ function buildRegionMapEntries(categories, values, options, resolveCode) {
7276
+ const entityIds = options?.entityIds ?? [];
7277
+ const categoryIndices = sourceIndices(options?.categorySourceIndices, categories.length);
7278
+ const valueIndices = sourceIndices(options?.valueSourceIndices, values.length);
7279
+ const entityIndices = sourceIndices(options?.entityIdSourceIndices, entityIds.length);
7280
+ const indices = [.../* @__PURE__ */ new Set([...categoryIndices, ...valueIndices, ...entityIndices])].sort(
7281
+ (a, b) => a - b
7282
+ );
7283
+ return indices.map((sourceIndex) => {
7284
+ const category = valueAtSource(categories, categoryIndices, sourceIndex) ?? "";
7285
+ const value = valueAtSource(values, valueIndices, sourceIndex) ?? 0;
7286
+ const entityId = valueAtSource(entityIds, entityIndices, sourceIndex);
7287
+ return {
7288
+ sourceIndex,
7289
+ label: category || entityId || `Region ${sourceIndex + 1}`,
7290
+ value,
7291
+ ...entityId ? { entityId } : {},
7292
+ code: resolveRegionEntityCode(entityId, options, resolveCode) ?? resolveCode(category)
7293
+ };
7294
+ });
7295
+ }
7296
+ function shouldRenderRegionLabel(layout, projectedWidth, projectedHeight) {
7297
+ if (layout === "none") {
7298
+ return false;
7299
+ }
7300
+ if (layout === "bestFitOnly") {
7301
+ return projectedWidth >= 18 && projectedHeight >= 10;
7302
+ }
7303
+ return true;
7304
+ }
7305
+ function formatRegionMapValue(value, cultureLanguage) {
7306
+ if (!cultureLanguage) {
7307
+ return String(value);
7308
+ }
7309
+ try {
7310
+ return new Intl.NumberFormat(cultureLanguage, { maximumFractionDigits: 2 }).format(value);
7311
+ } catch {
7312
+ return String(value);
7313
+ }
7314
+ }
7315
+ function buildWaterfallSteps(values, options) {
7316
+ const subtotalIndices = new Set(
7317
+ options?.subtotalIndices ?? (values.length > 0 ? [values.length - 1] : [])
7318
+ );
7319
+ const steps = [];
7320
+ let runningTotal = 0;
7321
+ for (let sourceIndex = 0; sourceIndex < values.length; sourceIndex++) {
7322
+ const value = values[sourceIndex] ?? 0;
7323
+ const isSubtotal = subtotalIndices.has(sourceIndex);
7324
+ const startValue = isSubtotal ? 0 : runningTotal;
7325
+ const endValue = isSubtotal ? value : runningTotal + value;
7326
+ steps.push({ sourceIndex, value, startValue, endValue, isSubtotal });
7327
+ runningTotal = endValue;
7328
+ }
7329
+ return steps;
7330
+ }
7331
+ function computeWaterfallRange(steps) {
7332
+ return computeValueRange2([
7333
+ {
7334
+ name: "Waterfall range",
7335
+ values: steps.flatMap((step) => [step.startValue, step.endValue])
7336
+ }
7337
+ ]);
7338
+ }
5655
7339
  var WF_COLOR_POSITIVE = "#22c55e";
5656
7340
  var WF_COLOR_NEGATIVE = "#ef4444";
5657
7341
  var WF_COLOR_TOTAL = "#6366f1";
5658
7342
  var WF_CONNECTOR_COLOR = "#94a3b8";
5659
7343
  function buildWaterfallViewModel(element, chartData, categoryLabels) {
5660
7344
  const layout = computePlotLayout(element.width, element.height, chartData, true);
5661
- const values = chartData.series[0]?.values ?? [];
5662
- const range = computeValueRange2(chartData.series);
7345
+ const series = chartData.series[0];
7346
+ const values = series?.values ?? [];
7347
+ const steps = buildWaterfallSteps(values, series?.waterfallOptions);
7348
+ const range = computeWaterfallRange(steps);
5663
7349
  const catCount = Math.max(categoryLabels.length, values.length, 1);
5664
7350
  const barWidth = layout.plotWidth / catCount * 0.6;
5665
7351
  const gap = layout.plotWidth / catCount * 0.2;
5666
7352
  const primitives = [];
5667
7353
  const dataLabels = [];
5668
- let runningTotal = 0;
5669
- for (let i = 0; i < values.length; i++) {
5670
- const val2 = values[i] ?? 0;
5671
- const isLast = i === values.length - 1;
5672
- const startVal = isLast ? 0 : runningTotal;
5673
- const endVal = runningTotal + val2;
5674
- const barStartY = valueToY2(startVal, range, layout.plotTop, layout.plotBottom);
5675
- const barEndY = valueToY2(endVal, range, layout.plotTop, layout.plotBottom);
7354
+ for (const step of steps) {
7355
+ const { sourceIndex, value, startValue, endValue, isSubtotal } = step;
7356
+ const barStartY = valueToY2(startValue, range, layout.plotTop, layout.plotBottom);
7357
+ const barEndY = valueToY2(endValue, range, layout.plotTop, layout.plotBottom);
7358
+ const i = sourceIndex;
5676
7359
  const x = layout.plotLeft + layout.plotWidth / catCount * i + gap;
5677
7360
  const y = Math.min(barStartY, barEndY);
5678
7361
  const h = Math.max(Math.abs(barEndY - barStartY), 1);
5679
- const barColor = isLast ? WF_COLOR_TOTAL : val2 >= 0 ? WF_COLOR_POSITIVE : WF_COLOR_NEGATIVE;
7362
+ const barColor = isSubtotal ? WF_COLOR_TOTAL : value >= 0 ? WF_COLOR_POSITIVE : WF_COLOR_NEGATIVE;
5680
7363
  primitives.push({
5681
7364
  kind: "rect",
5682
7365
  x,
@@ -5684,20 +7367,21 @@ function buildWaterfallViewModel(element, chartData, categoryLabels) {
5684
7367
  w: barWidth,
5685
7368
  h,
5686
7369
  fill: barColor,
5687
- rx: 1
7370
+ rx: 1,
7371
+ part: { role: "dataPoint", seriesIndex: 0, pointIndex: sourceIndex }
5688
7372
  });
5689
7373
  if (chartData.style?.hasDataLabels) {
5690
7374
  dataLabels.push({
5691
7375
  kind: "text",
5692
7376
  x: x + barWidth / 2,
5693
7377
  y: y - 4,
5694
- text: formatAxisValue2(isLast ? endVal : val2),
7378
+ text: formatAxisValue2(value),
5695
7379
  fontSize: 7,
5696
7380
  fill: "#334155",
5697
7381
  textAnchor: "middle"
5698
7382
  });
5699
7383
  }
5700
- if (!isLast && i < values.length - 1) {
7384
+ if (series?.waterfallOptions?.connectorLines !== false && i < values.length - 1) {
5701
7385
  const nextX = layout.plotLeft + layout.plotWidth / catCount * (i + 1) + gap;
5702
7386
  primitives.push({
5703
7387
  kind: "line",
@@ -5710,9 +7394,6 @@ function buildWaterfallViewModel(element, chartData, categoryLabels) {
5710
7394
  dashArray: "3 2"
5711
7395
  });
5712
7396
  }
5713
- if (!isLast) {
5714
- runningTotal += val2;
5715
- }
5716
7397
  }
5717
7398
  const { gridlines, axisLabels } = buildGridlinesAndLabels(range, layout);
5718
7399
  const zeroLine = buildZeroLine(range, layout);
@@ -5821,7 +7502,7 @@ function resolveRegionCode(label) {
5821
7502
  return REGION_ALIAS_MAP[normalized];
5822
7503
  }
5823
7504
  function lerpColor(a, b, t) {
5824
- const clamp3 = (v) => Math.max(0, Math.min(255, Math.round(v)));
7505
+ const clamp7 = (v) => Math.max(0, Math.min(255, Math.round(v)));
5825
7506
  const ha = a.replace("#", "");
5826
7507
  const hb = b.replace("#", "");
5827
7508
  const r1 = parseInt(ha.substring(0, 2), 16);
@@ -5830,9 +7511,9 @@ function lerpColor(a, b, t) {
5830
7511
  const r2 = parseInt(hb.substring(0, 2), 16);
5831
7512
  const g2 = parseInt(hb.substring(2, 4), 16);
5832
7513
  const b2 = parseInt(hb.substring(4, 6), 16);
5833
- const r = clamp3(r1 + (r2 - r1) * t);
5834
- const g = clamp3(g1 + (g2 - g1) * t);
5835
- const bl = clamp3(b1 + (b2 - b1) * t);
7514
+ const r = clamp7(r1 + (r2 - r1) * t);
7515
+ const g = clamp7(g1 + (g2 - g1) * t);
7516
+ const bl = clamp7(b1 + (b2 - b1) * t);
5836
7517
  const toHex = (n) => n.toString(16).padStart(2, "0");
5837
7518
  return `#${toHex(r)}${toHex(g)}${toHex(bl)}`;
5838
7519
  }
@@ -5983,24 +7664,61 @@ var WORLD_REGIONS = [
5983
7664
  labelXY: [838, 378]
5984
7665
  }
5985
7666
  ];
7667
+ function regionBounds(region) {
7668
+ const coordinates = region.path.match(/-?\d+(?:\.\d+)?/gu)?.map(Number) ?? [];
7669
+ const xs = [];
7670
+ const ys = [];
7671
+ for (let index = 0; index < coordinates.length; index += 2) {
7672
+ xs.push(coordinates[index] ?? 0);
7673
+ ys.push(coordinates[index + 1] ?? 0);
7674
+ }
7675
+ return {
7676
+ minX: Math.min(...xs),
7677
+ minY: Math.min(...ys),
7678
+ maxX: Math.max(...xs),
7679
+ maxY: Math.max(...ys)
7680
+ };
7681
+ }
7682
+ function regionViewBounds(viewedRegionType, regionValues) {
7683
+ if (!viewedRegionType || viewedRegionType === "world" || regionValues.size === 0) {
7684
+ return { minX: 0, minY: 0, maxX: 1e3, maxY: 500 };
7685
+ }
7686
+ const matched = WORLD_REGIONS.filter((region) => regionValues.has(region.code));
7687
+ const targets = viewedRegionType === "countryRegion" ? matched.slice(0, 1) : matched;
7688
+ if (targets.length === 0) {
7689
+ return { minX: 0, minY: 0, maxX: 1e3, maxY: 500 };
7690
+ }
7691
+ const bounds = targets.map(regionBounds);
7692
+ const padding = 10;
7693
+ return {
7694
+ minX: Math.max(0, Math.min(...bounds.map((item) => item.minX)) - padding),
7695
+ minY: Math.max(0, Math.min(...bounds.map((item) => item.minY)) - padding),
7696
+ maxX: Math.min(1e3, Math.max(...bounds.map((item) => item.maxX)) + padding),
7697
+ maxY: Math.min(500, Math.max(...bounds.map((item) => item.maxY)) + padding)
7698
+ };
7699
+ }
5986
7700
  function buildRegionMapViewModel(element, chartData, categoryLabels) {
5987
7701
  const svgWidth = Math.max(element.width, 320);
5988
7702
  const svgHeight = Math.max(element.height, 200);
5989
7703
  const categories = categoryLabels.length > 0 ? categoryLabels : chartData.categories;
5990
- const values = chartData.series.length > 0 ? chartData.series[0]?.values ?? [] : [];
7704
+ const series = chartData.series[0];
7705
+ const options = series?.regionMapOptions;
7706
+ const entries = buildRegionMapEntries(categories, series?.values ?? [], options, resolveRegionCode);
7707
+ const values = entries.map((entry) => entry.value);
5991
7708
  const finiteVals = values.filter((v) => Number.isFinite(v));
5992
7709
  const minVal = finiteVals.length > 0 ? Math.min(...finiteVals) : 0;
5993
7710
  const maxVal = finiteVals.length > 0 ? Math.max(...finiteVals) : 1;
5994
7711
  const regionValueMap = /* @__PURE__ */ new Map();
5995
7712
  const unmatchedRows = [];
5996
- for (let i = 0; i < categories.length; i++) {
5997
- const cat = categories[i] ?? "";
5998
- const value = values[i] ?? 0;
5999
- const code = resolveRegionCode(cat);
6000
- if (code !== void 0) {
6001
- regionValueMap.set(code, { value, label: cat });
7713
+ for (const entry of entries) {
7714
+ if (entry.code !== void 0) {
7715
+ regionValueMap.set(entry.code, {
7716
+ value: entry.value,
7717
+ label: entry.label,
7718
+ sourceIndex: entry.sourceIndex
7719
+ });
6002
7720
  } else {
6003
- unmatchedRows.push({ label: cat, value });
7721
+ unmatchedRows.push({ label: entry.label, value: entry.value });
6004
7722
  }
6005
7723
  }
6006
7724
  const legendHeight = 30;
@@ -6009,9 +7727,12 @@ function buildRegionMapViewModel(element, chartData, categoryLabels) {
6009
7727
  const fallbackTableH = unmatchedRows.length > 0 ? (maxFallbackRows + 1) * fallbackRowH + 8 : 0;
6010
7728
  const titleH = chartData.title ? 22 : 0;
6011
7729
  const mapAreaH = Math.max(svgHeight - titleH - legendHeight - fallbackTableH - 8, 80);
6012
- const mapScale = Math.min((svgWidth - 20) / 1e3, mapAreaH / 500);
6013
- const mapOffsetX = (svgWidth - 1e3 * mapScale) / 2;
6014
- const mapOffsetY = titleH + 4;
7730
+ const viewBounds = regionViewBounds(options?.viewedRegionType, regionValueMap);
7731
+ const viewWidth = Math.max(viewBounds.maxX - viewBounds.minX, 1);
7732
+ const viewHeight = Math.max(viewBounds.maxY - viewBounds.minY, 1);
7733
+ const mapScale = Math.min((svgWidth - 20) / viewWidth, mapAreaH / viewHeight);
7734
+ const mapOffsetX = (svgWidth - viewWidth * mapScale) / 2 - viewBounds.minX * mapScale;
7735
+ const mapOffsetY = titleH + 4 - viewBounds.minY * mapScale;
6015
7736
  const primitives = [];
6016
7737
  primitives.push({
6017
7738
  kind: "rect",
@@ -6046,16 +7767,28 @@ function buildRegionMapViewModel(element, chartData, categoryLabels) {
6046
7767
  d: scaledPath,
6047
7768
  fill,
6048
7769
  stroke: "#94a3b8",
6049
- strokeWidth: Math.max(0.5 / mapScale, 0.3)
7770
+ strokeWidth: Math.max(0.5 / mapScale, 0.3),
7771
+ ...entry ? {
7772
+ part: {
7773
+ role: "dataPoint",
7774
+ seriesIndex: 0,
7775
+ pointIndex: entry.sourceIndex
7776
+ }
7777
+ } : {}
6050
7778
  });
6051
- if (entry !== void 0) {
7779
+ const bounds = regionBounds(region);
7780
+ if (entry !== void 0 && shouldRenderRegionLabel(
7781
+ options?.regionLabelLayout,
7782
+ (bounds.maxX - bounds.minX) * mapScale,
7783
+ (bounds.maxY - bounds.minY) * mapScale
7784
+ )) {
6052
7785
  const lx = region.labelXY[0] * mapScale + mapOffsetX;
6053
7786
  const ly = region.labelXY[1] * mapScale + mapOffsetY + 4;
6054
7787
  primitives.push({
6055
7788
  kind: "text",
6056
7789
  x: lx,
6057
7790
  y: ly,
6058
- text: formatAxisValue2(entry.value),
7791
+ text: formatRegionMapValue(entry.value, options?.cultureLanguage),
6059
7792
  fontSize: Math.max(6, 7 * mapScale),
6060
7793
  fill: "#1e293b",
6061
7794
  textAnchor: "middle",
@@ -6110,6 +7843,17 @@ function buildRegionMapViewModel(element, chartData, categoryLabels) {
6110
7843
  textAnchor: "middle"
6111
7844
  }
6112
7845
  );
7846
+ if (options?.attribution) {
7847
+ primitives.push({
7848
+ kind: "text",
7849
+ x: svgWidth - 4,
7850
+ y: svgHeight - 4,
7851
+ text: options.attribution,
7852
+ fontSize: 5,
7853
+ fill: "#64748b",
7854
+ textAnchor: "end"
7855
+ });
7856
+ }
6113
7857
  if (unmatchedRows.length > 0) {
6114
7858
  const tableY = legendY + 26;
6115
7859
  const fontSize = Math.min(8, fallbackRowH * 0.7);
@@ -6287,14 +8031,17 @@ function computeStackedValueRange(series, catCount) {
6287
8031
  }
6288
8032
  function valueToY2(val2, range, topY, bottomY) {
6289
8033
  const usable = bottomY - topY;
8034
+ let ratio;
6290
8035
  if (range.logScale && range.logBase) {
6291
8036
  const base = range.logBase;
6292
8037
  const clampedVal = Math.max(val2, range.min);
6293
8038
  const logVal = Math.log(clampedVal) / Math.log(base);
6294
8039
  const logMin = Math.log(range.min) / Math.log(base);
6295
- return bottomY - (logVal - logMin) / range.span * usable;
8040
+ ratio = (logVal - logMin) / range.span;
8041
+ } else {
8042
+ ratio = (val2 - range.min) / range.span;
6296
8043
  }
6297
- return bottomY - (val2 - range.min) / range.span * usable;
8044
+ return range.reverseOrder ? topY + ratio * usable : bottomY - ratio * usable;
6298
8045
  }
6299
8046
  function formatAxisValue2(val2) {
6300
8047
  if (Math.abs(val2) >= 1e6) {
@@ -6355,7 +8102,7 @@ function computePlotLayout(elementWidth, elementHeight, chartData, hasAxes, opti
6355
8102
  };
6356
8103
  }
6357
8104
  var GRIDLINE_COLOR2 = "#e2e8f0";
6358
- var AXIS_LABEL_COLOR2 = "#64748b";
8105
+ var AXIS_LABEL_COLOR = "#64748b";
6359
8106
  var ZERO_LINE_COLOR = "#94a3b8";
6360
8107
  var TICK_COUNT2 = 5;
6361
8108
  function buildGridlinesAndLabels(range, layout) {
@@ -6379,7 +8126,7 @@ function buildGridlinesAndLabels(range, layout) {
6379
8126
  y,
6380
8127
  text: formatAxisValue2(val2),
6381
8128
  fontSize: 8,
6382
- fill: AXIS_LABEL_COLOR2,
8129
+ fill: AXIS_LABEL_COLOR,
6383
8130
  textAnchor: "end",
6384
8131
  dominantBaseline: "central"
6385
8132
  });
@@ -6411,7 +8158,7 @@ function buildCategoryLabels(categoryLabels, layout, catSpacing) {
6411
8158
  y: layout.plotBottom + 12,
6412
8159
  text: label,
6413
8160
  fontSize: 8,
6414
- fill: AXIS_LABEL_COLOR2,
8161
+ fill: AXIS_LABEL_COLOR,
6415
8162
  textAnchor: "middle"
6416
8163
  };
6417
8164
  });
@@ -6565,9 +8312,12 @@ function computePieSlices(values, cx, cy, outerR, innerR) {
6565
8312
  return computePieSlicePath(cx, cy, outerR, innerR, startAngle, cumAngle);
6566
8313
  });
6567
8314
  }
6568
- function computeScatterDots(values, maxXIndex, layout, range) {
8315
+ function computeScatterDots(values, maxXIndex, layout, range, xValues) {
8316
+ const finiteX = xValues?.slice(0, values.length).filter(Number.isFinite);
8317
+ const minX = finiteX?.length ? Math.min(...finiteX) : 0;
8318
+ const spanX = finiteX?.length ? Math.max(Math.max(...finiteX) - minX, 1) : maxXIndex;
6569
8319
  return values.map((val2, i) => ({
6570
- cx: layout.plotLeft + (maxXIndex > 0 ? i / maxXIndex : 0) * layout.plotWidth,
8320
+ cx: layout.plotLeft + (spanX > 0 ? (Number.isFinite(xValues?.[i]) ? xValues[i] - minX : i) / spanX : 0) * layout.plotWidth,
6571
8321
  cy: valueToY2(val2, range, layout.plotTop, layout.plotBottom)
6572
8322
  }));
6573
8323
  }
@@ -6983,13 +8733,14 @@ function valueFromY(y, range, topY, bottomY) {
6983
8733
  if (usable === 0) {
6984
8734
  return range.min;
6985
8735
  }
8736
+ const ratio = range.reverseOrder ? (y - topY) / usable : (bottomY - y) / usable;
6986
8737
  if (range.logScale && range.logBase) {
6987
8738
  const base = range.logBase;
6988
8739
  const logMin = Math.log(range.min) / Math.log(base);
6989
- const logVal = logMin + (bottomY - y) / usable * range.span;
8740
+ const logVal = logMin + ratio * range.span;
6990
8741
  return base ** logVal;
6991
8742
  }
6992
- return range.min + (bottomY - y) / usable * range.span;
8743
+ return range.min + ratio * range.span;
6993
8744
  }
6994
8745
  function roundDragValue(value, range) {
6995
8746
  if (!Number.isFinite(value) || range.span <= 0) {
@@ -6999,16 +8750,16 @@ function roundDragValue(value, range) {
6999
8750
  const rounded = Math.round(value / step) * step;
7000
8751
  return Number.parseFloat(rounded.toPrecision(12));
7001
8752
  }
7002
- function rangeForSeries(drag, seriesIndex) {
8753
+ function rangeForSeries2(drag, seriesIndex) {
7003
8754
  const useSecondary = drag.secondaryRange !== void 0 && (drag.secondarySeriesIndexes?.includes(seriesIndex) ?? false);
7004
8755
  return useSecondary && drag.secondaryRange ? drag.secondaryRange : drag.range;
7005
8756
  }
7006
8757
  function dragValueForPart(viewY, drag, seriesIndex) {
7007
- const range = rangeForSeries(drag, seriesIndex);
8758
+ const range = rangeForSeries2(drag, seriesIndex);
7008
8759
  return roundDragValue(valueFromY(viewY, range, drag.plotTop, drag.plotBottom), range);
7009
8760
  }
7010
8761
  function dragAnchorViewY(value, drag, seriesIndex) {
7011
- return valueToY2(value, rangeForSeries(drag, seriesIndex), drag.plotTop, drag.plotBottom);
8762
+ return valueToY2(value, rangeForSeries2(drag, seriesIndex), drag.plotTop, drag.plotBottom);
7012
8763
  }
7013
8764
  function withChartPointValue(chartData, seriesIndex, pointIndex, value) {
7014
8765
  const series = chartData.series[seriesIndex];
@@ -7311,8 +9062,8 @@ function hexToRgb3(hex) {
7311
9062
  };
7312
9063
  }
7313
9064
  function rgbToHex3(r, g, b) {
7314
- const clamp3 = (v) => Math.max(0, Math.min(255, Math.round(v)));
7315
- return `#${clamp3(r).toString(16).padStart(2, "0")}${clamp3(g).toString(16).padStart(2, "0")}${clamp3(b).toString(16).padStart(2, "0")}`;
9065
+ const clamp7 = (v) => Math.max(0, Math.min(255, Math.round(v)));
9066
+ return `#${clamp7(r).toString(16).padStart(2, "0")}${clamp7(g).toString(16).padStart(2, "0")}${clamp7(b).toString(16).padStart(2, "0")}`;
7316
9067
  }
7317
9068
  function rgbToHsl(r, g, b) {
7318
9069
  const rn = r / 255;
@@ -10206,7 +11957,7 @@ function rotateDelta(dx, dy, rotationDeg) {
10206
11957
  }
10207
11958
  function applyResize(box, handle, dxScreen, dyScreen, zoom, opts = {}) {
10208
11959
  const scale = zoom || 1;
10209
- const minSize = opts.minSize ?? chunkEXDUEXTO_js.MIN_ELEMENT_SIZE;
11960
+ const minSize = opts.minSize ?? chunkAD3EAEY6_js.MIN_ELEMENT_SIZE;
10210
11961
  const rotation = rotationOf(box);
10211
11962
  const local = rotateDelta(dxScreen / scale, dyScreen / scale, rotation);
10212
11963
  const dx = local.x;
@@ -10233,7 +11984,7 @@ function applyResize(box, handle, dxScreen, dyScreen, zoom, opts = {}) {
10233
11984
  }
10234
11985
  return { x: newX, y: newY, width: newW, height: newH, rotation };
10235
11986
  }
10236
- function snapBoxToGrid(box, handle, gridSpacingPx, minSize = chunkEXDUEXTO_js.MIN_ELEMENT_SIZE) {
11987
+ function snapBoxToGrid(box, handle, gridSpacingPx, minSize = chunkAD3EAEY6_js.MIN_ELEMENT_SIZE) {
10237
11988
  if (handle === null || gridSpacingPx <= 0) {
10238
11989
  return box;
10239
11990
  }
@@ -10263,7 +12014,7 @@ function snapBoxToGrid(box, handle, gridSpacingPx, minSize = chunkEXDUEXTO_js.MI
10263
12014
  }
10264
12015
  return { x, y, width, height };
10265
12016
  }
10266
- function computeMarqueeHitIds(marquee, elements, minSize = chunkEXDUEXTO_js.MIN_ELEMENT_SIZE) {
12017
+ function computeMarqueeHitIds(marquee, elements, minSize = chunkAD3EAEY6_js.MIN_ELEMENT_SIZE) {
10267
12018
  const minX = Math.min(marquee.startX, marquee.currentX);
10268
12019
  const minY = Math.min(marquee.startY, marquee.currentY);
10269
12020
  const maxX = Math.max(marquee.startX, marquee.currentX);
@@ -10366,6 +12117,16 @@ function getSlideBackgroundStyle(slide) {
10366
12117
  style["background-repeat"] = "no-repeat";
10367
12118
  } else if (slide?.backgroundGradient) {
10368
12119
  style["background-image"] = slide.backgroundGradient;
12120
+ } else if (pattern) {
12121
+ const svg = getPatternSvg(
12122
+ pattern.preset,
12123
+ pattern.fgColor ?? solid ?? "#000000",
12124
+ pattern.bgColor ?? DEFAULT_SLIDE_BACKGROUND
12125
+ );
12126
+ if (svg) {
12127
+ style["background-image"] = `url("data:image/svg+xml,${encodeURIComponent(svg)}")`;
12128
+ style["background-repeat"] = "repeat";
12129
+ }
10369
12130
  }
10370
12131
  return style;
10371
12132
  }
@@ -10571,6 +12332,37 @@ function resolveSlideId(slide, index) {
10571
12332
  const cSld = rawXml?.["p:sld"];
10572
12333
  return String(cSld?.["@_id"] || slide?.slideNumber || index + 1);
10573
12334
  }
12335
+ function groupSlidesBySection(sections, slides) {
12336
+ if (slides.length === 0) {
12337
+ return [];
12338
+ }
12339
+ if (sections.length === 0) {
12340
+ return [
12341
+ { section: void 0, slides: [...slides], slideIndexes: slides.map((_slide, i) => i) }
12342
+ ];
12343
+ }
12344
+ const sectionById = new Map(sections.map((section) => [section.id, section]));
12345
+ const grouped = /* @__PURE__ */ new Map();
12346
+ const ungrouped = {
12347
+ section: void 0,
12348
+ slides: [],
12349
+ slideIndexes: []
12350
+ };
12351
+ for (const section of sections) {
12352
+ grouped.set(section.id, { section, slides: [], slideIndexes: [] });
12353
+ }
12354
+ slides.forEach((slide, index) => {
12355
+ const group = slide.sectionId ? grouped.get(slide.sectionId) : void 0;
12356
+ const target = group && sectionById.has(slide.sectionId ?? "") ? group : ungrouped;
12357
+ target.slides.push(slide);
12358
+ target.slideIndexes.push(index);
12359
+ });
12360
+ const result = sections.map((section) => grouped.get(section.id)).filter((group) => group.slides.length > 0);
12361
+ if (ungrouped.slides.length > 0) {
12362
+ result.push(ungrouped);
12363
+ }
12364
+ return result;
12365
+ }
10574
12366
  function addSection(sections, slides, name, afterSlideIndex, idGenerator = generateSectionId) {
10575
12367
  const newId = idGenerator();
10576
12368
  const slideAtIndex = slides[afterSlideIndex];
@@ -10899,6 +12691,19 @@ function generateTicks(slideLengthPx, scale, unit) {
10899
12691
  }
10900
12692
  return ticks;
10901
12693
  }
12694
+ function resolvePictureBullet(info, baseFontSize) {
12695
+ if (!info.imageDataUrl && !info.imageRelId && !info.imageBlipFillXml) {
12696
+ return void 0;
12697
+ }
12698
+ const sizePx = typeof info.sizePts === "number" ? info.sizePts : typeof info.sizePercent === "number" ? baseFontSize * (info.sizePercent / 100) : baseFontSize;
12699
+ return {
12700
+ ...info.imageDataUrl ? { src: info.imageDataUrl } : {},
12701
+ sizePx,
12702
+ fallbackMarker: "\u2022",
12703
+ accessibleLabel: "Bullet",
12704
+ ...info.imageRelId ? { imageRelId: info.imageRelId } : {}
12705
+ };
12706
+ }
10902
12707
  var BLOCKED_PROTOCOLS = /* @__PURE__ */ new Set([
10903
12708
  `${"javascript"}:`,
10904
12709
  "data:",
@@ -11705,16 +13510,12 @@ function purifyFn() {
11705
13510
  const purify = DOMPurify__default.default;
11706
13511
  return typeof purify.sanitize === "function" ? purify.sanitize : void 0;
11707
13512
  }
11708
- function sanitizeMarkupOrRaw(markup, config) {
11709
- const sanitize = purifyFn();
11710
- return sanitize ? sanitize(markup, config) : markup;
11711
- }
11712
13513
  function sanitizeMarkupOrEmpty(markup, config) {
11713
13514
  const sanitize = purifyFn();
11714
13515
  return sanitize ? sanitize(markup, config) : "";
11715
13516
  }
11716
13517
  function sanitizeMathMl(markup) {
11717
- const sanitized = sanitizeMarkupOrRaw(markup, { USE_PROFILES: { mathMl: true, svg: true } });
13518
+ const sanitized = sanitizeMarkupOrEmpty(markup, { USE_PROFILES: { mathMl: true, svg: true } });
11718
13519
  if (/<math(?:\s|>)/iu.test(markup) && !/<math(?:\s|>)/iu.test(sanitized) && sanitized) {
11719
13520
  return `<math xmlns="http://www.w3.org/1998/Math/MathML" display="inline">${sanitized}</math>`;
11720
13521
  }
@@ -11729,8 +13530,8 @@ function hexToRgb6(hex) {
11729
13530
  };
11730
13531
  }
11731
13532
  function rgbToHex5(r, g, b) {
11732
- const clamp3 = (v) => Math.max(0, Math.min(255, Math.round(v)));
11733
- return `#${clamp3(r).toString(16).padStart(2, "0").toUpperCase()}${clamp3(g).toString(16).padStart(2, "0").toUpperCase()}${clamp3(b).toString(16).padStart(2, "0").toUpperCase()}`;
13533
+ const clamp7 = (v) => Math.max(0, Math.min(255, Math.round(v)));
13534
+ return `#${clamp7(r).toString(16).padStart(2, "0").toUpperCase()}${clamp7(g).toString(16).padStart(2, "0").toUpperCase()}${clamp7(b).toString(16).padStart(2, "0").toUpperCase()}`;
11734
13535
  }
11735
13536
  function tintColor2(hex, tintFactor) {
11736
13537
  const { r, g, b } = hexToRgb6(hex);
@@ -11768,7 +13569,7 @@ var THEME_COLOR_LABELS = {
11768
13569
  };
11769
13570
  function buildThemeColorGrid(colorScheme) {
11770
13571
  return THEME_COLOR_TINT_ROWS.map(
11771
- (row) => chunkEXDUEXTO_js.THEME_COLOR_SCHEME_KEYS.map((key) => ({
13572
+ (row) => chunkAD3EAEY6_js.THEME_COLOR_SCHEME_KEYS.map((key) => ({
11772
13573
  hex: row.transform(colorScheme[key]),
11773
13574
  schemeKey: key,
11774
13575
  rowLabel: row.label,
@@ -12244,7 +14045,7 @@ function svgLineCap(lineCap) {
12244
14045
  }
12245
14046
  function copyFormatFromElement(element) {
12246
14047
  const result = {};
12247
- if (chunkEXDUEXTO_js.hasShapeProperties(element) && element.shapeStyle) {
14048
+ if (chunkAD3EAEY6_js.hasShapeProperties(element) && element.shapeStyle) {
12248
14049
  const s = element.shapeStyle;
12249
14050
  result.shapeStyle = {
12250
14051
  fillColor: s.fillColor,
@@ -12273,7 +14074,7 @@ function copyFormatFromElement(element) {
12273
14074
  softEdgeRadius: s.softEdgeRadius
12274
14075
  };
12275
14076
  }
12276
- if (chunkEXDUEXTO_js.hasTextProperties(element) && element.textStyle) {
14077
+ if (chunkAD3EAEY6_js.hasTextProperties(element) && element.textStyle) {
12277
14078
  const t = element.textStyle;
12278
14079
  result.textStyle = {
12279
14080
  fontFamily: t.fontFamily,
@@ -12304,7 +14105,7 @@ function definedEntries(obj) {
12304
14105
  }
12305
14106
  function applyFormatToElement(element, format) {
12306
14107
  let updated = { ...element };
12307
- if (format.shapeStyle && chunkEXDUEXTO_js.hasShapeProperties(updated)) {
14108
+ if (format.shapeStyle && chunkAD3EAEY6_js.hasShapeProperties(updated)) {
12308
14109
  updated = {
12309
14110
  ...updated,
12310
14111
  shapeStyle: {
@@ -12313,7 +14114,7 @@ function applyFormatToElement(element, format) {
12313
14114
  }
12314
14115
  };
12315
14116
  }
12316
- if (format.textStyle && chunkEXDUEXTO_js.hasTextProperties(updated)) {
14117
+ if (format.textStyle && chunkAD3EAEY6_js.hasTextProperties(updated)) {
12317
14118
  updated = {
12318
14119
  ...updated,
12319
14120
  textStyle: {
@@ -12328,7 +14129,7 @@ function hasCopyableFormat(element) {
12328
14129
  if (!element) {
12329
14130
  return false;
12330
14131
  }
12331
- return chunkEXDUEXTO_js.hasShapeProperties(element) || chunkEXDUEXTO_js.hasTextProperties(element);
14132
+ return chunkAD3EAEY6_js.hasShapeProperties(element) || chunkAD3EAEY6_js.hasTextProperties(element);
12332
14133
  }
12333
14134
  function copySegmentMetadata(from, to) {
12334
14135
  if (from.equationXml !== void 0) {
@@ -12465,7 +14266,7 @@ function getRoundRectRadiusPx(element) {
12465
14266
  return Math.min(Math.max(element.width, 1), Math.max(element.height, 1)) * 0.5 * normalizedAdjustment;
12466
14267
  }
12467
14268
  function getShapeAdjustmentHandleDescriptor(element) {
12468
- if (!chunkEXDUEXTO_js.hasShapeProperties(element)) {
14269
+ if (!chunkAD3EAEY6_js.hasShapeProperties(element)) {
12469
14270
  return null;
12470
14271
  }
12471
14272
  const normalizedShapeType = String(element.shapeType || "").toLowerCase();
@@ -12918,6 +14719,7 @@ var SCALAR_ELEMENT_KEYS = /* @__PURE__ */ new Set([
12918
14719
  "mediaMimeType",
12919
14720
  "mediaReferenceKind",
12920
14721
  "mediaReferenceName",
14722
+ "mediaReferenceContentType",
12921
14723
  "trimStartMs",
12922
14724
  "trimEndMs",
12923
14725
  "posterFramePath",
@@ -12952,9 +14754,11 @@ var SCALAR_ELEMENT_KEYS = /* @__PURE__ */ new Set([
12952
14754
  "inkWidths",
12953
14755
  "inkOpacities",
12954
14756
  "inkTool",
14757
+ "inkPartPath",
12955
14758
  "zoomType",
12956
14759
  "targetSlideIndex",
12957
14760
  "targetSectionId",
14761
+ "summaryLayout",
12958
14762
  "modelPath",
12959
14763
  "modelMimeType",
12960
14764
  "posterImage",
@@ -12988,6 +14792,8 @@ var COMPLEX_ELEMENT_FIELDS = {
12988
14792
  groupFill: "_gf",
12989
14793
  inkPointPressures: "_ipp",
12990
14794
  inkStrokes: "_cis",
14795
+ inkPartRawXml: "_cirx",
14796
+ summaryTargets: "_zst",
12991
14797
  extensionXml: "_ext",
12992
14798
  customGeometryPaths: "_cgp",
12993
14799
  customGeometryRawData: "_cgr",
@@ -13451,7 +15257,7 @@ function createSyncGate(onOpen, graceMs = INITIAL_SYNC_GRACE_MS) {
13451
15257
  var POSITION_THRESHOLD = 2;
13452
15258
  var SIZE_THRESHOLD = 2;
13453
15259
  function getElementText(element) {
13454
- if (!chunkEXDUEXTO_js.hasTextProperties(element)) {
15260
+ if (!chunkAD3EAEY6_js.hasTextProperties(element)) {
13455
15261
  return "";
13456
15262
  }
13457
15263
  if (element.textSegments && element.textSegments.length > 0) {
@@ -13629,6 +15435,38 @@ function compareSlides(base, compare) {
13629
15435
  function comparePresentation(base, compare) {
13630
15436
  return compareSlides(base.slides, compare.slides);
13631
15437
  }
15438
+ function applyAcceptSlide(slides, diff) {
15439
+ const next = [...slides];
15440
+ if (diff.status === "added" && diff.compareSlide) {
15441
+ next.splice(Math.min(diff.compareIndex, next.length), 0, { ...diff.compareSlide });
15442
+ } else if (diff.status === "changed" && diff.compareSlide && diff.baseIndex >= 0) {
15443
+ next[diff.baseIndex] = { ...diff.compareSlide };
15444
+ } else if (diff.status === "removed" && diff.baseIndex >= 0) {
15445
+ next.splice(diff.baseIndex, 1);
15446
+ }
15447
+ return next;
15448
+ }
15449
+ function applyAcceptAllSlides(slides, compareResult) {
15450
+ const next = [...slides];
15451
+ const diffs = [...compareResult.diffs];
15452
+ for (const diff of diffs) {
15453
+ if (diff.status === "changed" && diff.compareSlide && diff.baseIndex >= 0 && diff.baseIndex < next.length) {
15454
+ next[diff.baseIndex] = { ...diff.compareSlide };
15455
+ }
15456
+ }
15457
+ for (let index = diffs.length - 1; index >= 0; index--) {
15458
+ const diff = diffs[index];
15459
+ if (diff.status === "removed" && diff.baseIndex >= 0 && diff.baseIndex < next.length) {
15460
+ next.splice(diff.baseIndex, 1);
15461
+ }
15462
+ }
15463
+ for (const diff of diffs) {
15464
+ if (diff.status === "added" && diff.compareSlide) {
15465
+ next.splice(Math.min(diff.compareIndex, next.length), 0, { ...diff.compareSlide });
15466
+ }
15467
+ }
15468
+ return next;
15469
+ }
13632
15470
  function resolveDirection(direction, defaultDir) {
13633
15471
  switch (direction) {
13634
15472
  case "l":
@@ -16850,6 +18688,15 @@ function setCachedResult(key, dataUrl) {
16850
18688
  }
16851
18689
  colorChangeCache.set(key, dataUrl);
16852
18690
  }
18691
+ function getImageColorWashStyle(wash) {
18692
+ if (!wash?.color) {
18693
+ return void 0;
18694
+ }
18695
+ return {
18696
+ backgroundColor: wash.color,
18697
+ opacity: Math.max(0, Math.min(100, wash.opacity)) / 100
18698
+ };
18699
+ }
16853
18700
  function mapDuotonePixels(data, shadow, highlight) {
16854
18701
  const len = data.length;
16855
18702
  for (let i = 0; i < len; i += 4) {
@@ -16984,7 +18831,7 @@ function getAriaRole(element) {
16984
18831
  case "model3d":
16985
18832
  return "img";
16986
18833
  case "shape": {
16987
- if (chunkEXDUEXTO_js.hasTextProperties(element) && element.text) {
18834
+ if (chunkAD3EAEY6_js.hasTextProperties(element) && element.text) {
16988
18835
  return "group";
16989
18836
  }
16990
18837
  return "img";
@@ -16997,7 +18844,7 @@ function getAriaLabel(element) {
16997
18844
  if ((element.type === "image" || element.type === "picture") && "altText" in element && typeof element.altText === "string" && element.altText.trim()) {
16998
18845
  return element.altText.trim();
16999
18846
  }
17000
- if (chunkEXDUEXTO_js.hasTextProperties(element) && element.text) {
18847
+ if (chunkAD3EAEY6_js.hasTextProperties(element) && element.text) {
17001
18848
  const text = element.text.trim();
17002
18849
  if (text) {
17003
18850
  return text.length > 120 ? `${text.slice(0, 117)}...` : text;
@@ -17404,7 +19251,7 @@ var DEFAULT_CHART_POSITION = { x: 120, y: 120, width: 480, height: 320 };
17404
19251
  var DEFAULT_CATEGORIES = ["Category 1", "Category 2", "Category 3"];
17405
19252
  var DEFAULT_SERIES_VALUES = [4, 3, 5];
17406
19253
  function createDefaultChartElement(chartType = DEFAULT_INSERT_CHART_TYPE, position) {
17407
- return chunkEXDUEXTO_js.createChartElement(
19254
+ return chunkAD3EAEY6_js.createChartElement(
17408
19255
  chartType,
17409
19256
  {
17410
19257
  categories: [...DEFAULT_CATEGORIES],
@@ -17536,6 +19383,55 @@ function rebuildDrawingShapesIfCleared(smartArtData, layout, palette, style, ele
17536
19383
  drawingShapes: reflowToDrawingShapes(layoutResult, smartArtData.nodes)
17537
19384
  };
17538
19385
  }
19386
+ function buildSummaryZoomView(element, lookup) {
19387
+ if (element.zoomType !== "summary" || !element.summaryTargets?.length) {
19388
+ return void 0;
19389
+ }
19390
+ const layout = element.summaryLayout ?? "grid";
19391
+ const columns = Math.max(1, Math.ceil(Math.sqrt(element.summaryTargets.length)));
19392
+ const tiles = element.summaryTargets.map((target, index) => {
19393
+ const targetInfo = lookup?.(target.targetSlideIndex);
19394
+ const label = target.title || targetInfo?.sectionName || target.sectionId;
19395
+ const slideNumber = targetInfo?.slideNumber ?? target.targetSlideIndex + 1;
19396
+ return {
19397
+ key: `${target.sectionId}:${index}`,
19398
+ sectionId: target.sectionId,
19399
+ targetSlideIndex: target.targetSlideIndex,
19400
+ label,
19401
+ slideLabel: `Slide ${slideNumber}`,
19402
+ imageSrc: target.imageData,
19403
+ backgroundColor: targetInfo?.backgroundColor ?? "#f0f0f0",
19404
+ style: layout === "fixed" ? fixedTileStyle(element, target.x, target.y, target.width, target.height) : { position: "relative", minWidth: "0", minHeight: "0" },
19405
+ ariaLabel: `Zoom to section ${label}, slide ${slideNumber}`
19406
+ };
19407
+ });
19408
+ return {
19409
+ layout,
19410
+ containerStyle: layout === "fixed" ? { position: "relative", width: "100%", height: "100%" } : {
19411
+ display: "grid",
19412
+ gridTemplateColumns: `repeat(${columns}, minmax(0, 1fr))`,
19413
+ gap: "4px",
19414
+ width: "100%",
19415
+ height: "100%"
19416
+ },
19417
+ tiles,
19418
+ ariaLabel: `Summary Zoom with ${tiles.length} sections`
19419
+ };
19420
+ }
19421
+ function fixedTileStyle(element, x, y, width, height) {
19422
+ const safeWidth = Math.max(element.width, 1);
19423
+ const safeHeight = Math.max(element.height, 1);
19424
+ return {
19425
+ position: "absolute",
19426
+ left: percent((x - element.x) / safeWidth),
19427
+ top: percent((y - element.y) / safeHeight),
19428
+ width: percent(width / safeWidth),
19429
+ height: percent(height / safeHeight)
19430
+ };
19431
+ }
19432
+ function percent(value) {
19433
+ return `${Math.round(value * 1e5) / 1e3}%`;
19434
+ }
17539
19435
  var ARTISTIC_EFFECTS = [
17540
19436
  ["none", "pptx.image.effectNone", ""],
17541
19437
  ["blur", "pptx.image.effectBlur", "blur(4px)"],
@@ -18132,6 +20028,55 @@ function putAutosaveRecord(filePath, data) {
18132
20028
  })
18133
20029
  );
18134
20030
  }
20031
+ async function getAutosaveSnapshot(filePath) {
20032
+ const db = await openAutosaveDb();
20033
+ return new Promise((resolve) => {
20034
+ const tx = db.transaction(AUTOSAVE_STORE_NAME, "readonly");
20035
+ const store = tx.objectStore(AUTOSAVE_STORE_NAME);
20036
+ const req = store.get(filePath);
20037
+ req.onsuccess = () => {
20038
+ db.close();
20039
+ resolve(req.result);
20040
+ };
20041
+ req.onerror = () => {
20042
+ db.close();
20043
+ resolve(void 0);
20044
+ };
20045
+ });
20046
+ }
20047
+ async function listAutosaveSnapshots() {
20048
+ const db = await openAutosaveDb();
20049
+ return new Promise((resolve) => {
20050
+ const results = [];
20051
+ try {
20052
+ const tx = db.transaction(AUTOSAVE_STORE_NAME, "readonly");
20053
+ const store = tx.objectStore(AUTOSAVE_STORE_NAME);
20054
+ const cursorReq = store.openCursor();
20055
+ cursorReq.onsuccess = () => {
20056
+ const cursor = cursorReq.result;
20057
+ if (cursor) {
20058
+ const val2 = cursor.value;
20059
+ results.push({ key: val2.key, timestamp: val2.timestamp, size: val2.size });
20060
+ cursor.continue();
20061
+ }
20062
+ };
20063
+ tx.oncomplete = () => {
20064
+ db.close();
20065
+ resolve(results);
20066
+ };
20067
+ tx.onerror = () => {
20068
+ db.close();
20069
+ resolve([]);
20070
+ };
20071
+ } catch {
20072
+ try {
20073
+ db.close();
20074
+ } catch {
20075
+ }
20076
+ resolve([]);
20077
+ }
20078
+ });
20079
+ }
18135
20080
  async function saveAutosaveSnapshot(filePath, data) {
18136
20081
  try {
18137
20082
  return await putAutosaveRecord(filePath, data);
@@ -18147,6 +20092,233 @@ async function saveAutosaveSnapshot(filePath, data) {
18147
20092
  return putAutosaveRecord(filePath, data);
18148
20093
  }
18149
20094
  }
20095
+ var BACKSTAGE_NAV = [
20096
+ { id: "home", label: "Home" },
20097
+ { id: "new", label: "New" },
20098
+ { id: "open", label: "Open" },
20099
+ { id: "info", label: "Info" },
20100
+ { id: "save", label: "Save" },
20101
+ { id: "saveAs", label: "Save As" },
20102
+ { id: "print", label: "Print" },
20103
+ { id: "share", label: "Share" },
20104
+ { id: "export", label: "Export" },
20105
+ { id: "close", label: "Close" },
20106
+ { id: "account", label: "Account", group: "footer" },
20107
+ { id: "options", label: "Options", group: "footer" }
20108
+ ];
20109
+ var BACKSTAGE_TEMPLATES = [
20110
+ {
20111
+ id: "blank",
20112
+ name: "Blank Presentation",
20113
+ description: "Start with a clean canvas",
20114
+ preview: "linear-gradient(145deg, #fff 0 88%, #d34a1f 88%)"
20115
+ },
20116
+ {
20117
+ id: "warm",
20118
+ name: "Warm Welcome",
20119
+ description: "Bold editorial title slides",
20120
+ preview: "linear-gradient(135deg, #d94b20 0 62%, #f4b183 62%)"
20121
+ },
20122
+ {
20123
+ id: "geometry",
20124
+ name: "Geometric",
20125
+ description: "Modern shapes and strong contrast",
20126
+ preview: "conic-gradient(from 220deg, #173b8f, #dce6ff, #efb7bd, #173b8f)"
20127
+ },
20128
+ {
20129
+ id: "mono",
20130
+ name: "Urban Monochrome",
20131
+ description: "Architectural black and white",
20132
+ preview: "linear-gradient(125deg, #171717, #eee 49%, #777 50%, #fafafa)"
20133
+ },
20134
+ {
20135
+ id: "earth",
20136
+ name: "Earthy Inspiration",
20137
+ description: "Natural, calm presentation system",
20138
+ preview: "radial-gradient(circle at 70% 30%, #be9473, #34271f 38%, #111 70%)"
20139
+ },
20140
+ {
20141
+ id: "future",
20142
+ name: "Future Forward",
20143
+ description: "Clean technology storytelling",
20144
+ preview: "repeating-radial-gradient(ellipse at bottom, #111 0 3px, #fff 4px 13px)"
20145
+ }
20146
+ ];
20147
+ var TEMPLATE_BACKGROUNDS = {
20148
+ blank: { backgroundColor: "#ffffff" },
20149
+ warm: {
20150
+ backgroundColor: "#d94b20",
20151
+ backgroundGradient: "linear-gradient(135deg, #d94b20 0 62%, #f4b183 62%)"
20152
+ },
20153
+ geometry: {
20154
+ backgroundColor: "#dce6ff",
20155
+ backgroundGradient: "linear-gradient(135deg, #173b8f, #dce6ff 54%, #efb7bd)"
20156
+ },
20157
+ mono: {
20158
+ backgroundColor: "#f4f4f4",
20159
+ backgroundGradient: "linear-gradient(125deg, #171717, #eeeeee 49%, #777777 50%, #fafafa)"
20160
+ },
20161
+ earth: {
20162
+ backgroundColor: "#34271f",
20163
+ backgroundGradient: "radial-gradient(circle at 70% 30%, #be9473, #34271f 38%, #111111 70%)"
20164
+ },
20165
+ future: {
20166
+ backgroundColor: "#ffffff",
20167
+ backgroundGradient: "repeating-radial-gradient(ellipse at bottom, #111111 0 3px, #ffffff 4px 13px)"
20168
+ }
20169
+ };
20170
+ function createBackstagePresentation(templateId) {
20171
+ const slide = createBlankSlide(1);
20172
+ return [{ ...slide, ...TEMPLATE_BACKGROUNDS[templateId] ?? TEMPLATE_BACKGROUNDS.blank }];
20173
+ }
20174
+ function splitFilePath(path) {
20175
+ const normalized = path.replace(/\\/g, "/");
20176
+ const parts = normalized.split("/").filter(Boolean);
20177
+ return {
20178
+ name: parts[parts.length - 1] || "Untitled Presentation.pptx",
20179
+ location: parts.slice(0, -1).join("/") || "Browser storage"
20180
+ };
20181
+ }
20182
+ async function listBackstageRecentFiles() {
20183
+ if (typeof indexedDB === "undefined") {
20184
+ return [];
20185
+ }
20186
+ try {
20187
+ const snapshots = await listAutosaveSnapshots();
20188
+ return snapshots.map((snapshot) => ({ ...snapshot, ...splitFilePath(snapshot.key) })).sort((a, b) => b.timestamp - a.timestamp);
20189
+ } catch {
20190
+ return [];
20191
+ }
20192
+ }
20193
+ async function readBackstageRecentFile(key) {
20194
+ if (typeof indexedDB === "undefined") {
20195
+ return void 0;
20196
+ }
20197
+ return (await getAutosaveSnapshot(key))?.data;
20198
+ }
20199
+ function formatBackstageDate(timestamp, now = Date.now()) {
20200
+ const elapsed = Math.max(0, now - timestamp);
20201
+ if (elapsed < 6e4) {
20202
+ return "Just now";
20203
+ }
20204
+ if (elapsed < 36e5) {
20205
+ return `${Math.floor(elapsed / 6e4)} min ago`;
20206
+ }
20207
+ if (elapsed < 864e5) {
20208
+ return `${Math.floor(elapsed / 36e5)} hr ago`;
20209
+ }
20210
+ return new Intl.DateTimeFormat(void 0, { month: "short", day: "numeric" }).format(timestamp);
20211
+ }
20212
+ function formatBackstageSize(bytes) {
20213
+ if (bytes < 1024 * 1024) {
20214
+ return `${Math.max(1, Math.round(bytes / 1024))} KB`;
20215
+ }
20216
+ return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
20217
+ }
20218
+ var DEFAULT_VIRTUAL_OVERSCAN = 5;
20219
+ var SLIDE_VIRTUALIZATION_THRESHOLD = 50;
20220
+ function computeVirtualRange(totalItems, itemHeight, scrollTop, viewportHeight, overscan = DEFAULT_VIRTUAL_OVERSCAN) {
20221
+ const safeCount = Math.max(0, totalItems);
20222
+ const safeItemHeight = Math.max(itemHeight, 1);
20223
+ const totalHeight = safeCount * safeItemHeight;
20224
+ if (safeCount === 0) {
20225
+ return {
20226
+ startIndex: 0,
20227
+ endIndex: -1,
20228
+ totalHeight: 0,
20229
+ offsetY: 0,
20230
+ visibleRange: { start: 0, end: -1 }
20231
+ };
20232
+ }
20233
+ const visibleStart = Math.min(safeCount - 1, Math.max(0, Math.floor(scrollTop / safeItemHeight)));
20234
+ const visibleEnd = Math.min(
20235
+ safeCount - 1,
20236
+ Math.max(visibleStart, Math.floor((scrollTop + Math.max(0, viewportHeight)) / safeItemHeight))
20237
+ );
20238
+ const safeOverscan = Math.max(0, overscan);
20239
+ const startIndex = Math.max(0, visibleStart - safeOverscan);
20240
+ const endIndex = Math.min(safeCount - 1, visibleEnd + safeOverscan);
20241
+ return {
20242
+ startIndex,
20243
+ endIndex,
20244
+ totalHeight,
20245
+ offsetY: startIndex * safeItemHeight,
20246
+ visibleRange: { start: visibleStart, end: visibleEnd }
20247
+ };
20248
+ }
20249
+ function collectFontsFromElement(element, fonts) {
20250
+ if (chunkAD3EAEY6_js.hasTextProperties(element)) {
20251
+ if (element.textStyle?.fontFamily) {
20252
+ fonts.add(element.textStyle.fontFamily);
20253
+ }
20254
+ for (const segment of element.textSegments ?? []) {
20255
+ if (segment.style?.fontFamily) {
20256
+ fonts.add(segment.style.fontFamily);
20257
+ }
20258
+ }
20259
+ }
20260
+ if (element.type === "group") {
20261
+ for (const child2 of element.children ?? []) {
20262
+ collectFontsFromElement(child2, fonts);
20263
+ }
20264
+ }
20265
+ }
20266
+ function collectUsedFonts(slides) {
20267
+ const fonts = /* @__PURE__ */ new Set();
20268
+ for (const slide of slides) {
20269
+ for (const element of slide.elements ?? []) {
20270
+ collectFontsFromElement(element, fonts);
20271
+ }
20272
+ }
20273
+ return [...fonts].sort();
20274
+ }
20275
+ function browserFontSource() {
20276
+ return typeof document === "undefined" ? void 0 : document.fonts;
20277
+ }
20278
+ function isFontFamilyAvailable(family, source = browserFontSource()) {
20279
+ if (!source) {
20280
+ return false;
20281
+ }
20282
+ try {
20283
+ const escaped = family.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
20284
+ return source.check(`12px "${escaped}"`);
20285
+ } catch {
20286
+ return false;
20287
+ }
20288
+ }
20289
+ async function scanAvailableFontFamilies(families, source = browserFontSource()) {
20290
+ if (!source) {
20291
+ return /* @__PURE__ */ new Set();
20292
+ }
20293
+ try {
20294
+ await source.ready;
20295
+ return new Set(families.filter((family) => isFontFamilyAvailable(family, source)));
20296
+ } catch {
20297
+ return /* @__PURE__ */ new Set();
20298
+ }
20299
+ }
20300
+ function shouldLoopContinuously(input) {
20301
+ return Boolean(input.loopContinuously) || input.showType === "kiosk";
20302
+ }
20303
+ function applyRehearsalTimings(slides, timings) {
20304
+ return slides.map((slide, index) => {
20305
+ const advanceAfterMs = timings[index];
20306
+ if (typeof advanceAfterMs !== "number") {
20307
+ return slide;
20308
+ }
20309
+ return {
20310
+ ...slide,
20311
+ transition: {
20312
+ ...slide.transition,
20313
+ type: slide.transition?.type ?? "none",
20314
+ advanceAfterMs
20315
+ }
20316
+ };
20317
+ });
20318
+ }
20319
+ function computeEntranceAnimationDelay(delayMs, animationIndex) {
20320
+ return Math.max(0, delayMs || 0) + animationIndex * 60;
20321
+ }
18150
20322
  var FALLBACK_DOWNLOAD_NAME = "presentation.pptx";
18151
20323
  var REVOKE_DELAY_MS = 200;
18152
20324
  var OPEN_REVOKE_DELAY_MS = 6e4;
@@ -18239,6 +20411,22 @@ function canvasToJpegData(canvas, quality = 0.92) {
18239
20411
  }
18240
20412
  return { bytes, w: canvas.width, h: canvas.height };
18241
20413
  }
20414
+ function generatePackageReadme(presentationFilename) {
20415
+ return [
20416
+ "Presentation Package",
20417
+ "====================",
20418
+ "",
20419
+ `This folder contains the presentation "${presentationFilename}" along with`,
20420
+ "all linked media files (images, audio, video) in the /media subfolder.",
20421
+ "",
20422
+ "To view this presentation:",
20423
+ "1. Open the presentation file with any compatible presentation software",
20424
+ "2. Ensure the /media folder remains alongside the presentation file",
20425
+ "",
20426
+ `Packaged on ${(/* @__PURE__ */ new Date()).toLocaleDateString()}`,
20427
+ ""
20428
+ ].join("\n");
20429
+ }
18242
20430
  function encodeGif(frames, delay = {}) {
18243
20431
  if (frames.length === 0) {
18244
20432
  throw new Error("[gif-encoder] encodeGif: frames array must not be empty");
@@ -18699,11 +20887,11 @@ function buildNotesTextStream(lines, startY) {
18699
20887
  let content = `BT /F1 ${NOTES_FONT_SIZE} Tf 0 0 0 rg `;
18700
20888
  content += `${NOTES_MARGIN} ${startY.toFixed(2)} Td `;
18701
20889
  for (let li = 0; li < lines.length; li++) {
18702
- const line = lines[li];
20890
+ const line2 = lines[li];
18703
20891
  if (li === 0) {
18704
- content += `(${escapePdfText(line)}) Tj `;
20892
+ content += `(${escapePdfText(line2)}) Tj `;
18705
20893
  } else {
18706
- content += `0 ${(-15.399999999999999).toFixed(2)} Td (${escapePdfText(line)}) Tj `;
20894
+ content += `0 ${(-15.399999999999999).toFixed(2)} Td (${escapePdfText(line2)}) Tj `;
18707
20895
  }
18708
20896
  }
18709
20897
  content += "ET\n";
@@ -18748,12 +20936,24 @@ function isSafeSvgMarkup(svg) {
18748
20936
  }
18749
20937
  return !EVENT_HANDLER_ATTR_RE.test(trimmed);
18750
20938
  }
20939
+ function sanitizeSlideSvg(svg, width, height) {
20940
+ if (!isSafeSvgMarkup(svg)) {
20941
+ return "";
20942
+ }
20943
+ const sanitized = sanitizeMarkupOrEmpty(svg, { USE_PROFILES: { svg: true } }).trim();
20944
+ if (!sanitized || sanitized.toLowerCase().startsWith("<svg")) {
20945
+ return sanitized;
20946
+ }
20947
+ const safeWidth = Number.isFinite(width) && width > 0 ? width : 1;
20948
+ const safeHeight = Number.isFinite(height) && height > 0 ? height : 1;
20949
+ return `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 ${safeWidth} ${safeHeight}" width="${safeWidth}" height="${safeHeight}">${sanitized}</svg>`;
20950
+ }
18751
20951
  function buildPrintDocument(svgs, width, height, options = {}) {
18752
20952
  const { title = "Print", orientation = "landscape", colorFilter = "" } = options;
18753
20953
  const safeOrientation = sanitizeOrientation(orientation);
18754
20954
  const safeColorFilter = sanitizeCssDeclaration(colorFilter);
18755
20955
  const slidePages = svgs.map((svg, i) => {
18756
- const safeSvg = isSafeSvgMarkup(svg) ? sanitizeMarkupOrEmpty(svg, { USE_PROFILES: { svg: true } }) : "";
20956
+ const safeSvg = sanitizeSlideSvg(svg, width, height);
18757
20957
  return `<section class="print-slide-page" aria-label="Slide ${i + 1}">
18758
20958
  ${safeSvg}
18759
20959
  </section>`;
@@ -19749,6 +21949,8 @@ function segmentFrameCount(durationMs, fps) {
19749
21949
 
19750
21950
  exports.ACTION_BUTTON_PRESETS = ACTION_BUTTON_PRESETS;
19751
21951
  exports.ARTISTIC_EFFECTS = ARTISTIC_EFFECTS;
21952
+ exports.BACKSTAGE_NAV = BACKSTAGE_NAV;
21953
+ exports.BACKSTAGE_TEMPLATES = BACKSTAGE_TEMPLATES;
19752
21954
  exports.BROADCAST_THROTTLE_MS = BROADCAST_THROTTLE_MS;
19753
21955
  exports.CATEGORIES = CATEGORIES;
19754
21956
  exports.CONNECTION_TIMEOUT_MS = CONNECTION_TIMEOUT_MS;
@@ -19756,6 +21958,7 @@ exports.DEFAULT_BROADCAST_SERVER_URL = DEFAULT_BROADCAST_SERVER_URL;
19756
21958
  exports.DEFAULT_COLOR_CHANGE_TOLERANCE = DEFAULT_COLOR_CHANGE_TOLERANCE;
19757
21959
  exports.DEFAULT_INSERT_CHART_TYPE = DEFAULT_INSERT_CHART_TYPE;
19758
21960
  exports.DEFAULT_ROW_HEIGHT = DEFAULT_ROW_HEIGHT;
21961
+ exports.DEFAULT_VIRTUAL_OVERSCAN = DEFAULT_VIRTUAL_OVERSCAN;
19759
21962
  exports.DIRECTIONAL_PRESETS = DIRECTIONAL_PRESETS;
19760
21963
  exports.DUOTONE_PRESETS = DUOTONE_PRESETS;
19761
21964
  exports.EXPORT_ASSEMBLING_PERCENT = EXPORT_ASSEMBLING_PERCENT;
@@ -19785,6 +21988,7 @@ exports.SECTION_HEADING = SECTION_HEADING;
19785
21988
  exports.SEL = SEL;
19786
21989
  exports.SHAPE_PRESET_DEFS = SHAPE_PRESET_DEFS;
19787
21990
  exports.SLIDE_TRANSITION_KEYFRAMES = SLIDE_TRANSITION_KEYFRAMES;
21991
+ exports.SLIDE_VIRTUALIZATION_THRESHOLD = SLIDE_VIRTUALIZATION_THRESHOLD;
19788
21992
  exports.TABLET_BREAKPOINT = TABLET_BREAKPOINT;
19789
21993
  exports.TABLE_STYLE_PRESETS = TABLE_STYLE_PRESETS;
19790
21994
  exports.TAB_ROW_ACTION_CLASSES = TAB_ROW_ACTION_CLASSES;
@@ -19799,10 +22003,13 @@ exports.addSection = addSection;
19799
22003
  exports.alignElements = alignElements;
19800
22004
  exports.appendPresentationInkPoint = appendPresentationInkPoint;
19801
22005
  exports.apply3dEffects = apply3dEffects;
22006
+ exports.applyAcceptAllSlides = applyAcceptAllSlides;
22007
+ exports.applyAcceptSlide = applyAcceptSlide;
19802
22008
  exports.applyCaseTransformToSegments = applyCaseTransformToSegments;
19803
22009
  exports.applyColorChange = applyColorChange;
19804
22010
  exports.applyDuotone = applyDuotone;
19805
22011
  exports.applyFormatToElement = applyFormatToElement;
22012
+ exports.applyRehearsalTimings = applyRehearsalTimings;
19806
22013
  exports.applyReroutedConnectors = applyReroutedConnectors;
19807
22014
  exports.applyResize = applyResize;
19808
22015
  exports.applyStyleToSelectedSegments = applyStyleToSelectedSegments;
@@ -19838,6 +22045,7 @@ exports.buildSlidesPdfBytes = buildSlidesPdfBytes;
19838
22045
  exports.buildSmartArt3DModel = buildSmartArt3DModel;
19839
22046
  exports.buildSmartArtA11y = buildSmartArtA11y;
19840
22047
  exports.buildSmartArtPresetData = buildSmartArtPresetData;
22048
+ exports.buildSummaryZoomView = buildSummaryZoomView;
19841
22049
  exports.buildTextBody3DSceneStyle = buildTextBody3DSceneStyle;
19842
22050
  exports.buildTextFillCss = buildTextFillCss;
19843
22051
  exports.buildTextReflectionCss = buildTextReflectionCss;
@@ -19858,11 +22066,13 @@ exports.cloneSlide = cloneSlide;
19858
22066
  exports.cloneTemplateElementsBySlideId = cloneTemplateElementsBySlideId;
19859
22067
  exports.collectImagePaths = collectImagePaths;
19860
22068
  exports.collectMediaElements = collectMediaElements;
22069
+ exports.collectUsedFonts = collectUsedFonts;
19861
22070
  exports.colorWithOpacity = colorWithOpacity;
19862
22071
  exports.comparePresentation = comparePresentation;
19863
22072
  exports.computeAllNotesPages = computeAllNotesPages;
19864
22073
  exports.computeAutoFitTextStyle = computeAutoFitTextStyle;
19865
22074
  exports.computeColumnBoundaries = computeColumnBoundaries;
22075
+ exports.computeEntranceAnimationDelay = computeEntranceAnimationDelay;
19866
22076
  exports.computeHandoutLayout = computeHandoutLayout;
19867
22077
  exports.computeInlineEditorRect = computeInlineEditorRect;
19868
22078
  exports.computeKeyboardInset = computeKeyboardInset;
@@ -19880,11 +22090,13 @@ exports.computeSnapToShape = computeSnapToShape;
19880
22090
  exports.computeSplitCell = computeSplitCell;
19881
22091
  exports.computeValueRange = computeValueRange;
19882
22092
  exports.computeValueRangeForChart = computeValueRangeForChart;
22093
+ exports.computeVirtualRange = computeVirtualRange;
19883
22094
  exports.convertLatexToOmml = convertLatexToOmml;
19884
22095
  exports.convertOmmlToLatex = convertOmmlToLatex;
19885
22096
  exports.convertOmmlToMathMl = convertOmmlToMathMl;
19886
22097
  exports.copyFormatFromElement = copyFormatFromElement;
19887
22098
  exports.countTextSegments = countTextSegments;
22099
+ exports.createBackstagePresentation = createBackstagePresentation;
19888
22100
  exports.createBlankSlide = createBlankSlide;
19889
22101
  exports.createDefaultChartElement = createDefaultChartElement;
19890
22102
  exports.createInitialPresentationSnapshot = createInitialPresentationSnapshot;
@@ -19915,6 +22127,8 @@ exports.findChartPartTarget = findChartPartTarget;
19915
22127
  exports.findSmartArtNodeText = findSmartArtNodeText;
19916
22128
  exports.formatAxisValue = formatAxisValue;
19917
22129
  exports.formatAxisValueWithUnits = formatAxisValueWithUnits;
22130
+ exports.formatBackstageDate = formatBackstageDate;
22131
+ exports.formatBackstageSize = formatBackstageSize;
19918
22132
  exports.formatBytes = formatBytes;
19919
22133
  exports.formatCommentTimestamp = formatCommentTimestamp;
19920
22134
  exports.formatElapsed = formatElapsed;
@@ -19928,6 +22142,7 @@ exports.generateBroadcastRoomId = generateBroadcastRoomId;
19928
22142
  exports.generateElementId = generateElementId;
19929
22143
  exports.generateLogTicks = generateLogTicks;
19930
22144
  exports.generateNoteLineCount = generateNoteLineCount;
22145
+ exports.generatePackageReadme = generatePackageReadme;
19931
22146
  exports.generatePressureCircles = generatePressureCircles;
19932
22147
  exports.generateTicks = generateTicks;
19933
22148
  exports.getAnimationInitialStyle = getAnimationInitialStyle;
@@ -19950,8 +22165,10 @@ exports.getEffectDagFilter = getEffectDagFilter;
19950
22165
  exports.getElementLabel = getElementLabel;
19951
22166
  exports.getElementTransform = getElementTransform;
19952
22167
  exports.getElementTransformWithoutRotation = getElementTransformWithoutRotation;
22168
+ exports.getImageColorWashStyle = getImageColorWashStyle;
19953
22169
  exports.getImageEffectsFilter = getImageEffectsFilter;
19954
22170
  exports.getImageEffectsOpacity = getImageEffectsOpacity;
22171
+ exports.getImageSvgFilters = getImageSvgFilters;
19955
22172
  exports.getInkReplayStyles = getInkReplayStyles;
19956
22173
  exports.getInlineEditorSelection = getInlineEditorSelection;
19957
22174
  exports.getKinsokuLineBreakStyles = getKinsokuLineBreakStyles;
@@ -19974,6 +22191,7 @@ exports.getTextCompensationTransform = getTextCompensationTransform;
19974
22191
  exports.getWarpPath = getWarpPath;
19975
22192
  exports.groupElements = groupElements;
19976
22193
  exports.groupIntoParagraphs = groupIntoParagraphs;
22194
+ exports.groupSlidesBySection = groupSlidesBySection;
19977
22195
  exports.hasCopyableFormat = hasCopyableFormat;
19978
22196
  exports.hasDistinctScriptFonts = hasDistinctScriptFonts;
19979
22197
  exports.hasPressureVariation = hasPressureVariation;
@@ -19993,6 +22211,7 @@ exports.isPresentationSessionMessage = isPresentationSessionMessage;
19993
22211
  exports.isTemplateElement = isTemplateElement;
19994
22212
  exports.isTemplateElementId = isTemplateElementId;
19995
22213
  exports.isUrlSafe = isUrlSafe;
22214
+ exports.listBackstageRecentFiles = listBackstageRecentFiles;
19996
22215
  exports.loadPresentationDeck = loadPresentationDeck;
19997
22216
  exports.makeCloneId = makeCloneId;
19998
22217
  exports.makeSlideId = makeSlideId;
@@ -20027,6 +22246,7 @@ exports.preprocessCssForCapture = preprocessCssForCapture;
20027
22246
  exports.presentationInkPath = presentationInkPath;
20028
22247
  exports.presenterElapsed = presenterElapsed;
20029
22248
  exports.pressuresToWidths = pressuresToWidths;
22249
+ exports.readBackstageRecentFile = readBackstageRecentFile;
20030
22250
  exports.readSlidesFromYDoc = readSlidesFromYDoc;
20031
22251
  exports.readViewportMetrics = readViewportMetrics;
20032
22252
  exports.rebuildDrawingShapesIfCleared = rebuildDrawingShapesIfCleared;
@@ -20048,6 +22268,7 @@ exports.resolveLineHeight = resolveLineHeight;
20048
22268
  exports.resolveOleType = resolveOleType;
20049
22269
  exports.resolveParagraphAlign = resolveParagraphAlign;
20050
22270
  exports.resolveParagraphRtl = resolveParagraphRtl;
22271
+ exports.resolvePictureBullet = resolvePictureBullet;
20051
22272
  exports.resolveRegionCode = resolveRegionCode;
20052
22273
  exports.resolveTitleBarStatusKey = resolveTitleBarStatusKey;
20053
22274
  exports.resolveTransitionDurationMs = resolveTransitionDurationMs;
@@ -20059,6 +22280,7 @@ exports.sanitizeColor = sanitizeColor;
20059
22280
  exports.sanitizeDownloadFilename = sanitizeDownloadFilename;
20060
22281
  exports.sanitizeMathMl = sanitizeMathMl;
20061
22282
  exports.saveAutosaveSnapshot = saveAutosaveSnapshot;
22283
+ exports.scanAvailableFontFamilies = scanAvailableFontFamilies;
20062
22284
  exports.segmentByScript = segmentByScript;
20063
22285
  exports.segmentFrameCount = segmentFrameCount;
20064
22286
  exports.sendBackward = sendBackward;
@@ -20070,6 +22292,7 @@ exports.setDuotoneCachedResult = setDuotoneCachedResult;
20070
22292
  exports.setPendingSelectionRestore = setPendingSelectionRestore;
20071
22293
  exports.shadeColor2 = shadeColor2;
20072
22294
  exports.shouldCommitSmartArtNodeText = shouldCommitSmartArtNodeText;
22295
+ exports.shouldLoopContinuously = shouldLoopContinuously;
20073
22296
  exports.shouldUseSvgWarp = shouldUseSvgWarp;
20074
22297
  exports.slideProgressPercent = slideProgressPercent;
20075
22298
  exports.slideStatusLabel = slideStatusLabel;