@shbernal/ts-pptx 3.5.0 → 3.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -0
- package/dist/{autopage-BYlTzX-l.js → autopage-DkjYZUFD.js} +3 -3
- package/dist/{autopage-BYlTzX-l.js.map → autopage-DkjYZUFD.js.map} +1 -1
- package/dist/browser.d.ts +5 -5
- package/dist/browser.js +4 -4
- package/dist/browser.js.map +1 -1
- package/dist/{diagnostics-BDuR8UkG.d.ts → diagnostics-DfBdDHre.d.ts} +20 -5
- package/dist/diagnostics-DfBdDHre.d.ts.map +1 -0
- package/dist/{errors-CgnueTYL.d.ts → errors-PflMPWBn.d.ts} +2 -2
- package/dist/{errors-CgnueTYL.d.ts.map → errors-PflMPWBn.d.ts.map} +1 -1
- package/dist/{fit-TjpNbMru.js → fit-BKs0zxMI.js} +3 -3
- package/dist/{fit-TjpNbMru.js.map → fit-BKs0zxMI.js.map} +1 -1
- package/dist/{html-dom-yUSdCExA.js → html-dom-B0I0QSbU.js} +4 -4
- package/dist/{html-dom-yUSdCExA.js.map → html-dom-B0I0QSbU.js.map} +1 -1
- package/dist/html.d.ts +3 -3
- package/dist/html.js +1 -1
- package/dist/index.d.ts +5 -5
- package/dist/index.js +3 -3
- package/dist/inspect.d.ts +1 -1
- package/dist/inspect.js +4 -5
- package/dist/inspect.js.map +1 -1
- package/dist/math.d.ts +1 -1
- package/dist/measure.d.ts +2 -2
- package/dist/measure.js +1 -1
- package/dist/{namespaces-CcKuzeuE.js → namespaces-BVnNu7sg.js} +74 -3
- package/dist/namespaces-BVnNu7sg.js.map +1 -0
- package/dist/node.d.ts +5 -5
- package/dist/node.js +3 -3
- package/dist/{notes-DNqAggXx.js → notes-CJFJaG6M.js} +310 -313
- package/dist/notes-CJFJaG6M.js.map +1 -0
- package/dist/{pres-Dybf7ZUl.d.ts → pres-BcBR3CSM.d.ts} +2 -2
- package/dist/{pres-Dybf7ZUl.d.ts.map → pres-BcBR3CSM.d.ts.map} +1 -1
- package/dist/{presentation-VfJ_FT7E.js → presentation-DrJtj3-C.js} +414 -515
- package/dist/presentation-DrJtj3-C.js.map +1 -0
- package/dist/{presentation-types-CpkTx9Xa.d.ts → presentation-types-CDjScsev.d.ts} +351 -274
- package/dist/presentation-types-CDjScsev.d.ts.map +1 -0
- package/dist/read.d.ts +31 -48
- package/dist/read.d.ts.map +1 -1
- package/dist/read.js +3 -3
- package/dist/script.d.ts +2 -2
- package/dist/script.d.ts.map +1 -1
- package/dist/script.js +18 -47
- package/dist/script.js.map +1 -1
- package/dist/{shapes-Kt51vry6.js → shapes-BemroU-z.js} +625 -265
- package/dist/shapes-BemroU-z.js.map +1 -0
- package/dist/{slide-B_aInw3N.d.ts → slide-ZqAdVvHV.d.ts} +1135 -1058
- package/dist/slide-ZqAdVvHV.d.ts.map +1 -0
- package/dist/{text-D04NUMvA.js → text-B8SLEaZx.js} +2089 -1418
- package/dist/text-B8SLEaZx.js.map +1 -0
- package/dist/units-1kRzYShk.js +231 -0
- package/dist/units-1kRzYShk.js.map +1 -0
- package/dist/units-internal-Dg95w_YD.js +753 -0
- package/dist/units-internal-Dg95w_YD.js.map +1 -0
- package/dist/zip.d.ts +1 -1
- package/package.json +2 -1
- package/dist/diagnostics-BDuR8UkG.d.ts.map +0 -1
- package/dist/diagnostics-CPVADSL1.js +0 -90
- package/dist/diagnostics-CPVADSL1.js.map +0 -1
- package/dist/namespaces-CcKuzeuE.js.map +0 -1
- package/dist/notes-DNqAggXx.js.map +0 -1
- package/dist/presentation-VfJ_FT7E.js.map +0 -1
- package/dist/presentation-types-CpkTx9Xa.d.ts.map +0 -1
- package/dist/shapes-Kt51vry6.js.map +0 -1
- package/dist/slide-B_aInw3N.d.ts.map +0 -1
- package/dist/text-D04NUMvA.js.map +0 -1
- package/dist/units-internal-DNvK2I6o.js +0 -896
- package/dist/units-internal-DNvK2I6o.js.map +0 -1
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { S as warnOnce, a as FIXED_PCT_PER_PERCENT, d as emuToInches, g as pixelsToEmu, i as EMU_PER_POINT, l as STANDARD_LAYOUTS, m as inchesToEmu, r as EMU_PER_INCH, s as PERCENT_SCALE, v as ptToHundredths, x as warn } from "./units-1kRzYShk.js";
|
|
2
2
|
import { n as InvalidOptionError, o as UnsupportedFeatureError, r as MediaError, t as InternalError } from "./errors-Bvln0H-7.js";
|
|
3
|
-
import {
|
|
4
|
-
import { A as
|
|
5
|
-
import { A as
|
|
6
|
-
import { t as getSlidesForTableRows } from "./autopage-
|
|
7
|
-
import { _ as parseFontMetrics, m as FontMetricsRegistry, n as measureText, r as computeTableLayout, t as applyMeasuredFit, v as isFontCollection } from "./fit-
|
|
3
|
+
import { A as getDuplicateObjectNames, C as createShadowEffectLst, D as voidEl, E as raw, F as validateObjectName, M as getUuid, N as isHyperlinkRel, O as decodeXmlAttrValue, P as mediaSlideKey, S as correctShadowOptions, T as el, _ as flattenEmbeddedFaces, a as makeXmlNotesSlideRel, b as genXmlGradientFill, c as genXmlNormAutofit, d as renderTextParagraphsXml, f as clampFontSizeSz, g as FONT_REL_TYPE, h as FONT_DATA_EXTENSION, i as makeXmlNotesSlide, j as getNewRelId, k as encodeXmlAttrValue, l as genXmlParagraphProperties, m as FONT_DATA_CONTENT_TYPE, n as makeXmlNotesMaster, p as EMBEDDED_FONT_SLOTS, r as makeXmlNotesMasterRel, s as externalHyperlinkRel, t as buildNotesSlideRels, u as groupRunsIntoLines, v as serializeEmbeddedFontLst, w as createColorElement, x as genXmlPatternFill, y as genXmlColorSelection } from "./notes-CJFJaG6M.js";
|
|
4
|
+
import { $ as isChartExType, A as LAYOUT_IDX_SERIES_BASE, C as DEF_PRES_LAYOUT, D as DEF_SLIDE_MARGIN_IN, E as DEF_SHAPE_SHADOW, F as SLDNUMFLDID, G as SchemeColor, H as ChartType, I as SLDNUM_PLACEHOLDER_TEXT, L as XML_DECL, N as PIECHART_COLORS, P as REGEX_HEX_COLOR, Q as connectorPresetFor, S as DEF_FONT_COLOR, W as PlaceholderType, X as VALID_SHAPE_PRESETS, Z as asChartType, _ as BARCHART_COLORS, a as inch2Emu, b as DEF_CHART_BORDER, et as isChartType, f as AXIS_ID_CATEGORY_PRIMARY, g as AXIS_ID_VALUE_SECONDARY, h as AXIS_ID_VALUE_PRIMARY, i as getSmartParseNumber, j as LETTERS, k as DEF_TEXT_SHADOW, l as ptsToEmuLenient, m as AXIS_ID_SERIES_PRIMARY, n as convertArcAngle, o as lineWidthToEmu, p as AXIS_ID_CATEGORY_SECONDARY, r as convertRotationDegrees, s as marginToEmu, t as convertAngleUnits, u as resolveTableColWidthsEmu, v as DEF_CELL_BORDER, w as DEF_PRES_LAYOUT_NAME, x as DEF_CHART_GRIDLINE, y as DEF_CELL_MARGIN_IN } from "./units-internal-Dg95w_YD.js";
|
|
5
|
+
import { A as LIGHT_RIG_DIRECTIONS, C as decodeBase64ToBytes, E as BEVEL_PRESETS, M as PRESET_MATERIALS, O as DEFAULT_COLOR_MAP, P as TEXT_HORZ_OVERFLOW, R as checkEnumOrWarn, S as bytesToBase64, T as toMediaDataUri, b as getImageSizeFromBase64, j as PRESET_LINE_DASHES, k as LIGHT_RIGS, l as OFFICE_REL, n as PML_ROOT_NS, t as OOXML_NS, u as PACKAGE_REL_NS, w as svgMarkupToDataUri, y as fitSrcRectPercents } from "./namespaces-BVnNu7sg.js";
|
|
6
|
+
import { t as getSlidesForTableRows } from "./autopage-DkjYZUFD.js";
|
|
7
|
+
import { _ as parseFontMetrics, m as FontMetricsRegistry, n as measureText, r as computeTableLayout, t as applyMeasuredFit, v as isFontCollection } from "./fit-BKs0zxMI.js";
|
|
8
8
|
import { ZipWriter } from "./zip.js";
|
|
9
9
|
//#region src/media/content-type.ts
|
|
10
10
|
/**
|
|
@@ -411,61 +411,49 @@ function createChartTextFonts(typeface) {
|
|
|
411
411
|
return voidEl("a:latin", { typeface }) + voidEl("a:ea", { typeface }) + voidEl("a:cs", { typeface });
|
|
412
412
|
}
|
|
413
413
|
function genXmlTitle(opts, chartX, chartY) {
|
|
414
|
-
const
|
|
415
|
-
const
|
|
416
|
-
const sizeAttr = opts.fontSize ? `sz="${ptToHundredths(opts.fontSize)}"` : "";
|
|
417
|
-
const titleBold = opts.titleBold ? 1 : 0;
|
|
418
|
-
const titleItalic = opts.titleItalic ? 1 : 0;
|
|
419
|
-
const titleUnderline = opts.titleUnderline ? "sng" : "none";
|
|
420
|
-
let layout = "<c:layout/>";
|
|
414
|
+
const runAttrs = ` ${opts.fontSize ? `sz="${ptToHundredths(opts.fontSize)}"` : ""} b="${opts.titleBold ? 1 : 0}" i="${opts.titleItalic ? 1 : 0}" u="${opts.titleUnderline ? "sng" : "none"}" strike="noStrike">`;
|
|
415
|
+
const runChildren = "\n " + genXmlColorSelection(opts.color || "000000") + "\n " + createChartTextFonts(opts.fontFace || "Arial") + "\n ";
|
|
421
416
|
const hasX = opts.titlePos && typeof opts.titlePos.x === "number";
|
|
422
417
|
const hasY = opts.titlePos && typeof opts.titlePos.y === "number";
|
|
418
|
+
/** Fold a slide-relative offset into the fraction-of-chart value `c:x`/`c:y` want. */
|
|
419
|
+
const edgeFraction = (offset) => {
|
|
420
|
+
let val = offset === 0 ? 0 : offset * (offset / 5) / 10;
|
|
421
|
+
if (val >= 1) val = val / 10;
|
|
422
|
+
if (val >= .1) val = val / 10;
|
|
423
|
+
return val;
|
|
424
|
+
};
|
|
425
|
+
let layout = voidEl("c:layout");
|
|
423
426
|
if (hasX || hasY) {
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
</a:defRPr>
|
|
455
|
-
</a:pPr>
|
|
456
|
-
<a:r>
|
|
457
|
-
<a:rPr ${sizeAttr} b="${titleBold}" i="${titleItalic}" u="${titleUnderline}" strike="noStrike">
|
|
458
|
-
${genXmlColorSelection(opts.color || "000000")}
|
|
459
|
-
${createChartTextFonts(opts.fontFace || "Arial")}
|
|
460
|
-
</a:rPr>
|
|
461
|
-
${el("a:t", null, opts.title ?? "")}
|
|
462
|
-
</a:r>
|
|
463
|
-
</a:p>
|
|
464
|
-
</c:rich>
|
|
465
|
-
</c:tx>
|
|
466
|
-
${layout}
|
|
467
|
-
<c:overlay val="0"/>
|
|
468
|
-
</c:title>`;
|
|
427
|
+
const modes = (hasX ? voidEl("c:xMode", { val: "edge" }) : "") + (hasY ? voidEl("c:yMode", { val: "edge" }) : "");
|
|
428
|
+
const vals = (hasX ? voidEl("c:x", { val: edgeFraction((opts.titlePos?.x ?? 0) + (chartX ?? 0)) }) : "") + (hasY ? voidEl("c:y", { val: edgeFraction((opts.titlePos?.y ?? 0) + (chartY ?? 0)) }) : "");
|
|
429
|
+
layout = el("c:layout", null, raw(el("c:manualLayout", null, raw(modes + vals))));
|
|
430
|
+
}
|
|
431
|
+
const paragraph = el("a:p", null, [raw(el("a:pPr", opts.titleAlign === "left" || opts.titleAlign === "right" ? { algn: opts.titleAlign.slice(0, 1) } : null, raw("\n <a:defRPr" + runAttrs + runChildren + "</a:defRPr>"), {
|
|
432
|
+
openPrefix: "\n ",
|
|
433
|
+
closePrefix: "\n "
|
|
434
|
+
})), raw(el("a:r", null, [raw("\n <a:rPr" + runAttrs + runChildren + "</a:rPr>"), raw("\n " + el("a:t", null, opts.title ?? ""))], {
|
|
435
|
+
openPrefix: "\n ",
|
|
436
|
+
closePrefix: "\n "
|
|
437
|
+
}))], {
|
|
438
|
+
openPrefix: "\n ",
|
|
439
|
+
closePrefix: "\n "
|
|
440
|
+
});
|
|
441
|
+
const rich = el("c:rich", null, [
|
|
442
|
+
raw(voidEl("a:bodyPr", { rot: opts.titleRotate ? convertAngleUnits(opts.titleRotate, "titleRotate") : void 0 }, { openPrefix: "\n " })),
|
|
443
|
+
raw(voidEl("a:lstStyle", null, { openPrefix: "\n " })),
|
|
444
|
+
raw(paragraph)
|
|
445
|
+
], {
|
|
446
|
+
openPrefix: "\n ",
|
|
447
|
+
closePrefix: "\n "
|
|
448
|
+
});
|
|
449
|
+
return el("c:title", null, [
|
|
450
|
+
raw(el("c:tx", null, raw(rich), {
|
|
451
|
+
openPrefix: "\n ",
|
|
452
|
+
closePrefix: "\n "
|
|
453
|
+
})),
|
|
454
|
+
raw("\n " + layout),
|
|
455
|
+
raw(voidEl("c:overlay", { val: 0 }, { openPrefix: "\n " }))
|
|
456
|
+
], { closePrefix: "\n " });
|
|
469
457
|
}
|
|
470
458
|
/**
|
|
471
459
|
* Create Grid Line Element
|
|
@@ -501,31 +489,62 @@ function createGridLineElement(glOpts) {
|
|
|
501
489
|
* @param leaderLines - emit the trailing `<c:showLeaderLines>` (category-axis plots only)
|
|
502
490
|
*/
|
|
503
491
|
function chartDataLabels(opts, leaderLines) {
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
492
|
+
const defRPr = el("a:defRPr", {
|
|
493
|
+
b: opts.dataLabelFontBold ? 1 : 0,
|
|
494
|
+
i: opts.dataLabelFontItalic ? 1 : 0,
|
|
495
|
+
strike: "noStrike",
|
|
496
|
+
sz: ptToHundredths(opts.dataLabelFontSize || 12),
|
|
497
|
+
u: "none"
|
|
498
|
+
}, [raw(genXmlColorSelection(opts.dataLabelColor || "000000")), raw(" " + createChartTextFonts(opts.dataLabelFontFace || "Arial"))], {
|
|
499
|
+
openPrefix: " ",
|
|
500
|
+
closePrefix: " "
|
|
501
|
+
});
|
|
502
|
+
const txPr = el("c:txPr", null, [
|
|
503
|
+
raw(voidEl("a:bodyPr", null, { openPrefix: " " })),
|
|
504
|
+
raw(voidEl("a:lstStyle", null, { openPrefix: " " })),
|
|
505
|
+
raw(el("a:p", null, raw(el("a:pPr", null, raw(defRPr), { closePrefix: " " })), { openPrefix: " " }))
|
|
506
|
+
], {
|
|
507
|
+
openPrefix: " ",
|
|
508
|
+
closePrefix: " "
|
|
509
|
+
});
|
|
510
|
+
return el("c:dLbls", null, [
|
|
511
|
+
raw(voidEl("c:numFmt", {
|
|
512
|
+
formatCode: (opts.dataLabelFormatCode ?? "") || "General",
|
|
513
|
+
sourceLinked: 0
|
|
514
|
+
}, { openPrefix: " " })),
|
|
515
|
+
raw(txPr),
|
|
516
|
+
opts.dataLabelPosition ? raw(voidEl("c:dLblPos", { val: opts.dataLabelPosition }, { openPrefix: " " })) : null,
|
|
517
|
+
raw(voidEl("c:showLegendKey", { val: 0 }, { openPrefix: " " })),
|
|
518
|
+
raw(voidEl("c:showVal", { val: opts.showValue ? 1 : 0 }, { openPrefix: " " })),
|
|
519
|
+
raw(voidEl("c:showCatName", { val: 0 }, { openPrefix: " " })),
|
|
520
|
+
raw(voidEl("c:showSerName", { val: opts.showSerName ? 1 : 0 }, { openPrefix: " " })),
|
|
521
|
+
raw(voidEl("c:showPercent", { val: 0 }, { openPrefix: " " })),
|
|
522
|
+
raw(voidEl("c:showBubbleSize", { val: 0 }, { openPrefix: " " })),
|
|
523
|
+
leaderLines ? raw(voidEl("c:showLeaderLines", { val: opts.showLeaderLines ? 1 : 0 }, { openPrefix: " " })) : null
|
|
524
|
+
], {
|
|
525
|
+
openPrefix: " ",
|
|
526
|
+
closePrefix: " "
|
|
508
527
|
});
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
528
|
+
}
|
|
529
|
+
/**
|
|
530
|
+
* An `<a:solidFill>` of the theme text colour dimmed towards the background — the grey the chart
|
|
531
|
+
* furniture (stock hi-low lines and up/down bars, the data-table grid) is drawn in.
|
|
532
|
+
* `lumMod`/`lumOff` are the two halves of one dimming: how much of the luminance survives, and
|
|
533
|
+
* how much white is mixed back in.
|
|
534
|
+
* @param lumMod - surviving luminance, in thousandths of a percent
|
|
535
|
+
* @param lumOff - luminance added back, in thousandths of a percent
|
|
536
|
+
*/
|
|
537
|
+
function dimmedTextFill(lumMod, lumOff) {
|
|
538
|
+
return el("a:solidFill", null, raw(el("a:schemeClr", { val: "tx1" }, [raw(voidEl("a:lumMod", { val: lumMod })), raw(voidEl("a:lumOff", { val: lumOff }))])));
|
|
539
|
+
}
|
|
540
|
+
/** The hairline outline drawn in {@link dimmedTextFill}, at the same three dimming levels. */
|
|
541
|
+
function dimmedTextLine(lumMod, lumOff, fmt) {
|
|
542
|
+
return el("a:ln", {
|
|
543
|
+
w: 9525,
|
|
544
|
+
cap: "flat",
|
|
545
|
+
cmpd: "sng",
|
|
546
|
+
algn: "ctr"
|
|
547
|
+
}, [raw(dimmedTextFill(lumMod, lumOff)), raw(voidEl("a:round"))], fmt);
|
|
529
548
|
}
|
|
530
549
|
/**
|
|
531
550
|
* Build a `<c:pt>` numeric-cache data point, or '' to leave a gap.
|
|
@@ -545,7 +564,7 @@ function numCachePt(idx, value) {
|
|
|
545
564
|
warn("chart/non-finite-value", `chart value "${value}" at index ${idx} is not a finite number; data point omitted.`);
|
|
546
565
|
return "";
|
|
547
566
|
}
|
|
548
|
-
return
|
|
567
|
+
return el("c:pt", { idx }, raw(el("c:v", null, value)));
|
|
549
568
|
}
|
|
550
569
|
/**
|
|
551
570
|
* Build the error-bar elements (`<c:errBars>`) for a single series.
|
|
@@ -568,29 +587,19 @@ function makeChartErrorBarsXml(chartType, errorBars, obj) {
|
|
|
568
587
|
const valueType = eb.valueType || "fixedVal";
|
|
569
588
|
const barType = eb.barType || "both";
|
|
570
589
|
const direction = eb.direction || "y";
|
|
571
|
-
|
|
572
|
-
strXml += `<c:errDir val="${direction}"/>`;
|
|
573
|
-
strXml += `<c:errBarType val="${barType}"/>`;
|
|
574
|
-
strXml += `<c:errValType val="${valueType}"/>`;
|
|
575
|
-
strXml += `<c:noEndCap val="${eb.noEndCap ? "1" : "0"}"/>`;
|
|
590
|
+
let children = voidEl("c:errDir", { val: direction }) + voidEl("c:errBarType", { val: barType }) + voidEl("c:errValType", { val: valueType }) + voidEl("c:noEndCap", { val: eb.noEndCap ? 1 : 0 });
|
|
576
591
|
if (valueType === "cust") {
|
|
577
592
|
if (barType !== "minus") {
|
|
578
593
|
if (!eb.plusValues?.length) warn("chart/error-bars-missing-values", `chart series "${obj.name}" errorBars valueType 'cust' needs \`plusValues\` for barType '${barType}'.`);
|
|
579
|
-
|
|
594
|
+
children += makeErrBarNumLit("plus", eb.plusValues || []);
|
|
580
595
|
}
|
|
581
596
|
if (barType !== "plus") {
|
|
582
597
|
if (!eb.minusValues?.length) warn("chart/error-bars-missing-values", `chart series "${obj.name}" errorBars valueType 'cust' needs \`minusValues\` for barType '${barType}'.`);
|
|
583
|
-
|
|
598
|
+
children += makeErrBarNumLit("minus", eb.minusValues || []);
|
|
584
599
|
}
|
|
585
|
-
} else if (valueType !== "stdErr")
|
|
586
|
-
if (eb.color || eb.size != null) {
|
|
587
|
-
|
|
588
|
-
strXml += eb.size != null ? ` w="${ptsToEmuLenient(eb.size)}"` : "";
|
|
589
|
-
strXml += ">";
|
|
590
|
-
strXml += eb.color ? genXmlColorSelection(eb.color) : "";
|
|
591
|
-
strXml += "</a:ln></c:spPr>";
|
|
592
|
-
}
|
|
593
|
-
strXml += "</c:errBars>";
|
|
600
|
+
} else if (valueType !== "stdErr") children += voidEl("c:val", { val: eb.value ?? 1 });
|
|
601
|
+
if (eb.color || eb.size != null) children += el("c:spPr", null, raw(el("a:ln", { w: eb.size != null ? ptsToEmuLenient(eb.size) : void 0 }, raw(eb.color ? genXmlColorSelection(eb.color) : ""))));
|
|
602
|
+
strXml += el("c:errBars", null, raw(children));
|
|
594
603
|
});
|
|
595
604
|
return strXml;
|
|
596
605
|
}
|
|
@@ -600,12 +609,12 @@ function makeChartErrorBarsXml(chartType, errorBars, obj) {
|
|
|
600
609
|
* @param values - per-point magnitudes (index-aligned with the series values)
|
|
601
610
|
*/
|
|
602
611
|
function makeErrBarNumLit(tag, values) {
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
return
|
|
612
|
+
const numLit = el("c:numLit", null, [
|
|
613
|
+
raw(el("c:formatCode", null, "General")),
|
|
614
|
+
raw(voidEl("c:ptCount", { val: values.length })),
|
|
615
|
+
raw(values.map((value, idx) => numCachePt(idx, value)).join(""))
|
|
616
|
+
]);
|
|
617
|
+
return el(`c:${tag}`, null, raw(numLit));
|
|
609
618
|
}
|
|
610
619
|
/**
|
|
611
620
|
* Build a `<c:serLines>` ("Series Lines") element for a bar chart.
|
|
@@ -614,7 +623,7 @@ function makeErrBarNumLit(tag, values) {
|
|
|
614
623
|
*/
|
|
615
624
|
function createSerLinesElement(opt) {
|
|
616
625
|
if (!opt) return "";
|
|
617
|
-
if (opt === true) return "
|
|
626
|
+
if (opt === true) return voidEl("c:serLines");
|
|
618
627
|
if (opt.style === "none") return "";
|
|
619
628
|
const line = el("a:ln", {
|
|
620
629
|
w: ptsToEmuLenient(opt.size || DEF_CHART_GRIDLINE.size || 1),
|
|
@@ -640,7 +649,15 @@ function createLeaderLinesElement(opts) {
|
|
|
640
649
|
if (!opts.leaderLineColor && opts.leaderLineSize == null) return "";
|
|
641
650
|
const w = ptsToEmuLenient(opts.leaderLineSize ?? .75);
|
|
642
651
|
const color = opts.leaderLineColor || "808080";
|
|
643
|
-
|
|
652
|
+
const line = el("a:ln", {
|
|
653
|
+
w,
|
|
654
|
+
cap: "flat"
|
|
655
|
+
}, [
|
|
656
|
+
raw(genXmlColorSelection(color)),
|
|
657
|
+
raw(voidEl("a:prstDash", { val: "solid" })),
|
|
658
|
+
raw(voidEl("a:round"))
|
|
659
|
+
]);
|
|
660
|
+
return el("c:leaderLines", null, raw(el("c:spPr", null, [raw(line), raw(voidEl("a:effectLst"))])));
|
|
644
661
|
}
|
|
645
662
|
/**
|
|
646
663
|
* Build a single custom `<c:dLbl>` (rich-text data label) overriding one data point's label.
|
|
@@ -656,24 +673,57 @@ function createLeaderLinesElement(opts) {
|
|
|
656
673
|
*/
|
|
657
674
|
function makeCustomDLblXml(idx, text, opts) {
|
|
658
675
|
const sz = ptToHundredths(opts.dataLabelFontSize || 12);
|
|
659
|
-
const bold = opts.dataLabelFontBold ?
|
|
660
|
-
const italic = opts.dataLabelFontItalic ?
|
|
676
|
+
const bold = opts.dataLabelFontBold ? 1 : 0;
|
|
677
|
+
const italic = opts.dataLabelFontItalic ? 1 : 0;
|
|
661
678
|
const color = createColorElement(opts.dataLabelColor || "000000");
|
|
662
679
|
const face = opts.dataLabelFontFace || "Arial";
|
|
663
680
|
const lang = opts.lang || "en-US";
|
|
664
|
-
|
|
681
|
+
const runChildren = [raw(el("a:solidFill", null, raw(color))), raw(createChartTextFonts(face))];
|
|
682
|
+
const fontAttrs = {
|
|
683
|
+
sz,
|
|
684
|
+
b: bold,
|
|
685
|
+
i: italic,
|
|
686
|
+
u: "none",
|
|
687
|
+
strike: "noStrike"
|
|
688
|
+
};
|
|
689
|
+
const paragraph = el("a:p", null, [raw(el("a:pPr", null, raw(el("a:defRPr", fontAttrs, runChildren)))), raw(el("a:r", null, [raw(el("a:rPr", {
|
|
690
|
+
lang,
|
|
691
|
+
...fontAttrs,
|
|
692
|
+
dirty: 0
|
|
693
|
+
}, runChildren)), raw(el("a:t", null, text))]))]);
|
|
694
|
+
const rich = el("c:rich", null, [
|
|
695
|
+
raw(voidEl("a:bodyPr")),
|
|
696
|
+
raw(voidEl("a:lstStyle")),
|
|
697
|
+
raw(paragraph)
|
|
698
|
+
]);
|
|
699
|
+
return el("c:dLbl", null, [
|
|
700
|
+
raw(voidEl("c:idx", { val: idx })),
|
|
701
|
+
raw(el("c:tx", null, raw(rich))),
|
|
702
|
+
raw(voidEl("c:showLegendKey", { val: 0 })),
|
|
703
|
+
raw(voidEl("c:showVal", { val: 0 })),
|
|
704
|
+
raw(voidEl("c:showCatName", { val: 0 })),
|
|
705
|
+
raw(voidEl("c:showSerName", { val: 0 })),
|
|
706
|
+
raw(voidEl("c:showPercent", { val: 0 })),
|
|
707
|
+
raw(voidEl("c:showBubbleSize", { val: 0 }))
|
|
708
|
+
]);
|
|
665
709
|
}
|
|
666
710
|
/**
|
|
667
711
|
* Build an `<a:ln>` border element from a per-data-point `BorderProps`.
|
|
668
712
|
* @param border - point border style (`type`, `color`, `pt`)
|
|
669
713
|
*/
|
|
670
714
|
function createChartBorderLine(border) {
|
|
671
|
-
if (border.type === "none") return "
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
715
|
+
if (border.type === "none") return el("a:ln", null, raw(voidEl("a:noFill")));
|
|
716
|
+
return el("a:ln", {
|
|
717
|
+
w: ptsToEmuLenient(resolveBorderWidth(border, 1)),
|
|
718
|
+
cap: "flat"
|
|
719
|
+
}, [
|
|
720
|
+
raw(genXmlColorSelection({
|
|
721
|
+
color: border.color || "666666",
|
|
722
|
+
transparency: border.transparency
|
|
723
|
+
})),
|
|
724
|
+
raw(voidEl("a:prstDash", { val: border.type === "dash" ? "dash" : "solid" })),
|
|
725
|
+
raw(voidEl("a:round"))
|
|
726
|
+
]);
|
|
677
727
|
}
|
|
678
728
|
/**
|
|
679
729
|
* Build `<c:dPt>` entries for a series in the bar/line/area/scatter loops.
|
|
@@ -705,30 +755,89 @@ function makeSeriesDataPointsXml(chartType, obj, opts, varyColors) {
|
|
|
705
755
|
const pattern = ptStyle?.pattern;
|
|
706
756
|
const border = ptStyle?.border;
|
|
707
757
|
if (!fillColor && !pattern && !border) return;
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
if (isBar) xml += "<c:invertIfNegative val=\"0\"/>";
|
|
711
|
-
xml += "<c:bubble3D val=\"0\"/>";
|
|
712
|
-
xml += "<c:spPr>";
|
|
713
|
-
if ((isBar || isScatter) && opts.lineSize === 0 && !border && !ptStyle?.fill && !pattern) xml += "<a:ln><a:noFill/></a:ln>";
|
|
758
|
+
let shape = "";
|
|
759
|
+
if ((isBar || isScatter) && opts.lineSize === 0 && !border && !ptStyle?.fill && !pattern) shape = el("a:ln", null, raw(voidEl("a:noFill")));
|
|
714
760
|
else {
|
|
715
|
-
if (pattern)
|
|
761
|
+
if (pattern) shape = genXmlPatternFill(fillColor && !pattern.fgColor ? {
|
|
716
762
|
...pattern,
|
|
717
763
|
fgColor: fillColor
|
|
718
764
|
} : pattern);
|
|
719
|
-
else if (fillColor)
|
|
720
|
-
|
|
721
|
-
else xml += genXmlColorSelection(fillColor);
|
|
722
|
-
}
|
|
723
|
-
if (border) xml += createChartBorderLine(border);
|
|
765
|
+
else if (fillColor) shape = chartType === "bar3D" ? el("a:ln", null, raw(genXmlColorSelection(fillColor))) : genXmlColorSelection(fillColor);
|
|
766
|
+
if (border) shape += createChartBorderLine(border);
|
|
724
767
|
}
|
|
725
|
-
xml +=
|
|
726
|
-
|
|
727
|
-
|
|
768
|
+
xml += el("c:dPt", null, [
|
|
769
|
+
raw(voidEl("c:idx", { val: index })),
|
|
770
|
+
isBar ? raw(voidEl("c:invertIfNegative", { val: 0 })) : null,
|
|
771
|
+
raw(voidEl("c:bubble3D", { val: 0 })),
|
|
772
|
+
raw(el("c:spPr", null, [raw(shape), raw(createShadowEffectLst(opts.shadow, DEF_SHAPE_SHADOW))]))
|
|
773
|
+
]);
|
|
728
774
|
});
|
|
729
775
|
return xml;
|
|
730
776
|
}
|
|
731
777
|
/**
|
|
778
|
+
* A `<c:tx>` series-name block: the `<c:f>` formula plus the one-point `<c:strCache>` mirroring
|
|
779
|
+
* the header cell it points at. The string counterpart of {@link numRefBlock}.
|
|
780
|
+
*
|
|
781
|
+
* Built through `el()`/`voidEl()` rather than by concatenation, with the indentation carried on
|
|
782
|
+
* the `openPrefix`/`childPrefix`/`closePrefix` byte-layout hooks those helpers already have. The
|
|
783
|
+
* five copies this replaces were all hand-built strings, so routing them here takes fifty-odd
|
|
784
|
+
* hand-written delimiters out of `src/gen/chart/` rather than moving them into one file.
|
|
785
|
+
* @param ref - the `<c:f>` formula, from {@link sheetCellRef} or written inline
|
|
786
|
+
* @param name - the series name to cache; escaped on the way into `<c:v>`
|
|
787
|
+
* @param layout - which of the three historical whitespace spellings to emit; see {@link StrRefLayout}
|
|
788
|
+
*/
|
|
789
|
+
function strRefBlock(ref, name, layout = "indented") {
|
|
790
|
+
const compact = layout === "compact";
|
|
791
|
+
const pt = el("c:pt", { idx: 0 }, raw(el("c:v", null, name)));
|
|
792
|
+
const cacheChildren = [raw(voidEl("c:ptCount", { val: 1 })), raw(pt)];
|
|
793
|
+
const strCache = layout === "expanded" ? el("c:strCache", null, cacheChildren, {
|
|
794
|
+
childPrefix: " ",
|
|
795
|
+
closePrefix: " "
|
|
796
|
+
}) : el("c:strCache", null, cacheChildren);
|
|
797
|
+
const indent = (spaces) => compact ? "" : spaces;
|
|
798
|
+
const strRef = el("c:strRef", null, [raw(el("c:f", null, ref)), raw(strCache)], {
|
|
799
|
+
openPrefix: indent(" "),
|
|
800
|
+
childPrefix: indent(" "),
|
|
801
|
+
closePrefix: indent(" ")
|
|
802
|
+
});
|
|
803
|
+
return el("c:tx", null, raw(strRef), {
|
|
804
|
+
openPrefix: indent(" "),
|
|
805
|
+
closePrefix: indent(" ")
|
|
806
|
+
});
|
|
807
|
+
}
|
|
808
|
+
/**
|
|
809
|
+
* A `<c:cat>` category reference: the `<c:f>` formula plus the `<c:numCache>`/`<c:strCache>` that
|
|
810
|
+
* mirrors the label cells it points at.
|
|
811
|
+
*
|
|
812
|
+
* `kind` picks the cache: `'num'` for numeric categories — dates, which need a `<c:formatCode>` so
|
|
813
|
+
* PowerPoint renders them as dates rather than serial numbers — and `'str'` for text ones. Stock
|
|
814
|
+
* and cat-axis each carried both arms of that choice, and surface carried the string one, five
|
|
815
|
+
* copies of the same `<c:f>` + `<c:ptCount>` + `<c:pt idx>` loop.
|
|
816
|
+
*
|
|
817
|
+
* `layout` preserves which whitespace spelling each site emitted, for the reason
|
|
818
|
+
* {@link StrRefLayout} gives. The `<c:multiLvlStrRef>` arm of a cat-axis is deliberately not
|
|
819
|
+
* folded in: multi-level categories nest a `<c:lvl>` per label group, which is a different shape
|
|
820
|
+
* rather than a different spelling.
|
|
821
|
+
* @param kind - `num` for a numeric (date) category cache, `str` for a text one
|
|
822
|
+
* @param ref - the `<c:f>` formula
|
|
823
|
+
* @param labels - the category labels, in order; escaped on the way into `<c:v>`
|
|
824
|
+
* @param formatCode - the cached `<c:formatCode>`; numeric caches only
|
|
825
|
+
* @param layout - which whitespace spelling to emit
|
|
826
|
+
*/
|
|
827
|
+
function catRefBlock(kind, ref, labels, formatCode, layout = "compact") {
|
|
828
|
+
const indent = (spaces) => layout === "indented" ? spaces : "";
|
|
829
|
+
const points = labels.map((label, idx) => el("c:pt", { idx }, raw(el("c:v", null, label)))).join("");
|
|
830
|
+
const cache = el(`c:${kind}Cache`, null, [formatCode === void 0 ? null : raw(el("c:formatCode", null, formatCode)), raw(voidEl("c:ptCount", { val: labels.length }) + points)], {
|
|
831
|
+
childPrefix: indent(" "),
|
|
832
|
+
closePrefix: indent(" ")
|
|
833
|
+
});
|
|
834
|
+
return el(`c:${kind}Ref`, null, [raw(el("c:f", null, ref)), raw(cache)], {
|
|
835
|
+
openPrefix: indent(" "),
|
|
836
|
+
childPrefix: indent(" "),
|
|
837
|
+
closePrefix: indent(" ")
|
|
838
|
+
});
|
|
839
|
+
}
|
|
840
|
+
/**
|
|
732
841
|
* A `<c:xVal>`/`<c:yVal>` numeric-reference block: the `<c:f>` formula plus the `<c:numCache>`
|
|
733
842
|
* that mirrors the cells it points at.
|
|
734
843
|
*
|
|
@@ -748,19 +857,19 @@ function makeSeriesDataPointsXml(chartType, obj, opts, varyColors) {
|
|
|
748
857
|
* change wearing a cleanup's clothes, which the byte-identity gate exists to refuse.
|
|
749
858
|
*/
|
|
750
859
|
function numRefBlock(tag, ref, formatCode, values, refIndent = " ") {
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
})
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
return
|
|
860
|
+
const numCache = el("c:numCache", null, [
|
|
861
|
+
raw(el("c:formatCode", null, formatCode, { openPrefix: " " })),
|
|
862
|
+
raw(voidEl("c:ptCount", { val: values.length }, { openPrefix: " " })),
|
|
863
|
+
raw(values.map((value, idx) => numCachePt(idx, value)).join(""))
|
|
864
|
+
], {
|
|
865
|
+
openPrefix: " ",
|
|
866
|
+
closePrefix: " "
|
|
867
|
+
});
|
|
868
|
+
const numRef = el("c:numRef", null, [raw(el("c:f", null, ref, { openPrefix: refIndent })), raw(numCache)], {
|
|
869
|
+
openPrefix: " ",
|
|
870
|
+
closePrefix: " "
|
|
871
|
+
});
|
|
872
|
+
return el(tag, null, raw(numRef));
|
|
764
873
|
}
|
|
765
874
|
//#endregion
|
|
766
875
|
//#region src/gen/define/chart.ts
|
|
@@ -1427,6 +1536,42 @@ function addConnectorDefinition(target, opts) {
|
|
|
1427
1536
|
target._slideObjects.push(newObject);
|
|
1428
1537
|
}
|
|
1429
1538
|
//#endregion
|
|
1539
|
+
//#region src/gen/define/image-rel.ts
|
|
1540
|
+
/**
|
|
1541
|
+
* Push an image media rel onto `target`, reusing an identical source's package part.
|
|
1542
|
+
*
|
|
1543
|
+
* De-dup is per target and by source, not by bytes: file-path images are matched on `path`,
|
|
1544
|
+
* while base64 `data` images have no real path — they all share the `preencoded.<extn>`
|
|
1545
|
+
* placeholder — so they are matched on their payload instead, which is what stops the same
|
|
1546
|
+
* inline image being embedded once per use. A rel already marked `isDuplicate` is never
|
|
1547
|
+
* matched against, so every duplicate points at the one original rather than at a chain.
|
|
1548
|
+
*
|
|
1549
|
+
* This is a *slide-local* optimization. `package/assemble.ts` runs a second, deck-wide collapse
|
|
1550
|
+
* keyed on extension + bytes once every rel's data is loaded, which subsumes this one for reuse
|
|
1551
|
+
* across slides and for sources that only turn out identical after loading.
|
|
1552
|
+
* @param target - slide (or layout/master) the rel is registered on
|
|
1553
|
+
* @param source - the resolved image source: a `path`, a base64 `data` payload, or both
|
|
1554
|
+
* @param relId - the relationship id already allocated for this use
|
|
1555
|
+
*/
|
|
1556
|
+
function registerImageMediaRel(target, source, relId) {
|
|
1557
|
+
const path = source.path || "";
|
|
1558
|
+
const data = source.data || "";
|
|
1559
|
+
const type = imageContentType(source.extn);
|
|
1560
|
+
const dupe = target._relsMedia.find((item) => {
|
|
1561
|
+
if (item.isDuplicate || !item.Target || item.type !== type) return false;
|
|
1562
|
+
return path ? item.path === path : !!data && item.data === data;
|
|
1563
|
+
});
|
|
1564
|
+
target._relsMedia.push({
|
|
1565
|
+
path: path || "preencoded." + source.extn,
|
|
1566
|
+
type,
|
|
1567
|
+
extn: source.extn,
|
|
1568
|
+
data,
|
|
1569
|
+
rId: relId,
|
|
1570
|
+
isDuplicate: !!dupe?.Target,
|
|
1571
|
+
Target: dupe?.Target ? dupe.Target : `../media/image-${mediaSlideKey(target)}-${target._relsMedia.length + 1}.${source.extn}`
|
|
1572
|
+
});
|
|
1573
|
+
}
|
|
1574
|
+
//#endregion
|
|
1430
1575
|
//#region src/gen/define/image.ts
|
|
1431
1576
|
/** DPI PowerPoint assumes when sizing an inserted raster image (natural pixels / 96 == inches) */
|
|
1432
1577
|
const IMAGE_NATURAL_DPI = 96;
|
|
@@ -1459,21 +1604,11 @@ function registerImageFillMedia(target, fill) {
|
|
|
1459
1604
|
return;
|
|
1460
1605
|
}
|
|
1461
1606
|
const imageRelId = getNewRelId(target);
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
});
|
|
1468
|
-
target._relsMedia.push({
|
|
1469
|
-
path: strImagePath || "preencoded." + strImgExtn,
|
|
1470
|
-
type: imgContentType,
|
|
1471
|
-
extn: strImgExtn,
|
|
1472
|
-
data: strImageData || "",
|
|
1473
|
-
rId: imageRelId,
|
|
1474
|
-
isDuplicate: !!dupeItem?.Target,
|
|
1475
|
-
Target: dupeItem?.Target ? dupeItem.Target : `../media/image-${mediaKey}-${target._relsMedia.length + 1}.${strImgExtn}`
|
|
1476
|
-
});
|
|
1607
|
+
registerImageMediaRel(target, {
|
|
1608
|
+
path: strImagePath,
|
|
1609
|
+
data: strImageData,
|
|
1610
|
+
extn: strImgExtn
|
|
1611
|
+
}, imageRelId);
|
|
1477
1612
|
fill.type = "image";
|
|
1478
1613
|
fill._imgRid = imageRelId;
|
|
1479
1614
|
}
|
|
@@ -1599,20 +1734,11 @@ function addImageDefinition(target, opt) {
|
|
|
1599
1734
|
});
|
|
1600
1735
|
newObject.imageRid = imageRelId + 1;
|
|
1601
1736
|
} else {
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
});
|
|
1607
|
-
target._relsMedia.push({
|
|
1608
|
-
path: strImagePath || "preencoded." + strImgExtn,
|
|
1609
|
-
type: imgContentType,
|
|
1610
|
-
extn: strImgExtn,
|
|
1611
|
-
data: strImageData || "",
|
|
1612
|
-
rId: imageRelId,
|
|
1613
|
-
isDuplicate: !!dupeItem?.Target,
|
|
1614
|
-
Target: dupeItem?.Target ? dupeItem.Target : `../media/image-${mediaKey}-${target._relsMedia.length + 1}.${strImgExtn}`
|
|
1615
|
-
});
|
|
1737
|
+
registerImageMediaRel(target, {
|
|
1738
|
+
path: strImagePath,
|
|
1739
|
+
data: strImageData,
|
|
1740
|
+
extn: strImgExtn
|
|
1741
|
+
}, imageRelId);
|
|
1616
1742
|
newObject.imageRid = imageRelId;
|
|
1617
1743
|
}
|
|
1618
1744
|
if (typeof objHyperlink === "object") {
|
|
@@ -1957,7 +2083,7 @@ const SHAPE_NAME_ALIASES = {
|
|
|
1957
2083
|
* @param {ShapeProps} opts shape options
|
|
1958
2084
|
*/
|
|
1959
2085
|
function addShapeDefinition(target, shapeName, opts) {
|
|
1960
|
-
const options = typeof opts === "object" ? opts : {};
|
|
2086
|
+
const options = typeof opts === "object" ? { ...opts } : {};
|
|
1961
2087
|
options.line = options.line || { type: "none" };
|
|
1962
2088
|
options.shadow = correctShadowOptions(options.shadow);
|
|
1963
2089
|
const resolvedShapeName = typeof shapeName === "string" && SHAPE_NAME_ALIASES[shapeName] ? SHAPE_NAME_ALIASES[shapeName] : shapeName;
|
|
@@ -1998,8 +2124,21 @@ function addShapeDefinition(target, shapeName, opts) {
|
|
|
1998
2124
|
* @param {boolean} isPlaceholder whether this a placeholder object
|
|
1999
2125
|
*/
|
|
2000
2126
|
function addTextDefinition(target, text, opts, isPlaceholder) {
|
|
2001
|
-
const
|
|
2002
|
-
|
|
2127
|
+
const owned = /* @__PURE__ */ new Map();
|
|
2128
|
+
/** Copy a caller-supplied options object once, returning the same copy for the same input. */
|
|
2129
|
+
const own = (source) => {
|
|
2130
|
+
if (!source) return {};
|
|
2131
|
+
const already = owned.get(source);
|
|
2132
|
+
if (already) return already;
|
|
2133
|
+
const copy = { ...source };
|
|
2134
|
+
owned.set(source, copy);
|
|
2135
|
+
return copy;
|
|
2136
|
+
};
|
|
2137
|
+
const textObjects = (!text || text.length === 0 ? [{ text: "" }] : text).map((item) => ({
|
|
2138
|
+
...item,
|
|
2139
|
+
options: own(item.options)
|
|
2140
|
+
}));
|
|
2141
|
+
const objectOptions = own(opts);
|
|
2003
2142
|
const newObject = {
|
|
2004
2143
|
_type: isPlaceholder ? "placeholder" : "text",
|
|
2005
2144
|
shape: opts.shape || "rect",
|
|
@@ -2032,7 +2171,7 @@ function addTextDefinition(target, text, opts, isPlaceholder) {
|
|
|
2032
2171
|
itemOpts.line = itemOpts.line || {};
|
|
2033
2172
|
itemOpts.lineSpacing = itemOpts.lineSpacing && !isNaN(itemOpts.lineSpacing) ? itemOpts.lineSpacing : void 0;
|
|
2034
2173
|
itemOpts.lineSpacingMultiple = itemOpts.lineSpacingMultiple && !isNaN(itemOpts.lineSpacingMultiple) ? itemOpts.lineSpacingMultiple : void 0;
|
|
2035
|
-
itemOpts._bodyProp = itemOpts._bodyProp
|
|
2174
|
+
itemOpts._bodyProp = { ...itemOpts._bodyProp };
|
|
2036
2175
|
itemOpts._bodyProp.anchor = !itemOpts.placeholder ? "ctr" : void 0;
|
|
2037
2176
|
itemOpts._bodyProp.vert = itemOpts.textDirection ?? itemOpts.vert;
|
|
2038
2177
|
itemOpts._bodyProp.wrap = typeof itemOpts.wrap === "boolean" ? itemOpts.wrap : true;
|
|
@@ -2248,6 +2387,20 @@ const GROUPABLE_TYPES = [
|
|
|
2248
2387
|
"group"
|
|
2249
2388
|
];
|
|
2250
2389
|
/**
|
|
2390
|
+
* Whether `groupObjects()` would accept this object, given only what it is. The remaining reasons a
|
|
2391
|
+
* call can still fail are about the *selection* rather than the object — an unresolved, duplicated
|
|
2392
|
+
* or ambiguous name — so a consumer cannot decide those from one object either way.
|
|
2393
|
+
*
|
|
2394
|
+
* Exported because `Slide.objects` reports it as `canGroup`, and a consumer that had to re-state the
|
|
2395
|
+
* rule would be pinning a copy of the list above: it would keep refusing the day grouping learns a
|
|
2396
|
+
* new kind, and go on offering the day one is withdrawn, with nothing failing in either direction.
|
|
2397
|
+
* @param {SlideObject} obj - a top-level authored object
|
|
2398
|
+
* @returns {boolean} true when its kind is groupable and it is not a placeholder
|
|
2399
|
+
*/
|
|
2400
|
+
function isGroupableObject(obj) {
|
|
2401
|
+
return GROUPABLE_TYPES.includes(obj._type) && !obj.options?.placeholder;
|
|
2402
|
+
}
|
|
2403
|
+
/**
|
|
2251
2404
|
* Depth-first search for an object whose *stored* name is `key`, among group children. Used only to
|
|
2252
2405
|
* explain a failed lookup, so it takes the same attribute-escaped key the caller already compared
|
|
2253
2406
|
* against `_slideObjects` (see `groupObjectsDefinition`) rather than escaping again per call.
|
|
@@ -2295,7 +2448,7 @@ function groupObjectsDefinition(target, objectNames, opts) {
|
|
|
2295
2448
|
throw new InvalidOptionError("group/unresolved-object-name", `groupObjects(): cannot group "${name}" — ${hint}.`);
|
|
2296
2449
|
}
|
|
2297
2450
|
if (ambiguous) throw new InvalidOptionError("group/ambiguous-object-name", `groupObjects(): objectName "${name}" is ambiguous — ${matches.length} objects on this slide share it. Give them unique objectNames.`);
|
|
2298
|
-
if (!
|
|
2451
|
+
if (!isGroupableObject(obj)) {
|
|
2299
2452
|
const kind = obj.options?.placeholder ? "placeholder" : obj._type;
|
|
2300
2453
|
throw new UnsupportedFeatureError("group/kind-not-groupable", `groupObjects(): cannot group "${name}" — grouping a ${String(kind)} is not supported yet.`);
|
|
2301
2454
|
}
|
|
@@ -2310,6 +2463,26 @@ function groupObjectsDefinition(target, objectNames, opts) {
|
|
|
2310
2463
|
target._slideObjects.splice(0, target._slideObjects.length, ...regrouped);
|
|
2311
2464
|
}
|
|
2312
2465
|
//#endregion
|
|
2466
|
+
//#region src/media/placeholders.ts
|
|
2467
|
+
/**
|
|
2468
|
+
* The three base64 placeholder images the library falls back to.
|
|
2469
|
+
*
|
|
2470
|
+
* Their own module because of where the bundler puts them, not because they group naturally.
|
|
2471
|
+
* The chunker splits by module, so a constant is pulled into every chunk that reaches the module
|
|
2472
|
+
* declaring it — and these lived in `constants-internal.ts` beside `XML_DECL`, `DEF_FONT_SIZE`
|
|
2473
|
+
* and the rest of the vocabulary all of `src/gen/` imports. The result was that `IMG_PLAYBTN`,
|
|
2474
|
+
* a 74 KB PNG wanted by exactly one module, landed in two chunks and cost 149 KB of the shipped
|
|
2475
|
+
* package, 13% of the largest chunk. A caller who only ever wrote text boxes paid for the video
|
|
2476
|
+
* poster.
|
|
2477
|
+
*
|
|
2478
|
+
* So the rule this module encodes: a payload measured in tens of kilobytes does not share a
|
|
2479
|
+
* module with vocabulary, however tidy that grouping reads.
|
|
2480
|
+
*/
|
|
2481
|
+
/** Shown in place of media that failed to load, under `onMediaError: 'placeholder'`. */
|
|
2482
|
+
const IMG_BROKEN = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGQAAAB3CAYAAAD1oOVhAAAGAUlEQVR4Xu2dT0xcRRzHf7tAYSsc0EBSIq2xEg8mtTGebVzEqOVIolz0siRE4gGTStqKwdpWsXoyGhMuyAVJOHBgqyvLNgonDkabeCBYW/8kTUr0wsJC+Wfm0bfuvn37Znbem9mR9303mJnf/Pb7ed95M7PDI5JIJPYJV5EC7e3t1N/fT62trdqViQCIu+bVgpIHEo/Hqbe3V/sdYVKHyWSSZmZm8ilVA0oeyNjYmEnaVC2Xvr6+qg5fAOJAz4DU1dURGzFSqZRVqtMpAFIGyMjICC0vL9PExIRWKADiAYTNshYWFrRCARAOEFZcCKWtrY0GBgaUTYkBRACIE4rKZwqACALR5RQAqQCIDqcASIVAVDsFQCSAqHQKgEgCUeUUAPEBRIVTAMQnEBvK5OQkbW9vk991CoAEAMQJxc86BUACAhKUUwAkQCBBOAVAAgbi1ykAogCIH6cAiCIgsk4BEIVAZJwCIIqBVLqiBxANQFgXS0tLND4+zl08AogmIG5OSSQS1gGKwgtANAIRcQqAaAbCe6YASBWA2E6xDyeyDUl7+AKQMkDYYevm5mZHabA/Li4uUiaTsYLau8QA4gLE/hU7wajyYtv1hReDAiAOxQcHBymbzark4BkbQKom/X8dp9Npmpqasn4BIAYAYSnYp+4BBEAMUcCwNOCQsAKZnp62NtQOw8WmwT09PUo+ijaHsOMx7GppaaH6+nolH0Z10K2tLVpdXbW6UfV3mNqBdHd3U1NTk2rtlMRfW1uj2dlZAFGirkRQAJEQTWUTAFGprkRsAJEQTWUTAFGprkRsAJEQTWUTAFGprkRsAJEQTWUTAFGprkRsAJEQTWUTAFGprkRsAJEQTWUTAGHqrm8caPzQ0WC1logbeiC7X3xJm0PvUmRzh45cuki1588FAmVn9BO6P3yF9utrqGH0MtW82S8UN9RA9v/4k7InjhcJFTs/TLVXLwmJV67S7vD7tHF5pKi46fYdosdOcOOGG8j1OcqefbFEJD9Q3GCwDhqT31HklS4A8VRgfYM2Op6k3bt/BQJl58J7lPvwg5JYNccepaMry0LPqFA7hCm39+NNyp2J0172b19QysGINj5CsRtpij57musOViH0QPJQXn6J9u7dlYJSFkbrMYolrwvDAJAC+WWdEpQz7FTgECeUCpzi6YxvvqXoM6eEhqnCSgDikEzUKUE7Aw7xuHctKB5OYU3dZlNR9syQdAaAcAYTC0pXF+39c09o2Ik+3EqxVKqiB7hbYAxZkk4pbBaEM+AQofv+wTrFwylBOQNABIGwavdfe4O2pg5elO+86l99nY58/VUF0byrYsjiSFluNlXYrOHcBar7+EogUADEQ0YRGHbzoKAASBkg2+9cpM1rV0tK2QOcXW7bLEFAARAXIF4w2DrDWoeUWaf4hQIgDiA8GPZ2iNfi0Q8UACkAIgrDbrJ385eDxaPLLrEsFAB5oG6lMPJQPLZZZKAACBGVhcG2Q+bmuLu2nk55e4jqPv1IeEoceiBeX7s2zCa5MAqdstl91vfXwaEGsv/rb5TtOFk6tWXOuJGh6KmnhO9sayrMninPx103JBtXblHkice58cINZP4Hyr5wpkgkdiChEmc4FWazLzenNKa/p0jncwDiqcD6BuWePk07t1asatZGoYQzSqA4nFJ7soNiP/+EUyfc25GI2GG53dHPrKo1g/1Cw4pIXLrzO+1c+/wg7tBbFDle/EbQcjFCPWQJCau5EoBoFpzXHYDwFNJcDiCaBed1ByA8hTSXA4hmwXndAQhPIc3lAKJZcF53AMJTSHM5gGgWnNcdgPAU0lwOIJoF53UHIDyFNJcfSiCdnZ0Ui8U0SxlMd7lcjubn561gh+Y1scFIU/0o/3sgeLO12E2k7UXKYumgFoAYdg8ACIAYpoBh6cAhAGKYAoalA4cAiGEKGJYOHAIghilgWDpwCIAYpoBh6cAhAGKYAoalA4cAiGEKGJYOHAIghilgWDpwCIAYpoBh6ZQ4JB6PKzviYthnNy4d9h+1M5mMlVckkUjsG5dhiBMCEMPg/wuOfrZZ/RSywQAAAABJRU5ErkJggg==";
|
|
2483
|
+
/** 1x1 transparent PNG, standing in for an SVG the runtime could not rasterize. */
|
|
2484
|
+
const IMG_SVG_PLACEHOLDER = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg==";
|
|
2485
|
+
//#endregion
|
|
2313
2486
|
//#region src/gen/define/media.ts
|
|
2314
2487
|
/**
|
|
2315
2488
|
* Adds a media object to a slide definition.
|
|
@@ -2436,21 +2609,11 @@ function registerPreviewImage(target, cover) {
|
|
|
2436
2609
|
if (!strImagePath && !strImageData) strImageData = "image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAxSURBVFhH7c4hAQAACMAw+geFGOAJAGbi5mpRmf1Z7HEdAAAAAAAAAAAAAAAAAADAAPwOyNPFH3F8AAAAAElFTkSuQmCC";
|
|
2437
2610
|
const extn = imageExtensionForSource(strImagePath, strImageData);
|
|
2438
2611
|
const rId = getNewRelId(target);
|
|
2439
|
-
|
|
2440
|
-
|
|
2441
|
-
|
|
2442
|
-
|
|
2443
|
-
|
|
2444
|
-
});
|
|
2445
|
-
target._relsMedia.push({
|
|
2446
|
-
path: strImagePath || "preencoded." + extn,
|
|
2447
|
-
type,
|
|
2448
|
-
extn,
|
|
2449
|
-
data: strImageData || "",
|
|
2450
|
-
rId,
|
|
2451
|
-
isDuplicate: !!dupe?.Target,
|
|
2452
|
-
Target: dupe?.Target ? dupe.Target : `../media/image-${mediaKey}-${target._relsMedia.length + 1}.${extn}`
|
|
2453
|
-
});
|
|
2612
|
+
registerImageMediaRel(target, {
|
|
2613
|
+
path: strImagePath,
|
|
2614
|
+
data: strImageData,
|
|
2615
|
+
extn
|
|
2616
|
+
}, rId);
|
|
2454
2617
|
return rId;
|
|
2455
2618
|
}
|
|
2456
2619
|
//#endregion
|
|
@@ -2555,7 +2718,8 @@ function addModel3dDefinition(target, opt) {
|
|
|
2555
2718
|
w: opt.w ?? 4,
|
|
2556
2719
|
h: opt.h ?? 3,
|
|
2557
2720
|
objectName,
|
|
2558
|
-
...opt.altText ? { altText: opt.altText } : {}
|
|
2721
|
+
...opt.altText ? { altText: opt.altText } : {},
|
|
2722
|
+
...opt.objectLock ? { objectLock: opt.objectLock } : {}
|
|
2559
2723
|
},
|
|
2560
2724
|
model3d: {
|
|
2561
2725
|
modelRid,
|
|
@@ -2709,6 +2873,70 @@ function addOleObjectDefinition(target, opt) {
|
|
|
2709
2873
|
target._slideObjects.push(slideData);
|
|
2710
2874
|
}
|
|
2711
2875
|
//#endregion
|
|
2876
|
+
//#region src/gen/table/spans.ts
|
|
2877
|
+
/**
|
|
2878
|
+
* The largest `colspan`/`rowspan` this library will honour.
|
|
2879
|
+
*
|
|
2880
|
+
* Unlike the read side's point-cache ceiling there is no format number to borrow: `a:tc@gridSpan`
|
|
2881
|
+
* is a bare `xsd:int`. So this is a sanity bound rather than a schema one, and it is set an order
|
|
2882
|
+
* of magnitude past PowerPoint's own maximum table (its Insert Table dialog stops at 75 columns
|
|
2883
|
+
* and 75 rows), which is what makes it something no authored table can reach. What it stops is
|
|
2884
|
+
* the other end, where the allocation takes the host process with it.
|
|
2885
|
+
*/
|
|
2886
|
+
const MAX_TABLE_SPAN = 1e3;
|
|
2887
|
+
/**
|
|
2888
|
+
* Validate one cell's `colspan`/`rowspan`, warning and falling back to `1` when it is not a whole
|
|
2889
|
+
* number in `1..MAX_TABLE_SPAN`.
|
|
2890
|
+
*
|
|
2891
|
+
* `undefined` is the common case and means "no span" — it warns about nothing and returns `1`.
|
|
2892
|
+
* Everything else is caller error: `NaN`, a negative, a fraction and a span past the ceiling all
|
|
2893
|
+
* describe a table that cannot be built (a fractional span silently truncates, a negative one
|
|
2894
|
+
* shifts every column after it, an enormous one is the allocation above).
|
|
2895
|
+
* @param value - the raw option value
|
|
2896
|
+
* @param kind - `'colspan'` or `'rowspan'`, for the diagnostic
|
|
2897
|
+
* @returns the span to use, at least 1
|
|
2898
|
+
*/
|
|
2899
|
+
function resolveSpan(value, kind) {
|
|
2900
|
+
if (value === void 0) return 1;
|
|
2901
|
+
if (!Number.isInteger(value) || value < 1 || value > 1e3) {
|
|
2902
|
+
warn("table/span-out-of-range", `table cell: ${kind} must be a whole number between 1 and ${MAX_TABLE_SPAN}; got ${String(value)}. Using 1.`);
|
|
2903
|
+
return 1;
|
|
2904
|
+
}
|
|
2905
|
+
return value;
|
|
2906
|
+
}
|
|
2907
|
+
/**
|
|
2908
|
+
* Re-clone `rows` with every out-of-range `colspan`/`rowspan` corrected to `1`.
|
|
2909
|
+
*
|
|
2910
|
+
* Runs once, up front, so the column count, the `_hmerge`/`_vmerge` dummies, the auto-pager's
|
|
2911
|
+
* grid and the emitted `gridSpan`/`rowSpan` attributes all read the same number — checking at
|
|
2912
|
+
* each of those sites instead would warn several times per bad cell and could still disagree.
|
|
2913
|
+
*
|
|
2914
|
+
* A cell whose spans are fine is passed through by identity, not copied: `_spanOrigin` links the
|
|
2915
|
+
* merge dummies back to the origin *object*, and the all-valid path is every real table, which
|
|
2916
|
+
* must stay allocation-free and byte-identical.
|
|
2917
|
+
* @param rows - the rows to check; row arrays are never mutated
|
|
2918
|
+
* @returns the same rows with only the offending cells replaced
|
|
2919
|
+
*/
|
|
2920
|
+
function withCheckedSpans(rows) {
|
|
2921
|
+
return rows.map((cells) => cells.map((cell) => {
|
|
2922
|
+
const opts = cell?.options;
|
|
2923
|
+
if (!opts) return cell;
|
|
2924
|
+
const colspan = resolveSpan(opts.colspan, "colspan");
|
|
2925
|
+
const rowspan = resolveSpan(opts.rowspan, "rowspan");
|
|
2926
|
+
const colspanOk = opts.colspan === void 0 || opts.colspan === colspan;
|
|
2927
|
+
const rowspanOk = opts.rowspan === void 0 || opts.rowspan === rowspan;
|
|
2928
|
+
if (colspanOk && rowspanOk) return cell;
|
|
2929
|
+
return {
|
|
2930
|
+
...cell,
|
|
2931
|
+
options: {
|
|
2932
|
+
...opts,
|
|
2933
|
+
...opts.colspan === void 0 ? {} : { colspan },
|
|
2934
|
+
...opts.rowspan === void 0 ? {} : { rowspan }
|
|
2935
|
+
}
|
|
2936
|
+
};
|
|
2937
|
+
}));
|
|
2938
|
+
}
|
|
2939
|
+
//#endregion
|
|
2712
2940
|
//#region src/gen/define/table.ts
|
|
2713
2941
|
/**
|
|
2714
2942
|
* Expand a cell/table border into the 4-side tuple the rest of the pipeline expects.
|
|
@@ -2907,7 +3135,8 @@ function registerTableImageFills(target, rows, opt) {
|
|
|
2907
3135
|
}
|
|
2908
3136
|
function addTableDefinition(target, tableRows, options, slideLayout, presLayout, addSlide, getSlide) {
|
|
2909
3137
|
const slides = [target];
|
|
2910
|
-
const opt = options && typeof options === "object" ? options : {};
|
|
3138
|
+
const opt = options && typeof options === "object" ? { ...options } : {};
|
|
3139
|
+
if (Array.isArray(opt.border)) opt.border = [...opt.border];
|
|
2911
3140
|
opt.objectName = opt.objectName ? encodeXmlAttrValue(validateObjectName(opt.objectName, "table")) : `Table ${target._slideObjects.filter((obj) => obj._type === "table").length}`;
|
|
2912
3141
|
if (opt.placeholder && slideLayout?._slideObjects) {
|
|
2913
3142
|
const placeHold = slideLayout._slideObjects.find((item) => item._type === "placeholder" && item.options?.placeholder === opt.placeholder);
|
|
@@ -2920,7 +3149,7 @@ function addTableDefinition(target, tableRows, options, slideLayout, presLayout,
|
|
|
2920
3149
|
}
|
|
2921
3150
|
if (tableRows === null || tableRows.length === 0 || !Array.isArray(tableRows)) throw new InvalidOptionError("table/rows-not-an-array", "addTable: Array expected! EX: 'slide.addTable( [rows], {options} );'");
|
|
2922
3151
|
if (!tableRows[0] || !Array.isArray(tableRows[0])) throw new InvalidOptionError("table/rows-not-nested", "addTable: 'rows' should be an array of cells! EX: 'slide.addTable( [ ['A'], ['B'], {text:'C',options:{align:'center'}} ] );'");
|
|
2923
|
-
const arrRows = normalizeTableRows(applyTableHeaderColumnSugar(tableRows, opt), opt);
|
|
3152
|
+
const arrRows = withCheckedSpans(normalizeTableRows(applyTableHeaderColumnSugar(tableRows, opt), opt));
|
|
2924
3153
|
if (opt.x === void 0 || opt.x === null) opt.x = .5;
|
|
2925
3154
|
if (opt.y === void 0 || opt.y === null) opt.y = .5;
|
|
2926
3155
|
opt.fontSize = opt.fontSize || 12;
|
|
@@ -3091,7 +3320,8 @@ function pushZoomObject(target, variant, opts, zoom) {
|
|
|
3091
3320
|
y: opts.y ?? 0,
|
|
3092
3321
|
w: opts.w ?? 0,
|
|
3093
3322
|
h: opts.h ?? 0,
|
|
3094
|
-
objectName
|
|
3323
|
+
objectName,
|
|
3324
|
+
...opts.objectLock ? { objectLock: opts.objectLock } : {}
|
|
3095
3325
|
},
|
|
3096
3326
|
zoom: {
|
|
3097
3327
|
variant,
|
|
@@ -3212,6 +3442,30 @@ function addSummaryZoomDefinition(target, opts, sections) {
|
|
|
3212
3442
|
}
|
|
3213
3443
|
//#endregion
|
|
3214
3444
|
//#region src/slide.ts
|
|
3445
|
+
/**
|
|
3446
|
+
* Project one authored render-object onto the public {@link SlideObjectInfo}, recursing into a
|
|
3447
|
+
* group's children.
|
|
3448
|
+
*
|
|
3449
|
+
* The name is decoded on the way out. Every `add*Definition` stores it attribute-escaped, and
|
|
3450
|
+
* `groupObjects()` escapes the caller's spelling before it compares, so handing the stored form
|
|
3451
|
+
* back would escape it twice and resolve nothing — the same mismatch that once made `groupObjects`
|
|
3452
|
+
* throw for an object plainly on the slide, arriving from the other direction.
|
|
3453
|
+
*
|
|
3454
|
+
* Every `add*Definition` also *generates* a name when the caller passed none, so the fallback below
|
|
3455
|
+
* is unreachable through the public API. It is there because the field is typed non-optional
|
|
3456
|
+
* internally only by convention, and an empty name would otherwise read back as `undefined` from a
|
|
3457
|
+
* surface that promises a string.
|
|
3458
|
+
*/
|
|
3459
|
+
function toSlideObjectInfo(obj) {
|
|
3460
|
+
const stored = obj.options?.objectName;
|
|
3461
|
+
return {
|
|
3462
|
+
type: obj._type,
|
|
3463
|
+
objectName: typeof stored === "string" && stored.length > 0 ? decodeXmlAttrValue(stored) : "",
|
|
3464
|
+
isPlaceholder: !!obj.options?.placeholder,
|
|
3465
|
+
canGroup: isGroupableObject(obj),
|
|
3466
|
+
children: (obj._groupObjects ?? []).map(toSlideObjectInfo)
|
|
3467
|
+
};
|
|
3468
|
+
}
|
|
3215
3469
|
/** Distinguish a multi-type (combo) chart array (`ChartMulti[]`) from a single chart's data (`OptsChartData[]`). */
|
|
3216
3470
|
function isMultiChart(arg) {
|
|
3217
3471
|
const first = arg[0];
|
|
@@ -3318,6 +3572,17 @@ var SlideBuilder = class {
|
|
|
3318
3572
|
get newAutoPagedSlides() {
|
|
3319
3573
|
return this._newAutoPagedSlides;
|
|
3320
3574
|
}
|
|
3575
|
+
/**
|
|
3576
|
+
* The objects authored on this slide so far, bottom-to-top in z-order.
|
|
3577
|
+
*
|
|
3578
|
+
* Built fresh on every access rather than cached: the underlying list is mutated in place by
|
|
3579
|
+
* `addGroup`/`groupObjects` as well as appended to, so a cache would have to be invalidated from
|
|
3580
|
+
* every authoring path and would go stale the first time one was added without remembering.
|
|
3581
|
+
* Building it costs a walk of a list a slide-sized deck keeps in the dozens.
|
|
3582
|
+
*/
|
|
3583
|
+
get objects() {
|
|
3584
|
+
return this._slideObjects.map(toSlideObjectInfo);
|
|
3585
|
+
}
|
|
3321
3586
|
/** Slide width in inches (resolved from the active presentation layout). */
|
|
3322
3587
|
get width() {
|
|
3323
3588
|
return emuToInches(this._presLayout.width);
|
|
@@ -3567,16 +3832,17 @@ var SlideBuilder = class {
|
|
|
3567
3832
|
* than one parameterized one. Called by {@link ./chart-xml}'s axis region.
|
|
3568
3833
|
*
|
|
3569
3834
|
* Sub-blocks are shared where they can be shared *exactly*: {@link axisLineSpPr} covers
|
|
3570
|
-
* `<c:spPr>`, which differs between the three only by indent width. `<c:txPr>`
|
|
3571
|
-
*
|
|
3572
|
-
*
|
|
3573
|
-
*
|
|
3574
|
-
*
|
|
3835
|
+
* `<c:spPr>`, which differs between the three only by indent width. `<c:txPr>` stays
|
|
3836
|
+
* duplicated — its inherited indentation is irregular *within* each copy as well as between
|
|
3837
|
+
* them (the category axis closes `</a:defRPr>` at three spaces, the value axis at six), so
|
|
3838
|
+
* one parameterised builder would take about as many indent arguments as it has lines, and
|
|
3839
|
+
* would hide the quirks rather than share the structure. Each copy states its own layout at
|
|
3840
|
+
* its own call site instead.
|
|
3575
3841
|
*
|
|
3576
|
-
*
|
|
3577
|
-
*
|
|
3578
|
-
*
|
|
3579
|
-
*
|
|
3842
|
+
* Regularising that whitespace so one builder *could* serve all three is still open, and
|
|
3843
|
+
* still a byte change — AGENTS.md is explicit that a whitespace-only diff is a STOP, not a
|
|
3844
|
+
* known divergence. It is a decision to take deliberately, with a re-baselined gate, not a
|
|
3845
|
+
* cleanup to fold into something else.
|
|
3580
3846
|
*/
|
|
3581
3847
|
/**
|
|
3582
3848
|
* The `<c:spPr>` axis-line block, identical in shape on all three axes.
|
|
@@ -3596,89 +3862,103 @@ var SlideBuilder = class {
|
|
|
3596
3862
|
*/
|
|
3597
3863
|
function axisLineSpPr(indent, widthEmu, show, color, dash) {
|
|
3598
3864
|
const at = (extra) => " ".repeat(indent + extra);
|
|
3599
|
-
|
|
3865
|
+
const line = el("a:ln", {
|
|
3866
|
+
w: widthEmu,
|
|
3867
|
+
cap: "flat"
|
|
3868
|
+
}, [
|
|
3869
|
+
raw(!show ? voidEl("a:noFill") : genXmlColorSelection(color || DEF_GRIDLINE_COLOR)),
|
|
3870
|
+
raw(voidEl("a:prstDash", { val: dash }, { openPrefix: at(4) })),
|
|
3871
|
+
raw(voidEl("a:round", null, { openPrefix: at(4) }))
|
|
3872
|
+
], {
|
|
3873
|
+
openPrefix: at(2),
|
|
3874
|
+
closePrefix: at(2)
|
|
3875
|
+
});
|
|
3876
|
+
return el("c:spPr", null, raw(line), {
|
|
3877
|
+
openPrefix: at(0),
|
|
3878
|
+
closePrefix: at(0)
|
|
3879
|
+
});
|
|
3600
3880
|
}
|
|
3601
3881
|
function makeCatAxis(opts, axisId, valAxisId) {
|
|
3602
|
-
let strXml = "";
|
|
3603
3882
|
const usesValueAxisForCategories = opts._type === "scatter" || opts._type === "bubble" || opts._type === "bubble3D";
|
|
3604
3883
|
const usesCategoryAxis = !usesValueAxisForCategories && !opts.catLabelFormatCode;
|
|
3605
|
-
|
|
3606
|
-
|
|
3607
|
-
|
|
3608
|
-
|
|
3609
|
-
|
|
3610
|
-
|
|
3611
|
-
|
|
3612
|
-
|
|
3613
|
-
|
|
3614
|
-
|
|
3615
|
-
strXml += opts.catGridLine && opts.catGridLine.style !== "none" ? createGridLineElement(opts.catGridLine) : "";
|
|
3616
|
-
if (opts.showCatAxisTitle) strXml += genXmlTitle({
|
|
3617
|
-
color: opts.catAxisTitleColor,
|
|
3618
|
-
fontFace: opts.catAxisTitleFontFace,
|
|
3619
|
-
fontSize: opts.catAxisTitleFontSize,
|
|
3620
|
-
titleRotate: opts.catAxisTitleRotate,
|
|
3621
|
-
title: opts.catAxisTitle || "Axis Title"
|
|
3622
|
-
});
|
|
3623
|
-
if (opts._type === "scatter" || opts._type === "bubble" || opts._type === "bubble3D") {
|
|
3624
|
-
const xAxisFmtCode = opts.catAxisLabelFormatCode ?? opts.valAxisLabelFormatCode;
|
|
3625
|
-
strXml += " " + voidEl("c:numFmt", {
|
|
3626
|
-
formatCode: xAxisFmtCode || "General",
|
|
3627
|
-
sourceLinked: 1
|
|
3628
|
-
});
|
|
3629
|
-
} else strXml += " " + voidEl("c:numFmt", {
|
|
3884
|
+
const tag = usesValueAxisForCategories ? "c:valAx" : opts.catLabelFormatCode ? "c:dateAx" : "c:catAx";
|
|
3885
|
+
const scaling = el("c:scaling", null, [
|
|
3886
|
+
raw(voidEl("c:orientation", { val: opts.catAxisOrientation || "minMax" })),
|
|
3887
|
+
opts.catAxisMaxVal || opts.catAxisMaxVal === 0 ? raw(voidEl("c:max", { val: opts.catAxisMaxVal })) : null,
|
|
3888
|
+
opts.catAxisMinVal || opts.catAxisMinVal === 0 ? raw(voidEl("c:min", { val: opts.catAxisMinVal })) : null
|
|
3889
|
+
], { openPrefix: " " });
|
|
3890
|
+
const numFmt = usesValueAxisForCategories ? voidEl("c:numFmt", {
|
|
3891
|
+
formatCode: (opts.catAxisLabelFormatCode ?? opts.valAxisLabelFormatCode) || "General",
|
|
3892
|
+
sourceLinked: 1
|
|
3893
|
+
}, { openPrefix: " " }) : voidEl("c:numFmt", {
|
|
3630
3894
|
formatCode: (opts.catLabelFormatCode ?? "") || "General",
|
|
3631
3895
|
sourceLinked: 1
|
|
3896
|
+
}, { openPrefix: " " });
|
|
3897
|
+
const ticks = opts._type === "scatter" ? voidEl("c:majorTickMark", { val: "none" }, { openPrefix: " " }) + voidEl("c:minorTickMark", { val: "none" }, { openPrefix: " " }) + voidEl("c:tickLblPos", { val: opts.catAxisLabelPos || "nextTo" }, { openPrefix: " " }) : voidEl("c:majorTickMark", { val: opts.catAxisMajorTickMark || "out" }, { openPrefix: " " }) + voidEl("c:minorTickMark", { val: opts.catAxisMinorTickMark || "none" }, { openPrefix: " " }) + voidEl("c:tickLblPos", { val: opts.catAxisLabelPos || (opts.barDir === "col" ? "low" : "nextTo") }, { openPrefix: " " });
|
|
3898
|
+
const defRPr = el("a:defRPr", {
|
|
3899
|
+
sz: ptToHundredths(opts.catAxisLabelFontSize || 12),
|
|
3900
|
+
b: opts.catAxisLabelFontBold ? 1 : 0,
|
|
3901
|
+
i: opts.catAxisLabelFontItalic ? 1 : 0,
|
|
3902
|
+
u: "none",
|
|
3903
|
+
strike: "noStrike"
|
|
3904
|
+
}, [raw(genXmlColorSelection(opts.catAxisLabelColor || "000000")), raw(" " + createChartTextFonts(opts.catAxisLabelFontFace || "Arial"))], {
|
|
3905
|
+
openPrefix: " ",
|
|
3906
|
+
closePrefix: " "
|
|
3907
|
+
});
|
|
3908
|
+
const txPr = el("c:txPr", null, [
|
|
3909
|
+
raw(voidEl("a:bodyPr", { rot: opts.catAxisLabelRotate ? convertAngleUnits(opts.catAxisLabelRotate, "catAxisLabelRotate") : void 0 })),
|
|
3910
|
+
raw(voidEl("a:lstStyle", null, { openPrefix: " " })),
|
|
3911
|
+
raw(el("a:p", null, [raw(el("a:pPr", null, raw(defRPr), {
|
|
3912
|
+
openPrefix: " ",
|
|
3913
|
+
closePrefix: " "
|
|
3914
|
+
})), raw(voidEl("a:endParaRPr", { lang: opts.lang || "en-US" }, { openPrefix: " " }))], {
|
|
3915
|
+
openPrefix: " ",
|
|
3916
|
+
closePrefix: " "
|
|
3917
|
+
}))
|
|
3918
|
+
], {
|
|
3919
|
+
openPrefix: " ",
|
|
3920
|
+
closePrefix: " "
|
|
3632
3921
|
});
|
|
3633
|
-
if (opts._type === "scatter") {
|
|
3634
|
-
strXml += " <c:majorTickMark val=\"none\"/>";
|
|
3635
|
-
strXml += " <c:minorTickMark val=\"none\"/>";
|
|
3636
|
-
strXml += " <c:tickLblPos val=\"" + (opts.catAxisLabelPos || "nextTo") + "\"/>";
|
|
3637
|
-
} else {
|
|
3638
|
-
strXml += " <c:majorTickMark val=\"" + (opts.catAxisMajorTickMark || "out") + "\"/>";
|
|
3639
|
-
strXml += " <c:minorTickMark val=\"" + (opts.catAxisMinorTickMark || "none") + "\"/>";
|
|
3640
|
-
strXml += " <c:tickLblPos val=\"" + (opts.catAxisLabelPos || (opts.barDir === "col" ? "low" : "nextTo")) + "\"/>";
|
|
3641
|
-
}
|
|
3642
|
-
strXml += axisLineSpPr(2, opts.catAxisLineSize ? ptsToEmuLenient(opts.catAxisLineSize) : EMU_PER_POINT, opts.catAxisLineShow, opts.catAxisLineColor, opts.catAxisLineStyle || "solid");
|
|
3643
|
-
strXml += " <c:txPr>";
|
|
3644
|
-
if (opts.catAxisLabelRotate) strXml += `<a:bodyPr rot="${convertAngleUnits(opts.catAxisLabelRotate, "catAxisLabelRotate")}"/>`;
|
|
3645
|
-
else strXml += "<a:bodyPr/>";
|
|
3646
|
-
strXml += " <a:lstStyle/>";
|
|
3647
|
-
strXml += " <a:p>";
|
|
3648
|
-
strXml += " <a:pPr>";
|
|
3649
|
-
strXml += ` <a:defRPr sz="${ptToHundredths(opts.catAxisLabelFontSize || 12)}" b="${opts.catAxisLabelFontBold ? 1 : 0}" i="${opts.catAxisLabelFontItalic ? 1 : 0}" u="none" strike="noStrike">`;
|
|
3650
|
-
strXml += genXmlColorSelection(opts.catAxisLabelColor || "000000");
|
|
3651
|
-
strXml += " " + createChartTextFonts(opts.catAxisLabelFontFace || "Arial");
|
|
3652
|
-
strXml += " </a:defRPr>";
|
|
3653
|
-
strXml += " </a:pPr>";
|
|
3654
|
-
strXml += " <a:endParaRPr lang=\"" + (opts.lang || "en-US") + "\"/>";
|
|
3655
|
-
strXml += " </a:p>";
|
|
3656
|
-
strXml += " </c:txPr>";
|
|
3657
|
-
strXml += " <c:crossAx val=\"" + valAxisId + "\"/>";
|
|
3658
3922
|
const valAxisCrossTag = typeof opts.valAxisCrossesAt === "number" ? "crossesAt" : "crosses";
|
|
3659
3923
|
const valAxisCrossValue = typeof opts.valAxisCrossesAt === "number" ? opts.valAxisCrossesAt : opts.valAxisCrossesAt || "autoZero";
|
|
3660
|
-
|
|
3661
|
-
if (!usesValueAxisForCategories) strXml += " <c:auto val=\"1\"/>";
|
|
3662
|
-
if (usesCategoryAxis) {
|
|
3663
|
-
strXml += " <c:lblAlgn val=\"ctr\"/>";
|
|
3664
|
-
if (opts.catAxisLabelFrequency) strXml += " <c:tickLblSkip val=\"" + opts.catAxisLabelFrequency + "\"/>";
|
|
3665
|
-
strXml += ` <c:noMultiLvlLbl val="${opts.catAxisMultiLevelLabels ? 0 : 1}"/>`;
|
|
3666
|
-
}
|
|
3924
|
+
let units = "";
|
|
3667
3925
|
if (opts.catLabelFormatCode || usesValueAxisForCategories) {
|
|
3668
3926
|
if (opts.catLabelFormatCode) {
|
|
3669
3927
|
const baseTimeUnit = validTimeUnit(opts.catAxisBaseTimeUnit, "catAxisBaseTimeUnit");
|
|
3670
3928
|
const majorTimeUnit = validTimeUnit(opts.catAxisMajorTimeUnit, "catAxisMajorTimeUnit");
|
|
3671
3929
|
const minorTimeUnit = validTimeUnit(opts.catAxisMinorTimeUnit, "catAxisMinorTimeUnit");
|
|
3672
|
-
if (baseTimeUnit)
|
|
3673
|
-
if (majorTimeUnit)
|
|
3674
|
-
if (minorTimeUnit)
|
|
3930
|
+
if (baseTimeUnit) units += voidEl("c:baseTimeUnit", { val: baseTimeUnit });
|
|
3931
|
+
if (majorTimeUnit) units += voidEl("c:majorTimeUnit", { val: majorTimeUnit });
|
|
3932
|
+
if (minorTimeUnit) units += voidEl("c:minorTimeUnit", { val: minorTimeUnit });
|
|
3675
3933
|
}
|
|
3676
|
-
if (opts.catAxisMajorUnit)
|
|
3677
|
-
if (opts.catAxisMinorUnit)
|
|
3678
|
-
}
|
|
3679
|
-
|
|
3680
|
-
|
|
3681
|
-
|
|
3934
|
+
if (opts.catAxisMajorUnit) units += voidEl("c:majorUnit", { val: opts.catAxisMajorUnit });
|
|
3935
|
+
if (opts.catAxisMinorUnit) units += voidEl("c:minorUnit", { val: opts.catAxisMinorUnit });
|
|
3936
|
+
}
|
|
3937
|
+
return el(tag, null, [
|
|
3938
|
+
raw(voidEl("c:axId", { val: axisId }, { openPrefix: " " })),
|
|
3939
|
+
raw(scaling),
|
|
3940
|
+
raw(voidEl("c:delete", { val: opts.catAxisHidden ? 1 : 0 }, { openPrefix: " " })),
|
|
3941
|
+
raw(voidEl("c:axPos", { val: opts.barDir === "col" ? "b" : "l" }, { openPrefix: " " })),
|
|
3942
|
+
raw(opts.catGridLine && opts.catGridLine.style !== "none" ? createGridLineElement(opts.catGridLine) : ""),
|
|
3943
|
+
opts.showCatAxisTitle ? raw(genXmlTitle({
|
|
3944
|
+
color: opts.catAxisTitleColor,
|
|
3945
|
+
fontFace: opts.catAxisTitleFontFace,
|
|
3946
|
+
fontSize: opts.catAxisTitleFontSize,
|
|
3947
|
+
titleRotate: opts.catAxisTitleRotate,
|
|
3948
|
+
title: opts.catAxisTitle || "Axis Title"
|
|
3949
|
+
})) : null,
|
|
3950
|
+
raw(numFmt),
|
|
3951
|
+
raw(ticks),
|
|
3952
|
+
raw(axisLineSpPr(2, opts.catAxisLineSize ? ptsToEmuLenient(opts.catAxisLineSize) : EMU_PER_POINT, opts.catAxisLineShow, opts.catAxisLineColor, opts.catAxisLineStyle || "solid")),
|
|
3953
|
+
raw(txPr),
|
|
3954
|
+
raw(voidEl("c:crossAx", { val: valAxisId }, { openPrefix: " " })),
|
|
3955
|
+
raw(voidEl(`c:${valAxisCrossTag}`, { val: valAxisCrossValue }, { openPrefix: " " })),
|
|
3956
|
+
usesValueAxisForCategories ? null : raw(voidEl("c:auto", { val: 1 }, { openPrefix: " " })),
|
|
3957
|
+
usesCategoryAxis ? raw(voidEl("c:lblAlgn", { val: "ctr" }, { openPrefix: " " })) : null,
|
|
3958
|
+
usesCategoryAxis && opts.catAxisLabelFrequency ? raw(voidEl("c:tickLblSkip", { val: opts.catAxisLabelFrequency }, { openPrefix: " " })) : null,
|
|
3959
|
+
usesCategoryAxis ? raw(voidEl("c:noMultiLvlLbl", { val: opts.catAxisMultiLevelLabels ? 0 : 1 }, { openPrefix: " " })) : null,
|
|
3960
|
+
raw(units)
|
|
3961
|
+
]);
|
|
3682
3962
|
}
|
|
3683
3963
|
/**
|
|
3684
3964
|
* Create Value Axis (Used by `bar3D`)
|
|
@@ -3690,61 +3970,68 @@ function makeValAxis(opts, valAxisId) {
|
|
|
3690
3970
|
let axisPos = valAxisId === "2094734552" ? opts.barDir === "col" ? "l" : "b" : opts.barDir !== "col" ? "r" : "t";
|
|
3691
3971
|
if (valAxisId === "2094734553") axisPos = "r";
|
|
3692
3972
|
const crossAxId = valAxisId === "2094734552" ? AXIS_ID_CATEGORY_PRIMARY : AXIS_ID_CATEGORY_SECONDARY;
|
|
3693
|
-
|
|
3694
|
-
|
|
3695
|
-
|
|
3696
|
-
|
|
3697
|
-
|
|
3698
|
-
|
|
3699
|
-
|
|
3700
|
-
|
|
3701
|
-
strXml += " </c:scaling>";
|
|
3702
|
-
strXml += ` <c:delete val="${opts.valAxisHidden ? 1 : 0}"/>`;
|
|
3703
|
-
strXml += " <c:axPos val=\"" + axisPos + "\"/>";
|
|
3704
|
-
if (opts.valGridLine && opts.valGridLine.style !== "none") strXml += createGridLineElement(opts.valGridLine);
|
|
3705
|
-
if (opts.showValAxisTitle) strXml += genXmlTitle({
|
|
3706
|
-
color: opts.valAxisTitleColor,
|
|
3707
|
-
fontFace: opts.valAxisTitleFontFace,
|
|
3708
|
-
fontSize: opts.valAxisTitleFontSize,
|
|
3709
|
-
titleRotate: opts.valAxisTitleRotate,
|
|
3710
|
-
title: opts.valAxisTitle || "Axis Title"
|
|
3711
|
-
});
|
|
3712
|
-
strXml += voidEl("c:numFmt", {
|
|
3713
|
-
formatCode: opts.valAxisLabelFormatCode || "General",
|
|
3714
|
-
sourceLinked: 0
|
|
3973
|
+
const scaling = el("c:scaling", null, [
|
|
3974
|
+
opts.valAxisLogScaleBase ? raw(voidEl("c:logBase", { val: opts.valAxisLogScaleBase })) : null,
|
|
3975
|
+
raw(voidEl("c:orientation", { val: opts.valAxisOrientation || "minMax" })),
|
|
3976
|
+
opts.valAxisMaxVal || opts.valAxisMaxVal === 0 ? raw(voidEl("c:max", { val: opts.valAxisMaxVal })) : null,
|
|
3977
|
+
opts.valAxisMinVal || opts.valAxisMinVal === 0 ? raw(voidEl("c:min", { val: opts.valAxisMinVal })) : null
|
|
3978
|
+
], {
|
|
3979
|
+
openPrefix: " ",
|
|
3980
|
+
closePrefix: " "
|
|
3715
3981
|
});
|
|
3716
|
-
|
|
3717
|
-
|
|
3718
|
-
|
|
3719
|
-
|
|
3720
|
-
|
|
3721
|
-
|
|
3722
|
-
|
|
3723
|
-
|
|
3724
|
-
|
|
3725
|
-
|
|
3726
|
-
|
|
3727
|
-
|
|
3728
|
-
|
|
3729
|
-
|
|
3730
|
-
|
|
3731
|
-
|
|
3732
|
-
|
|
3733
|
-
|
|
3734
|
-
|
|
3735
|
-
|
|
3736
|
-
|
|
3737
|
-
|
|
3738
|
-
|
|
3739
|
-
|
|
3740
|
-
|
|
3741
|
-
|
|
3742
|
-
|
|
3743
|
-
|
|
3744
|
-
|
|
3745
|
-
|
|
3746
|
-
|
|
3747
|
-
|
|
3982
|
+
const ticks = opts._type === "scatter" ? voidEl("c:majorTickMark", { val: "none" }, { openPrefix: " " }) + voidEl("c:minorTickMark", { val: "none" }, { openPrefix: " " }) + voidEl("c:tickLblPos", { val: "nextTo" }, { openPrefix: " " }) : voidEl("c:majorTickMark", { val: opts.valAxisMajorTickMark || "out" }, { openPrefix: " " }) + voidEl("c:minorTickMark", { val: opts.valAxisMinorTickMark || "none" }, { openPrefix: " " }) + voidEl("c:tickLblPos", { val: opts.valAxisLabelPos || (opts.barDir === "col" ? "nextTo" : "low") }, { openPrefix: " " });
|
|
3983
|
+
const defRPr = el("a:defRPr", {
|
|
3984
|
+
sz: ptToHundredths(opts.valAxisLabelFontSize || 12),
|
|
3985
|
+
b: opts.valAxisLabelFontBold ? 1 : 0,
|
|
3986
|
+
i: opts.valAxisLabelFontItalic ? 1 : 0,
|
|
3987
|
+
u: "none",
|
|
3988
|
+
strike: "noStrike"
|
|
3989
|
+
}, [raw(genXmlColorSelection(opts.valAxisLabelColor || "000000")), raw(" " + createChartTextFonts(opts.valAxisLabelFontFace || "Arial"))], {
|
|
3990
|
+
openPrefix: " ",
|
|
3991
|
+
closePrefix: " "
|
|
3992
|
+
});
|
|
3993
|
+
const txPr = el("c:txPr", null, [
|
|
3994
|
+
raw(voidEl("a:bodyPr", { rot: opts.valAxisLabelRotate ? convertAngleUnits(opts.valAxisLabelRotate, "valAxisLabelRotate") : void 0 }, { openPrefix: " " })),
|
|
3995
|
+
raw(voidEl("a:lstStyle", null, { openPrefix: " " })),
|
|
3996
|
+
raw(el("a:p", null, [raw(el("a:pPr", null, raw(defRPr), {
|
|
3997
|
+
openPrefix: " ",
|
|
3998
|
+
closePrefix: " "
|
|
3999
|
+
})), raw(voidEl("a:endParaRPr", { lang: opts.lang || "en-US" }, { openPrefix: " " }))], {
|
|
4000
|
+
openPrefix: " ",
|
|
4001
|
+
closePrefix: " "
|
|
4002
|
+
}))
|
|
4003
|
+
], {
|
|
4004
|
+
openPrefix: " ",
|
|
4005
|
+
closePrefix: " "
|
|
4006
|
+
});
|
|
4007
|
+
const crosses = typeof opts.catAxisCrossesAt === "number" ? voidEl("c:crossesAt", { val: opts.catAxisCrossesAt }, { openPrefix: " " }) : typeof opts.catAxisCrossesAt === "string" ? voidEl("c:crosses", { val: opts.catAxisCrossesAt }, { openPrefix: " " }) : voidEl("c:crosses", { val: axisPos === "r" || axisPos === "t" ? "max" : "autoZero" }, { openPrefix: " " });
|
|
4008
|
+
const crossBetween = opts.valAxisCrossBetween || (opts._type === "scatter" || !!(Array.isArray(opts._type) && opts._type.some((type) => asChartType(type.type) === "area")) ? "midCat" : "between");
|
|
4009
|
+
return el("c:valAx", null, [
|
|
4010
|
+
raw(voidEl("c:axId", { val: valAxisId }, { openPrefix: " " })),
|
|
4011
|
+
raw(scaling),
|
|
4012
|
+
raw(voidEl("c:delete", { val: opts.valAxisHidden ? 1 : 0 }, { openPrefix: " " })),
|
|
4013
|
+
raw(voidEl("c:axPos", { val: axisPos }, { openPrefix: " " })),
|
|
4014
|
+
opts.valGridLine && opts.valGridLine.style !== "none" ? raw(createGridLineElement(opts.valGridLine)) : null,
|
|
4015
|
+
opts.showValAxisTitle ? raw(genXmlTitle({
|
|
4016
|
+
color: opts.valAxisTitleColor,
|
|
4017
|
+
fontFace: opts.valAxisTitleFontFace,
|
|
4018
|
+
fontSize: opts.valAxisTitleFontSize,
|
|
4019
|
+
titleRotate: opts.valAxisTitleRotate,
|
|
4020
|
+
title: opts.valAxisTitle || "Axis Title"
|
|
4021
|
+
})) : null,
|
|
4022
|
+
raw(voidEl("c:numFmt", {
|
|
4023
|
+
formatCode: opts.valAxisLabelFormatCode || "General",
|
|
4024
|
+
sourceLinked: 0
|
|
4025
|
+
})),
|
|
4026
|
+
raw(ticks),
|
|
4027
|
+
raw(axisLineSpPr(1, opts.valAxisLineSize ? ptsToEmuLenient(opts.valAxisLineSize) : EMU_PER_POINT, opts.valAxisLineShow, opts.valAxisLineColor, opts.valAxisLineStyle || "solid")),
|
|
4028
|
+
raw(txPr),
|
|
4029
|
+
raw(voidEl("c:crossAx", { val: crossAxId }, { openPrefix: " " })),
|
|
4030
|
+
raw(crosses),
|
|
4031
|
+
raw(voidEl("c:crossBetween", { val: crossBetween }, { openPrefix: " " })),
|
|
4032
|
+
opts.valAxisMajorUnit ? raw(voidEl("c:majorUnit", { val: opts.valAxisMajorUnit }, { openPrefix: " " })) : null,
|
|
4033
|
+
opts.valAxisDisplayUnit ? raw(el("c:dispUnits", null, [raw(voidEl("c:builtInUnit", { val: opts.valAxisDisplayUnit })), raw(opts.valAxisDisplayUnitLabel ? voidEl("c:dispUnitsLbl") : "")])) : null
|
|
4034
|
+
]);
|
|
3748
4035
|
}
|
|
3749
4036
|
/**
|
|
3750
4037
|
* Create Series Axis (Used by `bar3D`)
|
|
@@ -3754,651 +4041,850 @@ function makeValAxis(opts, valAxisId) {
|
|
|
3754
4041
|
* @return {string} XML
|
|
3755
4042
|
*/
|
|
3756
4043
|
function makeSerAxis(opts, axisId, valAxisId) {
|
|
3757
|
-
|
|
3758
|
-
|
|
3759
|
-
|
|
3760
|
-
|
|
3761
|
-
|
|
3762
|
-
|
|
3763
|
-
|
|
3764
|
-
|
|
3765
|
-
|
|
3766
|
-
|
|
3767
|
-
|
|
3768
|
-
|
|
3769
|
-
|
|
3770
|
-
|
|
3771
|
-
|
|
3772
|
-
|
|
3773
|
-
|
|
4044
|
+
const defRPr = el("a:defRPr", {
|
|
4045
|
+
sz: ptToHundredths(opts.serAxisLabelFontSize || 12),
|
|
4046
|
+
b: opts.serAxisLabelFontBold ? 1 : 0,
|
|
4047
|
+
i: opts.serAxisLabelFontItalic ? 1 : 0,
|
|
4048
|
+
u: "none",
|
|
4049
|
+
strike: "noStrike"
|
|
4050
|
+
}, [raw(" " + genXmlColorSelection(opts.serAxisLabelColor || "000000")), raw(" " + createChartTextFonts(opts.serAxisLabelFontFace || "Arial"))], {
|
|
4051
|
+
openPrefix: " ",
|
|
4052
|
+
closePrefix: " "
|
|
4053
|
+
});
|
|
4054
|
+
const txPr = el("c:txPr", null, [
|
|
4055
|
+
raw(voidEl("a:bodyPr", null, { openPrefix: " " })),
|
|
4056
|
+
raw(voidEl("a:lstStyle", null, { openPrefix: " " })),
|
|
4057
|
+
raw(el("a:p", null, [raw(el("a:pPr", null, raw(defRPr), {
|
|
4058
|
+
openPrefix: " ",
|
|
4059
|
+
closePrefix: " "
|
|
4060
|
+
})), raw(voidEl("a:endParaRPr", { lang: opts.lang || "en-US" }, { openPrefix: " " }))], {
|
|
4061
|
+
openPrefix: " ",
|
|
4062
|
+
closePrefix: " "
|
|
4063
|
+
}))
|
|
4064
|
+
], {
|
|
4065
|
+
openPrefix: " ",
|
|
4066
|
+
closePrefix: " "
|
|
3774
4067
|
});
|
|
3775
|
-
|
|
3776
|
-
strXml += " <c:minorTickMark val=\"none\"/>";
|
|
3777
|
-
strXml += ` <c:tickLblPos val="${opts.serAxisLabelPos || (opts.barDir === "col" ? "low" : "nextTo")}"/>`;
|
|
3778
|
-
strXml += axisLineSpPr(2, EMU_PER_POINT, opts.serAxisLineShow, opts.serAxisLineColor, "solid");
|
|
3779
|
-
strXml += " <c:txPr>";
|
|
3780
|
-
strXml += " <a:bodyPr/>";
|
|
3781
|
-
strXml += " <a:lstStyle/>";
|
|
3782
|
-
strXml += " <a:p>";
|
|
3783
|
-
strXml += " <a:pPr>";
|
|
3784
|
-
strXml += ` <a:defRPr sz="${ptToHundredths(opts.serAxisLabelFontSize || 12)}" b="${opts.serAxisLabelFontBold ? "1" : "0"}" i="${opts.serAxisLabelFontItalic ? "1" : "0"}" u="none" strike="noStrike">`;
|
|
3785
|
-
strXml += ` ${genXmlColorSelection(opts.serAxisLabelColor || "000000")}`;
|
|
3786
|
-
strXml += " " + createChartTextFonts(opts.serAxisLabelFontFace || "Arial");
|
|
3787
|
-
strXml += " </a:defRPr>";
|
|
3788
|
-
strXml += " </a:pPr>";
|
|
3789
|
-
strXml += " <a:endParaRPr lang=\"" + (opts.lang || "en-US") + "\"/>";
|
|
3790
|
-
strXml += " </a:p>";
|
|
3791
|
-
strXml += " </c:txPr>";
|
|
3792
|
-
strXml += " <c:crossAx val=\"" + valAxisId + "\"/>";
|
|
3793
|
-
strXml += " <c:crosses val=\"autoZero\"/>";
|
|
3794
|
-
if (opts.serAxisLabelFrequency) strXml += " <c:tickLblSkip val=\"" + opts.serAxisLabelFrequency + "\"/>";
|
|
4068
|
+
let units = "";
|
|
3795
4069
|
if (opts.serLabelFormatCode) {
|
|
3796
4070
|
const baseTimeUnit = validTimeUnit(opts.serAxisBaseTimeUnit, "serAxisBaseTimeUnit");
|
|
3797
4071
|
const majorTimeUnit = validTimeUnit(opts.serAxisMajorTimeUnit, "serAxisMajorTimeUnit");
|
|
3798
4072
|
const minorTimeUnit = validTimeUnit(opts.serAxisMinorTimeUnit, "serAxisMinorTimeUnit");
|
|
3799
|
-
if (baseTimeUnit)
|
|
3800
|
-
if (majorTimeUnit)
|
|
3801
|
-
if (minorTimeUnit)
|
|
3802
|
-
if (opts.serAxisMajorUnit)
|
|
3803
|
-
if (opts.serAxisMinorUnit)
|
|
3804
|
-
}
|
|
3805
|
-
|
|
3806
|
-
|
|
4073
|
+
if (baseTimeUnit) units += ` <c:baseTimeUnit val="${baseTimeUnit}"/>`;
|
|
4074
|
+
if (majorTimeUnit) units += voidEl("c:majorTimeUnit", { val: majorTimeUnit }, { openPrefix: " " });
|
|
4075
|
+
if (minorTimeUnit) units += voidEl("c:minorTimeUnit", { val: minorTimeUnit }, { openPrefix: " " });
|
|
4076
|
+
if (opts.serAxisMajorUnit) units += voidEl("c:majorUnit", { val: opts.serAxisMajorUnit }, { openPrefix: " " });
|
|
4077
|
+
if (opts.serAxisMinorUnit) units += voidEl("c:minorUnit", { val: opts.serAxisMinorUnit }, { openPrefix: " " });
|
|
4078
|
+
}
|
|
4079
|
+
return el("c:serAx", null, [
|
|
4080
|
+
raw(voidEl("c:axId", { val: axisId }, { openPrefix: " " })),
|
|
4081
|
+
raw(el("c:scaling", null, raw(voidEl("c:orientation", { val: opts.serAxisOrientation || "minMax" })), { openPrefix: " " })),
|
|
4082
|
+
raw(voidEl("c:delete", { val: opts.serAxisHidden ? 1 : 0 }, { openPrefix: " " })),
|
|
4083
|
+
raw(voidEl("c:axPos", { val: opts.barDir === "col" ? "b" : "l" }, { openPrefix: " " })),
|
|
4084
|
+
raw(opts.serGridLine && opts.serGridLine.style !== "none" ? createGridLineElement(opts.serGridLine) : ""),
|
|
4085
|
+
opts.showSerAxisTitle ? raw(genXmlTitle({
|
|
4086
|
+
color: opts.serAxisTitleColor,
|
|
4087
|
+
fontFace: opts.serAxisTitleFontFace,
|
|
4088
|
+
fontSize: opts.serAxisTitleFontSize,
|
|
4089
|
+
titleRotate: opts.serAxisTitleRotate,
|
|
4090
|
+
title: opts.serAxisTitle || "Axis Title"
|
|
4091
|
+
})) : null,
|
|
4092
|
+
raw(voidEl("c:numFmt", {
|
|
4093
|
+
formatCode: (opts.serLabelFormatCode ?? "") || "General",
|
|
4094
|
+
sourceLinked: 0
|
|
4095
|
+
}, { openPrefix: " " })),
|
|
4096
|
+
raw(voidEl("c:majorTickMark", { val: "out" }, { openPrefix: " " })),
|
|
4097
|
+
raw(voidEl("c:minorTickMark", { val: "none" }, { openPrefix: " " })),
|
|
4098
|
+
raw(voidEl("c:tickLblPos", { val: opts.serAxisLabelPos || (opts.barDir === "col" ? "low" : "nextTo") }, { openPrefix: " " })),
|
|
4099
|
+
raw(axisLineSpPr(2, EMU_PER_POINT, opts.serAxisLineShow, opts.serAxisLineColor, "solid")),
|
|
4100
|
+
raw(txPr),
|
|
4101
|
+
raw(voidEl("c:crossAx", { val: valAxisId }, { openPrefix: " " })),
|
|
4102
|
+
raw(voidEl("c:crosses", { val: "autoZero" }, { openPrefix: " " })),
|
|
4103
|
+
opts.serAxisLabelFrequency ? raw(voidEl("c:tickLblSkip", { val: opts.serAxisLabelFrequency }, { openPrefix: " " })) : null,
|
|
4104
|
+
raw(units)
|
|
4105
|
+
]);
|
|
3807
4106
|
}
|
|
3808
|
-
/**
|
|
3809
|
-
* Create char title elements
|
|
3810
|
-
* @param {ChartPropsTitle} opts - options
|
|
3811
|
-
* @return {string} XML `<c:title>`
|
|
3812
|
-
*/
|
|
3813
4107
|
//#endregion
|
|
3814
4108
|
//#region src/gen/chart/plot-cat-axis.ts
|
|
3815
|
-
/**
|
|
3816
|
-
|
|
3817
|
-
|
|
3818
|
-
|
|
3819
|
-
|
|
3820
|
-
|
|
3821
|
-
let strXml = "";
|
|
3822
|
-
strXml += `<c:${chartType}Chart>`;
|
|
4109
|
+
/** The chart types drawn as a line (a marker per point, an optional smooth) rather than as a body. */
|
|
4110
|
+
const isLineLike = (chartType) => chartType === "line" || chartType === "radar";
|
|
4111
|
+
/** The two bar families, which share `<c:barDir>`, `<c:invertIfNegative>` and a gap width. */
|
|
4112
|
+
const isBarLike = (chartType) => chartType === "bar" || chartType === "bar3D";
|
|
4113
|
+
/** The type-gated children that open a plot element, before `<c:varyColors>`. */
|
|
4114
|
+
function plotGrouping(chartType, opts) {
|
|
3823
4115
|
if (chartType === "area" || chartType === "line") {
|
|
3824
4116
|
const lineGrouping = opts.barGrouping === "stacked" || opts.barGrouping === "percentStacked" ? opts.barGrouping : "standard";
|
|
3825
|
-
|
|
3826
|
-
}
|
|
3827
|
-
if (chartType === "bar" || chartType === "bar3D") {
|
|
3828
|
-
strXml += "<c:barDir val=\"" + opts.barDir + "\"/>";
|
|
3829
|
-
strXml += "<c:grouping val=\"" + (opts.barGrouping || "clustered") + "\"/>";
|
|
4117
|
+
return voidEl("c:grouping", { val: lineGrouping });
|
|
3830
4118
|
}
|
|
4119
|
+
if (isBarLike(chartType)) return voidEl("c:barDir", { val: opts.barDir }) + voidEl("c:grouping", { val: opts.barGrouping || "clustered" });
|
|
3831
4120
|
if (chartType === "radar") {
|
|
3832
4121
|
const radarStyleWire = {
|
|
3833
4122
|
radar: "standard",
|
|
3834
4123
|
markers: "marker",
|
|
3835
4124
|
filled: "filled"
|
|
3836
4125
|
}[opts.radarStyle || "radar"] ?? "standard";
|
|
3837
|
-
|
|
3838
|
-
}
|
|
3839
|
-
|
|
3840
|
-
|
|
3841
|
-
|
|
3842
|
-
|
|
3843
|
-
|
|
3844
|
-
|
|
3845
|
-
|
|
3846
|
-
|
|
3847
|
-
|
|
3848
|
-
|
|
3849
|
-
|
|
3850
|
-
|
|
3851
|
-
|
|
3852
|
-
|
|
3853
|
-
|
|
3854
|
-
|
|
3855
|
-
|
|
3856
|
-
|
|
3857
|
-
|
|
3858
|
-
|
|
3859
|
-
|
|
3860
|
-
else {
|
|
3861
|
-
strXml += `<a:ln w="${ptsToEmuLenient(effectiveLineSize)}" cap="${createLineCap(opts.lineCap)}">${chartColorLineFill(seriesColor)}`;
|
|
3862
|
-
strXml += voidEl("a:prstDash", { val: opts.lineDashValues?.[colorIndex] ?? opts.lineDash ?? "solid" }) + voidEl("a:round") + "</a:ln>";
|
|
3863
|
-
}
|
|
3864
|
-
} else if (opts.dataBorder) strXml += `<a:ln w="${ptsToEmuLenient(resolveBorderWidth(opts.dataBorder, .75))}" cap="${createLineCap(opts.lineCap)}">${genXmlColorSelection({
|
|
4126
|
+
return voidEl("c:radarStyle", { val: radarStyleWire });
|
|
4127
|
+
}
|
|
4128
|
+
return "";
|
|
4129
|
+
}
|
|
4130
|
+
/** Fill, outline and shadow for one series, from its resolved colour and the line/border options. */
|
|
4131
|
+
function serShapeProps(chartType, opts, seriesColor, lineSize, serIndex) {
|
|
4132
|
+
const fill = seriesColor === "transparent" ? voidEl("a:noFill") : opts.chartColorsOpacity ? el("a:solidFill", null, raw(createColorElement(seriesColor, voidEl("a:alpha", { val: Math.round(opts.chartColorsOpacity * FIXED_PCT_PER_PERCENT) })))) : genXmlColorSelection(seriesColor);
|
|
4133
|
+
let line = "";
|
|
4134
|
+
if (isLineLike(chartType)) {
|
|
4135
|
+
const effectiveLineSize = lineSize ?? opts.lineSize ?? 2;
|
|
4136
|
+
line = effectiveLineSize === 0 ? el("a:ln", null, raw(voidEl("a:noFill"))) : el("a:ln", {
|
|
4137
|
+
w: ptsToEmuLenient(effectiveLineSize),
|
|
4138
|
+
cap: createLineCap(opts.lineCap)
|
|
4139
|
+
}, [
|
|
4140
|
+
raw(chartColorLineFill(seriesColor)),
|
|
4141
|
+
raw(voidEl("a:prstDash", { val: opts.lineDashValues?.[serIndex] ?? opts.lineDash ?? "solid" })),
|
|
4142
|
+
raw(voidEl("a:round"))
|
|
4143
|
+
]);
|
|
4144
|
+
} else if (opts.dataBorder) line = el("a:ln", {
|
|
4145
|
+
w: ptsToEmuLenient(resolveBorderWidth(opts.dataBorder, .75)),
|
|
4146
|
+
cap: createLineCap(opts.lineCap)
|
|
4147
|
+
}, [
|
|
4148
|
+
raw(genXmlColorSelection({
|
|
3865
4149
|
color: opts.dataBorder.color ?? "363636",
|
|
3866
4150
|
transparency: opts.dataBorder.transparency
|
|
3867
|
-
})
|
|
3868
|
-
|
|
3869
|
-
|
|
3870
|
-
|
|
3871
|
-
|
|
3872
|
-
|
|
3873
|
-
|
|
3874
|
-
|
|
3875
|
-
|
|
3876
|
-
|
|
3877
|
-
|
|
3878
|
-
strXml += markerColor === "transparent" ? "<a:noFill/>" : genXmlColorSelection(markerColor);
|
|
3879
|
-
}
|
|
3880
|
-
strXml += ` <a:ln w="${opts.lineDataSymbolLineSize}" cap="flat">${chartColorLineFill(opts.lineDataSymbolLineColor || seriesColor)}<a:prstDash val="solid"/><a:round/></a:ln>`;
|
|
3881
|
-
strXml += " <a:effectLst/>";
|
|
3882
|
-
strXml += " </c:spPr>";
|
|
3883
|
-
strXml += "</c:marker>";
|
|
3884
|
-
}
|
|
3885
|
-
{
|
|
3886
|
-
const barVaryColors = (chartType === "bar" || chartType === "bar3D") && data.length === 1 && (opts.chartColors && opts.chartColors !== BARCHART_COLORS && opts.chartColors.length > 1 || opts.invertedColors?.length) ? opts.chartColors || BARCHART_COLORS : null;
|
|
3887
|
-
strXml += makeSeriesDataPointsXml(chartType, obj, opts, barVaryColors);
|
|
3888
|
-
}
|
|
3889
|
-
if (chartType !== "radar") {
|
|
3890
|
-
const lblColor = seriesOverride?.dataLabelColor ?? opts.dataLabelColor ?? "000000";
|
|
3891
|
-
const lblBold = seriesOverride?.dataLabelFontBold ?? opts.dataLabelFontBold ?? false;
|
|
3892
|
-
const lblItalic = seriesOverride?.dataLabelFontItalic ?? opts.dataLabelFontItalic ?? false;
|
|
3893
|
-
const lblSize = seriesOverride?.dataLabelFontSize ?? opts.dataLabelFontSize ?? 12;
|
|
3894
|
-
const lblFace = seriesOverride?.dataLabelFontFace ?? opts.dataLabelFontFace ?? "Arial";
|
|
3895
|
-
const lblFmtCode = seriesOverride?.dataLabelFormatCode ?? opts.dataLabelFormatCode;
|
|
3896
|
-
strXml += "<c:dLbls>";
|
|
3897
|
-
if (obj.customLabels?.length) obj.customLabels.forEach((lbl, idx) => {
|
|
3898
|
-
if (lbl) strXml += makeCustomDLblXml(idx, lbl, opts);
|
|
3899
|
-
});
|
|
3900
|
-
strXml += voidEl("c:numFmt", {
|
|
3901
|
-
formatCode: (lblFmtCode ?? "") || "General",
|
|
3902
|
-
sourceLinked: 0
|
|
3903
|
-
});
|
|
3904
|
-
if (opts.dataLabelBkgrdColors) strXml += `<c:spPr>${genXmlColorSelection(seriesColor)}</c:spPr>`;
|
|
3905
|
-
strXml += "<c:txPr><a:bodyPr/><a:lstStyle/><a:p><a:pPr>";
|
|
3906
|
-
strXml += `<a:defRPr b="${lblBold ? 1 : 0}" i="${lblItalic ? 1 : 0}" strike="noStrike" sz="${ptToHundredths(lblSize)}" u="none">`;
|
|
3907
|
-
strXml += genXmlColorSelection(lblColor);
|
|
3908
|
-
strXml += createChartTextFonts(lblFace);
|
|
3909
|
-
strXml += "</a:defRPr></a:pPr></a:p></c:txPr>";
|
|
3910
|
-
if (opts.dataLabelPosition) strXml += voidEl("c:dLblPos", { val: opts.dataLabelPosition });
|
|
3911
|
-
strXml += "<c:showLegendKey val=\"0\"/>";
|
|
3912
|
-
strXml += `<c:showVal val="${opts.showValue ? "1" : "0"}"/>`;
|
|
3913
|
-
strXml += `<c:showCatName val="0"/><c:showSerName val="${opts.showSerName ? "1" : "0"}"/><c:showPercent val="0"/><c:showBubbleSize val="0"/>`;
|
|
3914
|
-
strXml += `<c:showLeaderLines val="${opts.showLeaderLines ? "1" : "0"}"/>`;
|
|
3915
|
-
strXml += "</c:dLbls>";
|
|
3916
|
-
}
|
|
3917
|
-
if (chartType !== "radar") strXml += makeChartErrorBarsXml(chartType, obj.errorBars, obj);
|
|
3918
|
-
strXml += "<c:cat>";
|
|
3919
|
-
if (opts.catLabelFormatCode) {
|
|
3920
|
-
strXml += " <c:numRef>";
|
|
3921
|
-
strXml += ` <c:f>Sheet1!$A$2:$A$${firstLabelGroup(obj).length + 1}</c:f>`;
|
|
3922
|
-
strXml += " <c:numCache>";
|
|
3923
|
-
strXml += " <c:formatCode>" + (opts.catLabelFormatCode || "General") + "</c:formatCode>";
|
|
3924
|
-
strXml += ` <c:ptCount val="${firstLabelGroup(obj).length}"/>`;
|
|
3925
|
-
firstLabelGroup(obj).forEach((label, idx) => strXml += `<c:pt idx="${idx}">${el("c:v", null, label)}</c:pt>`);
|
|
3926
|
-
strXml += " </c:numCache>";
|
|
3927
|
-
strXml += " </c:numRef>";
|
|
3928
|
-
} else if (dataLabels(obj).length === 1) {
|
|
3929
|
-
strXml += " <c:strRef>";
|
|
3930
|
-
strXml += ` <c:f>Sheet1!$A$2:$A$${firstLabelGroup(obj).length + 1}</c:f>`;
|
|
3931
|
-
strXml += " <c:strCache>";
|
|
3932
|
-
strXml += ` <c:ptCount val="${firstLabelGroup(obj).length}"/>`;
|
|
3933
|
-
firstLabelGroup(obj).forEach((label, idx) => strXml += `<c:pt idx="${idx}">${el("c:v", null, label)}</c:pt>`);
|
|
3934
|
-
strXml += " </c:strCache>";
|
|
3935
|
-
strXml += " </c:strRef>";
|
|
3936
|
-
} else {
|
|
3937
|
-
strXml += " <c:multiLvlStrRef>";
|
|
3938
|
-
strXml += ` <c:f>${sheetRangeRef(1, 2, dataLabels(obj).length, firstLabelGroup(obj).length + 1)}</c:f>`;
|
|
3939
|
-
strXml += " <c:multiLvlStrCache>";
|
|
3940
|
-
strXml += ` <c:ptCount val="${firstLabelGroup(obj).length}"/>`;
|
|
3941
|
-
dataLabels(obj).forEach((labelsGroup) => {
|
|
3942
|
-
strXml += "<c:lvl>";
|
|
3943
|
-
labelsGroup.forEach((label, idx) => strXml += `<c:pt idx="${idx}">${el("c:v", null, label)}</c:pt>`);
|
|
3944
|
-
strXml += "</c:lvl>";
|
|
3945
|
-
});
|
|
3946
|
-
strXml += " </c:multiLvlStrCache>";
|
|
3947
|
-
strXml += " </c:multiLvlStrRef>";
|
|
3948
|
-
}
|
|
3949
|
-
strXml += "</c:cat>";
|
|
3950
|
-
strXml += "<c:val>";
|
|
3951
|
-
strXml += " <c:numRef>";
|
|
3952
|
-
strXml += `<c:f>${sheetRangeRef(obj._dataIndex + dataLabels(obj).length + 1, 2, obj._dataIndex + dataLabels(obj).length + 1, firstLabelGroup(obj).length + 1)}</c:f>`;
|
|
3953
|
-
strXml += " <c:numCache>";
|
|
3954
|
-
strXml += " <c:formatCode>" + valFmtCode + "</c:formatCode>";
|
|
3955
|
-
strXml += ` <c:ptCount val="${firstLabelGroup(obj).length}"/>`;
|
|
3956
|
-
dataValues(obj).forEach((value, idx) => {
|
|
3957
|
-
strXml += numCachePt(idx, value);
|
|
3958
|
-
});
|
|
3959
|
-
strXml += " </c:numCache>";
|
|
3960
|
-
strXml += " </c:numRef>";
|
|
3961
|
-
strXml += "</c:val>";
|
|
3962
|
-
if (chartType === "line") strXml += "<c:smooth val=\"" + (opts.lineSmooth ? "1" : "0") + "\"/>";
|
|
3963
|
-
strXml += "</c:ser>";
|
|
4151
|
+
})),
|
|
4152
|
+
raw(voidEl("a:prstDash", { val: "solid" })),
|
|
4153
|
+
raw(voidEl("a:round"))
|
|
4154
|
+
]);
|
|
4155
|
+
return el("c:spPr", null, [
|
|
4156
|
+
raw(fill),
|
|
4157
|
+
raw(line),
|
|
4158
|
+
raw(createShadowEffectLst(opts.shadow, DEF_SHAPE_SHADOW))
|
|
4159
|
+
], {
|
|
4160
|
+
openPrefix: " ",
|
|
4161
|
+
closePrefix: " "
|
|
3964
4162
|
});
|
|
3965
|
-
|
|
3966
|
-
|
|
3967
|
-
|
|
3968
|
-
|
|
3969
|
-
|
|
3970
|
-
|
|
3971
|
-
|
|
3972
|
-
|
|
3973
|
-
|
|
3974
|
-
|
|
3975
|
-
|
|
3976
|
-
|
|
3977
|
-
|
|
3978
|
-
|
|
4163
|
+
}
|
|
4164
|
+
/**
|
|
4165
|
+
* The point marker for a line/radar series. `<c:marker>` must precede `<c:dLbls>` in CT_LineSer
|
|
4166
|
+
* (schema order: spPr → marker → dPt → dLbls).
|
|
4167
|
+
*/
|
|
4168
|
+
function serMarker(opts, markerColor, seriesColor) {
|
|
4169
|
+
const spPr = el("c:spPr", null, [
|
|
4170
|
+
raw(markerColor === "transparent" ? voidEl("a:noFill") : genXmlColorSelection(markerColor)),
|
|
4171
|
+
raw(el("a:ln", {
|
|
4172
|
+
w: opts.lineDataSymbolLineSize,
|
|
4173
|
+
cap: "flat"
|
|
4174
|
+
}, [
|
|
4175
|
+
raw(chartColorLineFill(opts.lineDataSymbolLineColor || seriesColor)),
|
|
4176
|
+
raw(voidEl("a:prstDash", { val: "solid" })),
|
|
4177
|
+
raw(voidEl("a:round"))
|
|
4178
|
+
], { openPrefix: " " })),
|
|
4179
|
+
raw(voidEl("a:effectLst", null, { openPrefix: " " }))
|
|
4180
|
+
], {
|
|
4181
|
+
openPrefix: " ",
|
|
4182
|
+
closePrefix: " "
|
|
4183
|
+
});
|
|
4184
|
+
return el("c:marker", null, [
|
|
4185
|
+
raw(voidEl("c:symbol", { val: opts.lineDataSymbol }, { openPrefix: " " })),
|
|
4186
|
+
opts.lineDataSymbolSize ? raw(voidEl("c:size", { val: opts.lineDataSymbolSize })) : null,
|
|
4187
|
+
raw(spPr)
|
|
4188
|
+
]);
|
|
4189
|
+
}
|
|
4190
|
+
/** Per-series `<c:dLbls>`: number format, an optional label background, text style, show flags. */
|
|
4191
|
+
function serDataLabels(obj, opts, seriesColor) {
|
|
4192
|
+
const over = opts.seriesOptions?.[obj._dataIndex];
|
|
4193
|
+
const defRPr = el("a:defRPr", {
|
|
4194
|
+
b: over?.dataLabelFontBold ?? opts.dataLabelFontBold ?? false ? 1 : 0,
|
|
4195
|
+
i: over?.dataLabelFontItalic ?? opts.dataLabelFontItalic ?? false ? 1 : 0,
|
|
4196
|
+
strike: "noStrike",
|
|
4197
|
+
sz: ptToHundredths(over?.dataLabelFontSize ?? opts.dataLabelFontSize ?? 12),
|
|
4198
|
+
u: "none"
|
|
4199
|
+
}, [raw(genXmlColorSelection(over?.dataLabelColor ?? opts.dataLabelColor ?? "000000")), raw(createChartTextFonts(over?.dataLabelFontFace ?? opts.dataLabelFontFace ?? "Arial"))]);
|
|
4200
|
+
const txPr = el("c:txPr", null, [
|
|
4201
|
+
raw(voidEl("a:bodyPr")),
|
|
4202
|
+
raw(voidEl("a:lstStyle")),
|
|
4203
|
+
raw(el("a:p", null, raw(el("a:pPr", null, raw(defRPr)))))
|
|
4204
|
+
]);
|
|
4205
|
+
const lblFmtCode = over?.dataLabelFormatCode ?? opts.dataLabelFormatCode;
|
|
4206
|
+
return el("c:dLbls", null, [
|
|
4207
|
+
raw((obj.customLabels ?? []).map((lbl, idx) => lbl ? makeCustomDLblXml(idx, lbl, opts) : "").join("")),
|
|
4208
|
+
raw(voidEl("c:numFmt", {
|
|
4209
|
+
formatCode: (lblFmtCode ?? "") || "General",
|
|
4210
|
+
sourceLinked: 0
|
|
4211
|
+
})),
|
|
4212
|
+
opts.dataLabelBkgrdColors ? raw(el("c:spPr", null, raw(genXmlColorSelection(seriesColor)))) : null,
|
|
4213
|
+
raw(txPr),
|
|
4214
|
+
opts.dataLabelPosition ? raw(voidEl("c:dLblPos", { val: opts.dataLabelPosition })) : null,
|
|
4215
|
+
raw(voidEl("c:showLegendKey", { val: 0 })),
|
|
4216
|
+
raw(voidEl("c:showVal", { val: opts.showValue ? 1 : 0 })),
|
|
4217
|
+
raw(voidEl("c:showCatName", { val: 0 })),
|
|
4218
|
+
raw(voidEl("c:showSerName", { val: opts.showSerName ? 1 : 0 })),
|
|
4219
|
+
raw(voidEl("c:showPercent", { val: 0 })),
|
|
4220
|
+
raw(voidEl("c:showBubbleSize", { val: 0 })),
|
|
4221
|
+
raw(voidEl("c:showLeaderLines", { val: opts.showLeaderLines ? 1 : 0 }))
|
|
4222
|
+
]);
|
|
4223
|
+
}
|
|
4224
|
+
/**
|
|
4225
|
+
* The `<c:cat>` category reference. Numeric (date) categories and single-level text ones are
|
|
4226
|
+
* {@link catRefBlock}; multi-level labels nest a `<c:lvl>` per group, which is a different shape
|
|
4227
|
+
* rather than a different spelling of the same one.
|
|
4228
|
+
*/
|
|
4229
|
+
function serCategories(obj, opts) {
|
|
4230
|
+
const groups = dataLabels(obj);
|
|
4231
|
+
const cats = firstLabelGroup(obj);
|
|
4232
|
+
const catRef = `Sheet1!$A$2:$A$${cats.length + 1}`;
|
|
4233
|
+
if (opts.catLabelFormatCode) return el("c:cat", null, raw(catRefBlock("num", catRef, cats, opts.catLabelFormatCode || "General", "indented")));
|
|
4234
|
+
if (groups.length === 1) return el("c:cat", null, raw(catRefBlock("str", catRef, cats, void 0, "indented")));
|
|
4235
|
+
const lvls = groups.map((labelsGroup) => el("c:lvl", null, raw(labelsGroup.map((label, idx) => el("c:pt", { idx }, raw(el("c:v", null, label)))).join("")))).join("");
|
|
4236
|
+
const cache = el("c:multiLvlStrCache", null, [raw(voidEl("c:ptCount", { val: cats.length }, { openPrefix: " " })), raw(lvls)], {
|
|
4237
|
+
openPrefix: " ",
|
|
4238
|
+
closePrefix: " "
|
|
4239
|
+
});
|
|
4240
|
+
const ref = el("c:multiLvlStrRef", null, [raw(el("c:f", null, sheetRangeRef(1, 2, groups.length, cats.length + 1), { openPrefix: " " })), raw(cache)], {
|
|
4241
|
+
openPrefix: " ",
|
|
4242
|
+
closePrefix: " "
|
|
4243
|
+
});
|
|
4244
|
+
return el("c:cat", null, raw(ref));
|
|
4245
|
+
}
|
|
4246
|
+
/** The `<c:val>` numeric cache: the series' own sheet column, one point per category. */
|
|
4247
|
+
function serValues(obj, valFmtCode) {
|
|
4248
|
+
const valCol = obj._dataIndex + dataLabels(obj).length + 1;
|
|
4249
|
+
const catCount = firstLabelGroup(obj).length;
|
|
4250
|
+
const numCache = el("c:numCache", null, [
|
|
4251
|
+
raw(el("c:formatCode", null, valFmtCode, { openPrefix: " " })),
|
|
4252
|
+
raw(voidEl("c:ptCount", { val: catCount }, { openPrefix: " " })),
|
|
4253
|
+
raw(dataValues(obj).map((value, idx) => numCachePt(idx, value)).join(""))
|
|
4254
|
+
], {
|
|
4255
|
+
openPrefix: " ",
|
|
4256
|
+
closePrefix: " "
|
|
4257
|
+
});
|
|
4258
|
+
const numRef = el("c:numRef", null, [raw(el("c:f", null, sheetRangeRef(valCol, 2, valCol, catCount + 1))), raw(numCache)], {
|
|
4259
|
+
openPrefix: " ",
|
|
4260
|
+
closePrefix: " "
|
|
4261
|
+
});
|
|
4262
|
+
return el("c:val", null, raw(numRef));
|
|
4263
|
+
}
|
|
4264
|
+
/**
|
|
4265
|
+
* Plot a category-axis chart family (area / bar / bar3d / line / radar) into a
|
|
4266
|
+
* `<c:xxxChart>` element. These share the grouping / series / cat+val axis structure.
|
|
4267
|
+
*/
|
|
4268
|
+
function makeCatAxisPlot(chartType, data, opts, valAxisId, catAxisId, valFmtCode) {
|
|
4269
|
+
const chartColors = resolveChartPalette(opts);
|
|
4270
|
+
const barVaryColors = isBarLike(chartType) && data.length === 1 && (opts.chartColors && opts.chartColors !== BARCHART_COLORS && opts.chartColors.length > 1 || opts.invertedColors?.length) ? opts.chartColors || BARCHART_COLORS : null;
|
|
4271
|
+
const sers = data.map((obj, serIndex) => {
|
|
4272
|
+
const seriesOverride = opts.seriesOptions?.[obj._dataIndex];
|
|
4273
|
+
const seriesColor = seriesOverride?.color ?? paletteColor(chartColors, serIndex);
|
|
4274
|
+
return el("c:ser", null, [
|
|
4275
|
+
raw(voidEl("c:idx", { val: obj._dataIndex }, { openPrefix: " " })),
|
|
4276
|
+
raw(voidEl("c:order", { val: obj._dataIndex })),
|
|
4277
|
+
raw(strRefBlock(sheetCellRef(obj._dataIndex + dataLabels(obj).length + 1, 1), obj.name ?? "")),
|
|
4278
|
+
raw(serShapeProps(chartType, opts, seriesColor, seriesOverride?.lineSize, serIndex)),
|
|
4279
|
+
isBarLike(chartType) ? raw(voidEl("c:invertIfNegative", { val: 0 }, { openPrefix: " " })) : null,
|
|
4280
|
+
isLineLike(chartType) ? raw(serMarker(opts, paletteColor(chartColors, obj._dataIndex), seriesColor)) : null,
|
|
4281
|
+
raw(makeSeriesDataPointsXml(chartType, obj, opts, barVaryColors)),
|
|
4282
|
+
chartType === "radar" ? null : raw(serDataLabels(obj, opts, seriesColor)),
|
|
4283
|
+
chartType === "radar" ? null : raw(makeChartErrorBarsXml(chartType, obj.errorBars, obj)),
|
|
4284
|
+
raw(serCategories(obj, opts)),
|
|
4285
|
+
raw(serValues(obj, valFmtCode)),
|
|
4286
|
+
chartType === "line" ? raw(voidEl("c:smooth", { val: opts.lineSmooth ? 1 : 0 })) : null
|
|
4287
|
+
]);
|
|
4288
|
+
}).join("");
|
|
4289
|
+
let plotOptions = "";
|
|
4290
|
+
if (chartType === "bar") plotOptions = voidEl("c:gapWidth", { val: opts.barGapWidthPct }, { openPrefix: " " }) + voidEl("c:overlap", { val: opts.barOverlapPct ?? ((opts.barGrouping || "").includes("tacked") ? 100 : 0) }, { openPrefix: " " }) + createSerLinesElement(opts.barSeriesLine);
|
|
4291
|
+
else if (chartType === "bar3D") plotOptions = voidEl("c:gapWidth", { val: opts.barGapWidthPct }, { openPrefix: " " }) + voidEl("c:gapDepth", { val: opts.barGapDepthPct }, { openPrefix: " " }) + voidEl("c:shape", { val: opts.bar3DShape }, { openPrefix: " " });
|
|
4292
|
+
else if (chartType === "line") plotOptions = voidEl("c:marker", { val: 1 }, { openPrefix: " " });
|
|
4293
|
+
return el(`c:${chartType}Chart`, null, [
|
|
4294
|
+
raw(plotGrouping(chartType, opts)),
|
|
4295
|
+
raw(voidEl("c:varyColors", { val: 0 })),
|
|
4296
|
+
raw(sers),
|
|
4297
|
+
raw(chartDataLabels(opts, true)),
|
|
4298
|
+
raw(plotOptions),
|
|
4299
|
+
raw(voidEl("c:axId", { val: catAxisId })),
|
|
4300
|
+
raw(voidEl("c:axId", { val: valAxisId })),
|
|
4301
|
+
chartType === "bar3D" ? raw(voidEl("c:axId", { val: AXIS_ID_SERIES_PRIMARY })) : null
|
|
4302
|
+
]);
|
|
3979
4303
|
}
|
|
3980
4304
|
//#endregion
|
|
3981
4305
|
//#region src/gen/chart/plot-scatter.ts
|
|
4306
|
+
/** The font attributes a scatter label's `<a:defRPr>` and `<a:rPr>` both carry, in schema order. */
|
|
4307
|
+
function labelFontAttrs(opts) {
|
|
4308
|
+
return {
|
|
4309
|
+
sz: ptToHundredths(opts.dataLabelFontSize || 12),
|
|
4310
|
+
b: opts.dataLabelFontBold ? 1 : 0,
|
|
4311
|
+
i: opts.dataLabelFontItalic ? 1 : 0,
|
|
4312
|
+
u: "none",
|
|
4313
|
+
strike: "noStrike"
|
|
4314
|
+
};
|
|
4315
|
+
}
|
|
4316
|
+
/** The colour and typeface children of those run properties; `indent` is theirs, not the parent's. */
|
|
4317
|
+
function labelFontChildren(opts, indent) {
|
|
4318
|
+
return [raw(indent + el("a:solidFill", null, raw(createColorElement(opts.dataLabelColor || "000000")))), raw(indent + createChartTextFonts(opts.dataLabelFontFace || "Arial"))];
|
|
4319
|
+
}
|
|
4320
|
+
/**
|
|
4321
|
+
* The `(x, y)` runs appended to a `customXY` label: a literal `" ("`, an `XVALUE` field, a
|
|
4322
|
+
* `", "`, a `YVALUE` field and a `")"`.
|
|
4323
|
+
*
|
|
4324
|
+
* Each `<a:fld>` id is minted per build. A field id has to be unique, which is a property a
|
|
4325
|
+
* derived id would have to reproduce without an oracle for how far that uniqueness has to
|
|
4326
|
+
* reach — so the ids stay random and the *comparison* gives: `NORMALIZERS` in
|
|
4327
|
+
* `scripts/pptx-parts.mjs` erases exactly these two field types before the byte-identity gate
|
|
4328
|
+
* diffs a part. Do not "fix" the nondeterminism here.
|
|
4329
|
+
*/
|
|
4330
|
+
function customXYRuns(obj, opts) {
|
|
4331
|
+
const lang = opts.lang || "en-US";
|
|
4332
|
+
const literal = (text) => el("a:r", null, [raw(voidEl("a:rPr", {
|
|
4333
|
+
lang,
|
|
4334
|
+
baseline: 0,
|
|
4335
|
+
dirty: 0
|
|
4336
|
+
}, { openPrefix: " " })), raw(el("a:t", null, text, { openPrefix: " " }))], {
|
|
4337
|
+
openPrefix: " ",
|
|
4338
|
+
closePrefix: " "
|
|
4339
|
+
});
|
|
4340
|
+
const field = (type, text) => el("a:fld", {
|
|
4341
|
+
id: `{${getUuid("xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx")}}`,
|
|
4342
|
+
type
|
|
4343
|
+
}, [
|
|
4344
|
+
raw(voidEl("a:rPr", {
|
|
4345
|
+
lang,
|
|
4346
|
+
baseline: 0
|
|
4347
|
+
}, { openPrefix: " " })),
|
|
4348
|
+
raw(el("a:pPr", null, raw(voidEl("a:defRPr", null, { openPrefix: " " })), {
|
|
4349
|
+
openPrefix: " ",
|
|
4350
|
+
closePrefix: " "
|
|
4351
|
+
})),
|
|
4352
|
+
raw(" " + el("a:t", null, text))
|
|
4353
|
+
], {
|
|
4354
|
+
openPrefix: " ",
|
|
4355
|
+
closePrefix: " "
|
|
4356
|
+
});
|
|
4357
|
+
return literal(" (") + field("XVALUE", "[" + (obj.name ?? "")) + literal(", ") + field("YVALUE", "[" + (obj.name ?? "") + "]") + literal(")") + voidEl("a:endParaRPr", {
|
|
4358
|
+
lang,
|
|
4359
|
+
dirty: 0
|
|
4360
|
+
}, { openPrefix: " " });
|
|
4361
|
+
}
|
|
4362
|
+
/**
|
|
4363
|
+
* One per-point `<c:dLbl>` for the `custom` / `customXY` label formats: rich text carrying the
|
|
4364
|
+
* caller's label, optionally followed by the X/Y value fields.
|
|
4365
|
+
*/
|
|
4366
|
+
function scatterCustomLabel(obj, opts, label, idx, chartUuid) {
|
|
4367
|
+
const rich = el("c:rich", null, [
|
|
4368
|
+
raw(el("a:bodyPr", null, raw(voidEl("a:spAutoFit", null, { openPrefix: " " })), {
|
|
4369
|
+
openPrefix: " ",
|
|
4370
|
+
closePrefix: " "
|
|
4371
|
+
})),
|
|
4372
|
+
raw(voidEl("a:lstStyle", null, { openPrefix: " " })),
|
|
4373
|
+
raw(el("a:p", null, [
|
|
4374
|
+
raw(el("a:pPr", null, raw(el("a:defRPr", labelFontAttrs(opts), labelFontChildren(opts, " "), {
|
|
4375
|
+
openPrefix: " ",
|
|
4376
|
+
closePrefix: " "
|
|
4377
|
+
})), {
|
|
4378
|
+
openPrefix: " ",
|
|
4379
|
+
closePrefix: " "
|
|
4380
|
+
})),
|
|
4381
|
+
raw(el("a:r", null, [raw(el("a:rPr", {
|
|
4382
|
+
lang: opts.lang || "en-US",
|
|
4383
|
+
...labelFontAttrs(opts),
|
|
4384
|
+
dirty: 0
|
|
4385
|
+
}, labelFontChildren(opts, " "), {
|
|
4386
|
+
openPrefix: " ",
|
|
4387
|
+
closePrefix: " "
|
|
4388
|
+
})), raw(" " + el("a:t", null, label))], {
|
|
4389
|
+
openPrefix: " ",
|
|
4390
|
+
closePrefix: " "
|
|
4391
|
+
})),
|
|
4392
|
+
opts.dataLabelFormatScatter === "customXY" && !/^ *$/.test(label) ? raw(customXYRuns(obj, opts)) : null
|
|
4393
|
+
], {
|
|
4394
|
+
openPrefix: " ",
|
|
4395
|
+
closePrefix: " "
|
|
4396
|
+
}))
|
|
4397
|
+
], {
|
|
4398
|
+
openPrefix: " ",
|
|
4399
|
+
closePrefix: " "
|
|
4400
|
+
});
|
|
4401
|
+
const spPr = el("c:spPr", null, [
|
|
4402
|
+
raw(voidEl("a:noFill", null, { openPrefix: " " })),
|
|
4403
|
+
raw(el("a:ln", null, raw(voidEl("a:noFill", null, { openPrefix: " " })), {
|
|
4404
|
+
openPrefix: " ",
|
|
4405
|
+
closePrefix: " "
|
|
4406
|
+
})),
|
|
4407
|
+
raw(voidEl("a:effectLst", null, { openPrefix: " " }))
|
|
4408
|
+
], {
|
|
4409
|
+
openPrefix: " ",
|
|
4410
|
+
closePrefix: " "
|
|
4411
|
+
});
|
|
4412
|
+
const extLst = el("c:extLst", null, [raw(voidEl("c:ext", {
|
|
4413
|
+
uri: "{CE6537A1-D6FC-4f65-9D91-7224C49458BB}",
|
|
4414
|
+
"xmlns:c15": "http://schemas.microsoft.com/office/drawing/2012/chart"
|
|
4415
|
+
}, { openPrefix: " " })), raw(el("c:ext", {
|
|
4416
|
+
uri: "{C3380CC4-5D6E-409C-BE32-E72D297353CC}",
|
|
4417
|
+
"xmlns:c16": "http://schemas.microsoft.com/office/drawing/2014/chart"
|
|
4418
|
+
}, raw(voidEl("c16:uniqueId", { val: `{${String(idx + 1).padStart(8, "0")}${chartUuid}}` }, { openPrefix: " " })), {
|
|
4419
|
+
openPrefix: " ",
|
|
4420
|
+
closePrefix: " "
|
|
4421
|
+
}))], {
|
|
4422
|
+
openPrefix: " ",
|
|
4423
|
+
closePrefix: " "
|
|
4424
|
+
});
|
|
4425
|
+
return el("c:dLbl", null, [
|
|
4426
|
+
raw(voidEl("c:idx", { val: idx }, { openPrefix: " " })),
|
|
4427
|
+
raw(el("c:tx", null, raw(rich), {
|
|
4428
|
+
openPrefix: " ",
|
|
4429
|
+
closePrefix: " "
|
|
4430
|
+
})),
|
|
4431
|
+
raw(spPr),
|
|
4432
|
+
opts.dataLabelPosition ? raw(voidEl("c:dLblPos", { val: opts.dataLabelPosition }, { openPrefix: " " })) : null,
|
|
4433
|
+
raw(voidEl("c:showLegendKey", { val: 0 }, { openPrefix: " " })),
|
|
4434
|
+
raw(voidEl("c:showVal", { val: 0 }, { openPrefix: " " })),
|
|
4435
|
+
raw(voidEl("c:showCatName", { val: 0 }, { openPrefix: " " })),
|
|
4436
|
+
raw(voidEl("c:showSerName", { val: 0 }, { openPrefix: " " })),
|
|
4437
|
+
raw(voidEl("c:showPercent", { val: 0 }, { openPrefix: " " })),
|
|
4438
|
+
raw(voidEl("c:showBubbleSize", { val: 0 }, { openPrefix: " " })),
|
|
4439
|
+
raw(voidEl("c:showLeaderLines", { val: 1 }, { openPrefix: " " })),
|
|
4440
|
+
raw(extLst)
|
|
4441
|
+
], { openPrefix: " " });
|
|
4442
|
+
}
|
|
4443
|
+
/** The single chart-level `<c:dLbls>` of the `XY` label format: PowerPoint composes the text. */
|
|
4444
|
+
function scatterXYLabels(opts) {
|
|
4445
|
+
const spPr = el("c:spPr", null, [
|
|
4446
|
+
raw(voidEl("a:noFill", null, { openPrefix: " " })),
|
|
4447
|
+
raw(el("a:ln", null, raw(voidEl("a:noFill", null, { openPrefix: " " })), {
|
|
4448
|
+
openPrefix: " ",
|
|
4449
|
+
closePrefix: " "
|
|
4450
|
+
})),
|
|
4451
|
+
raw(voidEl("a:effectLst", null, { openPrefix: " " }))
|
|
4452
|
+
], {
|
|
4453
|
+
openPrefix: " ",
|
|
4454
|
+
closePrefix: " "
|
|
4455
|
+
});
|
|
4456
|
+
const txPr = el("c:txPr", null, [
|
|
4457
|
+
raw(el("a:bodyPr", null, raw(voidEl("a:spAutoFit", null, { openPrefix: " " })), {
|
|
4458
|
+
openPrefix: " ",
|
|
4459
|
+
closePrefix: " "
|
|
4460
|
+
})),
|
|
4461
|
+
raw(voidEl("a:lstStyle", null, { openPrefix: " " })),
|
|
4462
|
+
raw(el("a:p", null, [raw(el("a:pPr", null, raw(el("a:defRPr", labelFontAttrs(opts), labelFontChildren(opts, " "), {
|
|
4463
|
+
openPrefix: " ",
|
|
4464
|
+
closePrefix: " "
|
|
4465
|
+
})), {
|
|
4466
|
+
openPrefix: " ",
|
|
4467
|
+
closePrefix: " "
|
|
4468
|
+
})), raw(voidEl("a:endParaRPr", { lang: opts.lang || "en-US" }, { openPrefix: " " }))], {
|
|
4469
|
+
openPrefix: " ",
|
|
4470
|
+
closePrefix: " "
|
|
4471
|
+
}))
|
|
4472
|
+
], {
|
|
4473
|
+
openPrefix: " ",
|
|
4474
|
+
closePrefix: " "
|
|
4475
|
+
});
|
|
4476
|
+
const extLst = el("c:extLst", null, raw(el("c:ext", {
|
|
4477
|
+
uri: "{CE6537A1-D6FC-4f65-9D91-7224C49458BB}",
|
|
4478
|
+
"xmlns:c15": "http://schemas.microsoft.com/office/drawing/2012/chart"
|
|
4479
|
+
}, raw(voidEl("c15:showLeaderLines", { val: 1 }, { openPrefix: " " })), {
|
|
4480
|
+
openPrefix: " ",
|
|
4481
|
+
closePrefix: " "
|
|
4482
|
+
})), {
|
|
4483
|
+
openPrefix: " ",
|
|
4484
|
+
closePrefix: " "
|
|
4485
|
+
});
|
|
4486
|
+
return el("c:dLbls", null, [
|
|
4487
|
+
raw(spPr),
|
|
4488
|
+
raw(txPr),
|
|
4489
|
+
opts.dataLabelPosition ? raw(voidEl("c:dLblPos", { val: opts.dataLabelPosition }, { openPrefix: " " })) : null,
|
|
4490
|
+
raw(voidEl("c:showLegendKey", { val: 0 }, { openPrefix: " " })),
|
|
4491
|
+
raw(voidEl("c:showVal", { val: opts.showLabel ? 1 : 0 }, { openPrefix: " " })),
|
|
4492
|
+
raw(voidEl("c:showCatName", { val: opts.showLabel ? 1 : 0 }, { openPrefix: " " })),
|
|
4493
|
+
raw(voidEl("c:showSerName", { val: opts.showSerName ? 1 : 0 }, { openPrefix: " " })),
|
|
4494
|
+
raw(voidEl("c:showPercent", { val: 0 }, { openPrefix: " " })),
|
|
4495
|
+
raw(voidEl("c:showBubbleSize", { val: 0 }, { openPrefix: " " })),
|
|
4496
|
+
raw(extLst)
|
|
4497
|
+
]);
|
|
4498
|
+
}
|
|
4499
|
+
/** Fill, outline and shadow for one scatter series. */
|
|
4500
|
+
function scatterSerShapeProps(opts, serColor, serIndex) {
|
|
4501
|
+
const fill = serColor === "transparent" ? voidEl("a:noFill") : opts.chartColorsOpacity ? el("a:solidFill", null, raw(createColorElement(serColor, voidEl("a:alpha", { val: Math.round(opts.chartColorsOpacity * FIXED_PCT_PER_PERCENT) })))) : genXmlColorSelection(serColor);
|
|
4502
|
+
const line = opts.lineSize === 0 ? el("a:ln", null, raw(voidEl("a:noFill"))) : el("a:ln", {
|
|
4503
|
+
w: ptsToEmuLenient(opts.lineSize ?? 2),
|
|
4504
|
+
cap: createLineCap(opts.lineCap)
|
|
4505
|
+
}, [
|
|
4506
|
+
raw(chartColorLineFill(serColor)),
|
|
4507
|
+
raw(voidEl("a:prstDash", { val: opts.lineDashValues?.[serIndex] ?? opts.lineDash ?? "solid" })),
|
|
4508
|
+
raw(voidEl("a:round"))
|
|
4509
|
+
]);
|
|
4510
|
+
return el("c:spPr", null, [
|
|
4511
|
+
raw(fill),
|
|
4512
|
+
raw(line),
|
|
4513
|
+
raw(createShadowEffectLst(opts.shadow, DEF_SHAPE_SHADOW))
|
|
4514
|
+
], {
|
|
4515
|
+
openPrefix: " ",
|
|
4516
|
+
closePrefix: " "
|
|
4517
|
+
});
|
|
4518
|
+
}
|
|
4519
|
+
/** The point marker: symbol, optional size, and its own fill and outline. */
|
|
4520
|
+
function scatterMarker(opts, markerColor) {
|
|
4521
|
+
const spPr = el("c:spPr", null, [
|
|
4522
|
+
raw(markerColor === "transparent" ? voidEl("a:noFill") : genXmlColorSelection(markerColor)),
|
|
4523
|
+
raw(el("a:ln", {
|
|
4524
|
+
w: opts.lineDataSymbolLineSize,
|
|
4525
|
+
cap: "flat"
|
|
4526
|
+
}, [
|
|
4527
|
+
raw(chartColorLineFill(opts.lineDataSymbolLineColor || markerColor)),
|
|
4528
|
+
raw(voidEl("a:prstDash", { val: "solid" })),
|
|
4529
|
+
raw(voidEl("a:round"))
|
|
4530
|
+
])),
|
|
4531
|
+
raw(voidEl("a:effectLst"))
|
|
4532
|
+
]);
|
|
4533
|
+
return el("c:marker", null, [
|
|
4534
|
+
raw(voidEl("c:symbol", { val: opts.lineDataSymbol }, { openPrefix: " " })),
|
|
4535
|
+
opts.lineDataSymbolSize ? raw(voidEl("c:size", { val: opts.lineDataSymbolSize })) : null,
|
|
4536
|
+
raw(spPr)
|
|
4537
|
+
]);
|
|
4538
|
+
}
|
|
3982
4539
|
/**
|
|
3983
4540
|
* Plot an XY scatter chart into `<c:scatterChart>` (paired X/Y numeric series).
|
|
3984
4541
|
*/
|
|
3985
4542
|
function makeScatterPlot(chartType, data, opts, valAxisId, catAxisId, valFmtCode) {
|
|
3986
|
-
|
|
3987
|
-
|
|
3988
|
-
|
|
3989
|
-
|
|
3990
|
-
|
|
3991
|
-
|
|
3992
|
-
|
|
3993
|
-
|
|
3994
|
-
const chartColors = resolveChartPalette(opts);
|
|
3995
|
-
strXml += "<c:ser>";
|
|
3996
|
-
strXml += ` <c:idx val="${idx}"/>`;
|
|
3997
|
-
strXml += ` <c:order val="${idx}"/>`;
|
|
3998
|
-
strXml += " <c:tx>";
|
|
3999
|
-
strXml += " <c:strRef>";
|
|
4000
|
-
strXml += ` <c:f>${sheetCellRef(idx + 2, 1)}</c:f>`;
|
|
4001
|
-
strXml += " <c:strCache><c:ptCount val=\"1\"/><c:pt idx=\"0\">" + el("c:v", null, obj.name ?? "") + "</c:pt></c:strCache>";
|
|
4002
|
-
strXml += " </c:strRef>";
|
|
4003
|
-
strXml += " </c:tx>";
|
|
4004
|
-
strXml += " <c:spPr>";
|
|
4005
|
-
{
|
|
4006
|
-
const tmpSerColor = paletteColor(chartColors, colorIndex);
|
|
4007
|
-
if (tmpSerColor === "transparent") strXml += "<a:noFill/>";
|
|
4008
|
-
else if (opts.chartColorsOpacity) strXml += "<a:solidFill>" + createColorElement(tmpSerColor, "<a:alpha val=\"" + Math.round(opts.chartColorsOpacity * FIXED_PCT_PER_PERCENT).toString() + "\"/>") + "</a:solidFill>";
|
|
4009
|
-
else strXml += genXmlColorSelection(tmpSerColor);
|
|
4010
|
-
if (opts.lineSize === 0) strXml += "<a:ln><a:noFill/></a:ln>";
|
|
4011
|
-
else {
|
|
4012
|
-
strXml += `<a:ln w="${ptsToEmuLenient(opts.lineSize ?? 2)}" cap="${createLineCap(opts.lineCap)}">${chartColorLineFill(tmpSerColor)}`;
|
|
4013
|
-
strXml += voidEl("a:prstDash", { val: opts.lineDashValues?.[colorIndex] ?? opts.lineDash ?? "solid" }) + voidEl("a:round") + "</a:ln>";
|
|
4014
|
-
}
|
|
4015
|
-
strXml += createShadowEffectLst(opts.shadow, DEF_SHAPE_SHADOW);
|
|
4016
|
-
}
|
|
4017
|
-
strXml += " </c:spPr>";
|
|
4018
|
-
strXml += "<c:marker>";
|
|
4019
|
-
strXml += " <c:symbol val=\"" + opts.lineDataSymbol + "\"/>";
|
|
4020
|
-
if (opts.lineDataSymbolSize) strXml += `<c:size val="${opts.lineDataSymbolSize}"/>`;
|
|
4021
|
-
strXml += "<c:spPr>";
|
|
4022
|
-
{
|
|
4023
|
-
const markerColor = paletteColor(chartColors, idx);
|
|
4024
|
-
strXml += markerColor === "transparent" ? "<a:noFill/>" : genXmlColorSelection(markerColor);
|
|
4025
|
-
}
|
|
4026
|
-
strXml += `<a:ln w="${opts.lineDataSymbolLineSize}" cap="flat">${chartColorLineFill(opts.lineDataSymbolLineColor || paletteColor(chartColors, colorIndex))}<a:prstDash val="solid"/><a:round/></a:ln>`;
|
|
4027
|
-
strXml += "<a:effectLst/>";
|
|
4028
|
-
strXml += "</c:spPr>";
|
|
4029
|
-
strXml += "</c:marker>";
|
|
4030
|
-
{
|
|
4031
|
-
const scatterVaryColors = data.length === 1 && opts.chartColors !== BARCHART_COLORS ? opts.chartColors || BARCHART_COLORS : null;
|
|
4032
|
-
strXml += makeSeriesDataPointsXml(chartType, obj, opts, scatterVaryColors);
|
|
4033
|
-
}
|
|
4543
|
+
const chartColors = resolveChartPalette(opts);
|
|
4544
|
+
const xValues = dataValues(data[0]);
|
|
4545
|
+
const scatterVaryColors = data.length === 1 && opts.chartColors !== BARCHART_COLORS ? opts.chartColors || BARCHART_COLORS : null;
|
|
4546
|
+
const sers = data.slice(1).map((obj, idx) => {
|
|
4547
|
+
const serColor = paletteColor(chartColors, idx);
|
|
4548
|
+
const yValues = dataValues(obj);
|
|
4549
|
+
const values = numRefBlock("c:xVal", `Sheet1!$A$2:$A$${xValues.length + 1}`, valFmtCode, xValues) + numRefBlock("c:yVal", sheetRangeRef(idx + 2, 2, idx + 2, xValues.length + 1), valFmtCode, xValues.map((_value, i) => yValues[i]));
|
|
4550
|
+
let labels = "";
|
|
4034
4551
|
if (opts.showLabel) {
|
|
4035
4552
|
const chartUuid = getUuid("-xxxx-xxxx-xxxx-xxxxxxxxxxxx");
|
|
4036
|
-
|
|
4037
|
-
|
|
4038
|
-
|
|
4039
|
-
if (opts.dataLabelFormatScatter === "custom" || opts.dataLabelFormatScatter === "customXY") {
|
|
4040
|
-
strXml += " <c:dLbl>";
|
|
4041
|
-
strXml += ` <c:idx val="${idx}"/>`;
|
|
4042
|
-
strXml += " <c:tx>";
|
|
4043
|
-
strXml += " <c:rich>";
|
|
4044
|
-
strXml += " <a:bodyPr>";
|
|
4045
|
-
strXml += " <a:spAutoFit/>";
|
|
4046
|
-
strXml += " </a:bodyPr>";
|
|
4047
|
-
strXml += " <a:lstStyle/>";
|
|
4048
|
-
strXml += " <a:p>";
|
|
4049
|
-
strXml += " <a:pPr>";
|
|
4050
|
-
strXml += ` <a:defRPr sz="${ptToHundredths(opts.dataLabelFontSize || 12)}" b="${opts.dataLabelFontBold ? "1" : "0"}" i="${opts.dataLabelFontItalic ? "1" : "0"}" u="none" strike="noStrike">`;
|
|
4051
|
-
strXml += " <a:solidFill>" + createColorElement(opts.dataLabelColor || "000000") + "</a:solidFill>";
|
|
4052
|
-
strXml += " " + createChartTextFonts(opts.dataLabelFontFace || "Arial");
|
|
4053
|
-
strXml += " </a:defRPr>";
|
|
4054
|
-
strXml += " </a:pPr>";
|
|
4055
|
-
strXml += " <a:r>";
|
|
4056
|
-
strXml += ` <a:rPr lang="${encodeXmlEntities(opts.lang || "en-US")}" sz="${ptToHundredths(opts.dataLabelFontSize || 12)}" b="${opts.dataLabelFontBold ? "1" : "0"}" i="${opts.dataLabelFontItalic ? "1" : "0"}" u="none" strike="noStrike" dirty="0">`;
|
|
4057
|
-
strXml += " <a:solidFill>" + createColorElement(opts.dataLabelColor || "000000") + "</a:solidFill>";
|
|
4058
|
-
strXml += " " + createChartTextFonts(opts.dataLabelFontFace || "Arial");
|
|
4059
|
-
strXml += " </a:rPr>";
|
|
4060
|
-
strXml += " " + el("a:t", null, label);
|
|
4061
|
-
strXml += " </a:r>";
|
|
4062
|
-
if (opts.dataLabelFormatScatter === "customXY" && !/^ *$/.test(label)) {
|
|
4063
|
-
strXml += " <a:r>";
|
|
4064
|
-
strXml += " <a:rPr lang=\"" + (opts.lang || "en-US") + "\" baseline=\"0\" dirty=\"0\"/>";
|
|
4065
|
-
strXml += " <a:t> (</a:t>";
|
|
4066
|
-
strXml += " </a:r>";
|
|
4067
|
-
strXml += " <a:fld id=\"{" + getUuid("xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx") + "}\" type=\"XVALUE\">";
|
|
4068
|
-
strXml += " <a:rPr lang=\"" + (opts.lang || "en-US") + "\" baseline=\"0\"/>";
|
|
4069
|
-
strXml += " <a:pPr>";
|
|
4070
|
-
strXml += " <a:defRPr/>";
|
|
4071
|
-
strXml += " </a:pPr>";
|
|
4072
|
-
strXml += " " + el("a:t", null, "[" + (obj.name ?? ""));
|
|
4073
|
-
strXml += " </a:fld>";
|
|
4074
|
-
strXml += " <a:r>";
|
|
4075
|
-
strXml += " <a:rPr lang=\"" + (opts.lang || "en-US") + "\" baseline=\"0\" dirty=\"0\"/>";
|
|
4076
|
-
strXml += " <a:t>, </a:t>";
|
|
4077
|
-
strXml += " </a:r>";
|
|
4078
|
-
strXml += " <a:fld id=\"{" + getUuid("xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx") + "}\" type=\"YVALUE\">";
|
|
4079
|
-
strXml += " <a:rPr lang=\"" + (opts.lang || "en-US") + "\" baseline=\"0\"/>";
|
|
4080
|
-
strXml += " <a:pPr>";
|
|
4081
|
-
strXml += " <a:defRPr/>";
|
|
4082
|
-
strXml += " </a:pPr>";
|
|
4083
|
-
strXml += " " + el("a:t", null, "[" + (obj.name ?? "") + "]");
|
|
4084
|
-
strXml += " </a:fld>";
|
|
4085
|
-
strXml += " <a:r>";
|
|
4086
|
-
strXml += " <a:rPr lang=\"" + (opts.lang || "en-US") + "\" baseline=\"0\" dirty=\"0\"/>";
|
|
4087
|
-
strXml += " <a:t>)</a:t>";
|
|
4088
|
-
strXml += " </a:r>";
|
|
4089
|
-
strXml += " <a:endParaRPr lang=\"" + (opts.lang || "en-US") + "\" dirty=\"0\"/>";
|
|
4090
|
-
}
|
|
4091
|
-
strXml += " </a:p>";
|
|
4092
|
-
strXml += " </c:rich>";
|
|
4093
|
-
strXml += " </c:tx>";
|
|
4094
|
-
strXml += " <c:spPr>";
|
|
4095
|
-
strXml += " <a:noFill/>";
|
|
4096
|
-
strXml += " <a:ln>";
|
|
4097
|
-
strXml += " <a:noFill/>";
|
|
4098
|
-
strXml += " </a:ln>";
|
|
4099
|
-
strXml += " <a:effectLst/>";
|
|
4100
|
-
strXml += " </c:spPr>";
|
|
4101
|
-
if (opts.dataLabelPosition) strXml += " <c:dLblPos val=\"" + opts.dataLabelPosition + "\"/>";
|
|
4102
|
-
strXml += " <c:showLegendKey val=\"0\"/>";
|
|
4103
|
-
strXml += " <c:showVal val=\"0\"/>";
|
|
4104
|
-
strXml += " <c:showCatName val=\"0\"/>";
|
|
4105
|
-
strXml += " <c:showSerName val=\"0\"/>";
|
|
4106
|
-
strXml += " <c:showPercent val=\"0\"/>";
|
|
4107
|
-
strXml += " <c:showBubbleSize val=\"0\"/>";
|
|
4108
|
-
strXml += " <c:showLeaderLines val=\"1\"/>";
|
|
4109
|
-
strXml += " <c:extLst>";
|
|
4110
|
-
strXml += " <c:ext uri=\"{CE6537A1-D6FC-4f65-9D91-7224C49458BB}\" xmlns:c15=\"http://schemas.microsoft.com/office/drawing/2012/chart\"/>";
|
|
4111
|
-
strXml += " <c:ext uri=\"{C3380CC4-5D6E-409C-BE32-E72D297353CC}\" xmlns:c16=\"http://schemas.microsoft.com/office/drawing/2014/chart\">";
|
|
4112
|
-
strXml += ` <c16:uniqueId val="{${String(idx + 1).padStart(8, "0")}${chartUuid}}"/>`;
|
|
4113
|
-
strXml += " </c:ext>";
|
|
4114
|
-
strXml += " </c:extLst>";
|
|
4115
|
-
strXml += "</c:dLbl>";
|
|
4116
|
-
}
|
|
4117
|
-
});
|
|
4118
|
-
strXml += "</c:dLbls>";
|
|
4119
|
-
}
|
|
4120
|
-
if (opts.dataLabelFormatScatter === "XY") {
|
|
4121
|
-
strXml += "<c:dLbls>";
|
|
4122
|
-
strXml += " <c:spPr>";
|
|
4123
|
-
strXml += " <a:noFill/>";
|
|
4124
|
-
strXml += " <a:ln>";
|
|
4125
|
-
strXml += " <a:noFill/>";
|
|
4126
|
-
strXml += " </a:ln>";
|
|
4127
|
-
strXml += " <a:effectLst/>";
|
|
4128
|
-
strXml += " </c:spPr>";
|
|
4129
|
-
strXml += " <c:txPr>";
|
|
4130
|
-
strXml += " <a:bodyPr>";
|
|
4131
|
-
strXml += " <a:spAutoFit/>";
|
|
4132
|
-
strXml += " </a:bodyPr>";
|
|
4133
|
-
strXml += " <a:lstStyle/>";
|
|
4134
|
-
strXml += " <a:p>";
|
|
4135
|
-
strXml += " <a:pPr>";
|
|
4136
|
-
strXml += ` <a:defRPr sz="${ptToHundredths(opts.dataLabelFontSize || 12)}" b="${opts.dataLabelFontBold ? "1" : "0"}" i="${opts.dataLabelFontItalic ? "1" : "0"}" u="none" strike="noStrike">`;
|
|
4137
|
-
strXml += " <a:solidFill>" + createColorElement(opts.dataLabelColor || "000000") + "</a:solidFill>";
|
|
4138
|
-
strXml += " " + createChartTextFonts(opts.dataLabelFontFace || "Arial");
|
|
4139
|
-
strXml += " </a:defRPr>";
|
|
4140
|
-
strXml += " </a:pPr>";
|
|
4141
|
-
strXml += ` <a:endParaRPr lang="${encodeXmlEntities(opts.lang || "en-US")}"/>`;
|
|
4142
|
-
strXml += " </a:p>";
|
|
4143
|
-
strXml += " </c:txPr>";
|
|
4144
|
-
if (opts.dataLabelPosition) strXml += " <c:dLblPos val=\"" + opts.dataLabelPosition + "\"/>";
|
|
4145
|
-
strXml += " <c:showLegendKey val=\"0\"/>";
|
|
4146
|
-
strXml += ` <c:showVal val="${opts.showLabel ? "1" : "0"}"/>`;
|
|
4147
|
-
strXml += ` <c:showCatName val="${opts.showLabel ? "1" : "0"}"/>`;
|
|
4148
|
-
strXml += ` <c:showSerName val="${opts.showSerName ? "1" : "0"}"/>`;
|
|
4149
|
-
strXml += " <c:showPercent val=\"0\"/>";
|
|
4150
|
-
strXml += " <c:showBubbleSize val=\"0\"/>";
|
|
4151
|
-
strXml += " <c:extLst>";
|
|
4152
|
-
strXml += " <c:ext uri=\"{CE6537A1-D6FC-4f65-9D91-7224C49458BB}\" xmlns:c15=\"http://schemas.microsoft.com/office/drawing/2012/chart\">";
|
|
4153
|
-
strXml += " <c15:showLeaderLines val=\"1\"/>";
|
|
4154
|
-
strXml += " </c:ext>";
|
|
4155
|
-
strXml += " </c:extLst>";
|
|
4156
|
-
strXml += "</c:dLbls>";
|
|
4157
|
-
}
|
|
4553
|
+
const isCustom = opts.dataLabelFormatScatter === "custom" || opts.dataLabelFormatScatter === "customXY";
|
|
4554
|
+
if (dataLabels(obj)[0] && isCustom) labels += el("c:dLbls", null, raw(firstLabelGroup(obj).map((label, pointIdx) => scatterCustomLabel(obj, opts, label, pointIdx, chartUuid)).join("")));
|
|
4555
|
+
if (opts.dataLabelFormatScatter === "XY") labels += scatterXYLabels(opts);
|
|
4158
4556
|
}
|
|
4159
|
-
|
|
4160
|
-
|
|
4161
|
-
|
|
4162
|
-
|
|
4163
|
-
|
|
4164
|
-
|
|
4165
|
-
|
|
4166
|
-
|
|
4167
|
-
|
|
4557
|
+
return el("c:ser", null, [
|
|
4558
|
+
raw(voidEl("c:idx", { val: idx }, { openPrefix: " " })),
|
|
4559
|
+
raw(voidEl("c:order", { val: idx }, { openPrefix: " " })),
|
|
4560
|
+
raw(strRefBlock(sheetCellRef(idx + 2, 1), obj.name ?? "")),
|
|
4561
|
+
raw(scatterSerShapeProps(opts, serColor, idx)),
|
|
4562
|
+
raw(scatterMarker(opts, serColor)),
|
|
4563
|
+
raw(makeSeriesDataPointsXml(chartType, obj, opts, scatterVaryColors)),
|
|
4564
|
+
raw(labels),
|
|
4565
|
+
raw(makeChartErrorBarsXml(chartType, obj.errorBars, obj)),
|
|
4566
|
+
raw(values),
|
|
4567
|
+
raw(voidEl("c:smooth", { val: opts.lineSmooth ? 1 : 0 }))
|
|
4568
|
+
]);
|
|
4569
|
+
}).join("");
|
|
4570
|
+
return el(`c:${chartType}Chart`, null, [
|
|
4571
|
+
raw(voidEl("c:scatterStyle", { val: "lineMarker" })),
|
|
4572
|
+
raw(voidEl("c:varyColors", { val: 0 })),
|
|
4573
|
+
raw(sers),
|
|
4574
|
+
raw(chartDataLabels(opts, false)),
|
|
4575
|
+
raw(voidEl("c:axId", { val: catAxisId })),
|
|
4576
|
+
raw(voidEl("c:axId", { val: valAxisId }))
|
|
4577
|
+
]);
|
|
4578
|
+
}
|
|
4579
|
+
//#endregion
|
|
4580
|
+
//#region src/gen/chart/plot-bubble.ts
|
|
4581
|
+
/** Fill + outline + shadow for one bubble series, from the palette colour and the line options. */
|
|
4582
|
+
function bubbleSerShapeProps(opts, serColor, serIndex) {
|
|
4583
|
+
const fill = serColor === "transparent" ? voidEl("a:noFill") : opts.chartColorsOpacity ? el("a:solidFill", null, raw(createColorElement(serColor, voidEl("a:alpha", { val: Math.round(opts.chartColorsOpacity * FIXED_PCT_PER_PERCENT) })))) : genXmlColorSelection(serColor);
|
|
4584
|
+
const line = opts.lineSize === 0 ? el("a:ln", null, raw(voidEl("a:noFill"))) : opts.dataBorder ? el("a:ln", {
|
|
4585
|
+
w: ptsToEmuLenient(resolveBorderWidth(opts.dataBorder, .75)),
|
|
4586
|
+
cap: "flat"
|
|
4587
|
+
}, [
|
|
4588
|
+
raw(genXmlColorSelection({
|
|
4589
|
+
color: opts.dataBorder.color ?? "363636",
|
|
4590
|
+
transparency: opts.dataBorder.transparency
|
|
4591
|
+
})),
|
|
4592
|
+
raw(voidEl("a:prstDash", { val: "solid" })),
|
|
4593
|
+
raw(voidEl("a:round"))
|
|
4594
|
+
]) : el("a:ln", {
|
|
4595
|
+
w: ptsToEmuLenient(opts.lineSize ?? 2),
|
|
4596
|
+
cap: "flat"
|
|
4597
|
+
}, [
|
|
4598
|
+
raw(genXmlColorSelection(serColor)),
|
|
4599
|
+
raw(voidEl("a:prstDash", { val: opts.lineDashValues?.[serIndex] ?? opts.lineDash ?? "solid" })),
|
|
4600
|
+
raw(voidEl("a:round"))
|
|
4601
|
+
]);
|
|
4602
|
+
return el("c:spPr", null, [
|
|
4603
|
+
raw(fill),
|
|
4604
|
+
raw(line),
|
|
4605
|
+
raw(createShadowEffectLst(opts.shadow, DEF_SHAPE_SHADOW))
|
|
4606
|
+
]);
|
|
4607
|
+
}
|
|
4608
|
+
/**
|
|
4609
|
+
* The `<c:bubbleSize>` cache: the per-point sizes that scale each bubble. Its own block rather
|
|
4610
|
+
* than {@link numRefBlock} because the wrapping tag differs and so does the indentation — the
|
|
4611
|
+
* `<c:ptCount>` here sits three spaces further in than anything around it.
|
|
4612
|
+
*/
|
|
4613
|
+
function bubbleSizeBlock(obj, ref) {
|
|
4614
|
+
const sizes = dataSizes(obj);
|
|
4615
|
+
const numCache = el("c:numCache", null, [
|
|
4616
|
+
raw(el("c:formatCode", null, "General", { openPrefix: " " })),
|
|
4617
|
+
raw(voidEl("c:ptCount", { val: sizes.length }, { openPrefix: " " })),
|
|
4618
|
+
raw(sizes.map((value, idx) => numCachePt(idx, value)).join(""))
|
|
4619
|
+
], {
|
|
4620
|
+
openPrefix: " ",
|
|
4621
|
+
closePrefix: " "
|
|
4168
4622
|
});
|
|
4169
|
-
|
|
4170
|
-
|
|
4171
|
-
|
|
4172
|
-
|
|
4623
|
+
const numRef = el("c:numRef", null, [raw(el("c:f", null, ref)), raw(numCache)], {
|
|
4624
|
+
openPrefix: " ",
|
|
4625
|
+
closePrefix: " "
|
|
4626
|
+
});
|
|
4627
|
+
return el("c:bubbleSize", null, raw(numRef), {
|
|
4628
|
+
openPrefix: " ",
|
|
4629
|
+
closePrefix: " "
|
|
4630
|
+
});
|
|
4631
|
+
}
|
|
4632
|
+
/** The shared `<c:dLbls>` block: number format, label text style, and which parts are shown. */
|
|
4633
|
+
function bubbleDataLabels(opts) {
|
|
4634
|
+
const defRPr = el("a:defRPr", {
|
|
4635
|
+
b: opts.dataLabelFontBold ? 1 : 0,
|
|
4636
|
+
i: opts.dataLabelFontItalic ? 1 : 0,
|
|
4637
|
+
strike: "noStrike",
|
|
4638
|
+
sz: ptToHundredths(opts.dataLabelFontSize || 12),
|
|
4639
|
+
u: "none"
|
|
4640
|
+
}, [raw(genXmlColorSelection(opts.dataLabelColor || "000000")), raw(createChartTextFonts(opts.dataLabelFontFace || "Arial"))]);
|
|
4641
|
+
const txPr = el("c:txPr", null, [
|
|
4642
|
+
raw(voidEl("a:bodyPr")),
|
|
4643
|
+
raw(voidEl("a:lstStyle")),
|
|
4644
|
+
raw(el("a:p", null, raw(el("a:pPr", null, raw(defRPr)))))
|
|
4645
|
+
]);
|
|
4646
|
+
const extLst = el("c:extLst", null, raw(el("c:ext", {
|
|
4647
|
+
uri: "{CE6537A1-D6FC-4f65-9D91-7224C49458BB}",
|
|
4648
|
+
"xmlns:c15": "http://schemas.microsoft.com/office/drawing/2012/chart"
|
|
4649
|
+
}, raw(voidEl("c15:showLeaderLines", { val: opts.showLeaderLines ? 1 : 0 }, { openPrefix: " " })), {
|
|
4650
|
+
openPrefix: " ",
|
|
4651
|
+
closePrefix: " "
|
|
4652
|
+
})));
|
|
4653
|
+
return el("c:dLbls", null, [
|
|
4654
|
+
raw(voidEl("c:numFmt", {
|
|
4655
|
+
formatCode: (opts.dataLabelFormatCode ?? "") || "General",
|
|
4656
|
+
sourceLinked: 0
|
|
4657
|
+
})),
|
|
4658
|
+
raw(txPr),
|
|
4659
|
+
opts.dataLabelPosition ? raw(voidEl("c:dLblPos", { val: opts.dataLabelPosition })) : null,
|
|
4660
|
+
raw(voidEl("c:showLegendKey", { val: 0 })),
|
|
4661
|
+
raw(voidEl("c:showVal", { val: opts.showValue ? 1 : 0 })),
|
|
4662
|
+
raw(voidEl("c:showCatName", { val: 0 })),
|
|
4663
|
+
raw(voidEl("c:showSerName", { val: opts.showSerName ? 1 : 0 })),
|
|
4664
|
+
raw(voidEl("c:showPercent", { val: 0 })),
|
|
4665
|
+
raw(voidEl("c:showBubbleSize", { val: opts.showBubbleSize ? 1 : 0 })),
|
|
4666
|
+
raw(extLst)
|
|
4667
|
+
]);
|
|
4173
4668
|
}
|
|
4174
|
-
//#endregion
|
|
4175
|
-
//#region src/gen/chart/plot-bubble.ts
|
|
4176
4669
|
/**
|
|
4177
4670
|
* Plot a bubble / bubble3d chart into `<c:bubbleChart>` (X/Y plus per-point size).
|
|
4178
4671
|
*/
|
|
4179
4672
|
function makeBubblePlot(chartType, data, opts, valAxisId, catAxisId, valFmtCode) {
|
|
4180
|
-
|
|
4673
|
+
const chartColors = resolveChartPalette(opts);
|
|
4674
|
+
const xValues = dataValues(data[0]);
|
|
4181
4675
|
let idxColLtr = 1;
|
|
4182
|
-
|
|
4183
|
-
|
|
4184
|
-
|
|
4185
|
-
|
|
4186
|
-
|
|
4187
|
-
|
|
4188
|
-
strXml += "<c:ser>";
|
|
4189
|
-
strXml += ` <c:idx val="${idx}"/>`;
|
|
4190
|
-
strXml += ` <c:order val="${idx}"/>`;
|
|
4191
|
-
strXml += " <c:tx>";
|
|
4192
|
-
strXml += " <c:strRef>";
|
|
4193
|
-
strXml += ` <c:f>${sheetCellRef(idxColLtr + 1, 1)}</c:f>`;
|
|
4194
|
-
strXml += " <c:strCache><c:ptCount val=\"1\"/><c:pt idx=\"0\">" + el("c:v", null, obj.name ?? "") + "</c:pt></c:strCache>";
|
|
4195
|
-
strXml += " </c:strRef>";
|
|
4196
|
-
strXml += " </c:tx>";
|
|
4197
|
-
{
|
|
4198
|
-
strXml += "<c:spPr>";
|
|
4199
|
-
const tmpSerColor = paletteColor(resolveChartPalette(opts), colorIndex);
|
|
4200
|
-
if (tmpSerColor === "transparent") strXml += "<a:noFill/>";
|
|
4201
|
-
else if (opts.chartColorsOpacity) strXml += `<a:solidFill>${createColorElement(tmpSerColor, "<a:alpha val=\"" + Math.round(opts.chartColorsOpacity * FIXED_PCT_PER_PERCENT).toString() + "\"/>")}</a:solidFill>`;
|
|
4202
|
-
else strXml += genXmlColorSelection(tmpSerColor);
|
|
4203
|
-
if (opts.lineSize === 0) strXml += "<a:ln><a:noFill/></a:ln>";
|
|
4204
|
-
else if (opts.dataBorder) strXml += `<a:ln w="${ptsToEmuLenient(resolveBorderWidth(opts.dataBorder, .75))}" cap="flat">${genXmlColorSelection({
|
|
4205
|
-
color: opts.dataBorder.color ?? "363636",
|
|
4206
|
-
transparency: opts.dataBorder.transparency
|
|
4207
|
-
})}<a:prstDash val="solid"/><a:round/></a:ln>`;
|
|
4208
|
-
else {
|
|
4209
|
-
strXml += `<a:ln w="${ptsToEmuLenient(opts.lineSize ?? 2)}" cap="flat">${genXmlColorSelection(tmpSerColor)}`;
|
|
4210
|
-
strXml += voidEl("a:prstDash", { val: opts.lineDashValues?.[colorIndex] ?? opts.lineDash ?? "solid" }) + voidEl("a:round") + "</a:ln>";
|
|
4211
|
-
}
|
|
4212
|
-
strXml += createShadowEffectLst(opts.shadow, DEF_SHAPE_SHADOW);
|
|
4213
|
-
strXml += "</c:spPr>";
|
|
4214
|
-
}
|
|
4215
|
-
{
|
|
4216
|
-
const xValues = dataValues(data[0]);
|
|
4217
|
-
const yValues = dataValues(obj);
|
|
4218
|
-
strXml += numRefBlock("c:xVal", `Sheet1!$A$2:$A$${xValues.length + 1}`, valFmtCode, xValues);
|
|
4219
|
-
strXml += numRefBlock("c:yVal", sheetRangeRef(idxColLtr + 1, 2, idxColLtr + 1, xValues.length + 1), valFmtCode, xValues.map((_value, idx) => yValues[idx]), "");
|
|
4220
|
-
idxColLtr++;
|
|
4221
|
-
}
|
|
4222
|
-
strXml += " <c:bubbleSize>";
|
|
4223
|
-
strXml += " <c:numRef>";
|
|
4224
|
-
strXml += `<c:f>${sheetRangeRef(idxColLtr + 1, 2, idxColLtr + 1, dataSizes(obj).length + 1)}</c:f>`;
|
|
4676
|
+
const sers = data.slice(1).map((obj, idx) => {
|
|
4677
|
+
const name = strRefBlock(sheetCellRef(idxColLtr + 1, 1), obj.name ?? "");
|
|
4678
|
+
const spPr = bubbleSerShapeProps(opts, paletteColor(chartColors, idx), idx);
|
|
4679
|
+
const yValues = dataValues(obj);
|
|
4680
|
+
const xVal = numRefBlock("c:xVal", `Sheet1!$A$2:$A$${xValues.length + 1}`, valFmtCode, xValues);
|
|
4681
|
+
const yVal = numRefBlock("c:yVal", sheetRangeRef(idxColLtr + 1, 2, idxColLtr + 1, xValues.length + 1), valFmtCode, xValues.map((_value, i) => yValues[i]), "");
|
|
4225
4682
|
idxColLtr++;
|
|
4226
|
-
|
|
4227
|
-
|
|
4228
|
-
|
|
4229
|
-
|
|
4230
|
-
|
|
4231
|
-
|
|
4232
|
-
|
|
4233
|
-
|
|
4234
|
-
|
|
4235
|
-
|
|
4236
|
-
|
|
4237
|
-
|
|
4238
|
-
|
|
4239
|
-
|
|
4240
|
-
|
|
4241
|
-
|
|
4242
|
-
|
|
4243
|
-
|
|
4244
|
-
|
|
4245
|
-
|
|
4246
|
-
strXml += createChartTextFonts(opts.dataLabelFontFace || "Arial");
|
|
4247
|
-
strXml += "</a:defRPr></a:pPr></a:p></c:txPr>";
|
|
4248
|
-
if (opts.dataLabelPosition) strXml += voidEl("c:dLblPos", { val: opts.dataLabelPosition });
|
|
4249
|
-
strXml += "<c:showLegendKey val=\"0\"/>";
|
|
4250
|
-
strXml += `<c:showVal val="${opts.showValue ? "1" : "0"}"/>`;
|
|
4251
|
-
strXml += `<c:showCatName val="0"/><c:showSerName val="${opts.showSerName ? "1" : "0"}"/><c:showPercent val="0"/><c:showBubbleSize val="${opts.showBubbleSize ? "1" : "0"}"/>`;
|
|
4252
|
-
strXml += "<c:extLst>";
|
|
4253
|
-
strXml += " <c:ext uri=\"{CE6537A1-D6FC-4f65-9D91-7224C49458BB}\" xmlns:c15=\"http://schemas.microsoft.com/office/drawing/2012/chart\">";
|
|
4254
|
-
strXml += " <c15:showLeaderLines val=\"" + (opts.showLeaderLines ? "1" : "0") + "\"/>";
|
|
4255
|
-
strXml += " </c:ext>";
|
|
4256
|
-
strXml += "</c:extLst>";
|
|
4257
|
-
strXml += "</c:dLbls>";
|
|
4258
|
-
strXml += `<c:axId val="${catAxisId}"/><c:axId val="${valAxisId}"/>`;
|
|
4259
|
-
strXml += "</c:bubbleChart>";
|
|
4260
|
-
return strXml;
|
|
4683
|
+
const sizeRef = sheetRangeRef(idxColLtr + 1, 2, idxColLtr + 1, dataSizes(obj).length + 1);
|
|
4684
|
+
idxColLtr++;
|
|
4685
|
+
return el("c:ser", null, [
|
|
4686
|
+
raw(voidEl("c:idx", { val: idx }, { openPrefix: " " })),
|
|
4687
|
+
raw(voidEl("c:order", { val: idx }, { openPrefix: " " })),
|
|
4688
|
+
raw(name),
|
|
4689
|
+
raw(spPr),
|
|
4690
|
+
raw(xVal),
|
|
4691
|
+
raw(yVal),
|
|
4692
|
+
raw(bubbleSizeBlock(obj, sizeRef)),
|
|
4693
|
+
raw(voidEl("c:bubble3D", { val: chartType === "bubble3D" ? 1 : 0 }, { openPrefix: " " }))
|
|
4694
|
+
]);
|
|
4695
|
+
}).join("");
|
|
4696
|
+
return el("c:bubbleChart", null, [
|
|
4697
|
+
raw(voidEl("c:varyColors", { val: 0 })),
|
|
4698
|
+
raw(sers),
|
|
4699
|
+
raw(bubbleDataLabels(opts)),
|
|
4700
|
+
raw(voidEl("c:axId", { val: catAxisId })),
|
|
4701
|
+
raw(voidEl("c:axId", { val: valAxisId }))
|
|
4702
|
+
]);
|
|
4261
4703
|
}
|
|
4262
4704
|
//#endregion
|
|
4263
4705
|
//#region src/gen/chart/plot-pie.ts
|
|
4264
|
-
/**
|
|
4265
|
-
|
|
4266
|
-
|
|
4267
|
-
|
|
4268
|
-
|
|
4269
|
-
|
|
4270
|
-
|
|
4271
|
-
|
|
4272
|
-
|
|
4273
|
-
|
|
4274
|
-
|
|
4275
|
-
|
|
4276
|
-
|
|
4277
|
-
|
|
4278
|
-
|
|
4279
|
-
|
|
4280
|
-
|
|
4281
|
-
strXml += " <c:strRef>";
|
|
4282
|
-
strXml += " <c:f>Sheet1!$B$1</c:f>";
|
|
4283
|
-
strXml += " <c:strCache>";
|
|
4284
|
-
strXml += " <c:ptCount val=\"1\"/>";
|
|
4285
|
-
strXml += " <c:pt idx=\"0\">" + el("c:v", null, optsChartData.name ?? "") + "</c:pt>";
|
|
4286
|
-
strXml += " </c:strCache>";
|
|
4287
|
-
strXml += " </c:strRef>";
|
|
4288
|
-
strXml += " </c:tx>";
|
|
4289
|
-
strXml += " <c:spPr>";
|
|
4290
|
-
strXml += " <a:solidFill><a:schemeClr val=\"accent1\"/></a:solidFill>";
|
|
4291
|
-
strXml += " <a:ln w=\"9525\" cap=\"flat\"><a:solidFill><a:srgbClr val=\"F9F9F9\"/></a:solidFill><a:prstDash val=\"solid\"/><a:round/></a:ln>";
|
|
4292
|
-
if (opts.dataNoEffects) strXml += "<a:effectLst/>";
|
|
4293
|
-
else strXml += createShadowEffectLst(opts.shadow, DEF_SHAPE_SHADOW);
|
|
4294
|
-
strXml += " </c:spPr>";
|
|
4295
|
-
firstLabelGroup(optsChartData).forEach((_label, idx) => {
|
|
4296
|
-
const chartColors = resolveChartPalette(opts);
|
|
4297
|
-
const ptStyle = optsChartData.pointStyles?.[idx];
|
|
4298
|
-
strXml += "<c:dPt>";
|
|
4299
|
-
strXml += ` <c:idx val="${idx}"/>`;
|
|
4300
|
-
strXml += " <c:bubble3D val=\"0\"/>";
|
|
4301
|
-
strXml += " <c:spPr>";
|
|
4302
|
-
strXml += `<a:solidFill>${createColorElement(ptStyle?.fill || paletteColor(chartColors, idx))}</a:solidFill>`;
|
|
4303
|
-
if (ptStyle?.border) strXml += createChartBorderLine(ptStyle.border);
|
|
4304
|
-
else if (opts.dataBorder) strXml += `<a:ln w="${ptsToEmuLenient(resolveBorderWidth(opts.dataBorder, .75))}" cap="flat">${genXmlColorSelection({
|
|
4706
|
+
/** The label run properties both `<c:txPr>` spellings share, differing only in their indentation. */
|
|
4707
|
+
function labelDefRPr(opts, fontsIndent, fmt) {
|
|
4708
|
+
return el("a:defRPr", {
|
|
4709
|
+
sz: ptToHundredths(opts.dataLabelFontSize || 12),
|
|
4710
|
+
b: opts.dataLabelFontBold ? 1 : 0,
|
|
4711
|
+
i: opts.dataLabelFontItalic ? 1 : 0,
|
|
4712
|
+
u: "none",
|
|
4713
|
+
strike: "noStrike"
|
|
4714
|
+
}, [raw(genXmlColorSelection(opts.dataLabelColor || "000000")), raw(fontsIndent + createChartTextFonts(opts.dataLabelFontFace || "Arial"))], fmt);
|
|
4715
|
+
}
|
|
4716
|
+
/** One `<c:dPt>`: the slice's own fill, its border override, and the shared shadow. */
|
|
4717
|
+
function pieDataPoint(idx, ptStyle, opts, fallbackColor) {
|
|
4718
|
+
const border = ptStyle?.border ? createChartBorderLine(ptStyle.border) : opts.dataBorder ? el("a:ln", {
|
|
4719
|
+
w: ptsToEmuLenient(resolveBorderWidth(opts.dataBorder, .75)),
|
|
4720
|
+
cap: "flat"
|
|
4721
|
+
}, [
|
|
4722
|
+
raw(genXmlColorSelection({
|
|
4305
4723
|
color: opts.dataBorder.color ?? "363636",
|
|
4306
4724
|
transparency: opts.dataBorder.transparency
|
|
4307
|
-
})
|
|
4308
|
-
|
|
4309
|
-
|
|
4310
|
-
|
|
4311
|
-
|
|
4312
|
-
|
|
4313
|
-
|
|
4314
|
-
|
|
4315
|
-
|
|
4316
|
-
|
|
4317
|
-
|
|
4318
|
-
|
|
4319
|
-
|
|
4320
|
-
|
|
4321
|
-
})
|
|
4322
|
-
|
|
4323
|
-
|
|
4324
|
-
|
|
4325
|
-
|
|
4326
|
-
|
|
4327
|
-
|
|
4328
|
-
|
|
4329
|
-
|
|
4330
|
-
|
|
4331
|
-
|
|
4332
|
-
strXml += " <c:showLegendKey val=\"0\"/>";
|
|
4333
|
-
strXml += " <c:showVal val=\"" + (customLbl ? "0" : opts.showValue ? "1" : "0") + "\"/>";
|
|
4334
|
-
strXml += " <c:showCatName val=\"" + (opts.showLabel ? "1" : "0") + "\"/>";
|
|
4335
|
-
strXml += " <c:showSerName val=\"" + (opts.showSerName ? "1" : "0") + "\"/>";
|
|
4336
|
-
strXml += " <c:showPercent val=\"" + (opts.showPercent ? "1" : "0") + "\"/>";
|
|
4337
|
-
strXml += " <c:showBubbleSize val=\"0\"/>";
|
|
4338
|
-
strXml += " </c:dLbl>";
|
|
4339
|
-
});
|
|
4340
|
-
strXml += " " + voidEl("c:numFmt", {
|
|
4725
|
+
})),
|
|
4726
|
+
raw(voidEl("a:prstDash", { val: "solid" })),
|
|
4727
|
+
raw(voidEl("a:round"))
|
|
4728
|
+
]) : "";
|
|
4729
|
+
const spPr = el("c:spPr", null, [
|
|
4730
|
+
raw(el("a:solidFill", null, raw(createColorElement(ptStyle?.fill || fallbackColor)))),
|
|
4731
|
+
raw(border),
|
|
4732
|
+
raw(createShadowEffectLst(opts.shadow, DEF_SHAPE_SHADOW))
|
|
4733
|
+
], {
|
|
4734
|
+
openPrefix: " ",
|
|
4735
|
+
closePrefix: " "
|
|
4736
|
+
});
|
|
4737
|
+
return el("c:dPt", null, [
|
|
4738
|
+
raw(voidEl("c:idx", { val: idx }, { openPrefix: " " })),
|
|
4739
|
+
raw(voidEl("c:bubble3D", { val: 0 }, { openPrefix: " " })),
|
|
4740
|
+
raw(spPr)
|
|
4741
|
+
]);
|
|
4742
|
+
}
|
|
4743
|
+
/**
|
|
4744
|
+
* One `<c:dLbl>`: a pie labels its points, not its series, so every slice carries its own copy of
|
|
4745
|
+
* the number format, text style and show flags. A `customLabels` entry replaces the value with
|
|
4746
|
+
* literal rich text, which is why it also forces `<c:showVal>` off.
|
|
4747
|
+
*/
|
|
4748
|
+
function pieDataLabel(idx, customLbl, opts, chartType) {
|
|
4749
|
+
const numFmt = voidEl("c:numFmt", {
|
|
4341
4750
|
formatCode: (opts.dataLabelFormatCode ?? "") || "General",
|
|
4342
4751
|
sourceLinked: 0
|
|
4752
|
+
}, { openPrefix: " " });
|
|
4753
|
+
const txPr = el("c:txPr", null, [
|
|
4754
|
+
raw(voidEl("a:bodyPr", null, { openPrefix: " " })),
|
|
4755
|
+
raw(voidEl("a:lstStyle")),
|
|
4756
|
+
raw(el("a:p", null, raw(el("a:pPr", null, raw(labelDefRPr(opts, " ", {
|
|
4757
|
+
openPrefix: " ",
|
|
4758
|
+
closePrefix: " "
|
|
4759
|
+
})), { closePrefix: " " })), { openPrefix: " " }))
|
|
4760
|
+
], { closePrefix: " " });
|
|
4761
|
+
return el("c:dLbl", null, [
|
|
4762
|
+
raw(voidEl("c:idx", { val: idx }, { openPrefix: " " })),
|
|
4763
|
+
customLbl ? raw(el("c:tx", null, raw(el("c:rich", null, [
|
|
4764
|
+
raw(voidEl("a:bodyPr")),
|
|
4765
|
+
raw(voidEl("a:lstStyle")),
|
|
4766
|
+
raw(el("a:p", null, raw(el("a:r", null, [raw(voidEl("a:rPr", {
|
|
4767
|
+
lang: opts.lang || "en-US",
|
|
4768
|
+
dirty: 0
|
|
4769
|
+
})), raw(el("a:t", null, customLbl))]))))
|
|
4770
|
+
])))) : null,
|
|
4771
|
+
raw(numFmt),
|
|
4772
|
+
raw(voidEl("c:spPr", null, { openPrefix: " " })),
|
|
4773
|
+
raw(txPr),
|
|
4774
|
+
chartType === "pie" && opts.dataLabelPosition ? raw(voidEl("c:dLblPos", { val: opts.dataLabelPosition })) : null,
|
|
4775
|
+
raw(voidEl("c:showLegendKey", { val: 0 }, { openPrefix: " " })),
|
|
4776
|
+
raw(voidEl("c:showVal", { val: customLbl ? 0 : opts.showValue ? 1 : 0 }, { openPrefix: " " })),
|
|
4777
|
+
raw(voidEl("c:showCatName", { val: opts.showLabel ? 1 : 0 }, { openPrefix: " " })),
|
|
4778
|
+
raw(voidEl("c:showSerName", { val: opts.showSerName ? 1 : 0 }, { openPrefix: " " })),
|
|
4779
|
+
raw(voidEl("c:showPercent", { val: opts.showPercent ? 1 : 0 }, { openPrefix: " " })),
|
|
4780
|
+
raw(voidEl("c:showBubbleSize", { val: 0 }, { openPrefix: " " }))
|
|
4781
|
+
], { closePrefix: " " });
|
|
4782
|
+
}
|
|
4783
|
+
/** The `<c:cat>` slice-name reference and the `<c:val>` cache, both keyed on the label count. */
|
|
4784
|
+
function pieCategories(labels) {
|
|
4785
|
+
const strCache = el("c:strCache", null, [raw(voidEl("c:ptCount", { val: labels.length }, { openPrefix: " " })), raw(labels.map((label, idx) => el("c:pt", { idx }, raw(el("c:v", null, label)))).join(""))], {
|
|
4786
|
+
openPrefix: " ",
|
|
4787
|
+
closePrefix: " "
|
|
4788
|
+
});
|
|
4789
|
+
const strRef = el("c:strRef", null, [raw(el("c:f", null, `Sheet1!$A$2:$A$${labels.length + 1}`, { openPrefix: " " })), raw(strCache)], {
|
|
4790
|
+
openPrefix: " ",
|
|
4791
|
+
closePrefix: " "
|
|
4792
|
+
});
|
|
4793
|
+
return el("c:cat", null, raw(strRef));
|
|
4794
|
+
}
|
|
4795
|
+
/** The `<c:val>` numeric cache. A missing value keeps its `<c:pt>` with an empty `<c:v>`. */
|
|
4796
|
+
function pieValues(obj, count, valFmtCode) {
|
|
4797
|
+
const points = dataValues(obj).map((value, idx) => el("c:pt", { idx }, raw(el("c:v", null, value || value === 0 ? value : "")))).join("");
|
|
4798
|
+
const numCache = el("c:numCache", null, [
|
|
4799
|
+
raw(el("c:formatCode", null, valFmtCode, { openPrefix: " " })),
|
|
4800
|
+
raw(voidEl("c:ptCount", { val: count }, { openPrefix: " " })),
|
|
4801
|
+
raw(points)
|
|
4802
|
+
], {
|
|
4803
|
+
openPrefix: " ",
|
|
4804
|
+
closePrefix: " "
|
|
4805
|
+
});
|
|
4806
|
+
const numRef = el("c:numRef", null, [raw(el("c:f", null, `Sheet1!$B$2:$B$${count + 1}`, { openPrefix: " " })), raw(numCache)], {
|
|
4807
|
+
openPrefix: " ",
|
|
4808
|
+
closePrefix: " "
|
|
4809
|
+
});
|
|
4810
|
+
return el("c:val", null, raw(numRef), {
|
|
4811
|
+
openPrefix: " ",
|
|
4812
|
+
closePrefix: " "
|
|
4343
4813
|
});
|
|
4344
|
-
strXml += " <c:txPr>";
|
|
4345
|
-
strXml += " <a:bodyPr/>";
|
|
4346
|
-
strXml += " <a:lstStyle/>";
|
|
4347
|
-
strXml += " <a:p>";
|
|
4348
|
-
strXml += " <a:pPr>";
|
|
4349
|
-
strXml += ` <a:defRPr sz="${ptToHundredths(opts.dataLabelFontSize || 12)}" b="${opts.dataLabelFontBold ? "1" : "0"}" i="${opts.dataLabelFontItalic ? "1" : "0"}" u="none" strike="noStrike">`;
|
|
4350
|
-
strXml += genXmlColorSelection(opts.dataLabelColor || "000000");
|
|
4351
|
-
strXml += " " + createChartTextFonts(opts.dataLabelFontFace || "Arial");
|
|
4352
|
-
strXml += " </a:defRPr>";
|
|
4353
|
-
strXml += " </a:pPr>";
|
|
4354
|
-
strXml += " </a:p>";
|
|
4355
|
-
strXml += " </c:txPr>";
|
|
4356
|
-
strXml += chartType === "pie" ? voidEl("c:dLblPos", { val: opts.dataLabelPosition || "ctr" }) : "";
|
|
4357
|
-
strXml += " <c:showLegendKey val=\"0\"/>";
|
|
4358
|
-
strXml += " <c:showVal val=\"0\"/>";
|
|
4359
|
-
strXml += " <c:showCatName val=\"1\"/>";
|
|
4360
|
-
strXml += " <c:showSerName val=\"0\"/>";
|
|
4361
|
-
strXml += " <c:showPercent val=\"1\"/>";
|
|
4362
|
-
strXml += " <c:showBubbleSize val=\"0\"/>";
|
|
4363
|
-
strXml += ` <c:showLeaderLines val="${opts.showLeaderLines ? "1" : "0"}"/>`;
|
|
4364
|
-
strXml += createLeaderLinesElement(opts);
|
|
4365
|
-
strXml += "</c:dLbls>";
|
|
4366
|
-
strXml += "<c:cat>";
|
|
4367
|
-
strXml += " <c:strRef>";
|
|
4368
|
-
strXml += ` <c:f>Sheet1!$A$2:$A$${firstLabelGroup(optsChartData).length + 1}</c:f>`;
|
|
4369
|
-
strXml += " <c:strCache>";
|
|
4370
|
-
strXml += ` <c:ptCount val="${firstLabelGroup(optsChartData).length}"/>`;
|
|
4371
|
-
firstLabelGroup(optsChartData).forEach((label, idx) => {
|
|
4372
|
-
strXml += `<c:pt idx="${idx}">${el("c:v", null, label)}</c:pt>`;
|
|
4373
|
-
});
|
|
4374
|
-
strXml += " </c:strCache>";
|
|
4375
|
-
strXml += " </c:strRef>";
|
|
4376
|
-
strXml += "</c:cat>";
|
|
4377
|
-
strXml += " <c:val>";
|
|
4378
|
-
strXml += " <c:numRef>";
|
|
4379
|
-
strXml += ` <c:f>Sheet1!$B$2:$B$${firstLabelGroup(optsChartData).length + 1}</c:f>`;
|
|
4380
|
-
strXml += " <c:numCache>";
|
|
4381
|
-
strXml += " <c:formatCode>" + valFmtCode + "</c:formatCode>";
|
|
4382
|
-
strXml += ` <c:ptCount val="${firstLabelGroup(optsChartData).length}"/>`;
|
|
4383
|
-
dataValues(optsChartData).forEach((value, idx) => {
|
|
4384
|
-
strXml += `<c:pt idx="${idx}"><c:v>${value || value === 0 ? value : ""}</c:v></c:pt>`;
|
|
4385
|
-
});
|
|
4386
|
-
strXml += " </c:numCache>";
|
|
4387
|
-
strXml += " </c:numRef>";
|
|
4388
|
-
strXml += " </c:val>";
|
|
4389
|
-
strXml += " </c:ser>";
|
|
4390
|
-
strXml += ` <c:firstSliceAng val="${opts.firstSliceAng ? Math.round(opts.firstSliceAng) : 0}"/>`;
|
|
4391
|
-
if (chartType === "doughnut") strXml += `<c:holeSize val="${typeof opts.holeSize === "number" ? opts.holeSize : "50"}"/>`;
|
|
4392
|
-
strXml += "</c:" + chartType + "Chart>";
|
|
4393
|
-
return strXml;
|
|
4394
4814
|
}
|
|
4395
4815
|
/**
|
|
4396
|
-
*
|
|
4397
|
-
* @param {ChartOptsInternal} opts - chart options
|
|
4398
|
-
* @param {string} axisId - value
|
|
4399
|
-
* @param {string} valAxisId - value
|
|
4400
|
-
* @return {string} XML
|
|
4816
|
+
* Plot a single-series pie / doughnut chart into `<c:pieChart>` / `<c:doughnutChart>`.
|
|
4401
4817
|
*/
|
|
4818
|
+
function makePiePlot(chartType, data, opts, valFmtCode) {
|
|
4819
|
+
const optsChartData = data[0];
|
|
4820
|
+
if (!optsChartData) return "";
|
|
4821
|
+
const chartColors = resolveChartPalette(opts);
|
|
4822
|
+
const labels = firstLabelGroup(optsChartData);
|
|
4823
|
+
const spPr = el("c:spPr", null, [
|
|
4824
|
+
raw(el("a:solidFill", null, raw(voidEl("a:schemeClr", { val: "accent1" })), { openPrefix: " " })),
|
|
4825
|
+
raw(el("a:ln", {
|
|
4826
|
+
w: 9525,
|
|
4827
|
+
cap: "flat"
|
|
4828
|
+
}, [
|
|
4829
|
+
raw(el("a:solidFill", null, raw(voidEl("a:srgbClr", { val: "F9F9F9" })))),
|
|
4830
|
+
raw(voidEl("a:prstDash", { val: "solid" })),
|
|
4831
|
+
raw(voidEl("a:round"))
|
|
4832
|
+
], { openPrefix: " " })),
|
|
4833
|
+
raw(opts.dataNoEffects ? voidEl("a:effectLst") : createShadowEffectLst(opts.shadow, DEF_SHAPE_SHADOW))
|
|
4834
|
+
], {
|
|
4835
|
+
openPrefix: " ",
|
|
4836
|
+
closePrefix: " "
|
|
4837
|
+
});
|
|
4838
|
+
const dLbls = el("c:dLbls", null, [
|
|
4839
|
+
raw(labels.map((_label, idx) => pieDataLabel(idx, optsChartData.customLabels?.[idx], opts, chartType)).join("")),
|
|
4840
|
+
raw(voidEl("c:numFmt", {
|
|
4841
|
+
formatCode: (opts.dataLabelFormatCode ?? "") || "General",
|
|
4842
|
+
sourceLinked: 0
|
|
4843
|
+
}, { openPrefix: " " })),
|
|
4844
|
+
raw(el("c:txPr", null, [
|
|
4845
|
+
raw(voidEl("a:bodyPr", null, { openPrefix: " " })),
|
|
4846
|
+
raw(voidEl("a:lstStyle", null, { openPrefix: " " })),
|
|
4847
|
+
raw(el("a:p", null, raw(el("a:pPr", null, raw(labelDefRPr(opts, " ", {
|
|
4848
|
+
openPrefix: " ",
|
|
4849
|
+
closePrefix: " "
|
|
4850
|
+
})), {
|
|
4851
|
+
openPrefix: " ",
|
|
4852
|
+
closePrefix: " "
|
|
4853
|
+
})), {
|
|
4854
|
+
openPrefix: " ",
|
|
4855
|
+
closePrefix: " "
|
|
4856
|
+
}))
|
|
4857
|
+
], {
|
|
4858
|
+
openPrefix: " ",
|
|
4859
|
+
closePrefix: " "
|
|
4860
|
+
})),
|
|
4861
|
+
chartType === "pie" ? raw(voidEl("c:dLblPos", { val: opts.dataLabelPosition || "ctr" })) : null,
|
|
4862
|
+
raw(voidEl("c:showLegendKey", { val: 0 }, { openPrefix: " " })),
|
|
4863
|
+
raw(voidEl("c:showVal", { val: 0 }, { openPrefix: " " })),
|
|
4864
|
+
raw(voidEl("c:showCatName", { val: 1 }, { openPrefix: " " })),
|
|
4865
|
+
raw(voidEl("c:showSerName", { val: 0 }, { openPrefix: " " })),
|
|
4866
|
+
raw(voidEl("c:showPercent", { val: 1 }, { openPrefix: " " })),
|
|
4867
|
+
raw(voidEl("c:showBubbleSize", { val: 0 }, { openPrefix: " " })),
|
|
4868
|
+
raw(voidEl("c:showLeaderLines", { val: opts.showLeaderLines ? 1 : 0 }, { openPrefix: " " })),
|
|
4869
|
+
raw(createLeaderLinesElement(opts))
|
|
4870
|
+
]);
|
|
4871
|
+
const ser = el("c:ser", null, [
|
|
4872
|
+
raw(voidEl("c:idx", { val: 0 }, { openPrefix: " " })),
|
|
4873
|
+
raw(voidEl("c:order", { val: 0 }, { openPrefix: " " })),
|
|
4874
|
+
raw(strRefBlock("Sheet1!$B$1", optsChartData.name ?? "", "expanded")),
|
|
4875
|
+
raw(spPr),
|
|
4876
|
+
raw(labels.map((_label, idx) => pieDataPoint(idx, optsChartData.pointStyles?.[idx], opts, paletteColor(chartColors, idx))).join("")),
|
|
4877
|
+
raw(dLbls),
|
|
4878
|
+
raw(pieCategories(labels)),
|
|
4879
|
+
raw(pieValues(optsChartData, labels.length, valFmtCode))
|
|
4880
|
+
], { closePrefix: " " });
|
|
4881
|
+
return el(`c:${chartType}Chart`, null, [
|
|
4882
|
+
raw(voidEl("c:varyColors", { val: 1 }, { openPrefix: " " })),
|
|
4883
|
+
raw(ser),
|
|
4884
|
+
raw(voidEl("c:firstSliceAng", { val: opts.firstSliceAng ? Math.round(opts.firstSliceAng) : 0 }, { openPrefix: " " })),
|
|
4885
|
+
chartType === "doughnut" ? raw(voidEl("c:holeSize", { val: typeof opts.holeSize === "number" ? opts.holeSize : 50 })) : null
|
|
4886
|
+
]);
|
|
4887
|
+
}
|
|
4402
4888
|
//#endregion
|
|
4403
4889
|
//#region src/gen/chart/plot-stock.ts
|
|
4404
4890
|
/**
|
|
@@ -4432,54 +4918,56 @@ const STOCK_STYLE_SPEC = {
|
|
|
4432
4918
|
/** True when the given (already-normalized) stock style leads with a Volume bar series. */
|
|
4433
4919
|
const isVolumeStockStyle = (style) => !!style && STOCK_STYLE_SPEC[style].volume;
|
|
4434
4920
|
/** Minimal `<c:dLbls>` block (all labels off) shared by the stock and volume-bar subcharts. */
|
|
4435
|
-
const STOCK_DLBLS = "
|
|
4921
|
+
const STOCK_DLBLS = el("c:dLbls", null, [
|
|
4922
|
+
raw(voidEl("c:showLegendKey", { val: 0 })),
|
|
4923
|
+
raw(voidEl("c:showVal", { val: 0 })),
|
|
4924
|
+
raw(voidEl("c:showCatName", { val: 0 })),
|
|
4925
|
+
raw(voidEl("c:showSerName", { val: 0 })),
|
|
4926
|
+
raw(voidEl("c:showPercent", { val: 0 })),
|
|
4927
|
+
raw(voidEl("c:showBubbleSize", { val: 0 }))
|
|
4928
|
+
]);
|
|
4436
4929
|
/** Emit the shared `<c:cat>` + `<c:val>` refs for a stock/volume series (single-level categories). */
|
|
4437
4930
|
function stockCatVal(obj, opts, valFmtCode) {
|
|
4438
4931
|
const cats = firstLabelGroup(obj);
|
|
4439
4932
|
const valColRow = obj._dataIndex + dataLabels(obj).length + 1;
|
|
4440
|
-
|
|
4441
|
-
|
|
4442
|
-
|
|
4443
|
-
|
|
4444
|
-
|
|
4445
|
-
|
|
4446
|
-
|
|
4447
|
-
|
|
4448
|
-
|
|
4449
|
-
} else {
|
|
4450
|
-
strXml += "<c:strRef>";
|
|
4451
|
-
strXml += `<c:f>Sheet1!$A$2:$A$${cats.length + 1}</c:f>`;
|
|
4452
|
-
strXml += "<c:strCache>";
|
|
4453
|
-
strXml += `<c:ptCount val="${cats.length}"/>`;
|
|
4454
|
-
cats.forEach((label, idx) => strXml += `<c:pt idx="${idx}">${el("c:v", null, label)}</c:pt>`);
|
|
4455
|
-
strXml += "</c:strCache></c:strRef>";
|
|
4456
|
-
}
|
|
4457
|
-
strXml += "</c:cat>";
|
|
4458
|
-
strXml += "<c:val><c:numRef>";
|
|
4459
|
-
strXml += `<c:f>${sheetRangeRef(valColRow, 2, valColRow, cats.length + 1)}</c:f>`;
|
|
4460
|
-
strXml += "<c:numCache>";
|
|
4461
|
-
strXml += `<c:formatCode>${valFmtCode}</c:formatCode>`;
|
|
4462
|
-
strXml += `<c:ptCount val="${cats.length}"/>`;
|
|
4463
|
-
dataValues(obj).forEach((value, idx) => strXml += numCachePt(idx, value));
|
|
4464
|
-
strXml += "</c:numCache></c:numRef></c:val>";
|
|
4465
|
-
return strXml;
|
|
4933
|
+
const catRef = `Sheet1!$A$2:$A$${cats.length + 1}`;
|
|
4934
|
+
const cat = el("c:cat", null, raw(opts.catLabelFormatCode ? catRefBlock("num", catRef, cats, opts.catLabelFormatCode || "General") : catRefBlock("str", catRef, cats)));
|
|
4935
|
+
const numCache = el("c:numCache", null, [
|
|
4936
|
+
raw(el("c:formatCode", null, valFmtCode)),
|
|
4937
|
+
raw(voidEl("c:ptCount", { val: cats.length })),
|
|
4938
|
+
raw(dataValues(obj).map((value, idx) => numCachePt(idx, value)).join(""))
|
|
4939
|
+
]);
|
|
4940
|
+
const numRef = el("c:numRef", null, [raw(el("c:f", null, sheetRangeRef(valColRow, 2, valColRow, cats.length + 1))), raw(numCache)]);
|
|
4941
|
+
return cat + el("c:val", null, raw(numRef));
|
|
4466
4942
|
}
|
|
4467
4943
|
/** Emit the `<c:tx>` series-name reference for a stock/volume series. */
|
|
4468
4944
|
function stockSeriesName(obj) {
|
|
4469
|
-
return
|
|
4945
|
+
return strRefBlock(sheetCellRef(obj._dataIndex + dataLabels(obj).length + 1, 1), obj.name ?? "", "compact");
|
|
4470
4946
|
}
|
|
4471
4947
|
/** Emit a single stock (line) series: invisible line, optional close-marker, cat/val refs. */
|
|
4472
4948
|
function makeStockLineSer(obj, opts, valFmtCode, markCloseColor) {
|
|
4473
|
-
|
|
4474
|
-
|
|
4475
|
-
|
|
4476
|
-
|
|
4477
|
-
|
|
4478
|
-
|
|
4479
|
-
|
|
4480
|
-
|
|
4481
|
-
|
|
4482
|
-
|
|
4949
|
+
const spPr = el("c:spPr", null, [raw(el("a:ln", {
|
|
4950
|
+
w: 19050,
|
|
4951
|
+
cap: "rnd"
|
|
4952
|
+
}, [raw(voidEl("a:noFill")), raw(voidEl("a:round"))])), raw(voidEl("a:effectLst"))]);
|
|
4953
|
+
const marker = markCloseColor ? el("c:marker", null, [
|
|
4954
|
+
raw(voidEl("c:symbol", { val: "dot" })),
|
|
4955
|
+
raw(voidEl("c:size", { val: 5 })),
|
|
4956
|
+
raw(el("c:spPr", null, [
|
|
4957
|
+
raw(genXmlColorSelection(markCloseColor)),
|
|
4958
|
+
raw(el("a:ln", { w: 9525 }, raw(genXmlColorSelection(markCloseColor)))),
|
|
4959
|
+
raw(voidEl("a:effectLst"))
|
|
4960
|
+
]))
|
|
4961
|
+
]) : el("c:marker", null, raw(voidEl("c:symbol", { val: "none" })));
|
|
4962
|
+
return el("c:ser", null, [
|
|
4963
|
+
raw(voidEl("c:idx", { val: obj._dataIndex })),
|
|
4964
|
+
raw(voidEl("c:order", { val: obj._dataIndex })),
|
|
4965
|
+
raw(stockSeriesName(obj)),
|
|
4966
|
+
raw(spPr),
|
|
4967
|
+
raw(marker),
|
|
4968
|
+
raw(stockCatVal(obj, opts, valFmtCode)),
|
|
4969
|
+
raw(voidEl("c:smooth", { val: 0 }))
|
|
4970
|
+
]);
|
|
4483
4971
|
}
|
|
4484
4972
|
/**
|
|
4485
4973
|
* Plot a stock chart. For `vhlc`/`vohlc` the first data series is a Volume column drawn as a
|
|
@@ -4494,32 +4982,52 @@ function makeStockPlot(_chartType, data, opts, valAxisId, catAxisId, valFmtCode)
|
|
|
4494
4982
|
const stockSeries = spec.volume ? data.slice(1) : data;
|
|
4495
4983
|
let strXml = "";
|
|
4496
4984
|
if (volumeSeries) {
|
|
4497
|
-
|
|
4498
|
-
|
|
4499
|
-
|
|
4500
|
-
|
|
4501
|
-
|
|
4502
|
-
|
|
4503
|
-
|
|
4504
|
-
|
|
4505
|
-
strXml += "
|
|
4506
|
-
|
|
4507
|
-
|
|
4508
|
-
|
|
4509
|
-
|
|
4510
|
-
|
|
4511
|
-
|
|
4512
|
-
|
|
4513
|
-
|
|
4514
|
-
|
|
4515
|
-
}
|
|
4516
|
-
|
|
4517
|
-
|
|
4518
|
-
|
|
4985
|
+
const volumeSer = el("c:ser", null, [
|
|
4986
|
+
raw(voidEl("c:idx", { val: volumeSeries._dataIndex })),
|
|
4987
|
+
raw(voidEl("c:order", { val: volumeSeries._dataIndex })),
|
|
4988
|
+
raw(stockSeriesName(volumeSeries)),
|
|
4989
|
+
raw(el("c:spPr", null, raw(genXmlColorSelection(chartColors[0] ?? "4472C4")))),
|
|
4990
|
+
raw(voidEl("c:invertIfNegative", { val: 0 })),
|
|
4991
|
+
raw(stockCatVal(volumeSeries, opts, valFmtCode))
|
|
4992
|
+
]);
|
|
4993
|
+
strXml += el("c:barChart", null, [
|
|
4994
|
+
raw(voidEl("c:barDir", { val: "col" })),
|
|
4995
|
+
raw(voidEl("c:grouping", { val: "clustered" })),
|
|
4996
|
+
raw(voidEl("c:varyColors", { val: 0 })),
|
|
4997
|
+
raw(volumeSer),
|
|
4998
|
+
raw(STOCK_DLBLS),
|
|
4999
|
+
raw(voidEl("c:gapWidth", { val: 150 })),
|
|
5000
|
+
raw(voidEl("c:axId", { val: AXIS_ID_CATEGORY_PRIMARY })),
|
|
5001
|
+
raw(voidEl("c:axId", { val: AXIS_ID_VALUE_PRIMARY }))
|
|
5002
|
+
]);
|
|
5003
|
+
}
|
|
5004
|
+
const sers = stockSeries.map((obj, idx) => {
|
|
5005
|
+
return makeStockLineSer(obj, opts, valFmtCode, !spec.upDownBars && idx === stockSeries.length - 1 ? paletteColor(chartColors, obj._dataIndex, "ED7D31") : null);
|
|
5006
|
+
}).join("");
|
|
5007
|
+
const hiLowLines = el("c:hiLowLines", null, raw(el("c:spPr", null, [raw(dimmedTextLine(75e3, 25e3)), raw(voidEl("a:effectLst"))])));
|
|
5008
|
+
const upDownBars = spec.upDownBars ? el("c:upDownBars", null, [
|
|
5009
|
+
raw(voidEl("c:gapWidth", { val: 150 })),
|
|
5010
|
+
raw(el("c:upBars", null, raw(el("c:spPr", null, [
|
|
5011
|
+
raw(el("a:solidFill", null, raw(voidEl("a:schemeClr", { val: "bg1" })))),
|
|
5012
|
+
raw(dimmedTextLine(65e3, 35e3)),
|
|
5013
|
+
raw(voidEl("a:effectLst"))
|
|
5014
|
+
])))),
|
|
5015
|
+
raw(el("c:downBars", null, raw(el("c:spPr", null, [
|
|
5016
|
+
raw(dimmedTextFill(65e3, 35e3)),
|
|
5017
|
+
raw(dimmedTextLine(65e3, 35e3)),
|
|
5018
|
+
raw(voidEl("a:effectLst"))
|
|
5019
|
+
]))))
|
|
5020
|
+
]) : "";
|
|
4519
5021
|
const stockCatId = spec.volume ? AXIS_ID_CATEGORY_SECONDARY : catAxisId;
|
|
4520
5022
|
const stockValId = spec.volume ? AXIS_ID_VALUE_SECONDARY : valAxisId;
|
|
4521
|
-
strXml +=
|
|
4522
|
-
|
|
5023
|
+
strXml += el("c:stockChart", null, [
|
|
5024
|
+
raw(sers),
|
|
5025
|
+
raw(STOCK_DLBLS),
|
|
5026
|
+
raw(hiLowLines),
|
|
5027
|
+
raw(upDownBars),
|
|
5028
|
+
raw(voidEl("c:axId", { val: stockCatId })),
|
|
5029
|
+
raw(voidEl("c:axId", { val: stockValId }))
|
|
5030
|
+
]);
|
|
4523
5031
|
return strXml;
|
|
4524
5032
|
}
|
|
4525
5033
|
//#endregion
|
|
@@ -4530,28 +5038,30 @@ const isSurface3D = (opts) => opts.surface3D !== false;
|
|
|
4530
5038
|
function surfaceCatVal(obj, valFmtCode) {
|
|
4531
5039
|
const cats = firstLabelGroup(obj);
|
|
4532
5040
|
const valCol = obj._dataIndex + dataLabels(obj).length + 1;
|
|
4533
|
-
|
|
4534
|
-
|
|
4535
|
-
|
|
4536
|
-
|
|
4537
|
-
|
|
4538
|
-
|
|
4539
|
-
|
|
4540
|
-
strXml += `<c:numCache><c:formatCode>${valFmtCode}</c:formatCode><c:ptCount val="${cats.length}"/>`;
|
|
4541
|
-
dataValues(obj).forEach((value, idx) => strXml += numCachePt(idx, value));
|
|
4542
|
-
strXml += "</c:numCache></c:numRef></c:val>";
|
|
4543
|
-
return strXml;
|
|
5041
|
+
const numCache = el("c:numCache", null, [
|
|
5042
|
+
raw(el("c:formatCode", null, valFmtCode)),
|
|
5043
|
+
raw(voidEl("c:ptCount", { val: cats.length })),
|
|
5044
|
+
raw(dataValues(obj).map((value, idx) => numCachePt(idx, value)).join(""))
|
|
5045
|
+
]);
|
|
5046
|
+
const numRef = el("c:numRef", null, [raw(el("c:f", null, sheetRangeRef(valCol, 2, valCol, cats.length + 1))), raw(numCache)]);
|
|
5047
|
+
return el("c:cat", null, raw(catRefBlock("str", `Sheet1!$A$2:$A$${cats.length + 1}`, cats))) + el("c:val", null, raw(numRef));
|
|
4544
5048
|
}
|
|
4545
5049
|
/** Emit a single surface series: name ref, 3-D shape props, and cat/val refs. */
|
|
4546
5050
|
function makeSurfaceSer(obj, valFmtCode, seriesColor) {
|
|
4547
5051
|
const nameCol = obj._dataIndex + dataLabels(obj).length + 1;
|
|
4548
|
-
|
|
4549
|
-
|
|
4550
|
-
|
|
4551
|
-
|
|
4552
|
-
|
|
4553
|
-
|
|
4554
|
-
return
|
|
5052
|
+
const spPr = el("c:spPr", null, [
|
|
5053
|
+
raw(genXmlColorSelection(seriesColor)),
|
|
5054
|
+
raw(voidEl("a:ln")),
|
|
5055
|
+
raw(voidEl("a:effectLst")),
|
|
5056
|
+
raw(voidEl("a:sp3d"))
|
|
5057
|
+
]);
|
|
5058
|
+
return el("c:ser", null, [
|
|
5059
|
+
raw(voidEl("c:idx", { val: obj._dataIndex })),
|
|
5060
|
+
raw(voidEl("c:order", { val: obj._dataIndex })),
|
|
5061
|
+
raw(strRefBlock(sheetCellRef(nameCol, 1), obj.name ?? "", "compact")),
|
|
5062
|
+
raw(spPr),
|
|
5063
|
+
raw(surfaceCatVal(obj, valFmtCode))
|
|
5064
|
+
]);
|
|
4555
5065
|
}
|
|
4556
5066
|
/**
|
|
4557
5067
|
* Plot a surface chart into a `<c:surface3DChart>` (3-D) or `<c:surfaceChart>` (2-D contour). Every
|
|
@@ -4561,14 +5071,14 @@ function makeSurfaceSer(obj, valFmtCode, seriesColor) {
|
|
|
4561
5071
|
function makeSurfacePlot(_chartType, data, opts, valAxisId, catAxisId, valFmtCode) {
|
|
4562
5072
|
const tag = isSurface3D(opts) ? "surface3DChart" : "surfaceChart";
|
|
4563
5073
|
const chartColors = resolveChartPalette(opts);
|
|
4564
|
-
|
|
4565
|
-
|
|
4566
|
-
|
|
4567
|
-
|
|
4568
|
-
|
|
4569
|
-
|
|
4570
|
-
|
|
4571
|
-
|
|
5074
|
+
const sers = data.map((obj, idx) => makeSurfaceSer(obj, valFmtCode, paletteColor(chartColors, idx, "4472C4"))).join("");
|
|
5075
|
+
return el(`c:${tag}`, null, [
|
|
5076
|
+
raw(voidEl("c:wireframe", { val: opts.surfaceWireframe ? 1 : 0 })),
|
|
5077
|
+
raw(sers),
|
|
5078
|
+
raw(voidEl("c:axId", { val: catAxisId })),
|
|
5079
|
+
raw(voidEl("c:axId", { val: valAxisId })),
|
|
5080
|
+
raw(voidEl("c:axId", { val: AXIS_ID_SERIES_PRIMARY }))
|
|
5081
|
+
]);
|
|
4572
5082
|
}
|
|
4573
5083
|
/**
|
|
4574
5084
|
* Build the `<c:view3D>` + floor/side/back walls for a surface chart. A 3-D surface tilts the scene
|
|
@@ -4577,13 +5087,23 @@ function makeSurfacePlot(_chartType, data, opts, valAxisId, catAxisId, valFmtCod
|
|
|
4577
5087
|
* `<c:plotArea>` in CT_Chart document order (view3D → floor → sideWall → backWall → plotArea).
|
|
4578
5088
|
*/
|
|
4579
5089
|
function makeSurfaceScene(opts) {
|
|
4580
|
-
const wall = "
|
|
4581
|
-
|
|
4582
|
-
|
|
4583
|
-
|
|
4584
|
-
|
|
4585
|
-
|
|
4586
|
-
|
|
5090
|
+
const wall = voidEl("c:thickness", { val: 0 }) + el("c:spPr", null, [
|
|
5091
|
+
raw(voidEl("a:noFill")),
|
|
5092
|
+
raw(el("a:ln", null, raw(voidEl("a:noFill")))),
|
|
5093
|
+
raw(voidEl("a:effectLst")),
|
|
5094
|
+
raw(voidEl("a:sp3d"))
|
|
5095
|
+
]);
|
|
5096
|
+
const scene = isSurface3D(opts) ? [
|
|
5097
|
+
raw(voidEl("c:rotX", { val: opts.v3DRotX })),
|
|
5098
|
+
raw(voidEl("c:rotY", { val: opts.v3DRotY })),
|
|
5099
|
+
raw(voidEl("c:rAngAx", { val: 0 }))
|
|
5100
|
+
] : [
|
|
5101
|
+
raw(voidEl("c:rotX", { val: 90 })),
|
|
5102
|
+
raw(voidEl("c:rotY", { val: 0 })),
|
|
5103
|
+
raw(voidEl("c:rAngAx", { val: 0 })),
|
|
5104
|
+
raw(voidEl("c:perspective", { val: 0 }))
|
|
5105
|
+
];
|
|
5106
|
+
return el("c:view3D", null, scene) + el("c:floor", null, raw(wall)) + el("c:sideWall", null, raw(wall)) + el("c:backWall", null, raw(wall));
|
|
4587
5107
|
}
|
|
4588
5108
|
//#endregion
|
|
4589
5109
|
//#region src/gen/chart/chart-xml.ts
|
|
@@ -4602,6 +5122,12 @@ function makeSurfaceScene(opts) {
|
|
|
4602
5122
|
* written by the embedded workbook ({@link ./embed-xlsx}); that mapping lives in
|
|
4603
5123
|
* {@link ./data-refs}.
|
|
4604
5124
|
*/
|
|
5125
|
+
/** The three namespaces every `<c:chartSpace>` declares, in the order PowerPoint writes them. */
|
|
5126
|
+
const CHART_SPACE_NS = {
|
|
5127
|
+
"xmlns:c": "http://schemas.openxmlformats.org/drawingml/2006/chart",
|
|
5128
|
+
"xmlns:a": "http://schemas.openxmlformats.org/drawingml/2006/main",
|
|
5129
|
+
"xmlns:r": "http://schemas.openxmlformats.org/officeDocument/2006/relationships"
|
|
5130
|
+
};
|
|
4605
5131
|
/**
|
|
4606
5132
|
* Whether a chart-area/plot-area `fill` says anything the fill dispatch can act on.
|
|
4607
5133
|
*
|
|
@@ -4624,58 +5150,52 @@ function isStatedFill(fill) {
|
|
|
4624
5150
|
return Boolean(fill?.color || fill?.type);
|
|
4625
5151
|
}
|
|
4626
5152
|
/**
|
|
4627
|
-
*
|
|
4628
|
-
*
|
|
5153
|
+
* The chart title (or the `autoTitleDeleted` flag that suppresses PowerPoint's default one)
|
|
5154
|
+
* followed by the 3-D scene, for the two families that plot into one.
|
|
4629
5155
|
*/
|
|
4630
5156
|
function makeChartHeaderXml(rel) {
|
|
4631
|
-
const
|
|
4632
|
-
|
|
4633
|
-
|
|
4634
|
-
|
|
4635
|
-
|
|
4636
|
-
|
|
4637
|
-
|
|
4638
|
-
|
|
4639
|
-
|
|
4640
|
-
|
|
4641
|
-
|
|
4642
|
-
|
|
4643
|
-
|
|
4644
|
-
titleBold: rel.opts.titleBold,
|
|
4645
|
-
titleItalic: rel.opts.titleItalic,
|
|
4646
|
-
titleUnderline: rel.opts.titleUnderline,
|
|
4647
|
-
titlePos: rel.opts.titlePos,
|
|
4648
|
-
titleRotate: rel.opts.titleRotate
|
|
4649
|
-
}, rel.opts.x, rel.opts.y);
|
|
4650
|
-
strXml += voidEl("c:autoTitleDeleted", { val: 0 });
|
|
4651
|
-
} else strXml += voidEl("c:autoTitleDeleted", { val: 1 });
|
|
4652
|
-
/** Add 3D view tag
|
|
4653
|
-
* @see: https://c-rex.net/projects/samples/ooxml/e1/Part4/OOXML_P4_DOCX_perspective_topic_ID0E6BUQB.html
|
|
4654
|
-
*/
|
|
4655
|
-
if (rel.opts._type === "bar3D") strXml += el("c:view3D", null, [
|
|
5157
|
+
const title = rel.opts.showTitle ? genXmlTitle({
|
|
5158
|
+
title: rel.opts.title || "Chart Title",
|
|
5159
|
+
color: rel.opts.titleColor,
|
|
5160
|
+
fontFace: rel.opts.titleFontFace,
|
|
5161
|
+
fontSize: rel.opts.titleFontSize || 18,
|
|
5162
|
+
titleAlign: rel.opts.titleAlign,
|
|
5163
|
+
titleBold: rel.opts.titleBold,
|
|
5164
|
+
titleItalic: rel.opts.titleItalic,
|
|
5165
|
+
titleUnderline: rel.opts.titleUnderline,
|
|
5166
|
+
titlePos: rel.opts.titlePos,
|
|
5167
|
+
titleRotate: rel.opts.titleRotate
|
|
5168
|
+
}, rel.opts.x, rel.opts.y) + voidEl("c:autoTitleDeleted", { val: 0 }) : voidEl("c:autoTitleDeleted", { val: 1 });
|
|
5169
|
+
if (rel.opts._type === "bar3D") return title + el("c:view3D", null, [
|
|
4656
5170
|
raw(voidEl("c:rotX", { val: rel.opts.v3DRotX })),
|
|
4657
5171
|
raw(voidEl("c:rotY", { val: rel.opts.v3DRotY })),
|
|
4658
5172
|
raw(voidEl("c:rAngAx", { val: !rel.opts.v3DRAngAx ? 0 : 1 })),
|
|
4659
5173
|
raw(voidEl("c:perspective", { val: rel.opts.v3DPerspective }))
|
|
4660
5174
|
]);
|
|
4661
|
-
|
|
4662
|
-
|
|
4663
|
-
|
|
4664
|
-
|
|
4665
|
-
|
|
4666
|
-
|
|
4667
|
-
|
|
4668
|
-
|
|
4669
|
-
|
|
4670
|
-
|
|
4671
|
-
|
|
4672
|
-
|
|
4673
|
-
|
|
4674
|
-
|
|
4675
|
-
})
|
|
4676
|
-
|
|
4677
|
-
|
|
4678
|
-
|
|
5175
|
+
if (rel.opts._type === "surface") return title + makeSurfaceScene(rel.opts);
|
|
5176
|
+
return title;
|
|
5177
|
+
}
|
|
5178
|
+
/**
|
|
5179
|
+
* The plot area's `<c:layout>`. Manual layout is emitted only when the caller asked for one:
|
|
5180
|
+
* an empty `<c:layout/>` lets PowerPoint auto-fit, which it does well across all four TRBL
|
|
5181
|
+
* legend positions.
|
|
5182
|
+
*/
|
|
5183
|
+
function makePlotAreaLayoutXml(rel) {
|
|
5184
|
+
const layout = rel.opts.layout;
|
|
5185
|
+
if (!layout) return voidEl("c:layout");
|
|
5186
|
+
const manualLayout = el("c:manualLayout", null, [
|
|
5187
|
+
raw(voidEl("c:layoutTarget", { val: "inner" }, { closePrefix: " " })),
|
|
5188
|
+
raw(voidEl("c:xMode", { val: "edge" }, { closePrefix: " " })),
|
|
5189
|
+
raw(voidEl("c:yMode", { val: "edge" }, { closePrefix: " " })),
|
|
5190
|
+
raw(voidEl("c:x", { val: layout.x || 0 }, { closePrefix: " " })),
|
|
5191
|
+
raw(voidEl("c:y", { val: layout.y || 0 }, { closePrefix: " " })),
|
|
5192
|
+
raw(voidEl("c:w", { val: layout.w || 1 }, { closePrefix: " " })),
|
|
5193
|
+
raw(voidEl("c:h", { val: layout.h || 1 }, { closePrefix: " " }))
|
|
5194
|
+
], {
|
|
5195
|
+
childPrefix: " ",
|
|
5196
|
+
closePrefix: " "
|
|
5197
|
+
});
|
|
5198
|
+
return el("c:layout", null, raw(manualLayout), { childPrefix: " " });
|
|
4679
5199
|
}
|
|
4680
5200
|
/**
|
|
4681
5201
|
* Build the category/value/series axis XML (empty for pie/doughnut). Resolves combo-chart
|
|
@@ -4745,97 +5265,132 @@ function makeChartAxesXml(rel, usesSecondaryValAxis, usesSecondaryCatAxis, prima
|
|
|
4745
5265
|
return strXml;
|
|
4746
5266
|
}
|
|
4747
5267
|
/**
|
|
4748
|
-
*
|
|
5268
|
+
* The `<c:spPr>` shared by the plot area and the chart space: a stated fill or none, a border
|
|
5269
|
+
* or an explicit no-line, and an empty effect list. The two differ only in how far in they are
|
|
5270
|
+
* indented, which is what `fmt` and `effectIndent` carry.
|
|
4749
5271
|
*/
|
|
4750
|
-
function
|
|
4751
|
-
|
|
4752
|
-
|
|
4753
|
-
|
|
4754
|
-
|
|
4755
|
-
|
|
4756
|
-
|
|
4757
|
-
|
|
4758
|
-
|
|
4759
|
-
|
|
4760
|
-
|
|
4761
|
-
|
|
4762
|
-
|
|
4763
|
-
|
|
4764
|
-
|
|
4765
|
-
|
|
4766
|
-
|
|
4767
|
-
|
|
4768
|
-
|
|
4769
|
-
|
|
4770
|
-
|
|
4771
|
-
|
|
4772
|
-
|
|
4773
|
-
|
|
4774
|
-
|
|
4775
|
-
|
|
4776
|
-
|
|
4777
|
-
|
|
4778
|
-
|
|
4779
|
-
|
|
4780
|
-
|
|
4781
|
-
|
|
4782
|
-
|
|
4783
|
-
|
|
4784
|
-
|
|
4785
|
-
|
|
4786
|
-
|
|
4787
|
-
|
|
4788
|
-
|
|
4789
|
-
|
|
4790
|
-
|
|
4791
|
-
|
|
4792
|
-
|
|
4793
|
-
|
|
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
|
-
|
|
4829
|
-
|
|
4830
|
-
|
|
4831
|
-
|
|
4832
|
-
|
|
4833
|
-
|
|
4834
|
-
|
|
5272
|
+
function chartShapeProps(fill, border, effectIndent, fmt) {
|
|
5273
|
+
return el("c:spPr", null, [
|
|
5274
|
+
raw(isStatedFill(fill) ? genXmlColorSelection(fill) : voidEl("a:noFill")),
|
|
5275
|
+
raw(border ? el("a:ln", {
|
|
5276
|
+
w: ptsToEmuLenient(resolveBorderWidth(border, 1)),
|
|
5277
|
+
cap: "flat"
|
|
5278
|
+
}, raw(genXmlColorSelection({
|
|
5279
|
+
color: border.color ?? "363636",
|
|
5280
|
+
transparency: border.transparency
|
|
5281
|
+
}))) : el("a:ln", null, raw(voidEl("a:noFill")))),
|
|
5282
|
+
raw(voidEl("a:effectLst", null, { openPrefix: effectIndent }))
|
|
5283
|
+
], fmt);
|
|
5284
|
+
}
|
|
5285
|
+
/**
|
|
5286
|
+
* The `<c:dTable>` grid drawn under the plot. Sits between the last `</c:valAx>` and the plot
|
|
5287
|
+
* area's own `<c:spPr>`.
|
|
5288
|
+
*/
|
|
5289
|
+
function makeDataTableXml(rel) {
|
|
5290
|
+
const spPr = el("c:spPr", null, [
|
|
5291
|
+
raw(voidEl("a:noFill", null, { openPrefix: " " })),
|
|
5292
|
+
raw(dimmedTextLine(15e3, 85e3, { openPrefix: " " })),
|
|
5293
|
+
raw(voidEl("a:effectLst", null, { openPrefix: " " }))
|
|
5294
|
+
], {
|
|
5295
|
+
openPrefix: " ",
|
|
5296
|
+
closePrefix: " "
|
|
5297
|
+
});
|
|
5298
|
+
const defRPr = el("a:defRPr", {
|
|
5299
|
+
sz: ptToHundredths(rel.opts.dataTableFontSize || 12),
|
|
5300
|
+
b: 0,
|
|
5301
|
+
i: 0,
|
|
5302
|
+
u: "none",
|
|
5303
|
+
strike: "noStrike",
|
|
5304
|
+
kern: 1200,
|
|
5305
|
+
baseline: 0
|
|
5306
|
+
}, [
|
|
5307
|
+
raw(" " + dimmedTextFill(65e3, 35e3)),
|
|
5308
|
+
raw(voidEl("a:latin", { typeface: "+mn-lt" }, { openPrefix: " " })),
|
|
5309
|
+
raw(voidEl("a:ea", { typeface: "+mn-ea" }, { openPrefix: " " })),
|
|
5310
|
+
raw(voidEl("a:cs", { typeface: "+mn-cs" }, { openPrefix: " " }))
|
|
5311
|
+
], {
|
|
5312
|
+
openPrefix: " ",
|
|
5313
|
+
closePrefix: " "
|
|
5314
|
+
});
|
|
5315
|
+
const txPr = el("c:txPr", null, [
|
|
5316
|
+
raw(voidEl("a:bodyPr", {
|
|
5317
|
+
rot: 0,
|
|
5318
|
+
spcFirstLastPara: 1,
|
|
5319
|
+
vertOverflow: "ellipsis",
|
|
5320
|
+
vert: "horz",
|
|
5321
|
+
wrap: "square",
|
|
5322
|
+
anchor: "ctr",
|
|
5323
|
+
anchorCtr: 1
|
|
5324
|
+
}, { openPrefix: " " })),
|
|
5325
|
+
raw(voidEl("a:lstStyle", null, { openPrefix: " " })),
|
|
5326
|
+
raw(el("a:p", null, [raw(el("a:pPr", { rtl: 0 }, raw(defRPr), {
|
|
5327
|
+
openPrefix: " ",
|
|
5328
|
+
closePrefix: " "
|
|
5329
|
+
})), raw(voidEl("a:endParaRPr", { lang: "en-US" }, { openPrefix: " " }))], {
|
|
5330
|
+
openPrefix: " ",
|
|
5331
|
+
closePrefix: " "
|
|
5332
|
+
}))
|
|
5333
|
+
], {
|
|
5334
|
+
openPrefix: " ",
|
|
5335
|
+
closePrefix: " "
|
|
5336
|
+
});
|
|
5337
|
+
return el("c:dTable", null, [
|
|
5338
|
+
raw(voidEl("c:showHorzBorder", { val: !rel.opts.showDataTableHorzBorder ? 0 : 1 }, { openPrefix: " " })),
|
|
5339
|
+
raw(voidEl("c:showVertBorder", { val: !rel.opts.showDataTableVertBorder ? 0 : 1 }, { openPrefix: " " })),
|
|
5340
|
+
raw(` <c:showOutline val="${!rel.opts.showDataTableOutline ? 0 : 1}"/>`),
|
|
5341
|
+
raw(` <c:showKeys val="${!rel.opts.showDataTableKeys ? 0 : 1}"/>`),
|
|
5342
|
+
raw(spPr),
|
|
5343
|
+
raw(txPr)
|
|
5344
|
+
]);
|
|
5345
|
+
}
|
|
5346
|
+
/**
|
|
5347
|
+
* The `<c:legend>`: position, the entries a combo chart deletes, an optional manual placement,
|
|
5348
|
+
* and the text properties when any legend font option is set.
|
|
5349
|
+
*/
|
|
5350
|
+
function makeLegendXml(rel) {
|
|
5351
|
+
let entries = "";
|
|
5352
|
+
if (Array.isArray(rel.opts._type)) {
|
|
5353
|
+
let seriesIdx = 0;
|
|
5354
|
+
for (const type of rel.opts._type) {
|
|
5355
|
+
if (type.options?.showLegend === false) for (let i = 0; i < type.data.length; i++) entries += el("c:legendEntry", null, [raw(voidEl("c:idx", { val: seriesIdx + i })), raw(voidEl("c:delete", { val: 1 }))]);
|
|
5356
|
+
seriesIdx += type.data.length;
|
|
4835
5357
|
}
|
|
4836
|
-
strXml += "</c:legend>";
|
|
4837
5358
|
}
|
|
4838
|
-
|
|
5359
|
+
const legendLayout = rel.opts.legendLayout;
|
|
5360
|
+
const placed = (key) => typeof legendLayout?.[key] === "number";
|
|
5361
|
+
let layout = "";
|
|
5362
|
+
if (placed("x") || placed("y") || placed("w") || placed("h")) {
|
|
5363
|
+
const modes = (placed("x") ? voidEl("c:xMode", { val: "edge" }) : "") + (placed("y") ? voidEl("c:yMode", { val: "edge" }) : "");
|
|
5364
|
+
const vals = [
|
|
5365
|
+
"x",
|
|
5366
|
+
"y",
|
|
5367
|
+
"w",
|
|
5368
|
+
"h"
|
|
5369
|
+
].filter(placed).map((key) => voidEl(`c:${key}`, { val: legendLayout?.[key] })).join("");
|
|
5370
|
+
layout = el("c:layout", null, raw(el("c:manualLayout", null, raw(modes + vals))));
|
|
5371
|
+
}
|
|
5372
|
+
let txPr = "";
|
|
5373
|
+
if (rel.opts.legendFontFace || rel.opts.legendFontSize || rel.opts.legendColor) {
|
|
5374
|
+
const defRPr = el("a:defRPr", { sz: rel.opts.legendFontSize ? ptToHundredths(rel.opts.legendFontSize) : void 0 }, [raw(rel.opts.legendColor ? genXmlColorSelection(rel.opts.legendColor) : ""), raw(rel.opts.legendFontFace ? createChartTextFonts(rel.opts.legendFontFace) : "")], { closePrefix: " " });
|
|
5375
|
+
txPr = el("c:txPr", null, [
|
|
5376
|
+
raw(voidEl("a:bodyPr", null, { openPrefix: " " })),
|
|
5377
|
+
raw(voidEl("a:lstStyle", null, { openPrefix: " " })),
|
|
5378
|
+
raw(el("a:p", null, [raw(el("a:pPr", null, raw(defRPr), {
|
|
5379
|
+
openPrefix: " ",
|
|
5380
|
+
closePrefix: " "
|
|
5381
|
+
})), raw(voidEl("a:endParaRPr", { lang: "en-US" }, { openPrefix: " " }))], {
|
|
5382
|
+
openPrefix: " ",
|
|
5383
|
+
closePrefix: " "
|
|
5384
|
+
}))
|
|
5385
|
+
]);
|
|
5386
|
+
}
|
|
5387
|
+
return el("c:legend", null, [
|
|
5388
|
+
raw(voidEl("c:legendPos", { val: rel.opts.legendPos })),
|
|
5389
|
+
raw(entries),
|
|
5390
|
+
raw(layout),
|
|
5391
|
+
raw(voidEl("c:overlay", { val: 0 })),
|
|
5392
|
+
raw(txPr)
|
|
5393
|
+
]);
|
|
4839
5394
|
}
|
|
4840
5395
|
/**
|
|
4841
5396
|
* Main entry point method for create charts
|
|
@@ -4844,16 +5399,16 @@ function makeChartPlotAreaPropsXml(rel) {
|
|
|
4844
5399
|
* @return {string} XML
|
|
4845
5400
|
*/
|
|
4846
5401
|
function makeXmlCharts(rel) {
|
|
4847
|
-
let strXml = XML_DECL;
|
|
4848
5402
|
const chartArea = rel.opts.chartArea ?? {};
|
|
5403
|
+
const plotAreaOpts = rel.opts.plotArea ?? {};
|
|
4849
5404
|
let usesSecondaryValAxis = false;
|
|
4850
5405
|
let usesSecondaryCatAxis = false;
|
|
4851
5406
|
let primaryCatAxisValType = null;
|
|
4852
5407
|
let secondaryCatAxisValType = null;
|
|
4853
5408
|
let primaryCatAxisHasCategoryChart = false;
|
|
4854
5409
|
let secondaryCatAxisHasCategoryChart = false;
|
|
4855
|
-
|
|
4856
|
-
if (Array.isArray(rel.opts._type)) rel.opts._type
|
|
5410
|
+
let plots = "";
|
|
5411
|
+
if (Array.isArray(rel.opts._type)) for (const type of rel.opts._type) {
|
|
4857
5412
|
const options = {
|
|
4858
5413
|
...rel.opts,
|
|
4859
5414
|
...type.options
|
|
@@ -4869,27 +5424,36 @@ function makeXmlCharts(rel) {
|
|
|
4869
5424
|
else secondaryCatAxisHasCategoryChart = true;
|
|
4870
5425
|
} else if (usesValueXAxis) primaryCatAxisValType = subType;
|
|
4871
5426
|
else primaryCatAxisHasCategoryChart = true;
|
|
4872
|
-
|
|
4873
|
-
}
|
|
4874
|
-
else if (rel.opts._type)
|
|
4875
|
-
|
|
4876
|
-
|
|
4877
|
-
|
|
4878
|
-
|
|
4879
|
-
|
|
4880
|
-
|
|
4881
|
-
|
|
4882
|
-
|
|
4883
|
-
|
|
4884
|
-
|
|
4885
|
-
|
|
4886
|
-
|
|
4887
|
-
|
|
4888
|
-
|
|
4889
|
-
|
|
4890
|
-
|
|
4891
|
-
|
|
4892
|
-
|
|
5427
|
+
plots += makeChartType(subType, type.data, options, valAxisId, catAxisId);
|
|
5428
|
+
}
|
|
5429
|
+
else if (rel.opts._type) plots = makeChartType(rel.opts._type, rel.data, rel.opts, AXIS_ID_VALUE_PRIMARY, AXIS_ID_CATEGORY_PRIMARY);
|
|
5430
|
+
const axes = makeChartAxesXml(rel, usesSecondaryValAxis, usesSecondaryCatAxis, primaryCatAxisValType, secondaryCatAxisValType, primaryCatAxisHasCategoryChart, secondaryCatAxisHasCategoryChart);
|
|
5431
|
+
const plotArea = el("c:plotArea", null, [
|
|
5432
|
+
raw(makePlotAreaLayoutXml(rel)),
|
|
5433
|
+
raw(plots),
|
|
5434
|
+
raw(axes),
|
|
5435
|
+
rel.opts.showDataTable ? raw(makeDataTableXml(rel)) : null,
|
|
5436
|
+
raw(chartShapeProps(plotAreaOpts.fill, plotAreaOpts.border, " ", {
|
|
5437
|
+
openPrefix: " ",
|
|
5438
|
+
closePrefix: " "
|
|
5439
|
+
}))
|
|
5440
|
+
]);
|
|
5441
|
+
const chart = el("c:chart", null, [
|
|
5442
|
+
raw(makeChartHeaderXml(rel)),
|
|
5443
|
+
raw(plotArea),
|
|
5444
|
+
rel.opts.showLegend ? raw(makeLegendXml(rel)) : null,
|
|
5445
|
+
raw(voidEl("c:plotVisOnly", { val: 1 }, { openPrefix: " " })),
|
|
5446
|
+
raw(voidEl("c:dispBlanksAs", { val: rel.opts.displayBlanksAs }, { openPrefix: " " })),
|
|
5447
|
+
rel.opts._type === "scatter" ? raw(voidEl("c:showDLblsOverMax", { val: 1 })) : null
|
|
5448
|
+
]);
|
|
5449
|
+
return XML_DECL + el("c:chartSpace", CHART_SPACE_NS, [
|
|
5450
|
+
raw(voidEl("c:date1904", { val: 0 })),
|
|
5451
|
+
raw(voidEl("c:roundedCorners", { val: chartArea.roundedCorners ? 1 : 0 })),
|
|
5452
|
+
raw(chart),
|
|
5453
|
+
raw(chartShapeProps(chartArea.fill, chartArea.border, " ", {})),
|
|
5454
|
+
raw(el("c:externalData", { "r:id": "rId1" }, raw(voidEl("c:autoUpdate", { val: 0 })))),
|
|
5455
|
+
raw(genXmlChartMetadata(rel.opts.metadata))
|
|
5456
|
+
]);
|
|
4893
5457
|
}
|
|
4894
5458
|
/**
|
|
4895
5459
|
* Stable ts-pptx vendor GUID identifying the chart-metadata extension on `c:chartSpace/c:extLst`.
|
|
@@ -4944,7 +5508,7 @@ function genXmlChartMetadata(metadata) {
|
|
|
4944
5508
|
* @return {string} XML chart
|
|
4945
5509
|
*/
|
|
4946
5510
|
function makeChartType(chartType, data, opts, valAxisId, catAxisId) {
|
|
4947
|
-
const valFmtCode =
|
|
5511
|
+
const valFmtCode = opts.valLabelFormatCode || opts.dataTableFormatCode || opts.dataLabelFormatCode || "General";
|
|
4948
5512
|
switch (chartType) {
|
|
4949
5513
|
case "area":
|
|
4950
5514
|
case "bar":
|
|
@@ -5328,6 +5892,13 @@ function makeChartExStyleXml() {
|
|
|
5328
5892
|
//#region src/gen/chart/embed-xlsx.ts
|
|
5329
5893
|
/** MS chart-extension relationship types (chartEx style + color-style sidecar parts). */
|
|
5330
5894
|
const MS_CHART_REL = "http://schemas.microsoft.com/office/2011/relationships/";
|
|
5895
|
+
/** The SpreadsheetML namespace every part of the embedded workbook is written in. */
|
|
5896
|
+
const SML_NS = "http://schemas.openxmlformats.org/spreadsheetml/2006/main";
|
|
5897
|
+
/** OPC content types, and the prefix the four SpreadsheetML part types share. */
|
|
5898
|
+
const CT_NS = "http://schemas.openxmlformats.org/package/2006/content-types";
|
|
5899
|
+
const SML_CT = "application/vnd.openxmlformats-officedocument.spreadsheetml.";
|
|
5900
|
+
/** One `<si>` shared string carrying literal text. */
|
|
5901
|
+
const sharedString = (text) => el("si", null, raw(el("t", null, text)));
|
|
5331
5902
|
function relationship$2(id, type, target) {
|
|
5332
5903
|
return voidEl("Relationship", {
|
|
5333
5904
|
Id: id,
|
|
@@ -5340,6 +5911,17 @@ function relationships(rels) {
|
|
|
5340
5911
|
return el("Relationships", { xmlns: PACKAGE_REL_NS }, rels.map(raw));
|
|
5341
5912
|
}
|
|
5342
5913
|
/**
|
|
5914
|
+
* The embedded workbook's style sheet, captured verbatim from an Excel-authored chart workbook.
|
|
5915
|
+
* @raw-xml-asset
|
|
5916
|
+
*/
|
|
5917
|
+
const XLSX_STYLES_XML = "<styleSheet xmlns=\"http://schemas.openxmlformats.org/spreadsheetml/2006/main\"><numFmts count=\"1\"><numFmt numFmtId=\"0\" formatCode=\"General\"/></numFmts><fonts count=\"4\"><font><sz val=\"9\"/><color indexed=\"8\"/><name val=\"Geneva\"/></font><font><sz val=\"9\"/><color indexed=\"8\"/><name val=\"Geneva\"/></font><font><sz val=\"10\"/><color indexed=\"8\"/><name val=\"Geneva\"/></font><font><sz val=\"18\"/><color indexed=\"8\"/><name val=\"Arial\"/></font></fonts><fills count=\"2\"><fill><patternFill patternType=\"none\"/></fill><fill><patternFill patternType=\"gray125\"/></fill></fills><borders count=\"1\"><border><left/><right/><top/><bottom/><diagonal/></border></borders><dxfs count=\"0\"/><tableStyles count=\"0\"/><colors><indexedColors><rgbColor rgb=\"ff000000\"/><rgbColor rgb=\"ffffffff\"/><rgbColor rgb=\"ffff0000\"/><rgbColor rgb=\"ff00ff00\"/><rgbColor rgb=\"ff0000ff\"/><rgbColor rgb=\"ffffff00\"/><rgbColor rgb=\"ffff00ff\"/><rgbColor rgb=\"ff00ffff\"/><rgbColor rgb=\"ff000000\"/><rgbColor rgb=\"ffffffff\"/><rgbColor rgb=\"ff878787\"/><rgbColor rgb=\"fff9f9f9\"/></indexedColors></colors></styleSheet>\n";
|
|
5918
|
+
/**
|
|
5919
|
+
* The Office theme the embedded workbook ships, captured verbatim. PowerPoint reads it when a user
|
|
5920
|
+
* opens the chart's data, so it has to be exactly the bytes Office writes.
|
|
5921
|
+
* @raw-xml-asset
|
|
5922
|
+
*/
|
|
5923
|
+
const XLSX_THEME_XML = "<a:theme xmlns:a=\"http://schemas.openxmlformats.org/drawingml/2006/main\" name=\"Office Theme\"><a:themeElements><a:clrScheme name=\"Office\"><a:dk1><a:sysClr val=\"windowText\" lastClr=\"000000\"/></a:dk1><a:lt1><a:sysClr val=\"window\" lastClr=\"FFFFFF\"/></a:lt1><a:dk2><a:srgbClr val=\"44546A\"/></a:dk2><a:lt2><a:srgbClr val=\"E7E6E6\"/></a:lt2><a:accent1><a:srgbClr val=\"4472C4\"/></a:accent1><a:accent2><a:srgbClr val=\"ED7D31\"/></a:accent2><a:accent3><a:srgbClr val=\"A5A5A5\"/></a:accent3><a:accent4><a:srgbClr val=\"FFC000\"/></a:accent4><a:accent5><a:srgbClr val=\"5B9BD5\"/></a:accent5><a:accent6><a:srgbClr val=\"70AD47\"/></a:accent6><a:hlink><a:srgbClr val=\"0563C1\"/></a:hlink><a:folHlink><a:srgbClr val=\"954F72\"/></a:folHlink></a:clrScheme><a:fontScheme name=\"Office\"><a:majorFont><a:latin typeface=\"Calibri Light\" panose=\"020F0302020204030204\"/><a:ea typeface=\"\"/><a:cs typeface=\"\"/><a:font script=\"Jpan\" typeface=\"Yu Gothic Light\"/><a:font script=\"Hang\" typeface=\"맑은 고딕\"/><a:font script=\"Hans\" typeface=\"DengXian Light\"/><a:font script=\"Hant\" typeface=\"新細明體\"/><a:font script=\"Arab\" typeface=\"Times New Roman\"/><a:font script=\"Hebr\" typeface=\"Times New Roman\"/><a:font script=\"Thai\" typeface=\"Tahoma\"/><a:font script=\"Ethi\" typeface=\"Nyala\"/><a:font script=\"Beng\" typeface=\"Vrinda\"/><a:font script=\"Gujr\" typeface=\"Shruti\"/><a:font script=\"Khmr\" typeface=\"MoolBoran\"/><a:font script=\"Knda\" typeface=\"Tunga\"/><a:font script=\"Guru\" typeface=\"Raavi\"/><a:font script=\"Cans\" typeface=\"Euphemia\"/><a:font script=\"Cher\" typeface=\"Plantagenet Cherokee\"/><a:font script=\"Yiii\" typeface=\"Microsoft Yi Baiti\"/><a:font script=\"Tibt\" typeface=\"Microsoft Himalaya\"/><a:font script=\"Thaa\" typeface=\"MV Boli\"/><a:font script=\"Deva\" typeface=\"Mangal\"/><a:font script=\"Telu\" typeface=\"Gautami\"/><a:font script=\"Taml\" typeface=\"Latha\"/><a:font script=\"Syrc\" typeface=\"Estrangelo Edessa\"/><a:font script=\"Orya\" typeface=\"Kalinga\"/><a:font script=\"Mlym\" typeface=\"Kartika\"/><a:font script=\"Laoo\" typeface=\"DokChampa\"/><a:font script=\"Sinh\" typeface=\"Iskoola Pota\"/><a:font script=\"Mong\" typeface=\"Mongolian Baiti\"/><a:font script=\"Viet\" typeface=\"Times New Roman\"/><a:font script=\"Uigh\" typeface=\"Microsoft Uighur\"/><a:font script=\"Geor\" typeface=\"Sylfaen\"/></a:majorFont><a:minorFont><a:latin typeface=\"Calibri\" panose=\"020F0502020204030204\"/><a:ea typeface=\"\"/><a:cs typeface=\"\"/><a:font script=\"Jpan\" typeface=\"Yu Gothic\"/><a:font script=\"Hang\" typeface=\"맑은 고딕\"/><a:font script=\"Hans\" typeface=\"DengXian\"/><a:font script=\"Hant\" typeface=\"新細明體\"/><a:font script=\"Arab\" typeface=\"Arial\"/><a:font script=\"Hebr\" typeface=\"Arial\"/><a:font script=\"Thai\" typeface=\"Tahoma\"/><a:font script=\"Ethi\" typeface=\"Nyala\"/><a:font script=\"Beng\" typeface=\"Vrinda\"/><a:font script=\"Gujr\" typeface=\"Shruti\"/><a:font script=\"Khmr\" typeface=\"DaunPenh\"/><a:font script=\"Knda\" typeface=\"Tunga\"/><a:font script=\"Guru\" typeface=\"Raavi\"/><a:font script=\"Cans\" typeface=\"Euphemia\"/><a:font script=\"Cher\" typeface=\"Plantagenet Cherokee\"/><a:font script=\"Yiii\" typeface=\"Microsoft Yi Baiti\"/><a:font script=\"Tibt\" typeface=\"Microsoft Himalaya\"/><a:font script=\"Thaa\" typeface=\"MV Boli\"/><a:font script=\"Deva\" typeface=\"Mangal\"/><a:font script=\"Telu\" typeface=\"Gautami\"/><a:font script=\"Taml\" typeface=\"Latha\"/><a:font script=\"Syrc\" typeface=\"Estrangelo Edessa\"/><a:font script=\"Orya\" typeface=\"Kalinga\"/><a:font script=\"Mlym\" typeface=\"Kartika\"/><a:font script=\"Laoo\" typeface=\"DokChampa\"/><a:font script=\"Sinh\" typeface=\"Iskoola Pota\"/><a:font script=\"Mong\" typeface=\"Mongolian Baiti\"/><a:font script=\"Viet\" typeface=\"Arial\"/><a:font script=\"Uigh\" typeface=\"Microsoft Uighur\"/><a:font script=\"Geor\" typeface=\"Sylfaen\"/></a:minorFont></a:fontScheme><a:fmtScheme name=\"Office\"><a:fillStyleLst><a:solidFill><a:schemeClr val=\"phClr\"/></a:solidFill><a:gradFill rotWithShape=\"1\"><a:gsLst><a:gs pos=\"0\"><a:schemeClr val=\"phClr\"><a:lumMod val=\"110000\"/><a:satMod val=\"105000\"/><a:tint val=\"67000\"/></a:schemeClr></a:gs><a:gs pos=\"50000\"><a:schemeClr val=\"phClr\"><a:lumMod val=\"105000\"/><a:satMod val=\"103000\"/><a:tint val=\"73000\"/></a:schemeClr></a:gs><a:gs pos=\"100000\"><a:schemeClr val=\"phClr\"><a:lumMod val=\"105000\"/><a:satMod val=\"109000\"/><a:tint val=\"81000\"/></a:schemeClr></a:gs></a:gsLst><a:lin ang=\"5400000\" scaled=\"0\"/></a:gradFill><a:gradFill rotWithShape=\"1\"><a:gsLst><a:gs pos=\"0\"><a:schemeClr val=\"phClr\"><a:satMod val=\"103000\"/><a:lumMod val=\"102000\"/><a:tint val=\"94000\"/></a:schemeClr></a:gs><a:gs pos=\"50000\"><a:schemeClr val=\"phClr\"><a:satMod val=\"110000\"/><a:lumMod val=\"100000\"/><a:shade val=\"100000\"/></a:schemeClr></a:gs><a:gs pos=\"100000\"><a:schemeClr val=\"phClr\"><a:lumMod val=\"99000\"/><a:satMod val=\"120000\"/><a:shade val=\"78000\"/></a:schemeClr></a:gs></a:gsLst><a:lin ang=\"5400000\" scaled=\"0\"/></a:gradFill></a:fillStyleLst><a:lnStyleLst><a:ln w=\"6350\" cap=\"flat\" cmpd=\"sng\" algn=\"ctr\"><a:solidFill><a:schemeClr val=\"phClr\"/></a:solidFill><a:prstDash val=\"solid\"/><a:miter lim=\"800000\"/></a:ln><a:ln w=\"12700\" cap=\"flat\" cmpd=\"sng\" algn=\"ctr\"><a:solidFill><a:schemeClr val=\"phClr\"/></a:solidFill><a:prstDash val=\"solid\"/><a:miter lim=\"800000\"/></a:ln><a:ln w=\"19050\" cap=\"flat\" cmpd=\"sng\" algn=\"ctr\"><a:solidFill><a:schemeClr val=\"phClr\"/></a:solidFill><a:prstDash val=\"solid\"/><a:miter lim=\"800000\"/></a:ln></a:lnStyleLst><a:effectStyleLst><a:effectStyle><a:effectLst/></a:effectStyle><a:effectStyle><a:effectLst/></a:effectStyle><a:effectStyle><a:effectLst><a:outerShdw blurRad=\"57150\" dist=\"19050\" dir=\"5400000\" algn=\"ctr\" rotWithShape=\"0\"><a:srgbClr val=\"000000\"><a:alpha val=\"63000\"/></a:srgbClr></a:outerShdw></a:effectLst></a:effectStyle></a:effectStyleLst><a:bgFillStyleLst><a:solidFill><a:schemeClr val=\"phClr\"/></a:solidFill><a:solidFill><a:schemeClr val=\"phClr\"><a:tint val=\"95000\"/><a:satMod val=\"170000\"/></a:schemeClr></a:solidFill><a:gradFill rotWithShape=\"1\"><a:gsLst><a:gs pos=\"0\"><a:schemeClr val=\"phClr\"><a:tint val=\"93000\"/><a:satMod val=\"150000\"/><a:shade val=\"98000\"/><a:lumMod val=\"102000\"/></a:schemeClr></a:gs><a:gs pos=\"50000\"><a:schemeClr val=\"phClr\"><a:tint val=\"98000\"/><a:satMod val=\"130000\"/><a:shade val=\"90000\"/><a:lumMod val=\"103000\"/></a:schemeClr></a:gs><a:gs pos=\"100000\"><a:schemeClr val=\"phClr\"><a:shade val=\"63000\"/><a:satMod val=\"120000\"/></a:schemeClr></a:gs></a:gsLst><a:lin ang=\"5400000\" scaled=\"0\"/></a:gradFill></a:bgFillStyleLst></a:fmtScheme></a:themeElements><a:objectDefaults/><a:extraClrSchemeLst/><a:extLst><a:ext uri=\"{05A4C25C-085E-4340-85A3-A5531E510DB2}\"><thm15:themeFamily xmlns:thm15=\"http://schemas.microsoft.com/office/thememl/2012/main\" name=\"Office Theme\" id=\"{62F939B6-93AF-4DB8-9C6B-D6C7DFDC589F}\" vid=\"{4A3C46E8-61CC-4603-A589-7422A47A8E4A}\"/></a:ext></a:extLst></a:theme>";
|
|
5924
|
+
/**
|
|
5343
5925
|
* Build the chart's embedded Excel workbook as a standalone OPC package and
|
|
5344
5926
|
* return its bytes — the data source PowerPoint opens when a user edits the
|
|
5345
5927
|
* chart's data. Pure (no zip side effects), so both the package write path
|
|
@@ -5354,24 +5936,108 @@ function buildEmbeddedWorksheet(chartObject) {
|
|
|
5354
5936
|
const zipExcel = new ZipWriter();
|
|
5355
5937
|
const intBubbleCols = (data.length - 1) * 2 + 1;
|
|
5356
5938
|
const IS_MULTI_CAT_AXES = (data[0]?.labels?.length ?? 0) > 1;
|
|
5357
|
-
|
|
5358
|
-
|
|
5359
|
-
|
|
5360
|
-
|
|
5361
|
-
|
|
5362
|
-
|
|
5363
|
-
|
|
5364
|
-
|
|
5365
|
-
|
|
5366
|
-
|
|
5367
|
-
|
|
5368
|
-
|
|
5369
|
-
|
|
5370
|
-
|
|
5371
|
-
|
|
5372
|
-
|
|
5373
|
-
|
|
5374
|
-
|
|
5939
|
+
{
|
|
5940
|
+
const override = (partName, contentType) => voidEl("Override", {
|
|
5941
|
+
PartName: partName,
|
|
5942
|
+
ContentType: contentType
|
|
5943
|
+
}, { openPrefix: " " });
|
|
5944
|
+
zipExcel.add("[Content_Types].xml", XML_DECL + el("Types", { xmlns: CT_NS }, [
|
|
5945
|
+
raw(voidEl("Default", {
|
|
5946
|
+
Extension: "rels",
|
|
5947
|
+
ContentType: "application/vnd.openxmlformats-package.relationships+xml"
|
|
5948
|
+
}, { openPrefix: " " })),
|
|
5949
|
+
raw(voidEl("Default", {
|
|
5950
|
+
Extension: "xml",
|
|
5951
|
+
ContentType: "application/xml"
|
|
5952
|
+
}, { openPrefix: " " })),
|
|
5953
|
+
raw(override("/xl/workbook.xml", SML_CT + "sheet.main+xml")),
|
|
5954
|
+
raw(override("/xl/worksheets/sheet1.xml", SML_CT + "worksheet+xml")),
|
|
5955
|
+
raw(override("/xl/theme/theme1.xml", "application/vnd.openxmlformats-officedocument.theme+xml")),
|
|
5956
|
+
raw(override("/xl/styles.xml", SML_CT + "styles+xml")),
|
|
5957
|
+
raw(override("/xl/sharedStrings.xml", SML_CT + "sharedStrings+xml")),
|
|
5958
|
+
raw(override("/xl/tables/table1.xml", SML_CT + "table+xml")),
|
|
5959
|
+
raw(override("/docProps/core.xml", "application/vnd.openxmlformats-package.core-properties+xml")),
|
|
5960
|
+
raw(override("/docProps/app.xml", "application/vnd.openxmlformats-officedocument.extended-properties+xml"))
|
|
5961
|
+
]) + "\n");
|
|
5962
|
+
zipExcel.add("_rels/.rels", XML_DECL + relationships([
|
|
5963
|
+
relationship$2("rId1", PACKAGE_REL_NS + "/metadata/core-properties", "docProps/core.xml"),
|
|
5964
|
+
relationship$2("rId2", OFFICE_REL + "extended-properties", "docProps/app.xml"),
|
|
5965
|
+
relationship$2("rId3", OFFICE_REL + "officeDocument", "xl/workbook.xml")
|
|
5966
|
+
]) + "\n");
|
|
5967
|
+
const headingPairs = el("vt:vector", {
|
|
5968
|
+
size: 2,
|
|
5969
|
+
baseType: "variant"
|
|
5970
|
+
}, [raw(el("vt:variant", null, raw(el("vt:lpstr", null, "Worksheets")))), raw(el("vt:variant", null, raw(el("vt:i4", null, 1))))]);
|
|
5971
|
+
zipExcel.add("docProps/app.xml", XML_DECL + el("Properties", {
|
|
5972
|
+
xmlns: "http://schemas.openxmlformats.org/officeDocument/2006/extended-properties",
|
|
5973
|
+
"xmlns:vt": "http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes"
|
|
5974
|
+
}, [
|
|
5975
|
+
raw(el("Application", null, "Microsoft Macintosh Excel")),
|
|
5976
|
+
raw(el("DocSecurity", null, 0)),
|
|
5977
|
+
raw(el("ScaleCrop", null, "false")),
|
|
5978
|
+
raw(el("HeadingPairs", null, raw(headingPairs))),
|
|
5979
|
+
raw(el("TitlesOfParts", null, raw(el("vt:vector", {
|
|
5980
|
+
size: 1,
|
|
5981
|
+
baseType: "lpstr"
|
|
5982
|
+
}, raw(el("vt:lpstr", null, "Sheet1")))))),
|
|
5983
|
+
raw(el("Company", null)),
|
|
5984
|
+
raw(el("LinksUpToDate", null, "false")),
|
|
5985
|
+
raw(el("SharedDoc", null, "false")),
|
|
5986
|
+
raw(el("HyperlinksChanged", null, "false")),
|
|
5987
|
+
raw(el("AppVersion", null, "16.0300"))
|
|
5988
|
+
]) + "\n");
|
|
5989
|
+
zipExcel.add("docProps/core.xml", XML_DECL + el("cp:coreProperties", {
|
|
5990
|
+
"xmlns:cp": "http://schemas.openxmlformats.org/package/2006/metadata/core-properties",
|
|
5991
|
+
"xmlns:dc": "http://purl.org/dc/elements/1.1/",
|
|
5992
|
+
"xmlns:dcterms": "http://purl.org/dc/terms/",
|
|
5993
|
+
"xmlns:dcmitype": "http://purl.org/dc/dcmitype/",
|
|
5994
|
+
"xmlns:xsi": "http://www.w3.org/2001/XMLSchema-instance"
|
|
5995
|
+
}, [
|
|
5996
|
+
raw(el("dc:creator", null, "TsPptx")),
|
|
5997
|
+
raw(el("cp:lastModifiedBy", null, "TsPptx")),
|
|
5998
|
+
raw(el("dcterms:created", { "xsi:type": "dcterms:W3CDTF" }, (/* @__PURE__ */ new Date()).toISOString())),
|
|
5999
|
+
raw(el("dcterms:modified", { "xsi:type": "dcterms:W3CDTF" }, (/* @__PURE__ */ new Date()).toISOString()))
|
|
6000
|
+
]));
|
|
6001
|
+
zipExcel.add("xl/_rels/workbook.xml.rels", XML_DECL + relationships([
|
|
6002
|
+
relationship$2("rId3", OFFICE_REL + "styles", "styles.xml"),
|
|
6003
|
+
relationship$2("rId2", OFFICE_REL + "theme", "theme/theme1.xml"),
|
|
6004
|
+
relationship$2("rId1", OFFICE_REL + "worksheet", "worksheets/sheet1.xml"),
|
|
6005
|
+
relationship$2("rId4", OFFICE_REL + "sharedStrings", "sharedStrings.xml")
|
|
6006
|
+
]));
|
|
6007
|
+
zipExcel.add("xl/styles.xml", XML_DECL + XLSX_STYLES_XML);
|
|
6008
|
+
zipExcel.add("xl/theme/theme1.xml", XML_DECL + XLSX_THEME_XML);
|
|
6009
|
+
zipExcel.add("xl/workbook.xml", XML_DECL + el("workbook", {
|
|
6010
|
+
xmlns: SML_NS,
|
|
6011
|
+
"xmlns:r": "http://schemas.openxmlformats.org/officeDocument/2006/relationships",
|
|
6012
|
+
"xmlns:mc": "http://schemas.openxmlformats.org/markup-compatibility/2006",
|
|
6013
|
+
"mc:Ignorable": "x15",
|
|
6014
|
+
"xmlns:x15": "http://schemas.microsoft.com/office/spreadsheetml/2010/11/main"
|
|
6015
|
+
}, [
|
|
6016
|
+
raw(voidEl("fileVersion", {
|
|
6017
|
+
appName: "xl",
|
|
6018
|
+
lastEdited: 7,
|
|
6019
|
+
lowestEdited: 6,
|
|
6020
|
+
rupBuild: 10507
|
|
6021
|
+
})),
|
|
6022
|
+
raw(voidEl("workbookPr")),
|
|
6023
|
+
raw(el("bookViews", null, raw(voidEl("workbookView", {
|
|
6024
|
+
xWindow: 0,
|
|
6025
|
+
yWindow: 500,
|
|
6026
|
+
windowWidth: 20960,
|
|
6027
|
+
windowHeight: 15960
|
|
6028
|
+
})))),
|
|
6029
|
+
raw(el("sheets", null, raw(voidEl("sheet", {
|
|
6030
|
+
name: "Sheet1",
|
|
6031
|
+
sheetId: 1,
|
|
6032
|
+
"r:id": "rId1"
|
|
6033
|
+
})))),
|
|
6034
|
+
raw(voidEl("calcPr", {
|
|
6035
|
+
calcId: 0,
|
|
6036
|
+
concurrentCalc: 0
|
|
6037
|
+
}))
|
|
6038
|
+
]) + "\n");
|
|
6039
|
+
zipExcel.add("xl/worksheets/_rels/sheet1.xml.rels", XML_DECL + relationships([relationship$2("rId1", OFFICE_REL + "table", "../tables/table1.xml")]) + "\n");
|
|
6040
|
+
}
|
|
5375
6041
|
zipExcel.add("xl/sharedStrings.xml", buildXlsxSharedStrings(chartObject, data, intBubbleCols, IS_MULTI_CAT_AXES));
|
|
5376
6042
|
zipExcel.add("xl/tables/table1.xml", buildXlsxTable(chartObject, data, intBubbleCols));
|
|
5377
6043
|
zipExcel.add("xl/worksheets/sheet1.xml", buildXlsxSheet(chartObject, data, intBubbleCols, IS_MULTI_CAT_AXES));
|
|
@@ -5382,167 +6048,201 @@ function buildEmbeddedWorksheet(chartObject) {
|
|
|
5382
6048
|
* Build the embedded workbook's `xl/sharedStrings.xml` (series names + category labels).
|
|
5383
6049
|
*/
|
|
5384
6050
|
function buildXlsxSharedStrings(chartObject, data, intBubbleCols, IS_MULTI_CAT_AXES) {
|
|
5385
|
-
|
|
5386
|
-
|
|
5387
|
-
|
|
6051
|
+
const isBubble = chartObject.opts._type === "bubble" || chartObject.opts._type === "bubble3D";
|
|
6052
|
+
const isScatter = chartObject.opts._type === "scatter";
|
|
6053
|
+
let count;
|
|
6054
|
+
let uniqueCount;
|
|
6055
|
+
let blank = "";
|
|
6056
|
+
if (isBubble) count = uniqueCount = intBubbleCols;
|
|
6057
|
+
else if (isScatter) count = uniqueCount = data.length;
|
|
5388
6058
|
else if (IS_MULTI_CAT_AXES) {
|
|
5389
6059
|
let totCount = data.length + 1;
|
|
5390
6060
|
dataLabels(data[0]).forEach((arrLabel) => totCount += arrLabel.filter((label) => label && label !== "").length);
|
|
5391
|
-
|
|
5392
|
-
|
|
6061
|
+
count = uniqueCount = totCount;
|
|
6062
|
+
blank = el("si", null, raw(voidEl("t")));
|
|
5393
6063
|
} else {
|
|
5394
|
-
|
|
5395
|
-
|
|
5396
|
-
|
|
5397
|
-
|
|
5398
|
-
}
|
|
5399
|
-
|
|
5400
|
-
|
|
5401
|
-
|
|
5402
|
-
|
|
5403
|
-
|
|
5404
|
-
|
|
5405
|
-
|
|
5406
|
-
|
|
5407
|
-
|
|
5408
|
-
|
|
5409
|
-
if (chartObject.opts._type !== "bubble" && chartObject.opts._type !== "bubble3D" && chartObject.opts._type !== "scatter") dataLabels(data[0]).slice().reverse().forEach((labelsGroup) => {
|
|
5410
|
-
labelsGroup.filter((label) => label && label !== "").forEach((label) => {
|
|
5411
|
-
strSharedStrings += `<si><t>${encodeXmlEntities(label)}</t></si>`;
|
|
5412
|
-
});
|
|
5413
|
-
});
|
|
5414
|
-
strSharedStrings += "</sst>\n";
|
|
5415
|
-
return strSharedStrings;
|
|
6064
|
+
count = data.length + dataLabels(data[0]).length * firstLabelGroup(data[0]).length + dataLabels(data[0]).length;
|
|
6065
|
+
uniqueCount = data.length + dataLabels(data[0]).length * firstLabelGroup(data[0]).length + 1;
|
|
6066
|
+
blank = el("si", null, raw(el("t", { "xml:space": "preserve" })));
|
|
6067
|
+
}
|
|
6068
|
+
const names = isBubble ? data.map((objData, idx) => idx === 0 ? sharedString("X-Axis") : sharedString(objData.name || `Y-Axis${idx}`) + sharedString(`Size${idx}`)).join("") : data.map((objData) => sharedString((objData.name || " ").replace("X-Axis", "X-Values"))).join("");
|
|
6069
|
+
const labels = isBubble || isScatter ? "" : dataLabels(data[0]).slice().reverse().map((labelsGroup) => labelsGroup.filter((label) => label && label !== "").map((label) => sharedString(label)).join("")).join("");
|
|
6070
|
+
return XML_DECL + el("sst", {
|
|
6071
|
+
xmlns: SML_NS,
|
|
6072
|
+
count,
|
|
6073
|
+
uniqueCount
|
|
6074
|
+
}, [
|
|
6075
|
+
raw(blank),
|
|
6076
|
+
raw(names),
|
|
6077
|
+
raw(labels)
|
|
6078
|
+
]) + "\n";
|
|
5416
6079
|
}
|
|
5417
6080
|
/**
|
|
5418
6081
|
* Build the embedded workbook's `xl/tables/table1.xml` (the data table over the sheet range).
|
|
5419
6082
|
*/
|
|
5420
6083
|
function buildXlsxTable(chartObject, data, intBubbleCols) {
|
|
5421
|
-
|
|
6084
|
+
const labelCols = dataLabels(data[0]).length;
|
|
6085
|
+
let ref;
|
|
6086
|
+
let columns;
|
|
5422
6087
|
if (chartObject.opts._type === "bubble" || chartObject.opts._type === "bubble3D") {
|
|
5423
|
-
|
|
5424
|
-
strTableXml += `<tableColumns count="${intBubbleCols}">`;
|
|
6088
|
+
ref = `A1:${getExcelColName(intBubbleCols)}${intBubbleCols}`;
|
|
5425
6089
|
let idxColLtr = 1;
|
|
5426
|
-
data.
|
|
5427
|
-
if (idx === 0)
|
|
5428
|
-
|
|
5429
|
-
|
|
5430
|
-
|
|
5431
|
-
|
|
5432
|
-
|
|
5433
|
-
|
|
6090
|
+
columns = data.map((obj, idx) => {
|
|
6091
|
+
if (idx === 0) return voidEl("tableColumn", {
|
|
6092
|
+
id: idx + 1,
|
|
6093
|
+
name: "X-Values"
|
|
6094
|
+
});
|
|
6095
|
+
const nameCol = voidEl("tableColumn", {
|
|
6096
|
+
id: idx + idxColLtr,
|
|
6097
|
+
name: obj.name
|
|
6098
|
+
});
|
|
6099
|
+
idxColLtr++;
|
|
6100
|
+
return nameCol + voidEl("tableColumn", {
|
|
6101
|
+
id: idx + idxColLtr,
|
|
6102
|
+
name: `Size${idx}`
|
|
6103
|
+
});
|
|
6104
|
+
}).join("");
|
|
5434
6105
|
} else if (chartObject.opts._type === "scatter") {
|
|
5435
|
-
|
|
5436
|
-
|
|
5437
|
-
|
|
5438
|
-
|
|
5439
|
-
});
|
|
6106
|
+
ref = `A1:${getExcelColName(data.length)}${dataValues(data[0]).length + 1}`;
|
|
6107
|
+
columns = data.map((_obj, idx) => voidEl("tableColumn", {
|
|
6108
|
+
id: idx + 1,
|
|
6109
|
+
name: `${idx === 0 ? "X-Values" : "Y-Value "}${idx}`
|
|
6110
|
+
})).join("");
|
|
5440
6111
|
} else {
|
|
5441
|
-
|
|
5442
|
-
|
|
5443
|
-
|
|
5444
|
-
|
|
5445
|
-
})
|
|
5446
|
-
|
|
5447
|
-
|
|
5448
|
-
});
|
|
6112
|
+
ref = `A1:${getExcelColName(data.length + labelCols)}${firstLabelGroup(data[0]).length + 1}`;
|
|
6113
|
+
columns = dataLabels(data[0]).map((_labelsGroup, idx) => voidEl("tableColumn", {
|
|
6114
|
+
id: idx + 1,
|
|
6115
|
+
name: `Column${idx + 1}`
|
|
6116
|
+
})).join("") + data.map((obj, idx) => voidEl("tableColumn", {
|
|
6117
|
+
id: idx + labelCols + 1,
|
|
6118
|
+
name: obj.name ?? ""
|
|
6119
|
+
})).join("");
|
|
5449
6120
|
}
|
|
5450
|
-
|
|
5451
|
-
|
|
5452
|
-
|
|
5453
|
-
|
|
6121
|
+
const columnCount = chartObject.opts._type === "bubble" || chartObject.opts._type === "bubble3D" ? intBubbleCols : chartObject.opts._type === "scatter" ? data.length : data.length + labelCols;
|
|
6122
|
+
return XML_DECL + el("table", {
|
|
6123
|
+
xmlns: SML_NS,
|
|
6124
|
+
id: 1,
|
|
6125
|
+
name: "Table1",
|
|
6126
|
+
displayName: "Table1",
|
|
6127
|
+
ref,
|
|
6128
|
+
totalsRowShown: 0
|
|
6129
|
+
}, [raw(el("tableColumns", { count: columnCount }, raw(columns))), raw(voidEl("tableStyleInfo", {
|
|
6130
|
+
showFirstColumn: 0,
|
|
6131
|
+
showLastColumn: 0,
|
|
6132
|
+
showRowStripes: 1,
|
|
6133
|
+
showColumnStripes: 0
|
|
6134
|
+
}))]);
|
|
5454
6135
|
}
|
|
5455
6136
|
/**
|
|
5456
6137
|
* Build the embedded workbook's `xl/worksheets/sheet1.xml` (header row + per-series data rows).
|
|
5457
6138
|
*/
|
|
5458
6139
|
function buildXlsxSheet(chartObject, data, intBubbleCols, IS_MULTI_CAT_AXES) {
|
|
5459
|
-
|
|
5460
|
-
|
|
5461
|
-
|
|
5462
|
-
|
|
5463
|
-
|
|
5464
|
-
|
|
5465
|
-
|
|
5466
|
-
|
|
5467
|
-
|
|
5468
|
-
|
|
5469
|
-
|
|
5470
|
-
|
|
5471
|
-
|
|
6140
|
+
const isBubble = chartObject.opts._type === "bubble" || chartObject.opts._type === "bubble3D";
|
|
6141
|
+
const isScatter = chartObject.opts._type === "scatter";
|
|
6142
|
+
const labelCols = dataLabels(data[0]).length;
|
|
6143
|
+
/** One cell. `t="s"` marks a shared-string index; without it the value is a number. */
|
|
6144
|
+
const cell = (col, row, value, shared = false) => el("c", {
|
|
6145
|
+
r: `${getExcelColName(col)}${row}`,
|
|
6146
|
+
t: shared ? "s" : void 0
|
|
6147
|
+
}, raw(el("v", null, value)));
|
|
6148
|
+
/** One row, spanning the sheet's full column count. */
|
|
6149
|
+
const sheetRow = (row, span, cells) => el("row", {
|
|
6150
|
+
r: row,
|
|
6151
|
+
spans: `1:${span}`
|
|
6152
|
+
}, raw(cells));
|
|
6153
|
+
const colCount = isBubble ? intBubbleCols : isScatter ? data.length : data.length + labelCols;
|
|
6154
|
+
let rows = "";
|
|
6155
|
+
if (isBubble) {
|
|
6156
|
+
let header = "";
|
|
6157
|
+
for (let idx = 0; idx < intBubbleCols; idx++) header += cell(idx + 1, 1, idx, true);
|
|
6158
|
+
rows += sheetRow(1, intBubbleCols, header);
|
|
5472
6159
|
dataValues(data[0]).forEach((val, idx) => {
|
|
5473
|
-
|
|
5474
|
-
strSheetXml += `<c r="A${idx + 2}"><v>${val}</v></c>`;
|
|
6160
|
+
let cells = cell(1, idx + 2, val);
|
|
5475
6161
|
let idxColLtr = 2;
|
|
5476
6162
|
for (let idy = 1; idy < data.length; idy++) {
|
|
5477
|
-
|
|
5478
|
-
idxColLtr
|
|
5479
|
-
strSheetXml += `<c r="${getExcelColName(idxColLtr)}${idx + 2}"><v>${dataSizes(data[idy])[idx] ?? ""}</v></c>`;
|
|
5480
|
-
idxColLtr++;
|
|
6163
|
+
cells += cell(idxColLtr++, idx + 2, dataValues(data[idy])[idx] ?? "");
|
|
6164
|
+
cells += cell(idxColLtr++, idx + 2, dataSizes(data[idy])[idx] ?? "");
|
|
5481
6165
|
}
|
|
5482
|
-
|
|
6166
|
+
rows += sheetRow(idx + 2, intBubbleCols, cells);
|
|
5483
6167
|
});
|
|
5484
|
-
} else if (
|
|
5485
|
-
|
|
5486
|
-
|
|
5487
|
-
|
|
5488
|
-
strSheetXml += "</row>";
|
|
6168
|
+
} else if (isScatter) {
|
|
6169
|
+
let header = "";
|
|
6170
|
+
for (let idx = 0; idx < data.length; idx++) header += cell(idx + 1, 1, idx, true);
|
|
6171
|
+
rows += sheetRow(1, data.length, header);
|
|
5489
6172
|
dataValues(data[0]).forEach((val, idx) => {
|
|
5490
|
-
|
|
5491
|
-
|
|
5492
|
-
|
|
5493
|
-
|
|
6173
|
+
let cells = cell(1, idx + 2, val);
|
|
6174
|
+
for (let idy = 1; idy < data.length; idy++) {
|
|
6175
|
+
const yValue = dataValues(data[idy])[idx];
|
|
6176
|
+
cells += cell(idy + 1, idx + 2, yValue || yValue === 0 ? yValue : "");
|
|
6177
|
+
}
|
|
6178
|
+
rows += sheetRow(idx + 2, data.length, cells);
|
|
5494
6179
|
});
|
|
6180
|
+
} else if (!IS_MULTI_CAT_AXES) {
|
|
6181
|
+
let header = "";
|
|
6182
|
+
for (let idx = 0; idx < labelCols; idx++) header += cell(idx + 1, 1, 0, true);
|
|
6183
|
+
for (let idx = 0; idx < data.length; idx++) header += cell(idx + 1 + labelCols, 1, idx + 1, true);
|
|
6184
|
+
rows += sheetRow(1, data.length + labelCols, header);
|
|
6185
|
+
const rowCount = firstLabelGroup(data[0]).length || Math.max(0, ...data.map((series) => dataValues(series).length));
|
|
6186
|
+
for (let idx = 0; idx < rowCount; idx++) {
|
|
6187
|
+
let cells = "";
|
|
6188
|
+
for (let idx2 = labelCols - 1; idx2 >= 0; idx2--) cells += cell(labelCols - idx2, idx + 2, data.length + idx + 1, true);
|
|
6189
|
+
for (let idy = 0; idy < data.length; idy++) cells += cell(labelCols + idy + 1, idx + 2, dataValues(data[idy])[idx] ?? "");
|
|
6190
|
+
rows += sheetRow(idx + 2, data.length + labelCols, cells);
|
|
6191
|
+
}
|
|
5495
6192
|
} else {
|
|
5496
|
-
|
|
5497
|
-
|
|
5498
|
-
|
|
5499
|
-
|
|
5500
|
-
|
|
5501
|
-
|
|
5502
|
-
|
|
5503
|
-
|
|
5504
|
-
const rowCount = firstLabelGroup(data[0]).length || Math.max(0, ...data.map((series) => dataValues(series).length));
|
|
5505
|
-
for (let idx = 0; idx < rowCount; idx++) {
|
|
5506
|
-
strSheetXml += `<row r="${idx + 2}" spans="1:${data.length + dataLabels(data[0]).length}">`;
|
|
5507
|
-
for (let idx2 = dataLabels(data[0]).length - 1; idx2 >= 0; idx2--) {
|
|
5508
|
-
strSheetXml += `<c r="${getExcelColName(dataLabels(data[0]).length - idx2)}${idx + 2}" t="s">`;
|
|
5509
|
-
strSheetXml += `<v>${data.length + idx + 1}</v>`;
|
|
5510
|
-
strSheetXml += "</c>";
|
|
5511
|
-
}
|
|
5512
|
-
for (let idy = 0; idy < data.length; idy++) strSheetXml += `<c r="${getExcelColName(dataLabels(data[0]).length + idy + 1)}${idx + 2}"><v>${dataValues(data[idy])[idx] ?? ""}</v></c>`;
|
|
5513
|
-
strSheetXml += "</row>";
|
|
5514
|
-
}
|
|
5515
|
-
} else {
|
|
5516
|
-
const TOT_SER = data.length;
|
|
5517
|
-
const TOT_CAT = firstLabelGroup(data[0]).length;
|
|
5518
|
-
const TOT_LVL = dataLabels(data[0]).length;
|
|
5519
|
-
const revLabelGroups = dataLabels(data[0]).slice().reverse();
|
|
5520
|
-
const ssLabelMap = /* @__PURE__ */ new Map();
|
|
5521
|
-
let ssIdx = TOT_SER + 1;
|
|
5522
|
-
revLabelGroups.forEach((labelsGroup, revLevelIdx) => {
|
|
5523
|
-
labelsGroup.forEach((label, rowIdx) => {
|
|
5524
|
-
if (label && label !== "") ssLabelMap.set(`${revLevelIdx}:${rowIdx}`, ssIdx++);
|
|
5525
|
-
});
|
|
6193
|
+
const TOT_SER = data.length;
|
|
6194
|
+
const TOT_CAT = firstLabelGroup(data[0]).length;
|
|
6195
|
+
const revLabelGroups = dataLabels(data[0]).slice().reverse();
|
|
6196
|
+
const ssLabelMap = /* @__PURE__ */ new Map();
|
|
6197
|
+
let ssIdx = TOT_SER + 1;
|
|
6198
|
+
revLabelGroups.forEach((labelsGroup, revLevelIdx) => {
|
|
6199
|
+
labelsGroup.forEach((label, rowIdx) => {
|
|
6200
|
+
if (label && label !== "") ssLabelMap.set(`${revLevelIdx}:${rowIdx}`, ssIdx++);
|
|
5526
6201
|
});
|
|
5527
|
-
|
|
5528
|
-
|
|
5529
|
-
|
|
5530
|
-
|
|
5531
|
-
|
|
5532
|
-
|
|
5533
|
-
|
|
5534
|
-
|
|
5535
|
-
|
|
5536
|
-
|
|
5537
|
-
|
|
5538
|
-
|
|
5539
|
-
}
|
|
6202
|
+
});
|
|
6203
|
+
let header = "";
|
|
6204
|
+
for (let col = 1; col <= labelCols; col++) header += cell(col, 1, 0, true);
|
|
6205
|
+
for (let ser = 0; ser < TOT_SER; ser++) header += cell(labelCols + ser + 1, 1, ser + 1, true);
|
|
6206
|
+
rows += sheetRow(1, TOT_SER + labelCols, header);
|
|
6207
|
+
for (let idx = 0; idx < TOT_CAT; idx++) {
|
|
6208
|
+
let cells = revLabelGroups.map((labelsGroup, idy) => {
|
|
6209
|
+
const colLabel = labelsGroup[idx];
|
|
6210
|
+
return colLabel && colLabel !== "" ? cell(idy + 1, idx + 2, ssLabelMap.get(`${idy}:${idx}`) ?? "", true) : "";
|
|
6211
|
+
}).join("");
|
|
6212
|
+
for (let idy = 0; idy < TOT_SER; idy++) cells += cell(labelCols + idy + 1, idx + 2, dataValues(data[idy])[idx] ?? "");
|
|
6213
|
+
rows += sheetRow(idx + 2, TOT_SER + labelCols, cells);
|
|
5540
6214
|
}
|
|
5541
6215
|
}
|
|
5542
|
-
|
|
5543
|
-
|
|
5544
|
-
|
|
5545
|
-
|
|
6216
|
+
const sheetView = el("sheetViews", null, raw(el("sheetView", {
|
|
6217
|
+
tabSelected: 1,
|
|
6218
|
+
workbookViewId: 0
|
|
6219
|
+
}, raw(voidEl("selection", {
|
|
6220
|
+
activeCell: "B1",
|
|
6221
|
+
sqref: "B1"
|
|
6222
|
+
})))));
|
|
6223
|
+
return XML_DECL + el("worksheet", {
|
|
6224
|
+
xmlns: SML_NS,
|
|
6225
|
+
"xmlns:r": "http://schemas.openxmlformats.org/officeDocument/2006/relationships",
|
|
6226
|
+
"xmlns:mc": "http://schemas.openxmlformats.org/markup-compatibility/2006",
|
|
6227
|
+
"mc:Ignorable": "x14ac",
|
|
6228
|
+
"xmlns:x14ac": "http://schemas.microsoft.com/office/spreadsheetml/2009/9/ac"
|
|
6229
|
+
}, [
|
|
6230
|
+
raw(voidEl("dimension", { ref: `A1:${getExcelColName(colCount)}${dataValues(data[0]).length + 1}` })),
|
|
6231
|
+
raw(sheetView),
|
|
6232
|
+
raw(voidEl("sheetFormatPr", {
|
|
6233
|
+
baseColWidth: 10,
|
|
6234
|
+
defaultRowHeight: 16
|
|
6235
|
+
})),
|
|
6236
|
+
raw(el("sheetData", null, raw(rows))),
|
|
6237
|
+
raw(voidEl("pageMargins", {
|
|
6238
|
+
left: .7,
|
|
6239
|
+
right: .7,
|
|
6240
|
+
top: .75,
|
|
6241
|
+
bottom: .75,
|
|
6242
|
+
header: .3,
|
|
6243
|
+
footer: .3
|
|
6244
|
+
}))
|
|
6245
|
+
]) + "\n";
|
|
5546
6246
|
}
|
|
5547
6247
|
/**
|
|
5548
6248
|
* Build the standalone `.rels` for a chart part: a single `rId1` relationship to
|
|
@@ -7012,17 +7712,17 @@ function fallbackPic(picId, objectName, altText, model, xf) {
|
|
|
7012
7712
|
return el("p:pic", null, [
|
|
7013
7713
|
raw(el("p:nvPicPr", null, [
|
|
7014
7714
|
raw(cNvPrOpen(picId, objectName, altText) + "/>"),
|
|
7015
|
-
raw(el("p:cNvPicPr", null, raw(
|
|
7016
|
-
noGrp:
|
|
7017
|
-
noRot:
|
|
7018
|
-
noChangeAspect:
|
|
7019
|
-
noMove:
|
|
7020
|
-
noResize:
|
|
7021
|
-
noEditPoints:
|
|
7022
|
-
noAdjustHandles:
|
|
7023
|
-
noChangeArrowheads:
|
|
7024
|
-
noChangeShapeType:
|
|
7025
|
-
noCrop:
|
|
7715
|
+
raw(el("p:cNvPicPr", null, raw(genXmlObjectLock("a:picLocks", PICTURE_LOCK_ATTRS, {
|
|
7716
|
+
noGrp: true,
|
|
7717
|
+
noRot: true,
|
|
7718
|
+
noChangeAspect: true,
|
|
7719
|
+
noMove: true,
|
|
7720
|
+
noResize: true,
|
|
7721
|
+
noEditPoints: true,
|
|
7722
|
+
noAdjustHandles: true,
|
|
7723
|
+
noChangeArrowheads: true,
|
|
7724
|
+
noChangeShapeType: true,
|
|
7725
|
+
noCrop: true
|
|
7026
7726
|
})))),
|
|
7027
7727
|
raw(voidEl("p:nvPr"))
|
|
7028
7728
|
])),
|
|
@@ -7064,7 +7764,7 @@ function renderModel3dObject(slideItemObj, idx, x, y, cx, cy) {
|
|
|
7064
7764
|
const graphicFrame = el("p:graphicFrame", null, [
|
|
7065
7765
|
raw(el("p:nvGraphicFramePr", null, [
|
|
7066
7766
|
raw(cNvPrOpen(idx + 2, opts.objectName, altText) + "/>"),
|
|
7067
|
-
raw(el("p:cNvGraphicFramePr", null, raw(voidEl("a:graphicFrameLocks")))),
|
|
7767
|
+
raw(el("p:cNvGraphicFramePr", null, raw(genXmlObjectLock("a:graphicFrameLocks", GRAPHIC_FRAME_LOCK_ATTRS, opts.objectLock, opts.objectName) || voidEl("a:graphicFrameLocks")))),
|
|
7068
7768
|
raw(voidEl("p:nvPr"))
|
|
7069
7769
|
])),
|
|
7070
7770
|
raw(el("p:xfrm", null, [raw(voidEl("a:off", {
|
|
@@ -7355,7 +8055,7 @@ function renderTableObject(slideItemObj, idx, x, y, cx, cy, placeholderObj, item
|
|
|
7355
8055
|
let intColCnt = 0;
|
|
7356
8056
|
let tblInner = "";
|
|
7357
8057
|
let cellOpts = null;
|
|
7358
|
-
arrTabRows = (slideItemObj.arrTabRows ?? []).map((row) => [...row]);
|
|
8058
|
+
arrTabRows = withCheckedSpans((slideItemObj.arrTabRows ?? []).map((row) => [...row]));
|
|
7359
8059
|
objTabOpts = itemOpts;
|
|
7360
8060
|
intColCnt = 0;
|
|
7361
8061
|
(arrTabRows[0] ?? []).forEach((cell) => {
|
|
@@ -7639,16 +8339,16 @@ function zoomFallbackPic(picId, objectName, tile, absXf) {
|
|
|
7639
8339
|
"r:id": `rId${tile.fallbackSlideRid}`,
|
|
7640
8340
|
action: "ppaction://hlinksldjump"
|
|
7641
8341
|
}) + "</p:cNvPr>"),
|
|
7642
|
-
raw(el("p:cNvPicPr", null, raw(
|
|
7643
|
-
noGrp:
|
|
7644
|
-
noRot:
|
|
7645
|
-
noChangeAspect:
|
|
7646
|
-
noMove:
|
|
7647
|
-
noResize:
|
|
7648
|
-
noEditPoints:
|
|
7649
|
-
noAdjustHandles:
|
|
7650
|
-
noChangeArrowheads:
|
|
7651
|
-
noChangeShapeType:
|
|
8342
|
+
raw(el("p:cNvPicPr", null, raw(genXmlObjectLock("a:picLocks", PICTURE_LOCK_ATTRS, {
|
|
8343
|
+
noGrp: true,
|
|
8344
|
+
noRot: true,
|
|
8345
|
+
noChangeAspect: true,
|
|
8346
|
+
noMove: true,
|
|
8347
|
+
noResize: true,
|
|
8348
|
+
noEditPoints: true,
|
|
8349
|
+
noAdjustHandles: true,
|
|
8350
|
+
noChangeArrowheads: true,
|
|
8351
|
+
noChangeShapeType: true
|
|
7652
8352
|
})))),
|
|
7653
8353
|
raw(voidEl("p:nvPr"))
|
|
7654
8354
|
])),
|
|
@@ -7675,7 +8375,8 @@ function zoomFallbackPic(picId, objectName, tile, absXf) {
|
|
|
7675
8375
|
function renderZoomObject(slideItemObj, idx, x, y, cx, cy) {
|
|
7676
8376
|
const zoom = slideItemObj.zoom;
|
|
7677
8377
|
if (!zoom) return "";
|
|
7678
|
-
const
|
|
8378
|
+
const opts = slideItemObj.options || {};
|
|
8379
|
+
const objectName = opts.objectName;
|
|
7679
8380
|
const { uri, prefix, zm } = ZOOM_VARIANTS[zoom.variant];
|
|
7680
8381
|
const firstTile = zoom.tiles[0];
|
|
7681
8382
|
if (!firstTile) return "";
|
|
@@ -7693,7 +8394,10 @@ function renderZoomObject(slideItemObj, idx, x, y, cx, cy) {
|
|
|
7693
8394
|
const graphicFrame = el("p:graphicFrame", null, [
|
|
7694
8395
|
raw(el("p:nvGraphicFramePr", null, [
|
|
7695
8396
|
raw(cNvPrOpen(idx + 2, objectName, "") + "/>"),
|
|
7696
|
-
raw(el("p:cNvGraphicFramePr", null, raw(
|
|
8397
|
+
raw(el("p:cNvGraphicFramePr", null, raw(genXmlObjectLock("a:graphicFrameLocks", GRAPHIC_FRAME_LOCK_ATTRS, {
|
|
8398
|
+
noChangeAspect: true,
|
|
8399
|
+
...opts.objectLock
|
|
8400
|
+
}, objectName)))),
|
|
7697
8401
|
raw(voidEl("p:nvPr"))
|
|
7698
8402
|
])),
|
|
7699
8403
|
raw(el("p:xfrm", null, [raw(voidEl("a:off", {
|
|
@@ -8352,56 +9056,18 @@ function buildThemeClrScheme(scheme) {
|
|
|
8352
9056
|
return raw(el(`a:${slot}`, null, child));
|
|
8353
9057
|
}));
|
|
8354
9058
|
}
|
|
8355
|
-
|
|
8356
|
-
|
|
8357
|
-
|
|
8358
|
-
|
|
8359
|
-
|
|
8360
|
-
|
|
8361
|
-
|
|
8362
|
-
|
|
8363
|
-
|
|
8364
|
-
|
|
8365
|
-
|
|
8366
|
-
|
|
8367
|
-
["Knda", "Tunga"],
|
|
8368
|
-
["Guru", "Raavi"],
|
|
8369
|
-
["Cans", "Euphemia"],
|
|
8370
|
-
["Cher", "Plantagenet Cherokee"],
|
|
8371
|
-
["Yiii", "Microsoft Yi Baiti"],
|
|
8372
|
-
["Tibt", "Microsoft Himalaya"],
|
|
8373
|
-
["Thaa", "MV Boli"],
|
|
8374
|
-
["Deva", "Mangal"],
|
|
8375
|
-
["Telu", "Gautami"],
|
|
8376
|
-
["Taml", "Latha"],
|
|
8377
|
-
["Syrc", "Estrangelo Edessa"],
|
|
8378
|
-
["Orya", "Kalinga"],
|
|
8379
|
-
["Mlym", "Kartika"],
|
|
8380
|
-
["Laoo", "DokChampa"],
|
|
8381
|
-
["Sinh", "Iskoola Pota"],
|
|
8382
|
-
["Mong", "Mongolian Baiti"],
|
|
8383
|
-
["Viet", "Times New Roman"],
|
|
8384
|
-
["Uigh", "Microsoft Uighur"],
|
|
8385
|
-
["Geor", "Sylfaen"],
|
|
8386
|
-
["Armn", "Arial"],
|
|
8387
|
-
["Bugi", "Leelawadee UI"],
|
|
8388
|
-
["Bopo", "Microsoft JhengHei"],
|
|
8389
|
-
["Java", "Javanese Text"],
|
|
8390
|
-
["Lisu", "Segoe UI"],
|
|
8391
|
-
["Mymr", "Myanmar Text"],
|
|
8392
|
-
["Nkoo", "Ebrima"],
|
|
8393
|
-
["Olck", "Nirmala UI"],
|
|
8394
|
-
["Osma", "Ebrima"],
|
|
8395
|
-
["Phag", "Phagspa"],
|
|
8396
|
-
["Syrn", "Estrangelo Edessa"],
|
|
8397
|
-
["Syrj", "Estrangelo Edessa"],
|
|
8398
|
-
["Syre", "Estrangelo Edessa"],
|
|
8399
|
-
["Sora", "Nirmala UI"],
|
|
8400
|
-
["Tale", "Microsoft Tai Le"],
|
|
8401
|
-
["Talu", "Microsoft New Tai Lue"],
|
|
8402
|
-
["Tfng", "Ebrima"]
|
|
8403
|
-
];
|
|
8404
|
-
const MINOR_FONT_LIST = [
|
|
9059
|
+
/**
|
|
9060
|
+
* The per-script theme font fallback table (`a:fontScheme`'s CT_TextFont lists), in OOXML
|
|
9061
|
+
* document order. Static Office defaults — no caller data, no escaping risk — unlike the
|
|
9062
|
+
* `<a:latin>`/`<a:ea>`/`<a:cs>` slots above.
|
|
9063
|
+
*
|
|
9064
|
+
* Forty-one of the forty-seven scripts take the same face in the major and minor lists, so the
|
|
9065
|
+
* shared table below is the whole thing and the two override maps hold the six-odd rows that
|
|
9066
|
+
* actually differ. Written out twice, ninety-four lines said less than these do, and one row
|
|
9067
|
+
* mistyped in one copy produces a theme that opens fine and paints a script in the wrong face —
|
|
9068
|
+
* a difference nobody reviewing a diff of two 47-row tables would see.
|
|
9069
|
+
*/
|
|
9070
|
+
const THEME_FONT_LIST = [
|
|
8405
9071
|
["Jpan", "游ゴシック"],
|
|
8406
9072
|
["Hang", "맑은 고딕"],
|
|
8407
9073
|
["Hans", "等线"],
|
|
@@ -8450,6 +9116,24 @@ const MINOR_FONT_LIST = [
|
|
|
8450
9116
|
["Talu", "Microsoft New Tai Lue"],
|
|
8451
9117
|
["Tfng", "Ebrima"]
|
|
8452
9118
|
];
|
|
9119
|
+
/**
|
|
9120
|
+
* The seven scripts whose *heading* face differs from the body one. Latin and CJK headings take
|
|
9121
|
+
* the Light weight; the scripts with no Light cut take a serif (or, for Khmer, a different face
|
|
9122
|
+
* entirely) where the body takes a sans. Every other script in {@link THEME_FONT_LIST} uses one
|
|
9123
|
+
* face for both.
|
|
9124
|
+
*/
|
|
9125
|
+
const MAJOR_FONT_OVERRIDES = {
|
|
9126
|
+
Jpan: "游ゴシック Light",
|
|
9127
|
+
Hans: "等线 Light",
|
|
9128
|
+
Arab: "Times New Roman",
|
|
9129
|
+
Hebr: "Times New Roman",
|
|
9130
|
+
Thai: "Angsana New",
|
|
9131
|
+
Khmr: "MoolBoran",
|
|
9132
|
+
Viet: "Times New Roman"
|
|
9133
|
+
};
|
|
9134
|
+
/** The major (heading) and minor (body) lists, both derived from the one table. */
|
|
9135
|
+
const MAJOR_FONT_LIST = THEME_FONT_LIST.map(([script, face]) => [script, MAJOR_FONT_OVERRIDES[script] ?? face]);
|
|
9136
|
+
const MINOR_FONT_LIST = THEME_FONT_LIST;
|
|
8453
9137
|
function fontListChildren(scriptFaces) {
|
|
8454
9138
|
return scriptFaces.map(([script, typeface]) => raw(voidEl("a:font", {
|
|
8455
9139
|
script,
|
|
@@ -9390,20 +10074,7 @@ function makeXmlMaster(slide, layouts) {
|
|
|
9390
10074
|
id: LAYOUT_IDX_SERIES_BASE + idx,
|
|
9391
10075
|
"r:id": `rId${slide._rels.length + idx + 1}`
|
|
9392
10076
|
})).join("");
|
|
9393
|
-
const clrMap = voidEl("p:clrMap",
|
|
9394
|
-
bg1: "lt1",
|
|
9395
|
-
tx1: "dk1",
|
|
9396
|
-
bg2: "lt2",
|
|
9397
|
-
tx2: "dk2",
|
|
9398
|
-
accent1: "accent1",
|
|
9399
|
-
accent2: "accent2",
|
|
9400
|
-
accent3: "accent3",
|
|
9401
|
-
accent4: "accent4",
|
|
9402
|
-
accent5: "accent5",
|
|
9403
|
-
accent6: "accent6",
|
|
9404
|
-
hlink: "hlink",
|
|
9405
|
-
folHlink: "folHlink"
|
|
9406
|
-
});
|
|
10077
|
+
const clrMap = voidEl("p:clrMap", DEFAULT_COLOR_MAP);
|
|
9407
10078
|
const hf = voidEl("p:hf", {
|
|
9408
10079
|
sldNum: slide._slideNumberProps ? null : 0,
|
|
9409
10080
|
hdr: 0,
|
|
@@ -9671,7 +10342,7 @@ async function writePackage(source, props) {
|
|
|
9671
10342
|
* the OfficeGen project (Copyright 2013 Ziv Barber). This project is likewise MIT; the full
|
|
9672
10343
|
* license text is in `LICENSE` at the repository root.
|
|
9673
10344
|
*/
|
|
9674
|
-
const VERSION = "3.
|
|
10345
|
+
const VERSION = "3.7.0";
|
|
9675
10346
|
function standardLayoutToPresLayout(layout) {
|
|
9676
10347
|
return {
|
|
9677
10348
|
name: layout.name,
|
|
@@ -10651,6 +11322,6 @@ function textRuns(runs) {
|
|
|
10651
11322
|
return runs;
|
|
10652
11323
|
}
|
|
10653
11324
|
//#endregion
|
|
10654
|
-
export { fetchMediaBase64 as a, PresentationCore as c, fetchFontBytes as i, textRuns as n, isRemote as o, clipPath as r, placeholderSvgPreview as s, textRun as t };
|
|
11325
|
+
export { fetchMediaBase64 as a, PresentationCore as c, fetchFontBytes as i, IMG_SVG_PLACEHOLDER as l, textRuns as n, isRemote as o, clipPath as r, placeholderSvgPreview as s, textRun as t };
|
|
10655
11326
|
|
|
10656
|
-
//# sourceMappingURL=text-
|
|
11327
|
+
//# sourceMappingURL=text-B8SLEaZx.js.map
|