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.
- package/CHANGELOG.md +8 -0
- package/dist/{Model3DScene-GVWQ6SOM.js → Model3DScene-3RYDRQOD.js} +3 -3
- package/dist/Model3DScene-3RYDRQOD.js.br +0 -0
- package/dist/Model3DScene-3RYDRQOD.js.gz +0 -0
- package/dist/{Model3DScene-JGVLIDLD.mjs → Model3DScene-SLGODOXT.mjs} +2 -2
- package/dist/Model3DScene-SLGODOXT.mjs.br +0 -0
- package/dist/Model3DScene-SLGODOXT.mjs.gz +0 -0
- package/dist/PowerPointViewer-C4d7SKZf.d.ts.map +1 -1
- package/dist/{SurfaceChart3DScene-ZOTOHOIE.js → SurfaceChart3DScene-3UZ5HZ2W.js} +3 -3
- package/dist/SurfaceChart3DScene-3UZ5HZ2W.js.br +0 -0
- package/dist/SurfaceChart3DScene-3UZ5HZ2W.js.gz +0 -0
- package/dist/{SurfaceChart3DScene-DBWSDSKI.mjs → SurfaceChart3DScene-YL4QD3O5.mjs} +2 -2
- package/dist/SurfaceChart3DScene-YL4QD3O5.mjs.br +0 -0
- package/dist/SurfaceChart3DScene-YL4QD3O5.mjs.gz +0 -0
- package/dist/{chunk-Z4MDCPAY.mjs → chunk-3TRQKGBU.mjs} +26 -731
- package/dist/chunk-3TRQKGBU.mjs.br +0 -0
- package/dist/chunk-3TRQKGBU.mjs.gz +0 -0
- package/dist/{chunk-SBNTEQUA.mjs → chunk-3ZGCM6RC.mjs} +20269 -12232
- package/dist/chunk-3ZGCM6RC.mjs.br +0 -0
- package/dist/chunk-3ZGCM6RC.mjs.gz +0 -0
- package/dist/{chunk-73ST7AC6.js → chunk-7JYQRDRI.js} +6962 -6661
- package/dist/chunk-7JYQRDRI.js.br +0 -0
- package/dist/chunk-7JYQRDRI.js.gz +0 -0
- package/dist/{chunk-EXDUEXTO.js → chunk-AD3EAEY6.js} +20282 -12231
- package/dist/chunk-AD3EAEY6.js.br +0 -0
- package/dist/chunk-AD3EAEY6.js.gz +0 -0
- package/dist/{chunk-HBXPK572.js → chunk-G5GATDE4.js} +2969 -746
- package/dist/chunk-G5GATDE4.js.br +0 -0
- package/dist/chunk-G5GATDE4.js.gz +0 -0
- package/dist/{chunk-JDRC3PSY.js → chunk-H5V24JVW.js} +470 -1186
- package/dist/chunk-H5V24JVW.js.br +0 -0
- package/dist/chunk-H5V24JVW.js.gz +0 -0
- package/dist/{chunk-KMLIWCNL.mjs → chunk-TG2ZYU7Y.mjs} +5782 -5480
- package/dist/chunk-TG2ZYU7Y.mjs.br +0 -0
- package/dist/chunk-TG2ZYU7Y.mjs.gz +0 -0
- package/dist/{chunk-HHTZQHKZ.mjs → chunk-VOU7OCQM.mjs} +2922 -722
- package/dist/chunk-VOU7OCQM.mjs.br +0 -0
- package/dist/chunk-VOU7OCQM.mjs.gz +0 -0
- package/dist/dist-3YRZ26TL.mjs +2 -0
- package/dist/dist-3YRZ26TL.mjs.br +0 -0
- package/dist/dist-3YRZ26TL.mjs.gz +0 -0
- package/dist/{dist-KRRXYUGI.js → dist-M2P6HBG4.js} +602 -546
- package/dist/dist-M2P6HBG4.js.br +0 -0
- package/dist/dist-M2P6HBG4.js.gz +0 -0
- package/dist/hooks-unstable.d.ts +523 -49
- package/dist/hooks-unstable.d.ts.map +1 -1
- package/dist/hooks-unstable.js +77 -77
- package/dist/hooks-unstable.js.br +0 -0
- package/dist/hooks-unstable.js.gz +0 -0
- package/dist/hooks-unstable.mjs +3 -3
- package/dist/hooks-unstable.mjs.br +0 -0
- package/dist/hooks-unstable.mjs.gz +0 -0
- package/dist/index.d.ts +417 -21
- package/dist/index.js +18 -18
- package/dist/index.js.br +0 -0
- package/dist/index.js.gz +0 -0
- package/dist/index.mjs +4 -4
- package/dist/index.mjs.br +0 -0
- package/dist/index.mjs.gz +0 -0
- package/dist/pptx-viewer.css +2 -2
- package/dist/pptx-viewer.css.br +0 -0
- package/dist/pptx-viewer.css.gz +0 -0
- package/dist/viewer/index.d.ts +509 -27
- package/dist/viewer/index.js +20 -20
- package/dist/viewer/index.js.br +0 -0
- package/dist/viewer/index.js.gz +0 -0
- package/dist/viewer/index.mjs +4 -4
- package/dist/viewer/index.mjs.br +0 -0
- package/dist/viewer/index.mjs.gz +0 -0
- package/package.json +12 -12
- package/dist/Model3DScene-GVWQ6SOM.js.br +0 -0
- package/dist/Model3DScene-GVWQ6SOM.js.gz +0 -0
- package/dist/Model3DScene-JGVLIDLD.mjs.br +0 -0
- package/dist/Model3DScene-JGVLIDLD.mjs.gz +0 -0
- package/dist/SurfaceChart3DScene-DBWSDSKI.mjs.br +0 -0
- package/dist/SurfaceChart3DScene-DBWSDSKI.mjs.gz +0 -0
- package/dist/SurfaceChart3DScene-ZOTOHOIE.js.br +0 -0
- package/dist/SurfaceChart3DScene-ZOTOHOIE.js.gz +0 -0
- package/dist/chunk-73ST7AC6.js.br +0 -0
- package/dist/chunk-73ST7AC6.js.gz +0 -0
- package/dist/chunk-EXDUEXTO.js.br +0 -0
- package/dist/chunk-EXDUEXTO.js.gz +0 -0
- package/dist/chunk-HBXPK572.js.br +0 -0
- package/dist/chunk-HBXPK572.js.gz +0 -0
- package/dist/chunk-HHTZQHKZ.mjs.br +0 -0
- package/dist/chunk-HHTZQHKZ.mjs.gz +0 -0
- package/dist/chunk-JDRC3PSY.js.br +0 -0
- package/dist/chunk-JDRC3PSY.js.gz +0 -0
- package/dist/chunk-KMLIWCNL.mjs.br +0 -0
- package/dist/chunk-KMLIWCNL.mjs.gz +0 -0
- package/dist/chunk-SBNTEQUA.mjs.br +0 -0
- package/dist/chunk-SBNTEQUA.mjs.gz +0 -0
- package/dist/chunk-Z4MDCPAY.mjs.br +0 -0
- package/dist/chunk-Z4MDCPAY.mjs.gz +0 -0
- package/dist/dist-KRRXYUGI.js.br +0 -0
- package/dist/dist-KRRXYUGI.js.gz +0 -0
- package/dist/dist-N6PAPXK6.mjs +0 -2
- package/dist/dist-N6PAPXK6.mjs.br +0 -0
- package/dist/dist-N6PAPXK6.mjs.gz +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
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:
|
|
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:
|
|
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
|
|
259
|
+
return chunkAD3EAEY6_js.getShapeClipPath(shapeType);
|
|
248
260
|
}
|
|
249
261
|
if (adjustments && Object.keys(adjustments).length > 0) {
|
|
250
|
-
const adjusted =
|
|
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 =
|
|
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 =
|
|
271
|
+
const cloud = chunkAD3EAEY6_js.getCloudPathForRendering(shapeType, width, height);
|
|
260
272
|
if (cloud !== void 0) {
|
|
261
273
|
return cloud;
|
|
262
274
|
}
|
|
263
|
-
return
|
|
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
|
|
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) +
|
|
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) +
|
|
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) +
|
|
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) +
|
|
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) +
|
|
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) +
|
|
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) +
|
|
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) +
|
|
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) +
|
|
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) +
|
|
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) +
|
|
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) +
|
|
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) +
|
|
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) +
|
|
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) +
|
|
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) +
|
|
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
|
|
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 =
|
|
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 =
|
|
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(
|
|
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
|
|
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 (!
|
|
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
|
|
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
|
|
3294
|
-
return `#${
|
|
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
|
-
|
|
3689
|
+
ratio = (logVal - logMin) / range.span;
|
|
3690
|
+
} else {
|
|
3691
|
+
ratio = (val2 - range.min) / range.span;
|
|
3412
3692
|
}
|
|
3413
|
-
return
|
|
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((
|
|
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(
|
|
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
|
|
3499
|
-
|
|
3500
|
-
|
|
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
|
|
3803
|
+
return Array.from(
|
|
3804
|
+
{ length: lastExponent - firstExponent + 1 },
|
|
3805
|
+
(_unused, index) => base ** (firstExponent + index)
|
|
3806
|
+
);
|
|
3503
3807
|
}
|
|
3504
|
-
function
|
|
3505
|
-
|
|
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
|
|
3508
|
-
|
|
3509
|
-
|
|
3510
|
-
|
|
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
|
-
|
|
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 =
|
|
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
|
-
|
|
3641
|
-
|
|
3642
|
-
|
|
3643
|
-
|
|
3644
|
-
|
|
3645
|
-
|
|
3646
|
-
|
|
3647
|
-
|
|
3648
|
-
|
|
3649
|
-
|
|
3650
|
-
|
|
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
|
-
|
|
3653
|
-
|
|
3654
|
-
|
|
3655
|
-
|
|
3656
|
-
|
|
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
|
-
|
|
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
|
|
3682
|
-
const
|
|
3683
|
-
const
|
|
3684
|
-
|
|
3685
|
-
|
|
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
|
-
|
|
3688
|
-
|
|
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
|
-
|
|
3703
|
-
|
|
3704
|
-
|
|
3705
|
-
|
|
3706
|
-
|
|
3707
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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[
|
|
3763
|
-
const x = layout.plotLeft + barGroupWidth2 *
|
|
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:
|
|
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
|
|
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 ? {
|
|
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
|
|
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
|
|
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:
|
|
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[
|
|
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
|
|
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,
|
|
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:
|
|
4523
|
+
part: { role: "dataPoint", seriesIndex: si, pointIndex: sourceIndex }
|
|
3914
4524
|
});
|
|
3915
4525
|
});
|
|
3916
4526
|
if (showLabels) {
|
|
3917
|
-
|
|
3918
|
-
const pt = pts[
|
|
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
|
|
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: `${
|
|
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
|
-
|
|
3972
|
-
const pt = pts[
|
|
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
|
|
4078
|
-
if (
|
|
4079
|
-
|
|
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
|
-
|
|
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
|
|
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 ?
|
|
4695
|
-
|
|
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
|
|
4698
|
-
|
|
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(
|
|
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(
|
|
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
|
-
|
|
5777
|
+
displayChartData,
|
|
4732
5778
|
catCount,
|
|
4733
5779
|
layout,
|
|
4734
5780
|
primaryRange,
|
|
4735
5781
|
catAxisStyle,
|
|
4736
5782
|
chartData.colorPalette
|
|
4737
5783
|
),
|
|
4738
|
-
...computeErrorBarPrimitives(
|
|
5784
|
+
...computeErrorBarPrimitives(displayChartData, catCount, layout, primaryRange, catAxisStyle),
|
|
4739
5785
|
...computeAxisTitlePrimitives(chartData, layout)
|
|
4740
5786
|
];
|
|
4741
|
-
const dataTablePrims = computeDataTablePrimitives(
|
|
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:
|
|
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
|
-
|
|
4775
|
-
|
|
4776
|
-
|
|
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
|
|
4779
|
-
|
|
4780
|
-
|
|
4781
|
-
|
|
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
|
|
4794
|
-
|
|
4795
|
-
|
|
4796
|
-
|
|
4797
|
-
|
|
4798
|
-
|
|
4799
|
-
|
|
4800
|
-
|
|
4801
|
-
|
|
4802
|
-
|
|
4803
|
-
|
|
4804
|
-
|
|
4805
|
-
|
|
4806
|
-
|
|
4807
|
-
|
|
4808
|
-
|
|
4809
|
-
|
|
4810
|
-
|
|
4811
|
-
|
|
4812
|
-
|
|
4813
|
-
|
|
4814
|
-
|
|
4815
|
-
|
|
4816
|
-
|
|
4817
|
-
|
|
4818
|
-
|
|
4819
|
-
|
|
4820
|
-
|
|
4821
|
-
|
|
4822
|
-
|
|
4823
|
-
|
|
4824
|
-
|
|
4825
|
-
|
|
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
|
-
|
|
4832
|
-
|
|
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
|
|
4837
|
-
const
|
|
4838
|
-
const
|
|
4839
|
-
|
|
4840
|
-
|
|
4841
|
-
|
|
4842
|
-
|
|
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:
|
|
4846
|
-
stroke:
|
|
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
|
-
|
|
4851
|
-
|
|
4852
|
-
|
|
4853
|
-
|
|
4854
|
-
|
|
4855
|
-
|
|
4856
|
-
|
|
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
|
-
|
|
4861
|
-
|
|
4862
|
-
|
|
4863
|
-
|
|
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
|
-
|
|
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:
|
|
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(
|
|
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
|
|
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
|
|
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
|
|
4923
|
-
const
|
|
4924
|
-
const
|
|
4925
|
-
const
|
|
4926
|
-
const
|
|
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 *
|
|
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:
|
|
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
|
-
|
|
4986
|
-
|
|
4987
|
-
|
|
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((
|
|
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,
|
|
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(
|
|
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
|
|
5014
|
-
|
|
5015
|
-
|
|
5016
|
-
const
|
|
5017
|
-
|
|
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
|
-
|
|
6546
|
+
labels.length,
|
|
5021
6547
|
layout,
|
|
5022
6548
|
range,
|
|
5023
|
-
|
|
6549
|
+
series?.color,
|
|
5024
6550
|
chartData.colorPalette
|
|
5025
6551
|
);
|
|
5026
6552
|
const primitives = bars.map(
|
|
5027
|
-
(
|
|
6553
|
+
(bar, displayIndex) => ({
|
|
5028
6554
|
kind: "rect",
|
|
5029
|
-
x:
|
|
5030
|
-
y:
|
|
5031
|
-
w:
|
|
5032
|
-
h:
|
|
5033
|
-
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
|
-
|
|
5038
|
-
|
|
5039
|
-
|
|
5040
|
-
|
|
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
|
|
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
|
-
|
|
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:
|
|
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
|
|
5087
|
-
|
|
5088
|
-
|
|
5089
|
-
|
|
5090
|
-
const
|
|
5091
|
-
const
|
|
5092
|
-
|
|
5093
|
-
|
|
5094
|
-
|
|
5095
|
-
|
|
5096
|
-
|
|
5097
|
-
|
|
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
|
|
5101
|
-
const
|
|
5102
|
-
const
|
|
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
|
|
5106
|
-
const
|
|
5107
|
-
const
|
|
5108
|
-
|
|
5109
|
-
|
|
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
|
|
5128
|
-
|
|
5129
|
-
|
|
5130
|
-
|
|
5131
|
-
const
|
|
5132
|
-
|
|
5133
|
-
|
|
5134
|
-
|
|
5135
|
-
|
|
5136
|
-
|
|
5137
|
-
);
|
|
5138
|
-
const
|
|
5139
|
-
|
|
5140
|
-
|
|
5141
|
-
|
|
5142
|
-
|
|
5143
|
-
|
|
5144
|
-
|
|
5145
|
-
|
|
5146
|
-
|
|
5147
|
-
|
|
5148
|
-
|
|
5149
|
-
|
|
5150
|
-
|
|
5151
|
-
|
|
5152
|
-
|
|
5153
|
-
|
|
5154
|
-
|
|
5155
|
-
|
|
5156
|
-
|
|
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
|
-
|
|
5161
|
-
|
|
5162
|
-
|
|
5163
|
-
|
|
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
|
-
|
|
5181
|
-
|
|
5182
|
-
|
|
5183
|
-
|
|
5184
|
-
|
|
5185
|
-
|
|
5186
|
-
|
|
5187
|
-
|
|
5188
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
5662
|
-
const
|
|
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
|
-
|
|
5669
|
-
|
|
5670
|
-
const
|
|
5671
|
-
const
|
|
5672
|
-
const
|
|
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 =
|
|
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(
|
|
7378
|
+
text: formatAxisValue2(value),
|
|
5695
7379
|
fontSize: 7,
|
|
5696
7380
|
fill: "#334155",
|
|
5697
7381
|
textAnchor: "middle"
|
|
5698
7382
|
});
|
|
5699
7383
|
}
|
|
5700
|
-
if (
|
|
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
|
|
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 =
|
|
5834
|
-
const g =
|
|
5835
|
-
const bl =
|
|
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
|
|
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 (
|
|
5997
|
-
|
|
5998
|
-
|
|
5999
|
-
|
|
6000
|
-
|
|
6001
|
-
|
|
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:
|
|
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
|
|
6013
|
-
const
|
|
6014
|
-
const
|
|
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
|
-
|
|
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:
|
|
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
|
-
|
|
8040
|
+
ratio = (logVal - logMin) / range.span;
|
|
8041
|
+
} else {
|
|
8042
|
+
ratio = (val2 - range.min) / range.span;
|
|
6296
8043
|
}
|
|
6297
|
-
return
|
|
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
|
|
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:
|
|
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:
|
|
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 + (
|
|
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 +
|
|
8740
|
+
const logVal = logMin + ratio * range.span;
|
|
6990
8741
|
return base ** logVal;
|
|
6991
8742
|
}
|
|
6992
|
-
return range.min +
|
|
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
|
|
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 =
|
|
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,
|
|
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
|
|
7315
|
-
return `#${
|
|
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 ??
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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
|
|
11733
|
-
return `#${
|
|
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) =>
|
|
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 (
|
|
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 (
|
|
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 &&
|
|
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 &&
|
|
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
|
|
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 (!
|
|
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 (!
|
|
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 (
|
|
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 (
|
|
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
|
|
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
|
|
20890
|
+
const line2 = lines[li];
|
|
18703
20891
|
if (li === 0) {
|
|
18704
|
-
content += `(${escapePdfText(
|
|
20892
|
+
content += `(${escapePdfText(line2)}) Tj `;
|
|
18705
20893
|
} else {
|
|
18706
|
-
content += `0 ${(-15.399999999999999).toFixed(2)} Td (${escapePdfText(
|
|
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 =
|
|
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;
|