@shbernal/ts-pptx 3.5.0 → 3.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{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-Du_s75MT.d.ts} +20 -5
- package/dist/diagnostics-Du_s75MT.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-RLCwdlTE.js} +289 -313
- package/dist/{notes-DNqAggXx.js.map → notes-RLCwdlTE.js.map} +1 -1
- package/dist/{pres-Dybf7ZUl.d.ts → pres-C5__xkDh.d.ts} +2 -2
- package/dist/{pres-Dybf7ZUl.d.ts.map → pres-C5__xkDh.d.ts.map} +1 -1
- package/dist/{presentation-VfJ_FT7E.js → presentation-Cp7vzlAw.js} +414 -515
- package/dist/presentation-Cp7vzlAw.js.map +1 -0
- package/dist/{presentation-types-CpkTx9Xa.d.ts → presentation-types-DP_8jog7.d.ts} +351 -274
- package/dist/presentation-types-DP_8jog7.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-js0QpRV-.d.ts} +1278 -1254
- package/dist/slide-js0QpRV-.d.ts.map +1 -0
- package/dist/{text-D04NUMvA.js → text-CyetbF6p.js} +2039 -1417
- package/dist/text-CyetbF6p.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/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 { $ as
|
|
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 { $ 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";
|
|
4
|
+
import { A as getNewRelId, C as createShadowEffectLst, D as voidEl, E as raw, M as isHyperlinkRel, N as mediaSlideKey, O as encodeXmlAttrValue, P as validateObjectName, 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 getUuid, k as getDuplicateObjectNames, 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-RLCwdlTE.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: " "
|
|
508
501
|
});
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
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: " "
|
|
527
|
+
});
|
|
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;
|
|
@@ -2310,6 +2449,26 @@ function groupObjectsDefinition(target, objectNames, opts) {
|
|
|
2310
2449
|
target._slideObjects.splice(0, target._slideObjects.length, ...regrouped);
|
|
2311
2450
|
}
|
|
2312
2451
|
//#endregion
|
|
2452
|
+
//#region src/media/placeholders.ts
|
|
2453
|
+
/**
|
|
2454
|
+
* The three base64 placeholder images the library falls back to.
|
|
2455
|
+
*
|
|
2456
|
+
* Their own module because of where the bundler puts them, not because they group naturally.
|
|
2457
|
+
* The chunker splits by module, so a constant is pulled into every chunk that reaches the module
|
|
2458
|
+
* declaring it — and these lived in `constants-internal.ts` beside `XML_DECL`, `DEF_FONT_SIZE`
|
|
2459
|
+
* and the rest of the vocabulary all of `src/gen/` imports. The result was that `IMG_PLAYBTN`,
|
|
2460
|
+
* a 74 KB PNG wanted by exactly one module, landed in two chunks and cost 149 KB of the shipped
|
|
2461
|
+
* package, 13% of the largest chunk. A caller who only ever wrote text boxes paid for the video
|
|
2462
|
+
* poster.
|
|
2463
|
+
*
|
|
2464
|
+
* So the rule this module encodes: a payload measured in tens of kilobytes does not share a
|
|
2465
|
+
* module with vocabulary, however tidy that grouping reads.
|
|
2466
|
+
*/
|
|
2467
|
+
/** Shown in place of media that failed to load, under `onMediaError: 'placeholder'`. */
|
|
2468
|
+
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==";
|
|
2469
|
+
/** 1x1 transparent PNG, standing in for an SVG the runtime could not rasterize. */
|
|
2470
|
+
const IMG_SVG_PLACEHOLDER = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg==";
|
|
2471
|
+
//#endregion
|
|
2313
2472
|
//#region src/gen/define/media.ts
|
|
2314
2473
|
/**
|
|
2315
2474
|
* Adds a media object to a slide definition.
|
|
@@ -2436,21 +2595,11 @@ function registerPreviewImage(target, cover) {
|
|
|
2436
2595
|
if (!strImagePath && !strImageData) strImageData = "image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAxSURBVFhH7c4hAQAACMAw+geFGOAJAGbi5mpRmf1Z7HEdAAAAAAAAAAAAAAAAAADAAPwOyNPFH3F8AAAAAElFTkSuQmCC";
|
|
2437
2596
|
const extn = imageExtensionForSource(strImagePath, strImageData);
|
|
2438
2597
|
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
|
-
});
|
|
2598
|
+
registerImageMediaRel(target, {
|
|
2599
|
+
path: strImagePath,
|
|
2600
|
+
data: strImageData,
|
|
2601
|
+
extn
|
|
2602
|
+
}, rId);
|
|
2454
2603
|
return rId;
|
|
2455
2604
|
}
|
|
2456
2605
|
//#endregion
|
|
@@ -2555,7 +2704,8 @@ function addModel3dDefinition(target, opt) {
|
|
|
2555
2704
|
w: opt.w ?? 4,
|
|
2556
2705
|
h: opt.h ?? 3,
|
|
2557
2706
|
objectName,
|
|
2558
|
-
...opt.altText ? { altText: opt.altText } : {}
|
|
2707
|
+
...opt.altText ? { altText: opt.altText } : {},
|
|
2708
|
+
...opt.objectLock ? { objectLock: opt.objectLock } : {}
|
|
2559
2709
|
},
|
|
2560
2710
|
model3d: {
|
|
2561
2711
|
modelRid,
|
|
@@ -2709,6 +2859,70 @@ function addOleObjectDefinition(target, opt) {
|
|
|
2709
2859
|
target._slideObjects.push(slideData);
|
|
2710
2860
|
}
|
|
2711
2861
|
//#endregion
|
|
2862
|
+
//#region src/gen/table/spans.ts
|
|
2863
|
+
/**
|
|
2864
|
+
* The largest `colspan`/`rowspan` this library will honour.
|
|
2865
|
+
*
|
|
2866
|
+
* Unlike the read side's point-cache ceiling there is no format number to borrow: `a:tc@gridSpan`
|
|
2867
|
+
* is a bare `xsd:int`. So this is a sanity bound rather than a schema one, and it is set an order
|
|
2868
|
+
* of magnitude past PowerPoint's own maximum table (its Insert Table dialog stops at 75 columns
|
|
2869
|
+
* and 75 rows), which is what makes it something no authored table can reach. What it stops is
|
|
2870
|
+
* the other end, where the allocation takes the host process with it.
|
|
2871
|
+
*/
|
|
2872
|
+
const MAX_TABLE_SPAN = 1e3;
|
|
2873
|
+
/**
|
|
2874
|
+
* Validate one cell's `colspan`/`rowspan`, warning and falling back to `1` when it is not a whole
|
|
2875
|
+
* number in `1..MAX_TABLE_SPAN`.
|
|
2876
|
+
*
|
|
2877
|
+
* `undefined` is the common case and means "no span" — it warns about nothing and returns `1`.
|
|
2878
|
+
* Everything else is caller error: `NaN`, a negative, a fraction and a span past the ceiling all
|
|
2879
|
+
* describe a table that cannot be built (a fractional span silently truncates, a negative one
|
|
2880
|
+
* shifts every column after it, an enormous one is the allocation above).
|
|
2881
|
+
* @param value - the raw option value
|
|
2882
|
+
* @param kind - `'colspan'` or `'rowspan'`, for the diagnostic
|
|
2883
|
+
* @returns the span to use, at least 1
|
|
2884
|
+
*/
|
|
2885
|
+
function resolveSpan(value, kind) {
|
|
2886
|
+
if (value === void 0) return 1;
|
|
2887
|
+
if (!Number.isInteger(value) || value < 1 || value > 1e3) {
|
|
2888
|
+
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.`);
|
|
2889
|
+
return 1;
|
|
2890
|
+
}
|
|
2891
|
+
return value;
|
|
2892
|
+
}
|
|
2893
|
+
/**
|
|
2894
|
+
* Re-clone `rows` with every out-of-range `colspan`/`rowspan` corrected to `1`.
|
|
2895
|
+
*
|
|
2896
|
+
* Runs once, up front, so the column count, the `_hmerge`/`_vmerge` dummies, the auto-pager's
|
|
2897
|
+
* grid and the emitted `gridSpan`/`rowSpan` attributes all read the same number — checking at
|
|
2898
|
+
* each of those sites instead would warn several times per bad cell and could still disagree.
|
|
2899
|
+
*
|
|
2900
|
+
* A cell whose spans are fine is passed through by identity, not copied: `_spanOrigin` links the
|
|
2901
|
+
* merge dummies back to the origin *object*, and the all-valid path is every real table, which
|
|
2902
|
+
* must stay allocation-free and byte-identical.
|
|
2903
|
+
* @param rows - the rows to check; row arrays are never mutated
|
|
2904
|
+
* @returns the same rows with only the offending cells replaced
|
|
2905
|
+
*/
|
|
2906
|
+
function withCheckedSpans(rows) {
|
|
2907
|
+
return rows.map((cells) => cells.map((cell) => {
|
|
2908
|
+
const opts = cell?.options;
|
|
2909
|
+
if (!opts) return cell;
|
|
2910
|
+
const colspan = resolveSpan(opts.colspan, "colspan");
|
|
2911
|
+
const rowspan = resolveSpan(opts.rowspan, "rowspan");
|
|
2912
|
+
const colspanOk = opts.colspan === void 0 || opts.colspan === colspan;
|
|
2913
|
+
const rowspanOk = opts.rowspan === void 0 || opts.rowspan === rowspan;
|
|
2914
|
+
if (colspanOk && rowspanOk) return cell;
|
|
2915
|
+
return {
|
|
2916
|
+
...cell,
|
|
2917
|
+
options: {
|
|
2918
|
+
...opts,
|
|
2919
|
+
...opts.colspan === void 0 ? {} : { colspan },
|
|
2920
|
+
...opts.rowspan === void 0 ? {} : { rowspan }
|
|
2921
|
+
}
|
|
2922
|
+
};
|
|
2923
|
+
}));
|
|
2924
|
+
}
|
|
2925
|
+
//#endregion
|
|
2712
2926
|
//#region src/gen/define/table.ts
|
|
2713
2927
|
/**
|
|
2714
2928
|
* Expand a cell/table border into the 4-side tuple the rest of the pipeline expects.
|
|
@@ -2907,7 +3121,8 @@ function registerTableImageFills(target, rows, opt) {
|
|
|
2907
3121
|
}
|
|
2908
3122
|
function addTableDefinition(target, tableRows, options, slideLayout, presLayout, addSlide, getSlide) {
|
|
2909
3123
|
const slides = [target];
|
|
2910
|
-
const opt = options && typeof options === "object" ? options : {};
|
|
3124
|
+
const opt = options && typeof options === "object" ? { ...options } : {};
|
|
3125
|
+
if (Array.isArray(opt.border)) opt.border = [...opt.border];
|
|
2911
3126
|
opt.objectName = opt.objectName ? encodeXmlAttrValue(validateObjectName(opt.objectName, "table")) : `Table ${target._slideObjects.filter((obj) => obj._type === "table").length}`;
|
|
2912
3127
|
if (opt.placeholder && slideLayout?._slideObjects) {
|
|
2913
3128
|
const placeHold = slideLayout._slideObjects.find((item) => item._type === "placeholder" && item.options?.placeholder === opt.placeholder);
|
|
@@ -2920,7 +3135,7 @@ function addTableDefinition(target, tableRows, options, slideLayout, presLayout,
|
|
|
2920
3135
|
}
|
|
2921
3136
|
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
3137
|
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);
|
|
3138
|
+
const arrRows = withCheckedSpans(normalizeTableRows(applyTableHeaderColumnSugar(tableRows, opt), opt));
|
|
2924
3139
|
if (opt.x === void 0 || opt.x === null) opt.x = .5;
|
|
2925
3140
|
if (opt.y === void 0 || opt.y === null) opt.y = .5;
|
|
2926
3141
|
opt.fontSize = opt.fontSize || 12;
|
|
@@ -3091,7 +3306,8 @@ function pushZoomObject(target, variant, opts, zoom) {
|
|
|
3091
3306
|
y: opts.y ?? 0,
|
|
3092
3307
|
w: opts.w ?? 0,
|
|
3093
3308
|
h: opts.h ?? 0,
|
|
3094
|
-
objectName
|
|
3309
|
+
objectName,
|
|
3310
|
+
...opts.objectLock ? { objectLock: opts.objectLock } : {}
|
|
3095
3311
|
},
|
|
3096
3312
|
zoom: {
|
|
3097
3313
|
variant,
|
|
@@ -3567,16 +3783,17 @@ var SlideBuilder = class {
|
|
|
3567
3783
|
* than one parameterized one. Called by {@link ./chart-xml}'s axis region.
|
|
3568
3784
|
*
|
|
3569
3785
|
* 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
|
-
*
|
|
3786
|
+
* `<c:spPr>`, which differs between the three only by indent width. `<c:txPr>` stays
|
|
3787
|
+
* duplicated — its inherited indentation is irregular *within* each copy as well as between
|
|
3788
|
+
* them (the category axis closes `</a:defRPr>` at three spaces, the value axis at six), so
|
|
3789
|
+
* one parameterised builder would take about as many indent arguments as it has lines, and
|
|
3790
|
+
* would hide the quirks rather than share the structure. Each copy states its own layout at
|
|
3791
|
+
* its own call site instead.
|
|
3575
3792
|
*
|
|
3576
|
-
*
|
|
3577
|
-
*
|
|
3578
|
-
*
|
|
3579
|
-
*
|
|
3793
|
+
* Regularising that whitespace so one builder *could* serve all three is still open, and
|
|
3794
|
+
* still a byte change — AGENTS.md is explicit that a whitespace-only diff is a STOP, not a
|
|
3795
|
+
* known divergence. It is a decision to take deliberately, with a re-baselined gate, not a
|
|
3796
|
+
* cleanup to fold into something else.
|
|
3580
3797
|
*/
|
|
3581
3798
|
/**
|
|
3582
3799
|
* The `<c:spPr>` axis-line block, identical in shape on all three axes.
|
|
@@ -3596,89 +3813,103 @@ var SlideBuilder = class {
|
|
|
3596
3813
|
*/
|
|
3597
3814
|
function axisLineSpPr(indent, widthEmu, show, color, dash) {
|
|
3598
3815
|
const at = (extra) => " ".repeat(indent + extra);
|
|
3599
|
-
|
|
3816
|
+
const line = el("a:ln", {
|
|
3817
|
+
w: widthEmu,
|
|
3818
|
+
cap: "flat"
|
|
3819
|
+
}, [
|
|
3820
|
+
raw(!show ? voidEl("a:noFill") : genXmlColorSelection(color || DEF_GRIDLINE_COLOR)),
|
|
3821
|
+
raw(voidEl("a:prstDash", { val: dash }, { openPrefix: at(4) })),
|
|
3822
|
+
raw(voidEl("a:round", null, { openPrefix: at(4) }))
|
|
3823
|
+
], {
|
|
3824
|
+
openPrefix: at(2),
|
|
3825
|
+
closePrefix: at(2)
|
|
3826
|
+
});
|
|
3827
|
+
return el("c:spPr", null, raw(line), {
|
|
3828
|
+
openPrefix: at(0),
|
|
3829
|
+
closePrefix: at(0)
|
|
3830
|
+
});
|
|
3600
3831
|
}
|
|
3601
3832
|
function makeCatAxis(opts, axisId, valAxisId) {
|
|
3602
|
-
let strXml = "";
|
|
3603
3833
|
const usesValueAxisForCategories = opts._type === "scatter" || opts._type === "bubble" || opts._type === "bubble3D";
|
|
3604
3834
|
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", {
|
|
3835
|
+
const tag = usesValueAxisForCategories ? "c:valAx" : opts.catLabelFormatCode ? "c:dateAx" : "c:catAx";
|
|
3836
|
+
const scaling = el("c:scaling", null, [
|
|
3837
|
+
raw(voidEl("c:orientation", { val: opts.catAxisOrientation || "minMax" })),
|
|
3838
|
+
opts.catAxisMaxVal || opts.catAxisMaxVal === 0 ? raw(voidEl("c:max", { val: opts.catAxisMaxVal })) : null,
|
|
3839
|
+
opts.catAxisMinVal || opts.catAxisMinVal === 0 ? raw(voidEl("c:min", { val: opts.catAxisMinVal })) : null
|
|
3840
|
+
], { openPrefix: " " });
|
|
3841
|
+
const numFmt = usesValueAxisForCategories ? voidEl("c:numFmt", {
|
|
3842
|
+
formatCode: (opts.catAxisLabelFormatCode ?? opts.valAxisLabelFormatCode) || "General",
|
|
3843
|
+
sourceLinked: 1
|
|
3844
|
+
}, { openPrefix: " " }) : voidEl("c:numFmt", {
|
|
3630
3845
|
formatCode: (opts.catLabelFormatCode ?? "") || "General",
|
|
3631
3846
|
sourceLinked: 1
|
|
3847
|
+
}, { openPrefix: " " });
|
|
3848
|
+
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: " " });
|
|
3849
|
+
const defRPr = el("a:defRPr", {
|
|
3850
|
+
sz: ptToHundredths(opts.catAxisLabelFontSize || 12),
|
|
3851
|
+
b: opts.catAxisLabelFontBold ? 1 : 0,
|
|
3852
|
+
i: opts.catAxisLabelFontItalic ? 1 : 0,
|
|
3853
|
+
u: "none",
|
|
3854
|
+
strike: "noStrike"
|
|
3855
|
+
}, [raw(genXmlColorSelection(opts.catAxisLabelColor || "000000")), raw(" " + createChartTextFonts(opts.catAxisLabelFontFace || "Arial"))], {
|
|
3856
|
+
openPrefix: " ",
|
|
3857
|
+
closePrefix: " "
|
|
3858
|
+
});
|
|
3859
|
+
const txPr = el("c:txPr", null, [
|
|
3860
|
+
raw(voidEl("a:bodyPr", { rot: opts.catAxisLabelRotate ? convertAngleUnits(opts.catAxisLabelRotate, "catAxisLabelRotate") : void 0 })),
|
|
3861
|
+
raw(voidEl("a:lstStyle", null, { openPrefix: " " })),
|
|
3862
|
+
raw(el("a:p", null, [raw(el("a:pPr", null, raw(defRPr), {
|
|
3863
|
+
openPrefix: " ",
|
|
3864
|
+
closePrefix: " "
|
|
3865
|
+
})), raw(voidEl("a:endParaRPr", { lang: opts.lang || "en-US" }, { openPrefix: " " }))], {
|
|
3866
|
+
openPrefix: " ",
|
|
3867
|
+
closePrefix: " "
|
|
3868
|
+
}))
|
|
3869
|
+
], {
|
|
3870
|
+
openPrefix: " ",
|
|
3871
|
+
closePrefix: " "
|
|
3632
3872
|
});
|
|
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
3873
|
const valAxisCrossTag = typeof opts.valAxisCrossesAt === "number" ? "crossesAt" : "crosses";
|
|
3659
3874
|
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
|
-
}
|
|
3875
|
+
let units = "";
|
|
3667
3876
|
if (opts.catLabelFormatCode || usesValueAxisForCategories) {
|
|
3668
3877
|
if (opts.catLabelFormatCode) {
|
|
3669
3878
|
const baseTimeUnit = validTimeUnit(opts.catAxisBaseTimeUnit, "catAxisBaseTimeUnit");
|
|
3670
3879
|
const majorTimeUnit = validTimeUnit(opts.catAxisMajorTimeUnit, "catAxisMajorTimeUnit");
|
|
3671
3880
|
const minorTimeUnit = validTimeUnit(opts.catAxisMinorTimeUnit, "catAxisMinorTimeUnit");
|
|
3672
|
-
if (baseTimeUnit)
|
|
3673
|
-
if (majorTimeUnit)
|
|
3674
|
-
if (minorTimeUnit)
|
|
3881
|
+
if (baseTimeUnit) units += voidEl("c:baseTimeUnit", { val: baseTimeUnit });
|
|
3882
|
+
if (majorTimeUnit) units += voidEl("c:majorTimeUnit", { val: majorTimeUnit });
|
|
3883
|
+
if (minorTimeUnit) units += voidEl("c:minorTimeUnit", { val: minorTimeUnit });
|
|
3675
3884
|
}
|
|
3676
|
-
if (opts.catAxisMajorUnit)
|
|
3677
|
-
if (opts.catAxisMinorUnit)
|
|
3678
|
-
}
|
|
3679
|
-
|
|
3680
|
-
|
|
3681
|
-
|
|
3885
|
+
if (opts.catAxisMajorUnit) units += voidEl("c:majorUnit", { val: opts.catAxisMajorUnit });
|
|
3886
|
+
if (opts.catAxisMinorUnit) units += voidEl("c:minorUnit", { val: opts.catAxisMinorUnit });
|
|
3887
|
+
}
|
|
3888
|
+
return el(tag, null, [
|
|
3889
|
+
raw(voidEl("c:axId", { val: axisId }, { openPrefix: " " })),
|
|
3890
|
+
raw(scaling),
|
|
3891
|
+
raw(voidEl("c:delete", { val: opts.catAxisHidden ? 1 : 0 }, { openPrefix: " " })),
|
|
3892
|
+
raw(voidEl("c:axPos", { val: opts.barDir === "col" ? "b" : "l" }, { openPrefix: " " })),
|
|
3893
|
+
raw(opts.catGridLine && opts.catGridLine.style !== "none" ? createGridLineElement(opts.catGridLine) : ""),
|
|
3894
|
+
opts.showCatAxisTitle ? raw(genXmlTitle({
|
|
3895
|
+
color: opts.catAxisTitleColor,
|
|
3896
|
+
fontFace: opts.catAxisTitleFontFace,
|
|
3897
|
+
fontSize: opts.catAxisTitleFontSize,
|
|
3898
|
+
titleRotate: opts.catAxisTitleRotate,
|
|
3899
|
+
title: opts.catAxisTitle || "Axis Title"
|
|
3900
|
+
})) : null,
|
|
3901
|
+
raw(numFmt),
|
|
3902
|
+
raw(ticks),
|
|
3903
|
+
raw(axisLineSpPr(2, opts.catAxisLineSize ? ptsToEmuLenient(opts.catAxisLineSize) : EMU_PER_POINT, opts.catAxisLineShow, opts.catAxisLineColor, opts.catAxisLineStyle || "solid")),
|
|
3904
|
+
raw(txPr),
|
|
3905
|
+
raw(voidEl("c:crossAx", { val: valAxisId }, { openPrefix: " " })),
|
|
3906
|
+
raw(voidEl(`c:${valAxisCrossTag}`, { val: valAxisCrossValue }, { openPrefix: " " })),
|
|
3907
|
+
usesValueAxisForCategories ? null : raw(voidEl("c:auto", { val: 1 }, { openPrefix: " " })),
|
|
3908
|
+
usesCategoryAxis ? raw(voidEl("c:lblAlgn", { val: "ctr" }, { openPrefix: " " })) : null,
|
|
3909
|
+
usesCategoryAxis && opts.catAxisLabelFrequency ? raw(voidEl("c:tickLblSkip", { val: opts.catAxisLabelFrequency }, { openPrefix: " " })) : null,
|
|
3910
|
+
usesCategoryAxis ? raw(voidEl("c:noMultiLvlLbl", { val: opts.catAxisMultiLevelLabels ? 0 : 1 }, { openPrefix: " " })) : null,
|
|
3911
|
+
raw(units)
|
|
3912
|
+
]);
|
|
3682
3913
|
}
|
|
3683
3914
|
/**
|
|
3684
3915
|
* Create Value Axis (Used by `bar3D`)
|
|
@@ -3690,61 +3921,68 @@ function makeValAxis(opts, valAxisId) {
|
|
|
3690
3921
|
let axisPos = valAxisId === "2094734552" ? opts.barDir === "col" ? "l" : "b" : opts.barDir !== "col" ? "r" : "t";
|
|
3691
3922
|
if (valAxisId === "2094734553") axisPos = "r";
|
|
3692
3923
|
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
|
|
3924
|
+
const scaling = el("c:scaling", null, [
|
|
3925
|
+
opts.valAxisLogScaleBase ? raw(voidEl("c:logBase", { val: opts.valAxisLogScaleBase })) : null,
|
|
3926
|
+
raw(voidEl("c:orientation", { val: opts.valAxisOrientation || "minMax" })),
|
|
3927
|
+
opts.valAxisMaxVal || opts.valAxisMaxVal === 0 ? raw(voidEl("c:max", { val: opts.valAxisMaxVal })) : null,
|
|
3928
|
+
opts.valAxisMinVal || opts.valAxisMinVal === 0 ? raw(voidEl("c:min", { val: opts.valAxisMinVal })) : null
|
|
3929
|
+
], {
|
|
3930
|
+
openPrefix: " ",
|
|
3931
|
+
closePrefix: " "
|
|
3715
3932
|
});
|
|
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
|
-
|
|
3933
|
+
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: " " });
|
|
3934
|
+
const defRPr = el("a:defRPr", {
|
|
3935
|
+
sz: ptToHundredths(opts.valAxisLabelFontSize || 12),
|
|
3936
|
+
b: opts.valAxisLabelFontBold ? 1 : 0,
|
|
3937
|
+
i: opts.valAxisLabelFontItalic ? 1 : 0,
|
|
3938
|
+
u: "none",
|
|
3939
|
+
strike: "noStrike"
|
|
3940
|
+
}, [raw(genXmlColorSelection(opts.valAxisLabelColor || "000000")), raw(" " + createChartTextFonts(opts.valAxisLabelFontFace || "Arial"))], {
|
|
3941
|
+
openPrefix: " ",
|
|
3942
|
+
closePrefix: " "
|
|
3943
|
+
});
|
|
3944
|
+
const txPr = el("c:txPr", null, [
|
|
3945
|
+
raw(voidEl("a:bodyPr", { rot: opts.valAxisLabelRotate ? convertAngleUnits(opts.valAxisLabelRotate, "valAxisLabelRotate") : void 0 }, { openPrefix: " " })),
|
|
3946
|
+
raw(voidEl("a:lstStyle", null, { openPrefix: " " })),
|
|
3947
|
+
raw(el("a:p", null, [raw(el("a:pPr", null, raw(defRPr), {
|
|
3948
|
+
openPrefix: " ",
|
|
3949
|
+
closePrefix: " "
|
|
3950
|
+
})), raw(voidEl("a:endParaRPr", { lang: opts.lang || "en-US" }, { openPrefix: " " }))], {
|
|
3951
|
+
openPrefix: " ",
|
|
3952
|
+
closePrefix: " "
|
|
3953
|
+
}))
|
|
3954
|
+
], {
|
|
3955
|
+
openPrefix: " ",
|
|
3956
|
+
closePrefix: " "
|
|
3957
|
+
});
|
|
3958
|
+
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: " " });
|
|
3959
|
+
const crossBetween = opts.valAxisCrossBetween || (opts._type === "scatter" || !!(Array.isArray(opts._type) && opts._type.some((type) => asChartType(type.type) === "area")) ? "midCat" : "between");
|
|
3960
|
+
return el("c:valAx", null, [
|
|
3961
|
+
raw(voidEl("c:axId", { val: valAxisId }, { openPrefix: " " })),
|
|
3962
|
+
raw(scaling),
|
|
3963
|
+
raw(voidEl("c:delete", { val: opts.valAxisHidden ? 1 : 0 }, { openPrefix: " " })),
|
|
3964
|
+
raw(voidEl("c:axPos", { val: axisPos }, { openPrefix: " " })),
|
|
3965
|
+
opts.valGridLine && opts.valGridLine.style !== "none" ? raw(createGridLineElement(opts.valGridLine)) : null,
|
|
3966
|
+
opts.showValAxisTitle ? raw(genXmlTitle({
|
|
3967
|
+
color: opts.valAxisTitleColor,
|
|
3968
|
+
fontFace: opts.valAxisTitleFontFace,
|
|
3969
|
+
fontSize: opts.valAxisTitleFontSize,
|
|
3970
|
+
titleRotate: opts.valAxisTitleRotate,
|
|
3971
|
+
title: opts.valAxisTitle || "Axis Title"
|
|
3972
|
+
})) : null,
|
|
3973
|
+
raw(voidEl("c:numFmt", {
|
|
3974
|
+
formatCode: opts.valAxisLabelFormatCode || "General",
|
|
3975
|
+
sourceLinked: 0
|
|
3976
|
+
})),
|
|
3977
|
+
raw(ticks),
|
|
3978
|
+
raw(axisLineSpPr(1, opts.valAxisLineSize ? ptsToEmuLenient(opts.valAxisLineSize) : EMU_PER_POINT, opts.valAxisLineShow, opts.valAxisLineColor, opts.valAxisLineStyle || "solid")),
|
|
3979
|
+
raw(txPr),
|
|
3980
|
+
raw(voidEl("c:crossAx", { val: crossAxId }, { openPrefix: " " })),
|
|
3981
|
+
raw(crosses),
|
|
3982
|
+
raw(voidEl("c:crossBetween", { val: crossBetween }, { openPrefix: " " })),
|
|
3983
|
+
opts.valAxisMajorUnit ? raw(voidEl("c:majorUnit", { val: opts.valAxisMajorUnit }, { openPrefix: " " })) : null,
|
|
3984
|
+
opts.valAxisDisplayUnit ? raw(el("c:dispUnits", null, [raw(voidEl("c:builtInUnit", { val: opts.valAxisDisplayUnit })), raw(opts.valAxisDisplayUnitLabel ? voidEl("c:dispUnitsLbl") : "")])) : null
|
|
3985
|
+
]);
|
|
3748
3986
|
}
|
|
3749
3987
|
/**
|
|
3750
3988
|
* Create Series Axis (Used by `bar3D`)
|
|
@@ -3754,651 +3992,850 @@ function makeValAxis(opts, valAxisId) {
|
|
|
3754
3992
|
* @return {string} XML
|
|
3755
3993
|
*/
|
|
3756
3994
|
function makeSerAxis(opts, axisId, valAxisId) {
|
|
3757
|
-
|
|
3758
|
-
|
|
3759
|
-
|
|
3760
|
-
|
|
3761
|
-
|
|
3762
|
-
|
|
3763
|
-
|
|
3764
|
-
|
|
3765
|
-
|
|
3766
|
-
fontFace: opts.serAxisTitleFontFace,
|
|
3767
|
-
fontSize: opts.serAxisTitleFontSize,
|
|
3768
|
-
titleRotate: opts.serAxisTitleRotate,
|
|
3769
|
-
title: opts.serAxisTitle || "Axis Title"
|
|
3770
|
-
});
|
|
3771
|
-
strXml += " " + voidEl("c:numFmt", {
|
|
3772
|
-
formatCode: (opts.serLabelFormatCode ?? "") || "General",
|
|
3773
|
-
sourceLinked: 0
|
|
3995
|
+
const defRPr = el("a:defRPr", {
|
|
3996
|
+
sz: ptToHundredths(opts.serAxisLabelFontSize || 12),
|
|
3997
|
+
b: opts.serAxisLabelFontBold ? 1 : 0,
|
|
3998
|
+
i: opts.serAxisLabelFontItalic ? 1 : 0,
|
|
3999
|
+
u: "none",
|
|
4000
|
+
strike: "noStrike"
|
|
4001
|
+
}, [raw(" " + genXmlColorSelection(opts.serAxisLabelColor || "000000")), raw(" " + createChartTextFonts(opts.serAxisLabelFontFace || "Arial"))], {
|
|
4002
|
+
openPrefix: " ",
|
|
4003
|
+
closePrefix: " "
|
|
3774
4004
|
});
|
|
3775
|
-
|
|
3776
|
-
|
|
3777
|
-
|
|
3778
|
-
|
|
3779
|
-
|
|
3780
|
-
|
|
3781
|
-
|
|
3782
|
-
|
|
3783
|
-
|
|
3784
|
-
|
|
3785
|
-
|
|
3786
|
-
|
|
3787
|
-
|
|
3788
|
-
|
|
3789
|
-
|
|
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 + "\"/>";
|
|
4005
|
+
const txPr = el("c:txPr", null, [
|
|
4006
|
+
raw(voidEl("a:bodyPr", null, { openPrefix: " " })),
|
|
4007
|
+
raw(voidEl("a:lstStyle", null, { openPrefix: " " })),
|
|
4008
|
+
raw(el("a:p", null, [raw(el("a:pPr", null, raw(defRPr), {
|
|
4009
|
+
openPrefix: " ",
|
|
4010
|
+
closePrefix: " "
|
|
4011
|
+
})), raw(voidEl("a:endParaRPr", { lang: opts.lang || "en-US" }, { openPrefix: " " }))], {
|
|
4012
|
+
openPrefix: " ",
|
|
4013
|
+
closePrefix: " "
|
|
4014
|
+
}))
|
|
4015
|
+
], {
|
|
4016
|
+
openPrefix: " ",
|
|
4017
|
+
closePrefix: " "
|
|
4018
|
+
});
|
|
4019
|
+
let units = "";
|
|
3795
4020
|
if (opts.serLabelFormatCode) {
|
|
3796
4021
|
const baseTimeUnit = validTimeUnit(opts.serAxisBaseTimeUnit, "serAxisBaseTimeUnit");
|
|
3797
4022
|
const majorTimeUnit = validTimeUnit(opts.serAxisMajorTimeUnit, "serAxisMajorTimeUnit");
|
|
3798
4023
|
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
|
-
|
|
4024
|
+
if (baseTimeUnit) units += ` <c:baseTimeUnit val="${baseTimeUnit}"/>`;
|
|
4025
|
+
if (majorTimeUnit) units += voidEl("c:majorTimeUnit", { val: majorTimeUnit }, { openPrefix: " " });
|
|
4026
|
+
if (minorTimeUnit) units += voidEl("c:minorTimeUnit", { val: minorTimeUnit }, { openPrefix: " " });
|
|
4027
|
+
if (opts.serAxisMajorUnit) units += voidEl("c:majorUnit", { val: opts.serAxisMajorUnit }, { openPrefix: " " });
|
|
4028
|
+
if (opts.serAxisMinorUnit) units += voidEl("c:minorUnit", { val: opts.serAxisMinorUnit }, { openPrefix: " " });
|
|
4029
|
+
}
|
|
4030
|
+
return el("c:serAx", null, [
|
|
4031
|
+
raw(voidEl("c:axId", { val: axisId }, { openPrefix: " " })),
|
|
4032
|
+
raw(el("c:scaling", null, raw(voidEl("c:orientation", { val: opts.serAxisOrientation || "minMax" })), { openPrefix: " " })),
|
|
4033
|
+
raw(voidEl("c:delete", { val: opts.serAxisHidden ? 1 : 0 }, { openPrefix: " " })),
|
|
4034
|
+
raw(voidEl("c:axPos", { val: opts.barDir === "col" ? "b" : "l" }, { openPrefix: " " })),
|
|
4035
|
+
raw(opts.serGridLine && opts.serGridLine.style !== "none" ? createGridLineElement(opts.serGridLine) : ""),
|
|
4036
|
+
opts.showSerAxisTitle ? raw(genXmlTitle({
|
|
4037
|
+
color: opts.serAxisTitleColor,
|
|
4038
|
+
fontFace: opts.serAxisTitleFontFace,
|
|
4039
|
+
fontSize: opts.serAxisTitleFontSize,
|
|
4040
|
+
titleRotate: opts.serAxisTitleRotate,
|
|
4041
|
+
title: opts.serAxisTitle || "Axis Title"
|
|
4042
|
+
})) : null,
|
|
4043
|
+
raw(voidEl("c:numFmt", {
|
|
4044
|
+
formatCode: (opts.serLabelFormatCode ?? "") || "General",
|
|
4045
|
+
sourceLinked: 0
|
|
4046
|
+
}, { openPrefix: " " })),
|
|
4047
|
+
raw(voidEl("c:majorTickMark", { val: "out" }, { openPrefix: " " })),
|
|
4048
|
+
raw(voidEl("c:minorTickMark", { val: "none" }, { openPrefix: " " })),
|
|
4049
|
+
raw(voidEl("c:tickLblPos", { val: opts.serAxisLabelPos || (opts.barDir === "col" ? "low" : "nextTo") }, { openPrefix: " " })),
|
|
4050
|
+
raw(axisLineSpPr(2, EMU_PER_POINT, opts.serAxisLineShow, opts.serAxisLineColor, "solid")),
|
|
4051
|
+
raw(txPr),
|
|
4052
|
+
raw(voidEl("c:crossAx", { val: valAxisId }, { openPrefix: " " })),
|
|
4053
|
+
raw(voidEl("c:crosses", { val: "autoZero" }, { openPrefix: " " })),
|
|
4054
|
+
opts.serAxisLabelFrequency ? raw(voidEl("c:tickLblSkip", { val: opts.serAxisLabelFrequency }, { openPrefix: " " })) : null,
|
|
4055
|
+
raw(units)
|
|
4056
|
+
]);
|
|
3807
4057
|
}
|
|
3808
|
-
/**
|
|
3809
|
-
* Create char title elements
|
|
3810
|
-
* @param {ChartPropsTitle} opts - options
|
|
3811
|
-
* @return {string} XML `<c:title>`
|
|
3812
|
-
*/
|
|
3813
4058
|
//#endregion
|
|
3814
4059
|
//#region src/gen/chart/plot-cat-axis.ts
|
|
3815
|
-
/**
|
|
3816
|
-
|
|
3817
|
-
|
|
3818
|
-
|
|
3819
|
-
|
|
3820
|
-
|
|
3821
|
-
let strXml = "";
|
|
3822
|
-
strXml += `<c:${chartType}Chart>`;
|
|
4060
|
+
/** The chart types drawn as a line (a marker per point, an optional smooth) rather than as a body. */
|
|
4061
|
+
const isLineLike = (chartType) => chartType === "line" || chartType === "radar";
|
|
4062
|
+
/** The two bar families, which share `<c:barDir>`, `<c:invertIfNegative>` and a gap width. */
|
|
4063
|
+
const isBarLike = (chartType) => chartType === "bar" || chartType === "bar3D";
|
|
4064
|
+
/** The type-gated children that open a plot element, before `<c:varyColors>`. */
|
|
4065
|
+
function plotGrouping(chartType, opts) {
|
|
3823
4066
|
if (chartType === "area" || chartType === "line") {
|
|
3824
4067
|
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") + "\"/>";
|
|
4068
|
+
return voidEl("c:grouping", { val: lineGrouping });
|
|
3830
4069
|
}
|
|
4070
|
+
if (isBarLike(chartType)) return voidEl("c:barDir", { val: opts.barDir }) + voidEl("c:grouping", { val: opts.barGrouping || "clustered" });
|
|
3831
4071
|
if (chartType === "radar") {
|
|
3832
4072
|
const radarStyleWire = {
|
|
3833
4073
|
radar: "standard",
|
|
3834
4074
|
markers: "marker",
|
|
3835
4075
|
filled: "filled"
|
|
3836
4076
|
}[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({
|
|
4077
|
+
return voidEl("c:radarStyle", { val: radarStyleWire });
|
|
4078
|
+
}
|
|
4079
|
+
return "";
|
|
4080
|
+
}
|
|
4081
|
+
/** Fill, outline and shadow for one series, from its resolved colour and the line/border options. */
|
|
4082
|
+
function serShapeProps(chartType, opts, seriesColor, lineSize, serIndex) {
|
|
4083
|
+
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);
|
|
4084
|
+
let line = "";
|
|
4085
|
+
if (isLineLike(chartType)) {
|
|
4086
|
+
const effectiveLineSize = lineSize ?? opts.lineSize ?? 2;
|
|
4087
|
+
line = effectiveLineSize === 0 ? el("a:ln", null, raw(voidEl("a:noFill"))) : el("a:ln", {
|
|
4088
|
+
w: ptsToEmuLenient(effectiveLineSize),
|
|
4089
|
+
cap: createLineCap(opts.lineCap)
|
|
4090
|
+
}, [
|
|
4091
|
+
raw(chartColorLineFill(seriesColor)),
|
|
4092
|
+
raw(voidEl("a:prstDash", { val: opts.lineDashValues?.[serIndex] ?? opts.lineDash ?? "solid" })),
|
|
4093
|
+
raw(voidEl("a:round"))
|
|
4094
|
+
]);
|
|
4095
|
+
} else if (opts.dataBorder) line = el("a:ln", {
|
|
4096
|
+
w: ptsToEmuLenient(resolveBorderWidth(opts.dataBorder, .75)),
|
|
4097
|
+
cap: createLineCap(opts.lineCap)
|
|
4098
|
+
}, [
|
|
4099
|
+
raw(genXmlColorSelection({
|
|
3865
4100
|
color: opts.dataBorder.color ?? "363636",
|
|
3866
4101
|
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>";
|
|
4102
|
+
})),
|
|
4103
|
+
raw(voidEl("a:prstDash", { val: "solid" })),
|
|
4104
|
+
raw(voidEl("a:round"))
|
|
4105
|
+
]);
|
|
4106
|
+
return el("c:spPr", null, [
|
|
4107
|
+
raw(fill),
|
|
4108
|
+
raw(line),
|
|
4109
|
+
raw(createShadowEffectLst(opts.shadow, DEF_SHAPE_SHADOW))
|
|
4110
|
+
], {
|
|
4111
|
+
openPrefix: " ",
|
|
4112
|
+
closePrefix: " "
|
|
3964
4113
|
});
|
|
3965
|
-
|
|
3966
|
-
|
|
3967
|
-
|
|
3968
|
-
|
|
3969
|
-
|
|
3970
|
-
|
|
3971
|
-
|
|
3972
|
-
|
|
3973
|
-
|
|
3974
|
-
|
|
3975
|
-
|
|
3976
|
-
|
|
3977
|
-
|
|
3978
|
-
|
|
4114
|
+
}
|
|
4115
|
+
/**
|
|
4116
|
+
* The point marker for a line/radar series. `<c:marker>` must precede `<c:dLbls>` in CT_LineSer
|
|
4117
|
+
* (schema order: spPr → marker → dPt → dLbls).
|
|
4118
|
+
*/
|
|
4119
|
+
function serMarker(opts, markerColor, seriesColor) {
|
|
4120
|
+
const spPr = el("c:spPr", null, [
|
|
4121
|
+
raw(markerColor === "transparent" ? voidEl("a:noFill") : genXmlColorSelection(markerColor)),
|
|
4122
|
+
raw(el("a:ln", {
|
|
4123
|
+
w: opts.lineDataSymbolLineSize,
|
|
4124
|
+
cap: "flat"
|
|
4125
|
+
}, [
|
|
4126
|
+
raw(chartColorLineFill(opts.lineDataSymbolLineColor || seriesColor)),
|
|
4127
|
+
raw(voidEl("a:prstDash", { val: "solid" })),
|
|
4128
|
+
raw(voidEl("a:round"))
|
|
4129
|
+
], { openPrefix: " " })),
|
|
4130
|
+
raw(voidEl("a:effectLst", null, { openPrefix: " " }))
|
|
4131
|
+
], {
|
|
4132
|
+
openPrefix: " ",
|
|
4133
|
+
closePrefix: " "
|
|
4134
|
+
});
|
|
4135
|
+
return el("c:marker", null, [
|
|
4136
|
+
raw(voidEl("c:symbol", { val: opts.lineDataSymbol }, { openPrefix: " " })),
|
|
4137
|
+
opts.lineDataSymbolSize ? raw(voidEl("c:size", { val: opts.lineDataSymbolSize })) : null,
|
|
4138
|
+
raw(spPr)
|
|
4139
|
+
]);
|
|
4140
|
+
}
|
|
4141
|
+
/** Per-series `<c:dLbls>`: number format, an optional label background, text style, show flags. */
|
|
4142
|
+
function serDataLabels(obj, opts, seriesColor) {
|
|
4143
|
+
const over = opts.seriesOptions?.[obj._dataIndex];
|
|
4144
|
+
const defRPr = el("a:defRPr", {
|
|
4145
|
+
b: over?.dataLabelFontBold ?? opts.dataLabelFontBold ?? false ? 1 : 0,
|
|
4146
|
+
i: over?.dataLabelFontItalic ?? opts.dataLabelFontItalic ?? false ? 1 : 0,
|
|
4147
|
+
strike: "noStrike",
|
|
4148
|
+
sz: ptToHundredths(over?.dataLabelFontSize ?? opts.dataLabelFontSize ?? 12),
|
|
4149
|
+
u: "none"
|
|
4150
|
+
}, [raw(genXmlColorSelection(over?.dataLabelColor ?? opts.dataLabelColor ?? "000000")), raw(createChartTextFonts(over?.dataLabelFontFace ?? opts.dataLabelFontFace ?? "Arial"))]);
|
|
4151
|
+
const txPr = el("c:txPr", null, [
|
|
4152
|
+
raw(voidEl("a:bodyPr")),
|
|
4153
|
+
raw(voidEl("a:lstStyle")),
|
|
4154
|
+
raw(el("a:p", null, raw(el("a:pPr", null, raw(defRPr)))))
|
|
4155
|
+
]);
|
|
4156
|
+
const lblFmtCode = over?.dataLabelFormatCode ?? opts.dataLabelFormatCode;
|
|
4157
|
+
return el("c:dLbls", null, [
|
|
4158
|
+
raw((obj.customLabels ?? []).map((lbl, idx) => lbl ? makeCustomDLblXml(idx, lbl, opts) : "").join("")),
|
|
4159
|
+
raw(voidEl("c:numFmt", {
|
|
4160
|
+
formatCode: (lblFmtCode ?? "") || "General",
|
|
4161
|
+
sourceLinked: 0
|
|
4162
|
+
})),
|
|
4163
|
+
opts.dataLabelBkgrdColors ? raw(el("c:spPr", null, raw(genXmlColorSelection(seriesColor)))) : null,
|
|
4164
|
+
raw(txPr),
|
|
4165
|
+
opts.dataLabelPosition ? raw(voidEl("c:dLblPos", { val: opts.dataLabelPosition })) : null,
|
|
4166
|
+
raw(voidEl("c:showLegendKey", { val: 0 })),
|
|
4167
|
+
raw(voidEl("c:showVal", { val: opts.showValue ? 1 : 0 })),
|
|
4168
|
+
raw(voidEl("c:showCatName", { val: 0 })),
|
|
4169
|
+
raw(voidEl("c:showSerName", { val: opts.showSerName ? 1 : 0 })),
|
|
4170
|
+
raw(voidEl("c:showPercent", { val: 0 })),
|
|
4171
|
+
raw(voidEl("c:showBubbleSize", { val: 0 })),
|
|
4172
|
+
raw(voidEl("c:showLeaderLines", { val: opts.showLeaderLines ? 1 : 0 }))
|
|
4173
|
+
]);
|
|
4174
|
+
}
|
|
4175
|
+
/**
|
|
4176
|
+
* The `<c:cat>` category reference. Numeric (date) categories and single-level text ones are
|
|
4177
|
+
* {@link catRefBlock}; multi-level labels nest a `<c:lvl>` per group, which is a different shape
|
|
4178
|
+
* rather than a different spelling of the same one.
|
|
4179
|
+
*/
|
|
4180
|
+
function serCategories(obj, opts) {
|
|
4181
|
+
const groups = dataLabels(obj);
|
|
4182
|
+
const cats = firstLabelGroup(obj);
|
|
4183
|
+
const catRef = `Sheet1!$A$2:$A$${cats.length + 1}`;
|
|
4184
|
+
if (opts.catLabelFormatCode) return el("c:cat", null, raw(catRefBlock("num", catRef, cats, opts.catLabelFormatCode || "General", "indented")));
|
|
4185
|
+
if (groups.length === 1) return el("c:cat", null, raw(catRefBlock("str", catRef, cats, void 0, "indented")));
|
|
4186
|
+
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("");
|
|
4187
|
+
const cache = el("c:multiLvlStrCache", null, [raw(voidEl("c:ptCount", { val: cats.length }, { openPrefix: " " })), raw(lvls)], {
|
|
4188
|
+
openPrefix: " ",
|
|
4189
|
+
closePrefix: " "
|
|
4190
|
+
});
|
|
4191
|
+
const ref = el("c:multiLvlStrRef", null, [raw(el("c:f", null, sheetRangeRef(1, 2, groups.length, cats.length + 1), { openPrefix: " " })), raw(cache)], {
|
|
4192
|
+
openPrefix: " ",
|
|
4193
|
+
closePrefix: " "
|
|
4194
|
+
});
|
|
4195
|
+
return el("c:cat", null, raw(ref));
|
|
4196
|
+
}
|
|
4197
|
+
/** The `<c:val>` numeric cache: the series' own sheet column, one point per category. */
|
|
4198
|
+
function serValues(obj, valFmtCode) {
|
|
4199
|
+
const valCol = obj._dataIndex + dataLabels(obj).length + 1;
|
|
4200
|
+
const catCount = firstLabelGroup(obj).length;
|
|
4201
|
+
const numCache = el("c:numCache", null, [
|
|
4202
|
+
raw(el("c:formatCode", null, valFmtCode, { openPrefix: " " })),
|
|
4203
|
+
raw(voidEl("c:ptCount", { val: catCount }, { openPrefix: " " })),
|
|
4204
|
+
raw(dataValues(obj).map((value, idx) => numCachePt(idx, value)).join(""))
|
|
4205
|
+
], {
|
|
4206
|
+
openPrefix: " ",
|
|
4207
|
+
closePrefix: " "
|
|
4208
|
+
});
|
|
4209
|
+
const numRef = el("c:numRef", null, [raw(el("c:f", null, sheetRangeRef(valCol, 2, valCol, catCount + 1))), raw(numCache)], {
|
|
4210
|
+
openPrefix: " ",
|
|
4211
|
+
closePrefix: " "
|
|
4212
|
+
});
|
|
4213
|
+
return el("c:val", null, raw(numRef));
|
|
4214
|
+
}
|
|
4215
|
+
/**
|
|
4216
|
+
* Plot a category-axis chart family (area / bar / bar3d / line / radar) into a
|
|
4217
|
+
* `<c:xxxChart>` element. These share the grouping / series / cat+val axis structure.
|
|
4218
|
+
*/
|
|
4219
|
+
function makeCatAxisPlot(chartType, data, opts, valAxisId, catAxisId, valFmtCode) {
|
|
4220
|
+
const chartColors = resolveChartPalette(opts);
|
|
4221
|
+
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;
|
|
4222
|
+
const sers = data.map((obj, serIndex) => {
|
|
4223
|
+
const seriesOverride = opts.seriesOptions?.[obj._dataIndex];
|
|
4224
|
+
const seriesColor = seriesOverride?.color ?? paletteColor(chartColors, serIndex);
|
|
4225
|
+
return el("c:ser", null, [
|
|
4226
|
+
raw(voidEl("c:idx", { val: obj._dataIndex }, { openPrefix: " " })),
|
|
4227
|
+
raw(voidEl("c:order", { val: obj._dataIndex })),
|
|
4228
|
+
raw(strRefBlock(sheetCellRef(obj._dataIndex + dataLabels(obj).length + 1, 1), obj.name ?? "")),
|
|
4229
|
+
raw(serShapeProps(chartType, opts, seriesColor, seriesOverride?.lineSize, serIndex)),
|
|
4230
|
+
isBarLike(chartType) ? raw(voidEl("c:invertIfNegative", { val: 0 }, { openPrefix: " " })) : null,
|
|
4231
|
+
isLineLike(chartType) ? raw(serMarker(opts, paletteColor(chartColors, obj._dataIndex), seriesColor)) : null,
|
|
4232
|
+
raw(makeSeriesDataPointsXml(chartType, obj, opts, barVaryColors)),
|
|
4233
|
+
chartType === "radar" ? null : raw(serDataLabels(obj, opts, seriesColor)),
|
|
4234
|
+
chartType === "radar" ? null : raw(makeChartErrorBarsXml(chartType, obj.errorBars, obj)),
|
|
4235
|
+
raw(serCategories(obj, opts)),
|
|
4236
|
+
raw(serValues(obj, valFmtCode)),
|
|
4237
|
+
chartType === "line" ? raw(voidEl("c:smooth", { val: opts.lineSmooth ? 1 : 0 })) : null
|
|
4238
|
+
]);
|
|
4239
|
+
}).join("");
|
|
4240
|
+
let plotOptions = "";
|
|
4241
|
+
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);
|
|
4242
|
+
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: " " });
|
|
4243
|
+
else if (chartType === "line") plotOptions = voidEl("c:marker", { val: 1 }, { openPrefix: " " });
|
|
4244
|
+
return el(`c:${chartType}Chart`, null, [
|
|
4245
|
+
raw(plotGrouping(chartType, opts)),
|
|
4246
|
+
raw(voidEl("c:varyColors", { val: 0 })),
|
|
4247
|
+
raw(sers),
|
|
4248
|
+
raw(chartDataLabels(opts, true)),
|
|
4249
|
+
raw(plotOptions),
|
|
4250
|
+
raw(voidEl("c:axId", { val: catAxisId })),
|
|
4251
|
+
raw(voidEl("c:axId", { val: valAxisId })),
|
|
4252
|
+
chartType === "bar3D" ? raw(voidEl("c:axId", { val: AXIS_ID_SERIES_PRIMARY })) : null
|
|
4253
|
+
]);
|
|
3979
4254
|
}
|
|
3980
4255
|
//#endregion
|
|
3981
4256
|
//#region src/gen/chart/plot-scatter.ts
|
|
4257
|
+
/** The font attributes a scatter label's `<a:defRPr>` and `<a:rPr>` both carry, in schema order. */
|
|
4258
|
+
function labelFontAttrs(opts) {
|
|
4259
|
+
return {
|
|
4260
|
+
sz: ptToHundredths(opts.dataLabelFontSize || 12),
|
|
4261
|
+
b: opts.dataLabelFontBold ? 1 : 0,
|
|
4262
|
+
i: opts.dataLabelFontItalic ? 1 : 0,
|
|
4263
|
+
u: "none",
|
|
4264
|
+
strike: "noStrike"
|
|
4265
|
+
};
|
|
4266
|
+
}
|
|
4267
|
+
/** The colour and typeface children of those run properties; `indent` is theirs, not the parent's. */
|
|
4268
|
+
function labelFontChildren(opts, indent) {
|
|
4269
|
+
return [raw(indent + el("a:solidFill", null, raw(createColorElement(opts.dataLabelColor || "000000")))), raw(indent + createChartTextFonts(opts.dataLabelFontFace || "Arial"))];
|
|
4270
|
+
}
|
|
4271
|
+
/**
|
|
4272
|
+
* The `(x, y)` runs appended to a `customXY` label: a literal `" ("`, an `XVALUE` field, a
|
|
4273
|
+
* `", "`, a `YVALUE` field and a `")"`.
|
|
4274
|
+
*
|
|
4275
|
+
* Each `<a:fld>` id is minted per build. A field id has to be unique, which is a property a
|
|
4276
|
+
* derived id would have to reproduce without an oracle for how far that uniqueness has to
|
|
4277
|
+
* reach — so the ids stay random and the *comparison* gives: `NORMALIZERS` in
|
|
4278
|
+
* `scripts/pptx-parts.mjs` erases exactly these two field types before the byte-identity gate
|
|
4279
|
+
* diffs a part. Do not "fix" the nondeterminism here.
|
|
4280
|
+
*/
|
|
4281
|
+
function customXYRuns(obj, opts) {
|
|
4282
|
+
const lang = opts.lang || "en-US";
|
|
4283
|
+
const literal = (text) => el("a:r", null, [raw(voidEl("a:rPr", {
|
|
4284
|
+
lang,
|
|
4285
|
+
baseline: 0,
|
|
4286
|
+
dirty: 0
|
|
4287
|
+
}, { openPrefix: " " })), raw(el("a:t", null, text, { openPrefix: " " }))], {
|
|
4288
|
+
openPrefix: " ",
|
|
4289
|
+
closePrefix: " "
|
|
4290
|
+
});
|
|
4291
|
+
const field = (type, text) => el("a:fld", {
|
|
4292
|
+
id: `{${getUuid("xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx")}}`,
|
|
4293
|
+
type
|
|
4294
|
+
}, [
|
|
4295
|
+
raw(voidEl("a:rPr", {
|
|
4296
|
+
lang,
|
|
4297
|
+
baseline: 0
|
|
4298
|
+
}, { openPrefix: " " })),
|
|
4299
|
+
raw(el("a:pPr", null, raw(voidEl("a:defRPr", null, { openPrefix: " " })), {
|
|
4300
|
+
openPrefix: " ",
|
|
4301
|
+
closePrefix: " "
|
|
4302
|
+
})),
|
|
4303
|
+
raw(" " + el("a:t", null, text))
|
|
4304
|
+
], {
|
|
4305
|
+
openPrefix: " ",
|
|
4306
|
+
closePrefix: " "
|
|
4307
|
+
});
|
|
4308
|
+
return literal(" (") + field("XVALUE", "[" + (obj.name ?? "")) + literal(", ") + field("YVALUE", "[" + (obj.name ?? "") + "]") + literal(")") + voidEl("a:endParaRPr", {
|
|
4309
|
+
lang,
|
|
4310
|
+
dirty: 0
|
|
4311
|
+
}, { openPrefix: " " });
|
|
4312
|
+
}
|
|
4313
|
+
/**
|
|
4314
|
+
* One per-point `<c:dLbl>` for the `custom` / `customXY` label formats: rich text carrying the
|
|
4315
|
+
* caller's label, optionally followed by the X/Y value fields.
|
|
4316
|
+
*/
|
|
4317
|
+
function scatterCustomLabel(obj, opts, label, idx, chartUuid) {
|
|
4318
|
+
const rich = el("c:rich", null, [
|
|
4319
|
+
raw(el("a:bodyPr", null, raw(voidEl("a:spAutoFit", null, { openPrefix: " " })), {
|
|
4320
|
+
openPrefix: " ",
|
|
4321
|
+
closePrefix: " "
|
|
4322
|
+
})),
|
|
4323
|
+
raw(voidEl("a:lstStyle", null, { openPrefix: " " })),
|
|
4324
|
+
raw(el("a:p", null, [
|
|
4325
|
+
raw(el("a:pPr", null, raw(el("a:defRPr", labelFontAttrs(opts), labelFontChildren(opts, " "), {
|
|
4326
|
+
openPrefix: " ",
|
|
4327
|
+
closePrefix: " "
|
|
4328
|
+
})), {
|
|
4329
|
+
openPrefix: " ",
|
|
4330
|
+
closePrefix: " "
|
|
4331
|
+
})),
|
|
4332
|
+
raw(el("a:r", null, [raw(el("a:rPr", {
|
|
4333
|
+
lang: opts.lang || "en-US",
|
|
4334
|
+
...labelFontAttrs(opts),
|
|
4335
|
+
dirty: 0
|
|
4336
|
+
}, labelFontChildren(opts, " "), {
|
|
4337
|
+
openPrefix: " ",
|
|
4338
|
+
closePrefix: " "
|
|
4339
|
+
})), raw(" " + el("a:t", null, label))], {
|
|
4340
|
+
openPrefix: " ",
|
|
4341
|
+
closePrefix: " "
|
|
4342
|
+
})),
|
|
4343
|
+
opts.dataLabelFormatScatter === "customXY" && !/^ *$/.test(label) ? raw(customXYRuns(obj, opts)) : null
|
|
4344
|
+
], {
|
|
4345
|
+
openPrefix: " ",
|
|
4346
|
+
closePrefix: " "
|
|
4347
|
+
}))
|
|
4348
|
+
], {
|
|
4349
|
+
openPrefix: " ",
|
|
4350
|
+
closePrefix: " "
|
|
4351
|
+
});
|
|
4352
|
+
const spPr = el("c:spPr", null, [
|
|
4353
|
+
raw(voidEl("a:noFill", null, { openPrefix: " " })),
|
|
4354
|
+
raw(el("a:ln", null, raw(voidEl("a:noFill", null, { openPrefix: " " })), {
|
|
4355
|
+
openPrefix: " ",
|
|
4356
|
+
closePrefix: " "
|
|
4357
|
+
})),
|
|
4358
|
+
raw(voidEl("a:effectLst", null, { openPrefix: " " }))
|
|
4359
|
+
], {
|
|
4360
|
+
openPrefix: " ",
|
|
4361
|
+
closePrefix: " "
|
|
4362
|
+
});
|
|
4363
|
+
const extLst = el("c:extLst", null, [raw(voidEl("c:ext", {
|
|
4364
|
+
uri: "{CE6537A1-D6FC-4f65-9D91-7224C49458BB}",
|
|
4365
|
+
"xmlns:c15": "http://schemas.microsoft.com/office/drawing/2012/chart"
|
|
4366
|
+
}, { openPrefix: " " })), raw(el("c:ext", {
|
|
4367
|
+
uri: "{C3380CC4-5D6E-409C-BE32-E72D297353CC}",
|
|
4368
|
+
"xmlns:c16": "http://schemas.microsoft.com/office/drawing/2014/chart"
|
|
4369
|
+
}, raw(voidEl("c16:uniqueId", { val: `{${String(idx + 1).padStart(8, "0")}${chartUuid}}` }, { openPrefix: " " })), {
|
|
4370
|
+
openPrefix: " ",
|
|
4371
|
+
closePrefix: " "
|
|
4372
|
+
}))], {
|
|
4373
|
+
openPrefix: " ",
|
|
4374
|
+
closePrefix: " "
|
|
4375
|
+
});
|
|
4376
|
+
return el("c:dLbl", null, [
|
|
4377
|
+
raw(voidEl("c:idx", { val: idx }, { openPrefix: " " })),
|
|
4378
|
+
raw(el("c:tx", null, raw(rich), {
|
|
4379
|
+
openPrefix: " ",
|
|
4380
|
+
closePrefix: " "
|
|
4381
|
+
})),
|
|
4382
|
+
raw(spPr),
|
|
4383
|
+
opts.dataLabelPosition ? raw(voidEl("c:dLblPos", { val: opts.dataLabelPosition }, { openPrefix: " " })) : null,
|
|
4384
|
+
raw(voidEl("c:showLegendKey", { val: 0 }, { openPrefix: " " })),
|
|
4385
|
+
raw(voidEl("c:showVal", { val: 0 }, { openPrefix: " " })),
|
|
4386
|
+
raw(voidEl("c:showCatName", { val: 0 }, { openPrefix: " " })),
|
|
4387
|
+
raw(voidEl("c:showSerName", { val: 0 }, { openPrefix: " " })),
|
|
4388
|
+
raw(voidEl("c:showPercent", { val: 0 }, { openPrefix: " " })),
|
|
4389
|
+
raw(voidEl("c:showBubbleSize", { val: 0 }, { openPrefix: " " })),
|
|
4390
|
+
raw(voidEl("c:showLeaderLines", { val: 1 }, { openPrefix: " " })),
|
|
4391
|
+
raw(extLst)
|
|
4392
|
+
], { openPrefix: " " });
|
|
4393
|
+
}
|
|
4394
|
+
/** The single chart-level `<c:dLbls>` of the `XY` label format: PowerPoint composes the text. */
|
|
4395
|
+
function scatterXYLabels(opts) {
|
|
4396
|
+
const spPr = el("c:spPr", null, [
|
|
4397
|
+
raw(voidEl("a:noFill", null, { openPrefix: " " })),
|
|
4398
|
+
raw(el("a:ln", null, raw(voidEl("a:noFill", null, { openPrefix: " " })), {
|
|
4399
|
+
openPrefix: " ",
|
|
4400
|
+
closePrefix: " "
|
|
4401
|
+
})),
|
|
4402
|
+
raw(voidEl("a:effectLst", null, { openPrefix: " " }))
|
|
4403
|
+
], {
|
|
4404
|
+
openPrefix: " ",
|
|
4405
|
+
closePrefix: " "
|
|
4406
|
+
});
|
|
4407
|
+
const txPr = el("c:txPr", null, [
|
|
4408
|
+
raw(el("a:bodyPr", null, raw(voidEl("a:spAutoFit", null, { openPrefix: " " })), {
|
|
4409
|
+
openPrefix: " ",
|
|
4410
|
+
closePrefix: " "
|
|
4411
|
+
})),
|
|
4412
|
+
raw(voidEl("a:lstStyle", null, { openPrefix: " " })),
|
|
4413
|
+
raw(el("a:p", null, [raw(el("a:pPr", null, raw(el("a:defRPr", labelFontAttrs(opts), labelFontChildren(opts, " "), {
|
|
4414
|
+
openPrefix: " ",
|
|
4415
|
+
closePrefix: " "
|
|
4416
|
+
})), {
|
|
4417
|
+
openPrefix: " ",
|
|
4418
|
+
closePrefix: " "
|
|
4419
|
+
})), raw(voidEl("a:endParaRPr", { lang: opts.lang || "en-US" }, { openPrefix: " " }))], {
|
|
4420
|
+
openPrefix: " ",
|
|
4421
|
+
closePrefix: " "
|
|
4422
|
+
}))
|
|
4423
|
+
], {
|
|
4424
|
+
openPrefix: " ",
|
|
4425
|
+
closePrefix: " "
|
|
4426
|
+
});
|
|
4427
|
+
const extLst = el("c:extLst", null, raw(el("c:ext", {
|
|
4428
|
+
uri: "{CE6537A1-D6FC-4f65-9D91-7224C49458BB}",
|
|
4429
|
+
"xmlns:c15": "http://schemas.microsoft.com/office/drawing/2012/chart"
|
|
4430
|
+
}, raw(voidEl("c15:showLeaderLines", { val: 1 }, { openPrefix: " " })), {
|
|
4431
|
+
openPrefix: " ",
|
|
4432
|
+
closePrefix: " "
|
|
4433
|
+
})), {
|
|
4434
|
+
openPrefix: " ",
|
|
4435
|
+
closePrefix: " "
|
|
4436
|
+
});
|
|
4437
|
+
return el("c:dLbls", null, [
|
|
4438
|
+
raw(spPr),
|
|
4439
|
+
raw(txPr),
|
|
4440
|
+
opts.dataLabelPosition ? raw(voidEl("c:dLblPos", { val: opts.dataLabelPosition }, { openPrefix: " " })) : null,
|
|
4441
|
+
raw(voidEl("c:showLegendKey", { val: 0 }, { openPrefix: " " })),
|
|
4442
|
+
raw(voidEl("c:showVal", { val: opts.showLabel ? 1 : 0 }, { openPrefix: " " })),
|
|
4443
|
+
raw(voidEl("c:showCatName", { val: opts.showLabel ? 1 : 0 }, { openPrefix: " " })),
|
|
4444
|
+
raw(voidEl("c:showSerName", { val: opts.showSerName ? 1 : 0 }, { openPrefix: " " })),
|
|
4445
|
+
raw(voidEl("c:showPercent", { val: 0 }, { openPrefix: " " })),
|
|
4446
|
+
raw(voidEl("c:showBubbleSize", { val: 0 }, { openPrefix: " " })),
|
|
4447
|
+
raw(extLst)
|
|
4448
|
+
]);
|
|
4449
|
+
}
|
|
4450
|
+
/** Fill, outline and shadow for one scatter series. */
|
|
4451
|
+
function scatterSerShapeProps(opts, serColor, serIndex) {
|
|
4452
|
+
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);
|
|
4453
|
+
const line = opts.lineSize === 0 ? el("a:ln", null, raw(voidEl("a:noFill"))) : el("a:ln", {
|
|
4454
|
+
w: ptsToEmuLenient(opts.lineSize ?? 2),
|
|
4455
|
+
cap: createLineCap(opts.lineCap)
|
|
4456
|
+
}, [
|
|
4457
|
+
raw(chartColorLineFill(serColor)),
|
|
4458
|
+
raw(voidEl("a:prstDash", { val: opts.lineDashValues?.[serIndex] ?? opts.lineDash ?? "solid" })),
|
|
4459
|
+
raw(voidEl("a:round"))
|
|
4460
|
+
]);
|
|
4461
|
+
return el("c:spPr", null, [
|
|
4462
|
+
raw(fill),
|
|
4463
|
+
raw(line),
|
|
4464
|
+
raw(createShadowEffectLst(opts.shadow, DEF_SHAPE_SHADOW))
|
|
4465
|
+
], {
|
|
4466
|
+
openPrefix: " ",
|
|
4467
|
+
closePrefix: " "
|
|
4468
|
+
});
|
|
4469
|
+
}
|
|
4470
|
+
/** The point marker: symbol, optional size, and its own fill and outline. */
|
|
4471
|
+
function scatterMarker(opts, markerColor) {
|
|
4472
|
+
const spPr = el("c:spPr", null, [
|
|
4473
|
+
raw(markerColor === "transparent" ? voidEl("a:noFill") : genXmlColorSelection(markerColor)),
|
|
4474
|
+
raw(el("a:ln", {
|
|
4475
|
+
w: opts.lineDataSymbolLineSize,
|
|
4476
|
+
cap: "flat"
|
|
4477
|
+
}, [
|
|
4478
|
+
raw(chartColorLineFill(opts.lineDataSymbolLineColor || markerColor)),
|
|
4479
|
+
raw(voidEl("a:prstDash", { val: "solid" })),
|
|
4480
|
+
raw(voidEl("a:round"))
|
|
4481
|
+
])),
|
|
4482
|
+
raw(voidEl("a:effectLst"))
|
|
4483
|
+
]);
|
|
4484
|
+
return el("c:marker", null, [
|
|
4485
|
+
raw(voidEl("c:symbol", { val: opts.lineDataSymbol }, { openPrefix: " " })),
|
|
4486
|
+
opts.lineDataSymbolSize ? raw(voidEl("c:size", { val: opts.lineDataSymbolSize })) : null,
|
|
4487
|
+
raw(spPr)
|
|
4488
|
+
]);
|
|
4489
|
+
}
|
|
3982
4490
|
/**
|
|
3983
4491
|
* Plot an XY scatter chart into `<c:scatterChart>` (paired X/Y numeric series).
|
|
3984
4492
|
*/
|
|
3985
4493
|
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
|
-
}
|
|
4494
|
+
const chartColors = resolveChartPalette(opts);
|
|
4495
|
+
const xValues = dataValues(data[0]);
|
|
4496
|
+
const scatterVaryColors = data.length === 1 && opts.chartColors !== BARCHART_COLORS ? opts.chartColors || BARCHART_COLORS : null;
|
|
4497
|
+
const sers = data.slice(1).map((obj, idx) => {
|
|
4498
|
+
const serColor = paletteColor(chartColors, idx);
|
|
4499
|
+
const yValues = dataValues(obj);
|
|
4500
|
+
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]));
|
|
4501
|
+
let labels = "";
|
|
4034
4502
|
if (opts.showLabel) {
|
|
4035
4503
|
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
|
-
}
|
|
4158
|
-
}
|
|
4159
|
-
strXml += makeChartErrorBarsXml(chartType, obj.errorBars, obj);
|
|
4160
|
-
{
|
|
4161
|
-
const xValues = dataValues(data[0]);
|
|
4162
|
-
const yValues = dataValues(obj);
|
|
4163
|
-
strXml += numRefBlock("c:xVal", `Sheet1!$A$2:$A$${xValues.length + 1}`, valFmtCode, xValues);
|
|
4164
|
-
strXml += numRefBlock("c:yVal", sheetRangeRef(idx + 2, 2, idx + 2, xValues.length + 1), valFmtCode, xValues.map((_value, i) => yValues[i]));
|
|
4504
|
+
const isCustom = opts.dataLabelFormatScatter === "custom" || opts.dataLabelFormatScatter === "customXY";
|
|
4505
|
+
if (dataLabels(obj)[0] && isCustom) labels += el("c:dLbls", null, raw(firstLabelGroup(obj).map((label, pointIdx) => scatterCustomLabel(obj, opts, label, pointIdx, chartUuid)).join("")));
|
|
4506
|
+
if (opts.dataLabelFormatScatter === "XY") labels += scatterXYLabels(opts);
|
|
4165
4507
|
}
|
|
4166
|
-
|
|
4167
|
-
|
|
4508
|
+
return el("c:ser", null, [
|
|
4509
|
+
raw(voidEl("c:idx", { val: idx }, { openPrefix: " " })),
|
|
4510
|
+
raw(voidEl("c:order", { val: idx }, { openPrefix: " " })),
|
|
4511
|
+
raw(strRefBlock(sheetCellRef(idx + 2, 1), obj.name ?? "")),
|
|
4512
|
+
raw(scatterSerShapeProps(opts, serColor, idx)),
|
|
4513
|
+
raw(scatterMarker(opts, serColor)),
|
|
4514
|
+
raw(makeSeriesDataPointsXml(chartType, obj, opts, scatterVaryColors)),
|
|
4515
|
+
raw(labels),
|
|
4516
|
+
raw(makeChartErrorBarsXml(chartType, obj.errorBars, obj)),
|
|
4517
|
+
raw(values),
|
|
4518
|
+
raw(voidEl("c:smooth", { val: opts.lineSmooth ? 1 : 0 }))
|
|
4519
|
+
]);
|
|
4520
|
+
}).join("");
|
|
4521
|
+
return el(`c:${chartType}Chart`, null, [
|
|
4522
|
+
raw(voidEl("c:scatterStyle", { val: "lineMarker" })),
|
|
4523
|
+
raw(voidEl("c:varyColors", { val: 0 })),
|
|
4524
|
+
raw(sers),
|
|
4525
|
+
raw(chartDataLabels(opts, false)),
|
|
4526
|
+
raw(voidEl("c:axId", { val: catAxisId })),
|
|
4527
|
+
raw(voidEl("c:axId", { val: valAxisId }))
|
|
4528
|
+
]);
|
|
4529
|
+
}
|
|
4530
|
+
//#endregion
|
|
4531
|
+
//#region src/gen/chart/plot-bubble.ts
|
|
4532
|
+
/** Fill + outline + shadow for one bubble series, from the palette colour and the line options. */
|
|
4533
|
+
function bubbleSerShapeProps(opts, serColor, serIndex) {
|
|
4534
|
+
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);
|
|
4535
|
+
const line = opts.lineSize === 0 ? el("a:ln", null, raw(voidEl("a:noFill"))) : opts.dataBorder ? el("a:ln", {
|
|
4536
|
+
w: ptsToEmuLenient(resolveBorderWidth(opts.dataBorder, .75)),
|
|
4537
|
+
cap: "flat"
|
|
4538
|
+
}, [
|
|
4539
|
+
raw(genXmlColorSelection({
|
|
4540
|
+
color: opts.dataBorder.color ?? "363636",
|
|
4541
|
+
transparency: opts.dataBorder.transparency
|
|
4542
|
+
})),
|
|
4543
|
+
raw(voidEl("a:prstDash", { val: "solid" })),
|
|
4544
|
+
raw(voidEl("a:round"))
|
|
4545
|
+
]) : el("a:ln", {
|
|
4546
|
+
w: ptsToEmuLenient(opts.lineSize ?? 2),
|
|
4547
|
+
cap: "flat"
|
|
4548
|
+
}, [
|
|
4549
|
+
raw(genXmlColorSelection(serColor)),
|
|
4550
|
+
raw(voidEl("a:prstDash", { val: opts.lineDashValues?.[serIndex] ?? opts.lineDash ?? "solid" })),
|
|
4551
|
+
raw(voidEl("a:round"))
|
|
4552
|
+
]);
|
|
4553
|
+
return el("c:spPr", null, [
|
|
4554
|
+
raw(fill),
|
|
4555
|
+
raw(line),
|
|
4556
|
+
raw(createShadowEffectLst(opts.shadow, DEF_SHAPE_SHADOW))
|
|
4557
|
+
]);
|
|
4558
|
+
}
|
|
4559
|
+
/**
|
|
4560
|
+
* The `<c:bubbleSize>` cache: the per-point sizes that scale each bubble. Its own block rather
|
|
4561
|
+
* than {@link numRefBlock} because the wrapping tag differs and so does the indentation — the
|
|
4562
|
+
* `<c:ptCount>` here sits three spaces further in than anything around it.
|
|
4563
|
+
*/
|
|
4564
|
+
function bubbleSizeBlock(obj, ref) {
|
|
4565
|
+
const sizes = dataSizes(obj);
|
|
4566
|
+
const numCache = el("c:numCache", null, [
|
|
4567
|
+
raw(el("c:formatCode", null, "General", { openPrefix: " " })),
|
|
4568
|
+
raw(voidEl("c:ptCount", { val: sizes.length }, { openPrefix: " " })),
|
|
4569
|
+
raw(sizes.map((value, idx) => numCachePt(idx, value)).join(""))
|
|
4570
|
+
], {
|
|
4571
|
+
openPrefix: " ",
|
|
4572
|
+
closePrefix: " "
|
|
4168
4573
|
});
|
|
4169
|
-
|
|
4170
|
-
|
|
4171
|
-
|
|
4172
|
-
|
|
4574
|
+
const numRef = el("c:numRef", null, [raw(el("c:f", null, ref)), raw(numCache)], {
|
|
4575
|
+
openPrefix: " ",
|
|
4576
|
+
closePrefix: " "
|
|
4577
|
+
});
|
|
4578
|
+
return el("c:bubbleSize", null, raw(numRef), {
|
|
4579
|
+
openPrefix: " ",
|
|
4580
|
+
closePrefix: " "
|
|
4581
|
+
});
|
|
4582
|
+
}
|
|
4583
|
+
/** The shared `<c:dLbls>` block: number format, label text style, and which parts are shown. */
|
|
4584
|
+
function bubbleDataLabels(opts) {
|
|
4585
|
+
const defRPr = el("a:defRPr", {
|
|
4586
|
+
b: opts.dataLabelFontBold ? 1 : 0,
|
|
4587
|
+
i: opts.dataLabelFontItalic ? 1 : 0,
|
|
4588
|
+
strike: "noStrike",
|
|
4589
|
+
sz: ptToHundredths(opts.dataLabelFontSize || 12),
|
|
4590
|
+
u: "none"
|
|
4591
|
+
}, [raw(genXmlColorSelection(opts.dataLabelColor || "000000")), raw(createChartTextFonts(opts.dataLabelFontFace || "Arial"))]);
|
|
4592
|
+
const txPr = el("c:txPr", null, [
|
|
4593
|
+
raw(voidEl("a:bodyPr")),
|
|
4594
|
+
raw(voidEl("a:lstStyle")),
|
|
4595
|
+
raw(el("a:p", null, raw(el("a:pPr", null, raw(defRPr)))))
|
|
4596
|
+
]);
|
|
4597
|
+
const extLst = el("c:extLst", null, raw(el("c:ext", {
|
|
4598
|
+
uri: "{CE6537A1-D6FC-4f65-9D91-7224C49458BB}",
|
|
4599
|
+
"xmlns:c15": "http://schemas.microsoft.com/office/drawing/2012/chart"
|
|
4600
|
+
}, raw(voidEl("c15:showLeaderLines", { val: opts.showLeaderLines ? 1 : 0 }, { openPrefix: " " })), {
|
|
4601
|
+
openPrefix: " ",
|
|
4602
|
+
closePrefix: " "
|
|
4603
|
+
})));
|
|
4604
|
+
return el("c:dLbls", null, [
|
|
4605
|
+
raw(voidEl("c:numFmt", {
|
|
4606
|
+
formatCode: (opts.dataLabelFormatCode ?? "") || "General",
|
|
4607
|
+
sourceLinked: 0
|
|
4608
|
+
})),
|
|
4609
|
+
raw(txPr),
|
|
4610
|
+
opts.dataLabelPosition ? raw(voidEl("c:dLblPos", { val: opts.dataLabelPosition })) : null,
|
|
4611
|
+
raw(voidEl("c:showLegendKey", { val: 0 })),
|
|
4612
|
+
raw(voidEl("c:showVal", { val: opts.showValue ? 1 : 0 })),
|
|
4613
|
+
raw(voidEl("c:showCatName", { val: 0 })),
|
|
4614
|
+
raw(voidEl("c:showSerName", { val: opts.showSerName ? 1 : 0 })),
|
|
4615
|
+
raw(voidEl("c:showPercent", { val: 0 })),
|
|
4616
|
+
raw(voidEl("c:showBubbleSize", { val: opts.showBubbleSize ? 1 : 0 })),
|
|
4617
|
+
raw(extLst)
|
|
4618
|
+
]);
|
|
4173
4619
|
}
|
|
4174
|
-
//#endregion
|
|
4175
|
-
//#region src/gen/chart/plot-bubble.ts
|
|
4176
4620
|
/**
|
|
4177
4621
|
* Plot a bubble / bubble3d chart into `<c:bubbleChart>` (X/Y plus per-point size).
|
|
4178
4622
|
*/
|
|
4179
4623
|
function makeBubblePlot(chartType, data, opts, valAxisId, catAxisId, valFmtCode) {
|
|
4180
|
-
|
|
4624
|
+
const chartColors = resolveChartPalette(opts);
|
|
4625
|
+
const xValues = dataValues(data[0]);
|
|
4181
4626
|
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>`;
|
|
4627
|
+
const sers = data.slice(1).map((obj, idx) => {
|
|
4628
|
+
const name = strRefBlock(sheetCellRef(idxColLtr + 1, 1), obj.name ?? "");
|
|
4629
|
+
const spPr = bubbleSerShapeProps(opts, paletteColor(chartColors, idx), idx);
|
|
4630
|
+
const yValues = dataValues(obj);
|
|
4631
|
+
const xVal = numRefBlock("c:xVal", `Sheet1!$A$2:$A$${xValues.length + 1}`, valFmtCode, xValues);
|
|
4632
|
+
const yVal = numRefBlock("c:yVal", sheetRangeRef(idxColLtr + 1, 2, idxColLtr + 1, xValues.length + 1), valFmtCode, xValues.map((_value, i) => yValues[i]), "");
|
|
4225
4633
|
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;
|
|
4634
|
+
const sizeRef = sheetRangeRef(idxColLtr + 1, 2, idxColLtr + 1, dataSizes(obj).length + 1);
|
|
4635
|
+
idxColLtr++;
|
|
4636
|
+
return el("c:ser", null, [
|
|
4637
|
+
raw(voidEl("c:idx", { val: idx }, { openPrefix: " " })),
|
|
4638
|
+
raw(voidEl("c:order", { val: idx }, { openPrefix: " " })),
|
|
4639
|
+
raw(name),
|
|
4640
|
+
raw(spPr),
|
|
4641
|
+
raw(xVal),
|
|
4642
|
+
raw(yVal),
|
|
4643
|
+
raw(bubbleSizeBlock(obj, sizeRef)),
|
|
4644
|
+
raw(voidEl("c:bubble3D", { val: chartType === "bubble3D" ? 1 : 0 }, { openPrefix: " " }))
|
|
4645
|
+
]);
|
|
4646
|
+
}).join("");
|
|
4647
|
+
return el("c:bubbleChart", null, [
|
|
4648
|
+
raw(voidEl("c:varyColors", { val: 0 })),
|
|
4649
|
+
raw(sers),
|
|
4650
|
+
raw(bubbleDataLabels(opts)),
|
|
4651
|
+
raw(voidEl("c:axId", { val: catAxisId })),
|
|
4652
|
+
raw(voidEl("c:axId", { val: valAxisId }))
|
|
4653
|
+
]);
|
|
4261
4654
|
}
|
|
4262
4655
|
//#endregion
|
|
4263
4656
|
//#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({
|
|
4657
|
+
/** The label run properties both `<c:txPr>` spellings share, differing only in their indentation. */
|
|
4658
|
+
function labelDefRPr(opts, fontsIndent, fmt) {
|
|
4659
|
+
return el("a:defRPr", {
|
|
4660
|
+
sz: ptToHundredths(opts.dataLabelFontSize || 12),
|
|
4661
|
+
b: opts.dataLabelFontBold ? 1 : 0,
|
|
4662
|
+
i: opts.dataLabelFontItalic ? 1 : 0,
|
|
4663
|
+
u: "none",
|
|
4664
|
+
strike: "noStrike"
|
|
4665
|
+
}, [raw(genXmlColorSelection(opts.dataLabelColor || "000000")), raw(fontsIndent + createChartTextFonts(opts.dataLabelFontFace || "Arial"))], fmt);
|
|
4666
|
+
}
|
|
4667
|
+
/** One `<c:dPt>`: the slice's own fill, its border override, and the shared shadow. */
|
|
4668
|
+
function pieDataPoint(idx, ptStyle, opts, fallbackColor) {
|
|
4669
|
+
const border = ptStyle?.border ? createChartBorderLine(ptStyle.border) : opts.dataBorder ? el("a:ln", {
|
|
4670
|
+
w: ptsToEmuLenient(resolveBorderWidth(opts.dataBorder, .75)),
|
|
4671
|
+
cap: "flat"
|
|
4672
|
+
}, [
|
|
4673
|
+
raw(genXmlColorSelection({
|
|
4305
4674
|
color: opts.dataBorder.color ?? "363636",
|
|
4306
4675
|
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", {
|
|
4676
|
+
})),
|
|
4677
|
+
raw(voidEl("a:prstDash", { val: "solid" })),
|
|
4678
|
+
raw(voidEl("a:round"))
|
|
4679
|
+
]) : "";
|
|
4680
|
+
const spPr = el("c:spPr", null, [
|
|
4681
|
+
raw(el("a:solidFill", null, raw(createColorElement(ptStyle?.fill || fallbackColor)))),
|
|
4682
|
+
raw(border),
|
|
4683
|
+
raw(createShadowEffectLst(opts.shadow, DEF_SHAPE_SHADOW))
|
|
4684
|
+
], {
|
|
4685
|
+
openPrefix: " ",
|
|
4686
|
+
closePrefix: " "
|
|
4687
|
+
});
|
|
4688
|
+
return el("c:dPt", null, [
|
|
4689
|
+
raw(voidEl("c:idx", { val: idx }, { openPrefix: " " })),
|
|
4690
|
+
raw(voidEl("c:bubble3D", { val: 0 }, { openPrefix: " " })),
|
|
4691
|
+
raw(spPr)
|
|
4692
|
+
]);
|
|
4693
|
+
}
|
|
4694
|
+
/**
|
|
4695
|
+
* One `<c:dLbl>`: a pie labels its points, not its series, so every slice carries its own copy of
|
|
4696
|
+
* the number format, text style and show flags. A `customLabels` entry replaces the value with
|
|
4697
|
+
* literal rich text, which is why it also forces `<c:showVal>` off.
|
|
4698
|
+
*/
|
|
4699
|
+
function pieDataLabel(idx, customLbl, opts, chartType) {
|
|
4700
|
+
const numFmt = voidEl("c:numFmt", {
|
|
4341
4701
|
formatCode: (opts.dataLabelFormatCode ?? "") || "General",
|
|
4342
4702
|
sourceLinked: 0
|
|
4703
|
+
}, { openPrefix: " " });
|
|
4704
|
+
const txPr = el("c:txPr", null, [
|
|
4705
|
+
raw(voidEl("a:bodyPr", null, { openPrefix: " " })),
|
|
4706
|
+
raw(voidEl("a:lstStyle")),
|
|
4707
|
+
raw(el("a:p", null, raw(el("a:pPr", null, raw(labelDefRPr(opts, " ", {
|
|
4708
|
+
openPrefix: " ",
|
|
4709
|
+
closePrefix: " "
|
|
4710
|
+
})), { closePrefix: " " })), { openPrefix: " " }))
|
|
4711
|
+
], { closePrefix: " " });
|
|
4712
|
+
return el("c:dLbl", null, [
|
|
4713
|
+
raw(voidEl("c:idx", { val: idx }, { openPrefix: " " })),
|
|
4714
|
+
customLbl ? raw(el("c:tx", null, raw(el("c:rich", null, [
|
|
4715
|
+
raw(voidEl("a:bodyPr")),
|
|
4716
|
+
raw(voidEl("a:lstStyle")),
|
|
4717
|
+
raw(el("a:p", null, raw(el("a:r", null, [raw(voidEl("a:rPr", {
|
|
4718
|
+
lang: opts.lang || "en-US",
|
|
4719
|
+
dirty: 0
|
|
4720
|
+
})), raw(el("a:t", null, customLbl))]))))
|
|
4721
|
+
])))) : null,
|
|
4722
|
+
raw(numFmt),
|
|
4723
|
+
raw(voidEl("c:spPr", null, { openPrefix: " " })),
|
|
4724
|
+
raw(txPr),
|
|
4725
|
+
chartType === "pie" && opts.dataLabelPosition ? raw(voidEl("c:dLblPos", { val: opts.dataLabelPosition })) : null,
|
|
4726
|
+
raw(voidEl("c:showLegendKey", { val: 0 }, { openPrefix: " " })),
|
|
4727
|
+
raw(voidEl("c:showVal", { val: customLbl ? 0 : opts.showValue ? 1 : 0 }, { openPrefix: " " })),
|
|
4728
|
+
raw(voidEl("c:showCatName", { val: opts.showLabel ? 1 : 0 }, { openPrefix: " " })),
|
|
4729
|
+
raw(voidEl("c:showSerName", { val: opts.showSerName ? 1 : 0 }, { openPrefix: " " })),
|
|
4730
|
+
raw(voidEl("c:showPercent", { val: opts.showPercent ? 1 : 0 }, { openPrefix: " " })),
|
|
4731
|
+
raw(voidEl("c:showBubbleSize", { val: 0 }, { openPrefix: " " }))
|
|
4732
|
+
], { closePrefix: " " });
|
|
4733
|
+
}
|
|
4734
|
+
/** The `<c:cat>` slice-name reference and the `<c:val>` cache, both keyed on the label count. */
|
|
4735
|
+
function pieCategories(labels) {
|
|
4736
|
+
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(""))], {
|
|
4737
|
+
openPrefix: " ",
|
|
4738
|
+
closePrefix: " "
|
|
4739
|
+
});
|
|
4740
|
+
const strRef = el("c:strRef", null, [raw(el("c:f", null, `Sheet1!$A$2:$A$${labels.length + 1}`, { openPrefix: " " })), raw(strCache)], {
|
|
4741
|
+
openPrefix: " ",
|
|
4742
|
+
closePrefix: " "
|
|
4743
|
+
});
|
|
4744
|
+
return el("c:cat", null, raw(strRef));
|
|
4745
|
+
}
|
|
4746
|
+
/** The `<c:val>` numeric cache. A missing value keeps its `<c:pt>` with an empty `<c:v>`. */
|
|
4747
|
+
function pieValues(obj, count, valFmtCode) {
|
|
4748
|
+
const points = dataValues(obj).map((value, idx) => el("c:pt", { idx }, raw(el("c:v", null, value || value === 0 ? value : "")))).join("");
|
|
4749
|
+
const numCache = el("c:numCache", null, [
|
|
4750
|
+
raw(el("c:formatCode", null, valFmtCode, { openPrefix: " " })),
|
|
4751
|
+
raw(voidEl("c:ptCount", { val: count }, { openPrefix: " " })),
|
|
4752
|
+
raw(points)
|
|
4753
|
+
], {
|
|
4754
|
+
openPrefix: " ",
|
|
4755
|
+
closePrefix: " "
|
|
4756
|
+
});
|
|
4757
|
+
const numRef = el("c:numRef", null, [raw(el("c:f", null, `Sheet1!$B$2:$B$${count + 1}`, { openPrefix: " " })), raw(numCache)], {
|
|
4758
|
+
openPrefix: " ",
|
|
4759
|
+
closePrefix: " "
|
|
4760
|
+
});
|
|
4761
|
+
return el("c:val", null, raw(numRef), {
|
|
4762
|
+
openPrefix: " ",
|
|
4763
|
+
closePrefix: " "
|
|
4343
4764
|
});
|
|
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
4765
|
}
|
|
4395
4766
|
/**
|
|
4396
|
-
*
|
|
4397
|
-
* @param {ChartOptsInternal} opts - chart options
|
|
4398
|
-
* @param {string} axisId - value
|
|
4399
|
-
* @param {string} valAxisId - value
|
|
4400
|
-
* @return {string} XML
|
|
4767
|
+
* Plot a single-series pie / doughnut chart into `<c:pieChart>` / `<c:doughnutChart>`.
|
|
4401
4768
|
*/
|
|
4769
|
+
function makePiePlot(chartType, data, opts, valFmtCode) {
|
|
4770
|
+
const optsChartData = data[0];
|
|
4771
|
+
if (!optsChartData) return "";
|
|
4772
|
+
const chartColors = resolveChartPalette(opts);
|
|
4773
|
+
const labels = firstLabelGroup(optsChartData);
|
|
4774
|
+
const spPr = el("c:spPr", null, [
|
|
4775
|
+
raw(el("a:solidFill", null, raw(voidEl("a:schemeClr", { val: "accent1" })), { openPrefix: " " })),
|
|
4776
|
+
raw(el("a:ln", {
|
|
4777
|
+
w: 9525,
|
|
4778
|
+
cap: "flat"
|
|
4779
|
+
}, [
|
|
4780
|
+
raw(el("a:solidFill", null, raw(voidEl("a:srgbClr", { val: "F9F9F9" })))),
|
|
4781
|
+
raw(voidEl("a:prstDash", { val: "solid" })),
|
|
4782
|
+
raw(voidEl("a:round"))
|
|
4783
|
+
], { openPrefix: " " })),
|
|
4784
|
+
raw(opts.dataNoEffects ? voidEl("a:effectLst") : createShadowEffectLst(opts.shadow, DEF_SHAPE_SHADOW))
|
|
4785
|
+
], {
|
|
4786
|
+
openPrefix: " ",
|
|
4787
|
+
closePrefix: " "
|
|
4788
|
+
});
|
|
4789
|
+
const dLbls = el("c:dLbls", null, [
|
|
4790
|
+
raw(labels.map((_label, idx) => pieDataLabel(idx, optsChartData.customLabels?.[idx], opts, chartType)).join("")),
|
|
4791
|
+
raw(voidEl("c:numFmt", {
|
|
4792
|
+
formatCode: (opts.dataLabelFormatCode ?? "") || "General",
|
|
4793
|
+
sourceLinked: 0
|
|
4794
|
+
}, { openPrefix: " " })),
|
|
4795
|
+
raw(el("c:txPr", null, [
|
|
4796
|
+
raw(voidEl("a:bodyPr", null, { openPrefix: " " })),
|
|
4797
|
+
raw(voidEl("a:lstStyle", null, { openPrefix: " " })),
|
|
4798
|
+
raw(el("a:p", null, raw(el("a:pPr", null, raw(labelDefRPr(opts, " ", {
|
|
4799
|
+
openPrefix: " ",
|
|
4800
|
+
closePrefix: " "
|
|
4801
|
+
})), {
|
|
4802
|
+
openPrefix: " ",
|
|
4803
|
+
closePrefix: " "
|
|
4804
|
+
})), {
|
|
4805
|
+
openPrefix: " ",
|
|
4806
|
+
closePrefix: " "
|
|
4807
|
+
}))
|
|
4808
|
+
], {
|
|
4809
|
+
openPrefix: " ",
|
|
4810
|
+
closePrefix: " "
|
|
4811
|
+
})),
|
|
4812
|
+
chartType === "pie" ? raw(voidEl("c:dLblPos", { val: opts.dataLabelPosition || "ctr" })) : null,
|
|
4813
|
+
raw(voidEl("c:showLegendKey", { val: 0 }, { openPrefix: " " })),
|
|
4814
|
+
raw(voidEl("c:showVal", { val: 0 }, { openPrefix: " " })),
|
|
4815
|
+
raw(voidEl("c:showCatName", { val: 1 }, { openPrefix: " " })),
|
|
4816
|
+
raw(voidEl("c:showSerName", { val: 0 }, { openPrefix: " " })),
|
|
4817
|
+
raw(voidEl("c:showPercent", { val: 1 }, { openPrefix: " " })),
|
|
4818
|
+
raw(voidEl("c:showBubbleSize", { val: 0 }, { openPrefix: " " })),
|
|
4819
|
+
raw(voidEl("c:showLeaderLines", { val: opts.showLeaderLines ? 1 : 0 }, { openPrefix: " " })),
|
|
4820
|
+
raw(createLeaderLinesElement(opts))
|
|
4821
|
+
]);
|
|
4822
|
+
const ser = el("c:ser", null, [
|
|
4823
|
+
raw(voidEl("c:idx", { val: 0 }, { openPrefix: " " })),
|
|
4824
|
+
raw(voidEl("c:order", { val: 0 }, { openPrefix: " " })),
|
|
4825
|
+
raw(strRefBlock("Sheet1!$B$1", optsChartData.name ?? "", "expanded")),
|
|
4826
|
+
raw(spPr),
|
|
4827
|
+
raw(labels.map((_label, idx) => pieDataPoint(idx, optsChartData.pointStyles?.[idx], opts, paletteColor(chartColors, idx))).join("")),
|
|
4828
|
+
raw(dLbls),
|
|
4829
|
+
raw(pieCategories(labels)),
|
|
4830
|
+
raw(pieValues(optsChartData, labels.length, valFmtCode))
|
|
4831
|
+
], { closePrefix: " " });
|
|
4832
|
+
return el(`c:${chartType}Chart`, null, [
|
|
4833
|
+
raw(voidEl("c:varyColors", { val: 1 }, { openPrefix: " " })),
|
|
4834
|
+
raw(ser),
|
|
4835
|
+
raw(voidEl("c:firstSliceAng", { val: opts.firstSliceAng ? Math.round(opts.firstSliceAng) : 0 }, { openPrefix: " " })),
|
|
4836
|
+
chartType === "doughnut" ? raw(voidEl("c:holeSize", { val: typeof opts.holeSize === "number" ? opts.holeSize : 50 })) : null
|
|
4837
|
+
]);
|
|
4838
|
+
}
|
|
4402
4839
|
//#endregion
|
|
4403
4840
|
//#region src/gen/chart/plot-stock.ts
|
|
4404
4841
|
/**
|
|
@@ -4432,54 +4869,56 @@ const STOCK_STYLE_SPEC = {
|
|
|
4432
4869
|
/** True when the given (already-normalized) stock style leads with a Volume bar series. */
|
|
4433
4870
|
const isVolumeStockStyle = (style) => !!style && STOCK_STYLE_SPEC[style].volume;
|
|
4434
4871
|
/** Minimal `<c:dLbls>` block (all labels off) shared by the stock and volume-bar subcharts. */
|
|
4435
|
-
const STOCK_DLBLS = "
|
|
4872
|
+
const STOCK_DLBLS = el("c:dLbls", null, [
|
|
4873
|
+
raw(voidEl("c:showLegendKey", { val: 0 })),
|
|
4874
|
+
raw(voidEl("c:showVal", { val: 0 })),
|
|
4875
|
+
raw(voidEl("c:showCatName", { val: 0 })),
|
|
4876
|
+
raw(voidEl("c:showSerName", { val: 0 })),
|
|
4877
|
+
raw(voidEl("c:showPercent", { val: 0 })),
|
|
4878
|
+
raw(voidEl("c:showBubbleSize", { val: 0 }))
|
|
4879
|
+
]);
|
|
4436
4880
|
/** Emit the shared `<c:cat>` + `<c:val>` refs for a stock/volume series (single-level categories). */
|
|
4437
4881
|
function stockCatVal(obj, opts, valFmtCode) {
|
|
4438
4882
|
const cats = firstLabelGroup(obj);
|
|
4439
4883
|
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;
|
|
4884
|
+
const catRef = `Sheet1!$A$2:$A$${cats.length + 1}`;
|
|
4885
|
+
const cat = el("c:cat", null, raw(opts.catLabelFormatCode ? catRefBlock("num", catRef, cats, opts.catLabelFormatCode || "General") : catRefBlock("str", catRef, cats)));
|
|
4886
|
+
const numCache = el("c:numCache", null, [
|
|
4887
|
+
raw(el("c:formatCode", null, valFmtCode)),
|
|
4888
|
+
raw(voidEl("c:ptCount", { val: cats.length })),
|
|
4889
|
+
raw(dataValues(obj).map((value, idx) => numCachePt(idx, value)).join(""))
|
|
4890
|
+
]);
|
|
4891
|
+
const numRef = el("c:numRef", null, [raw(el("c:f", null, sheetRangeRef(valColRow, 2, valColRow, cats.length + 1))), raw(numCache)]);
|
|
4892
|
+
return cat + el("c:val", null, raw(numRef));
|
|
4466
4893
|
}
|
|
4467
4894
|
/** Emit the `<c:tx>` series-name reference for a stock/volume series. */
|
|
4468
4895
|
function stockSeriesName(obj) {
|
|
4469
|
-
return
|
|
4896
|
+
return strRefBlock(sheetCellRef(obj._dataIndex + dataLabels(obj).length + 1, 1), obj.name ?? "", "compact");
|
|
4470
4897
|
}
|
|
4471
4898
|
/** Emit a single stock (line) series: invisible line, optional close-marker, cat/val refs. */
|
|
4472
4899
|
function makeStockLineSer(obj, opts, valFmtCode, markCloseColor) {
|
|
4473
|
-
|
|
4474
|
-
|
|
4475
|
-
|
|
4476
|
-
|
|
4477
|
-
|
|
4478
|
-
|
|
4479
|
-
|
|
4480
|
-
|
|
4481
|
-
|
|
4482
|
-
|
|
4900
|
+
const spPr = el("c:spPr", null, [raw(el("a:ln", {
|
|
4901
|
+
w: 19050,
|
|
4902
|
+
cap: "rnd"
|
|
4903
|
+
}, [raw(voidEl("a:noFill")), raw(voidEl("a:round"))])), raw(voidEl("a:effectLst"))]);
|
|
4904
|
+
const marker = markCloseColor ? el("c:marker", null, [
|
|
4905
|
+
raw(voidEl("c:symbol", { val: "dot" })),
|
|
4906
|
+
raw(voidEl("c:size", { val: 5 })),
|
|
4907
|
+
raw(el("c:spPr", null, [
|
|
4908
|
+
raw(genXmlColorSelection(markCloseColor)),
|
|
4909
|
+
raw(el("a:ln", { w: 9525 }, raw(genXmlColorSelection(markCloseColor)))),
|
|
4910
|
+
raw(voidEl("a:effectLst"))
|
|
4911
|
+
]))
|
|
4912
|
+
]) : el("c:marker", null, raw(voidEl("c:symbol", { val: "none" })));
|
|
4913
|
+
return el("c:ser", null, [
|
|
4914
|
+
raw(voidEl("c:idx", { val: obj._dataIndex })),
|
|
4915
|
+
raw(voidEl("c:order", { val: obj._dataIndex })),
|
|
4916
|
+
raw(stockSeriesName(obj)),
|
|
4917
|
+
raw(spPr),
|
|
4918
|
+
raw(marker),
|
|
4919
|
+
raw(stockCatVal(obj, opts, valFmtCode)),
|
|
4920
|
+
raw(voidEl("c:smooth", { val: 0 }))
|
|
4921
|
+
]);
|
|
4483
4922
|
}
|
|
4484
4923
|
/**
|
|
4485
4924
|
* Plot a stock chart. For `vhlc`/`vohlc` the first data series is a Volume column drawn as a
|
|
@@ -4494,32 +4933,52 @@ function makeStockPlot(_chartType, data, opts, valAxisId, catAxisId, valFmtCode)
|
|
|
4494
4933
|
const stockSeries = spec.volume ? data.slice(1) : data;
|
|
4495
4934
|
let strXml = "";
|
|
4496
4935
|
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
|
-
|
|
4936
|
+
const volumeSer = el("c:ser", null, [
|
|
4937
|
+
raw(voidEl("c:idx", { val: volumeSeries._dataIndex })),
|
|
4938
|
+
raw(voidEl("c:order", { val: volumeSeries._dataIndex })),
|
|
4939
|
+
raw(stockSeriesName(volumeSeries)),
|
|
4940
|
+
raw(el("c:spPr", null, raw(genXmlColorSelection(chartColors[0] ?? "4472C4")))),
|
|
4941
|
+
raw(voidEl("c:invertIfNegative", { val: 0 })),
|
|
4942
|
+
raw(stockCatVal(volumeSeries, opts, valFmtCode))
|
|
4943
|
+
]);
|
|
4944
|
+
strXml += el("c:barChart", null, [
|
|
4945
|
+
raw(voidEl("c:barDir", { val: "col" })),
|
|
4946
|
+
raw(voidEl("c:grouping", { val: "clustered" })),
|
|
4947
|
+
raw(voidEl("c:varyColors", { val: 0 })),
|
|
4948
|
+
raw(volumeSer),
|
|
4949
|
+
raw(STOCK_DLBLS),
|
|
4950
|
+
raw(voidEl("c:gapWidth", { val: 150 })),
|
|
4951
|
+
raw(voidEl("c:axId", { val: AXIS_ID_CATEGORY_PRIMARY })),
|
|
4952
|
+
raw(voidEl("c:axId", { val: AXIS_ID_VALUE_PRIMARY }))
|
|
4953
|
+
]);
|
|
4954
|
+
}
|
|
4955
|
+
const sers = stockSeries.map((obj, idx) => {
|
|
4956
|
+
return makeStockLineSer(obj, opts, valFmtCode, !spec.upDownBars && idx === stockSeries.length - 1 ? paletteColor(chartColors, obj._dataIndex, "ED7D31") : null);
|
|
4957
|
+
}).join("");
|
|
4958
|
+
const hiLowLines = el("c:hiLowLines", null, raw(el("c:spPr", null, [raw(dimmedTextLine(75e3, 25e3)), raw(voidEl("a:effectLst"))])));
|
|
4959
|
+
const upDownBars = spec.upDownBars ? el("c:upDownBars", null, [
|
|
4960
|
+
raw(voidEl("c:gapWidth", { val: 150 })),
|
|
4961
|
+
raw(el("c:upBars", null, raw(el("c:spPr", null, [
|
|
4962
|
+
raw(el("a:solidFill", null, raw(voidEl("a:schemeClr", { val: "bg1" })))),
|
|
4963
|
+
raw(dimmedTextLine(65e3, 35e3)),
|
|
4964
|
+
raw(voidEl("a:effectLst"))
|
|
4965
|
+
])))),
|
|
4966
|
+
raw(el("c:downBars", null, raw(el("c:spPr", null, [
|
|
4967
|
+
raw(dimmedTextFill(65e3, 35e3)),
|
|
4968
|
+
raw(dimmedTextLine(65e3, 35e3)),
|
|
4969
|
+
raw(voidEl("a:effectLst"))
|
|
4970
|
+
]))))
|
|
4971
|
+
]) : "";
|
|
4519
4972
|
const stockCatId = spec.volume ? AXIS_ID_CATEGORY_SECONDARY : catAxisId;
|
|
4520
4973
|
const stockValId = spec.volume ? AXIS_ID_VALUE_SECONDARY : valAxisId;
|
|
4521
|
-
strXml +=
|
|
4522
|
-
|
|
4974
|
+
strXml += el("c:stockChart", null, [
|
|
4975
|
+
raw(sers),
|
|
4976
|
+
raw(STOCK_DLBLS),
|
|
4977
|
+
raw(hiLowLines),
|
|
4978
|
+
raw(upDownBars),
|
|
4979
|
+
raw(voidEl("c:axId", { val: stockCatId })),
|
|
4980
|
+
raw(voidEl("c:axId", { val: stockValId }))
|
|
4981
|
+
]);
|
|
4523
4982
|
return strXml;
|
|
4524
4983
|
}
|
|
4525
4984
|
//#endregion
|
|
@@ -4530,28 +4989,30 @@ const isSurface3D = (opts) => opts.surface3D !== false;
|
|
|
4530
4989
|
function surfaceCatVal(obj, valFmtCode) {
|
|
4531
4990
|
const cats = firstLabelGroup(obj);
|
|
4532
4991
|
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;
|
|
4992
|
+
const numCache = el("c:numCache", null, [
|
|
4993
|
+
raw(el("c:formatCode", null, valFmtCode)),
|
|
4994
|
+
raw(voidEl("c:ptCount", { val: cats.length })),
|
|
4995
|
+
raw(dataValues(obj).map((value, idx) => numCachePt(idx, value)).join(""))
|
|
4996
|
+
]);
|
|
4997
|
+
const numRef = el("c:numRef", null, [raw(el("c:f", null, sheetRangeRef(valCol, 2, valCol, cats.length + 1))), raw(numCache)]);
|
|
4998
|
+
return el("c:cat", null, raw(catRefBlock("str", `Sheet1!$A$2:$A$${cats.length + 1}`, cats))) + el("c:val", null, raw(numRef));
|
|
4544
4999
|
}
|
|
4545
5000
|
/** Emit a single surface series: name ref, 3-D shape props, and cat/val refs. */
|
|
4546
5001
|
function makeSurfaceSer(obj, valFmtCode, seriesColor) {
|
|
4547
5002
|
const nameCol = obj._dataIndex + dataLabels(obj).length + 1;
|
|
4548
|
-
|
|
4549
|
-
|
|
4550
|
-
|
|
4551
|
-
|
|
4552
|
-
|
|
4553
|
-
|
|
4554
|
-
return
|
|
5003
|
+
const spPr = el("c:spPr", null, [
|
|
5004
|
+
raw(genXmlColorSelection(seriesColor)),
|
|
5005
|
+
raw(voidEl("a:ln")),
|
|
5006
|
+
raw(voidEl("a:effectLst")),
|
|
5007
|
+
raw(voidEl("a:sp3d"))
|
|
5008
|
+
]);
|
|
5009
|
+
return el("c:ser", null, [
|
|
5010
|
+
raw(voidEl("c:idx", { val: obj._dataIndex })),
|
|
5011
|
+
raw(voidEl("c:order", { val: obj._dataIndex })),
|
|
5012
|
+
raw(strRefBlock(sheetCellRef(nameCol, 1), obj.name ?? "", "compact")),
|
|
5013
|
+
raw(spPr),
|
|
5014
|
+
raw(surfaceCatVal(obj, valFmtCode))
|
|
5015
|
+
]);
|
|
4555
5016
|
}
|
|
4556
5017
|
/**
|
|
4557
5018
|
* Plot a surface chart into a `<c:surface3DChart>` (3-D) or `<c:surfaceChart>` (2-D contour). Every
|
|
@@ -4561,14 +5022,14 @@ function makeSurfaceSer(obj, valFmtCode, seriesColor) {
|
|
|
4561
5022
|
function makeSurfacePlot(_chartType, data, opts, valAxisId, catAxisId, valFmtCode) {
|
|
4562
5023
|
const tag = isSurface3D(opts) ? "surface3DChart" : "surfaceChart";
|
|
4563
5024
|
const chartColors = resolveChartPalette(opts);
|
|
4564
|
-
|
|
4565
|
-
|
|
4566
|
-
|
|
4567
|
-
|
|
4568
|
-
|
|
4569
|
-
|
|
4570
|
-
|
|
4571
|
-
|
|
5025
|
+
const sers = data.map((obj, idx) => makeSurfaceSer(obj, valFmtCode, paletteColor(chartColors, idx, "4472C4"))).join("");
|
|
5026
|
+
return el(`c:${tag}`, null, [
|
|
5027
|
+
raw(voidEl("c:wireframe", { val: opts.surfaceWireframe ? 1 : 0 })),
|
|
5028
|
+
raw(sers),
|
|
5029
|
+
raw(voidEl("c:axId", { val: catAxisId })),
|
|
5030
|
+
raw(voidEl("c:axId", { val: valAxisId })),
|
|
5031
|
+
raw(voidEl("c:axId", { val: AXIS_ID_SERIES_PRIMARY }))
|
|
5032
|
+
]);
|
|
4572
5033
|
}
|
|
4573
5034
|
/**
|
|
4574
5035
|
* Build the `<c:view3D>` + floor/side/back walls for a surface chart. A 3-D surface tilts the scene
|
|
@@ -4577,13 +5038,23 @@ function makeSurfacePlot(_chartType, data, opts, valAxisId, catAxisId, valFmtCod
|
|
|
4577
5038
|
* `<c:plotArea>` in CT_Chart document order (view3D → floor → sideWall → backWall → plotArea).
|
|
4578
5039
|
*/
|
|
4579
5040
|
function makeSurfaceScene(opts) {
|
|
4580
|
-
const wall = "
|
|
4581
|
-
|
|
4582
|
-
|
|
4583
|
-
|
|
4584
|
-
|
|
4585
|
-
|
|
4586
|
-
|
|
5041
|
+
const wall = voidEl("c:thickness", { val: 0 }) + el("c:spPr", null, [
|
|
5042
|
+
raw(voidEl("a:noFill")),
|
|
5043
|
+
raw(el("a:ln", null, raw(voidEl("a:noFill")))),
|
|
5044
|
+
raw(voidEl("a:effectLst")),
|
|
5045
|
+
raw(voidEl("a:sp3d"))
|
|
5046
|
+
]);
|
|
5047
|
+
const scene = isSurface3D(opts) ? [
|
|
5048
|
+
raw(voidEl("c:rotX", { val: opts.v3DRotX })),
|
|
5049
|
+
raw(voidEl("c:rotY", { val: opts.v3DRotY })),
|
|
5050
|
+
raw(voidEl("c:rAngAx", { val: 0 }))
|
|
5051
|
+
] : [
|
|
5052
|
+
raw(voidEl("c:rotX", { val: 90 })),
|
|
5053
|
+
raw(voidEl("c:rotY", { val: 0 })),
|
|
5054
|
+
raw(voidEl("c:rAngAx", { val: 0 })),
|
|
5055
|
+
raw(voidEl("c:perspective", { val: 0 }))
|
|
5056
|
+
];
|
|
5057
|
+
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
5058
|
}
|
|
4588
5059
|
//#endregion
|
|
4589
5060
|
//#region src/gen/chart/chart-xml.ts
|
|
@@ -4602,6 +5073,12 @@ function makeSurfaceScene(opts) {
|
|
|
4602
5073
|
* written by the embedded workbook ({@link ./embed-xlsx}); that mapping lives in
|
|
4603
5074
|
* {@link ./data-refs}.
|
|
4604
5075
|
*/
|
|
5076
|
+
/** The three namespaces every `<c:chartSpace>` declares, in the order PowerPoint writes them. */
|
|
5077
|
+
const CHART_SPACE_NS = {
|
|
5078
|
+
"xmlns:c": "http://schemas.openxmlformats.org/drawingml/2006/chart",
|
|
5079
|
+
"xmlns:a": "http://schemas.openxmlformats.org/drawingml/2006/main",
|
|
5080
|
+
"xmlns:r": "http://schemas.openxmlformats.org/officeDocument/2006/relationships"
|
|
5081
|
+
};
|
|
4605
5082
|
/**
|
|
4606
5083
|
* Whether a chart-area/plot-area `fill` says anything the fill dispatch can act on.
|
|
4607
5084
|
*
|
|
@@ -4624,58 +5101,52 @@ function isStatedFill(fill) {
|
|
|
4624
5101
|
return Boolean(fill?.color || fill?.type);
|
|
4625
5102
|
}
|
|
4626
5103
|
/**
|
|
4627
|
-
*
|
|
4628
|
-
*
|
|
5104
|
+
* The chart title (or the `autoTitleDeleted` flag that suppresses PowerPoint's default one)
|
|
5105
|
+
* followed by the 3-D scene, for the two families that plot into one.
|
|
4629
5106
|
*/
|
|
4630
5107
|
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, [
|
|
5108
|
+
const title = rel.opts.showTitle ? genXmlTitle({
|
|
5109
|
+
title: rel.opts.title || "Chart Title",
|
|
5110
|
+
color: rel.opts.titleColor,
|
|
5111
|
+
fontFace: rel.opts.titleFontFace,
|
|
5112
|
+
fontSize: rel.opts.titleFontSize || 18,
|
|
5113
|
+
titleAlign: rel.opts.titleAlign,
|
|
5114
|
+
titleBold: rel.opts.titleBold,
|
|
5115
|
+
titleItalic: rel.opts.titleItalic,
|
|
5116
|
+
titleUnderline: rel.opts.titleUnderline,
|
|
5117
|
+
titlePos: rel.opts.titlePos,
|
|
5118
|
+
titleRotate: rel.opts.titleRotate
|
|
5119
|
+
}, rel.opts.x, rel.opts.y) + voidEl("c:autoTitleDeleted", { val: 0 }) : voidEl("c:autoTitleDeleted", { val: 1 });
|
|
5120
|
+
if (rel.opts._type === "bar3D") return title + el("c:view3D", null, [
|
|
4656
5121
|
raw(voidEl("c:rotX", { val: rel.opts.v3DRotX })),
|
|
4657
5122
|
raw(voidEl("c:rotY", { val: rel.opts.v3DRotY })),
|
|
4658
5123
|
raw(voidEl("c:rAngAx", { val: !rel.opts.v3DRAngAx ? 0 : 1 })),
|
|
4659
5124
|
raw(voidEl("c:perspective", { val: rel.opts.v3DPerspective }))
|
|
4660
5125
|
]);
|
|
4661
|
-
|
|
4662
|
-
|
|
4663
|
-
|
|
4664
|
-
|
|
4665
|
-
|
|
4666
|
-
|
|
4667
|
-
|
|
4668
|
-
|
|
4669
|
-
|
|
4670
|
-
|
|
4671
|
-
|
|
4672
|
-
|
|
4673
|
-
|
|
4674
|
-
|
|
4675
|
-
})
|
|
4676
|
-
|
|
4677
|
-
|
|
4678
|
-
|
|
5126
|
+
if (rel.opts._type === "surface") return title + makeSurfaceScene(rel.opts);
|
|
5127
|
+
return title;
|
|
5128
|
+
}
|
|
5129
|
+
/**
|
|
5130
|
+
* The plot area's `<c:layout>`. Manual layout is emitted only when the caller asked for one:
|
|
5131
|
+
* an empty `<c:layout/>` lets PowerPoint auto-fit, which it does well across all four TRBL
|
|
5132
|
+
* legend positions.
|
|
5133
|
+
*/
|
|
5134
|
+
function makePlotAreaLayoutXml(rel) {
|
|
5135
|
+
const layout = rel.opts.layout;
|
|
5136
|
+
if (!layout) return voidEl("c:layout");
|
|
5137
|
+
const manualLayout = el("c:manualLayout", null, [
|
|
5138
|
+
raw(voidEl("c:layoutTarget", { val: "inner" }, { closePrefix: " " })),
|
|
5139
|
+
raw(voidEl("c:xMode", { val: "edge" }, { closePrefix: " " })),
|
|
5140
|
+
raw(voidEl("c:yMode", { val: "edge" }, { closePrefix: " " })),
|
|
5141
|
+
raw(voidEl("c:x", { val: layout.x || 0 }, { closePrefix: " " })),
|
|
5142
|
+
raw(voidEl("c:y", { val: layout.y || 0 }, { closePrefix: " " })),
|
|
5143
|
+
raw(voidEl("c:w", { val: layout.w || 1 }, { closePrefix: " " })),
|
|
5144
|
+
raw(voidEl("c:h", { val: layout.h || 1 }, { closePrefix: " " }))
|
|
5145
|
+
], {
|
|
5146
|
+
childPrefix: " ",
|
|
5147
|
+
closePrefix: " "
|
|
5148
|
+
});
|
|
5149
|
+
return el("c:layout", null, raw(manualLayout), { childPrefix: " " });
|
|
4679
5150
|
}
|
|
4680
5151
|
/**
|
|
4681
5152
|
* Build the category/value/series axis XML (empty for pie/doughnut). Resolves combo-chart
|
|
@@ -4745,97 +5216,132 @@ function makeChartAxesXml(rel, usesSecondaryValAxis, usesSecondaryCatAxis, prima
|
|
|
4745
5216
|
return strXml;
|
|
4746
5217
|
}
|
|
4747
5218
|
/**
|
|
4748
|
-
*
|
|
5219
|
+
* The `<c:spPr>` shared by the plot area and the chart space: a stated fill or none, a border
|
|
5220
|
+
* or an explicit no-line, and an empty effect list. The two differ only in how far in they are
|
|
5221
|
+
* indented, which is what `fmt` and `effectIndent` carry.
|
|
4749
5222
|
*/
|
|
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
|
-
|
|
5223
|
+
function chartShapeProps(fill, border, effectIndent, fmt) {
|
|
5224
|
+
return el("c:spPr", null, [
|
|
5225
|
+
raw(isStatedFill(fill) ? genXmlColorSelection(fill) : voidEl("a:noFill")),
|
|
5226
|
+
raw(border ? el("a:ln", {
|
|
5227
|
+
w: ptsToEmuLenient(resolveBorderWidth(border, 1)),
|
|
5228
|
+
cap: "flat"
|
|
5229
|
+
}, raw(genXmlColorSelection({
|
|
5230
|
+
color: border.color ?? "363636",
|
|
5231
|
+
transparency: border.transparency
|
|
5232
|
+
}))) : el("a:ln", null, raw(voidEl("a:noFill")))),
|
|
5233
|
+
raw(voidEl("a:effectLst", null, { openPrefix: effectIndent }))
|
|
5234
|
+
], fmt);
|
|
5235
|
+
}
|
|
5236
|
+
/**
|
|
5237
|
+
* The `<c:dTable>` grid drawn under the plot. Sits between the last `</c:valAx>` and the plot
|
|
5238
|
+
* area's own `<c:spPr>`.
|
|
5239
|
+
*/
|
|
5240
|
+
function makeDataTableXml(rel) {
|
|
5241
|
+
const spPr = el("c:spPr", null, [
|
|
5242
|
+
raw(voidEl("a:noFill", null, { openPrefix: " " })),
|
|
5243
|
+
raw(dimmedTextLine(15e3, 85e3, { openPrefix: " " })),
|
|
5244
|
+
raw(voidEl("a:effectLst", null, { openPrefix: " " }))
|
|
5245
|
+
], {
|
|
5246
|
+
openPrefix: " ",
|
|
5247
|
+
closePrefix: " "
|
|
5248
|
+
});
|
|
5249
|
+
const defRPr = el("a:defRPr", {
|
|
5250
|
+
sz: ptToHundredths(rel.opts.dataTableFontSize || 12),
|
|
5251
|
+
b: 0,
|
|
5252
|
+
i: 0,
|
|
5253
|
+
u: "none",
|
|
5254
|
+
strike: "noStrike",
|
|
5255
|
+
kern: 1200,
|
|
5256
|
+
baseline: 0
|
|
5257
|
+
}, [
|
|
5258
|
+
raw(" " + dimmedTextFill(65e3, 35e3)),
|
|
5259
|
+
raw(voidEl("a:latin", { typeface: "+mn-lt" }, { openPrefix: " " })),
|
|
5260
|
+
raw(voidEl("a:ea", { typeface: "+mn-ea" }, { openPrefix: " " })),
|
|
5261
|
+
raw(voidEl("a:cs", { typeface: "+mn-cs" }, { openPrefix: " " }))
|
|
5262
|
+
], {
|
|
5263
|
+
openPrefix: " ",
|
|
5264
|
+
closePrefix: " "
|
|
5265
|
+
});
|
|
5266
|
+
const txPr = el("c:txPr", null, [
|
|
5267
|
+
raw(voidEl("a:bodyPr", {
|
|
5268
|
+
rot: 0,
|
|
5269
|
+
spcFirstLastPara: 1,
|
|
5270
|
+
vertOverflow: "ellipsis",
|
|
5271
|
+
vert: "horz",
|
|
5272
|
+
wrap: "square",
|
|
5273
|
+
anchor: "ctr",
|
|
5274
|
+
anchorCtr: 1
|
|
5275
|
+
}, { openPrefix: " " })),
|
|
5276
|
+
raw(voidEl("a:lstStyle", null, { openPrefix: " " })),
|
|
5277
|
+
raw(el("a:p", null, [raw(el("a:pPr", { rtl: 0 }, raw(defRPr), {
|
|
5278
|
+
openPrefix: " ",
|
|
5279
|
+
closePrefix: " "
|
|
5280
|
+
})), raw(voidEl("a:endParaRPr", { lang: "en-US" }, { openPrefix: " " }))], {
|
|
5281
|
+
openPrefix: " ",
|
|
5282
|
+
closePrefix: " "
|
|
5283
|
+
}))
|
|
5284
|
+
], {
|
|
5285
|
+
openPrefix: " ",
|
|
5286
|
+
closePrefix: " "
|
|
5287
|
+
});
|
|
5288
|
+
return el("c:dTable", null, [
|
|
5289
|
+
raw(voidEl("c:showHorzBorder", { val: !rel.opts.showDataTableHorzBorder ? 0 : 1 }, { openPrefix: " " })),
|
|
5290
|
+
raw(voidEl("c:showVertBorder", { val: !rel.opts.showDataTableVertBorder ? 0 : 1 }, { openPrefix: " " })),
|
|
5291
|
+
raw(` <c:showOutline val="${!rel.opts.showDataTableOutline ? 0 : 1}"/>`),
|
|
5292
|
+
raw(` <c:showKeys val="${!rel.opts.showDataTableKeys ? 0 : 1}"/>`),
|
|
5293
|
+
raw(spPr),
|
|
5294
|
+
raw(txPr)
|
|
5295
|
+
]);
|
|
5296
|
+
}
|
|
5297
|
+
/**
|
|
5298
|
+
* The `<c:legend>`: position, the entries a combo chart deletes, an optional manual placement,
|
|
5299
|
+
* and the text properties when any legend font option is set.
|
|
5300
|
+
*/
|
|
5301
|
+
function makeLegendXml(rel) {
|
|
5302
|
+
let entries = "";
|
|
5303
|
+
if (Array.isArray(rel.opts._type)) {
|
|
5304
|
+
let seriesIdx = 0;
|
|
5305
|
+
for (const type of rel.opts._type) {
|
|
5306
|
+
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 }))]);
|
|
5307
|
+
seriesIdx += type.data.length;
|
|
4835
5308
|
}
|
|
4836
|
-
strXml += "</c:legend>";
|
|
4837
5309
|
}
|
|
4838
|
-
|
|
5310
|
+
const legendLayout = rel.opts.legendLayout;
|
|
5311
|
+
const placed = (key) => typeof legendLayout?.[key] === "number";
|
|
5312
|
+
let layout = "";
|
|
5313
|
+
if (placed("x") || placed("y") || placed("w") || placed("h")) {
|
|
5314
|
+
const modes = (placed("x") ? voidEl("c:xMode", { val: "edge" }) : "") + (placed("y") ? voidEl("c:yMode", { val: "edge" }) : "");
|
|
5315
|
+
const vals = [
|
|
5316
|
+
"x",
|
|
5317
|
+
"y",
|
|
5318
|
+
"w",
|
|
5319
|
+
"h"
|
|
5320
|
+
].filter(placed).map((key) => voidEl(`c:${key}`, { val: legendLayout?.[key] })).join("");
|
|
5321
|
+
layout = el("c:layout", null, raw(el("c:manualLayout", null, raw(modes + vals))));
|
|
5322
|
+
}
|
|
5323
|
+
let txPr = "";
|
|
5324
|
+
if (rel.opts.legendFontFace || rel.opts.legendFontSize || rel.opts.legendColor) {
|
|
5325
|
+
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: " " });
|
|
5326
|
+
txPr = el("c:txPr", null, [
|
|
5327
|
+
raw(voidEl("a:bodyPr", null, { openPrefix: " " })),
|
|
5328
|
+
raw(voidEl("a:lstStyle", null, { openPrefix: " " })),
|
|
5329
|
+
raw(el("a:p", null, [raw(el("a:pPr", null, raw(defRPr), {
|
|
5330
|
+
openPrefix: " ",
|
|
5331
|
+
closePrefix: " "
|
|
5332
|
+
})), raw(voidEl("a:endParaRPr", { lang: "en-US" }, { openPrefix: " " }))], {
|
|
5333
|
+
openPrefix: " ",
|
|
5334
|
+
closePrefix: " "
|
|
5335
|
+
}))
|
|
5336
|
+
]);
|
|
5337
|
+
}
|
|
5338
|
+
return el("c:legend", null, [
|
|
5339
|
+
raw(voidEl("c:legendPos", { val: rel.opts.legendPos })),
|
|
5340
|
+
raw(entries),
|
|
5341
|
+
raw(layout),
|
|
5342
|
+
raw(voidEl("c:overlay", { val: 0 })),
|
|
5343
|
+
raw(txPr)
|
|
5344
|
+
]);
|
|
4839
5345
|
}
|
|
4840
5346
|
/**
|
|
4841
5347
|
* Main entry point method for create charts
|
|
@@ -4844,16 +5350,16 @@ function makeChartPlotAreaPropsXml(rel) {
|
|
|
4844
5350
|
* @return {string} XML
|
|
4845
5351
|
*/
|
|
4846
5352
|
function makeXmlCharts(rel) {
|
|
4847
|
-
let strXml = XML_DECL;
|
|
4848
5353
|
const chartArea = rel.opts.chartArea ?? {};
|
|
5354
|
+
const plotAreaOpts = rel.opts.plotArea ?? {};
|
|
4849
5355
|
let usesSecondaryValAxis = false;
|
|
4850
5356
|
let usesSecondaryCatAxis = false;
|
|
4851
5357
|
let primaryCatAxisValType = null;
|
|
4852
5358
|
let secondaryCatAxisValType = null;
|
|
4853
5359
|
let primaryCatAxisHasCategoryChart = false;
|
|
4854
5360
|
let secondaryCatAxisHasCategoryChart = false;
|
|
4855
|
-
|
|
4856
|
-
if (Array.isArray(rel.opts._type)) rel.opts._type
|
|
5361
|
+
let plots = "";
|
|
5362
|
+
if (Array.isArray(rel.opts._type)) for (const type of rel.opts._type) {
|
|
4857
5363
|
const options = {
|
|
4858
5364
|
...rel.opts,
|
|
4859
5365
|
...type.options
|
|
@@ -4869,27 +5375,36 @@ function makeXmlCharts(rel) {
|
|
|
4869
5375
|
else secondaryCatAxisHasCategoryChart = true;
|
|
4870
5376
|
} else if (usesValueXAxis) primaryCatAxisValType = subType;
|
|
4871
5377
|
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
|
-
|
|
5378
|
+
plots += makeChartType(subType, type.data, options, valAxisId, catAxisId);
|
|
5379
|
+
}
|
|
5380
|
+
else if (rel.opts._type) plots = makeChartType(rel.opts._type, rel.data, rel.opts, AXIS_ID_VALUE_PRIMARY, AXIS_ID_CATEGORY_PRIMARY);
|
|
5381
|
+
const axes = makeChartAxesXml(rel, usesSecondaryValAxis, usesSecondaryCatAxis, primaryCatAxisValType, secondaryCatAxisValType, primaryCatAxisHasCategoryChart, secondaryCatAxisHasCategoryChart);
|
|
5382
|
+
const plotArea = el("c:plotArea", null, [
|
|
5383
|
+
raw(makePlotAreaLayoutXml(rel)),
|
|
5384
|
+
raw(plots),
|
|
5385
|
+
raw(axes),
|
|
5386
|
+
rel.opts.showDataTable ? raw(makeDataTableXml(rel)) : null,
|
|
5387
|
+
raw(chartShapeProps(plotAreaOpts.fill, plotAreaOpts.border, " ", {
|
|
5388
|
+
openPrefix: " ",
|
|
5389
|
+
closePrefix: " "
|
|
5390
|
+
}))
|
|
5391
|
+
]);
|
|
5392
|
+
const chart = el("c:chart", null, [
|
|
5393
|
+
raw(makeChartHeaderXml(rel)),
|
|
5394
|
+
raw(plotArea),
|
|
5395
|
+
rel.opts.showLegend ? raw(makeLegendXml(rel)) : null,
|
|
5396
|
+
raw(voidEl("c:plotVisOnly", { val: 1 }, { openPrefix: " " })),
|
|
5397
|
+
raw(voidEl("c:dispBlanksAs", { val: rel.opts.displayBlanksAs }, { openPrefix: " " })),
|
|
5398
|
+
rel.opts._type === "scatter" ? raw(voidEl("c:showDLblsOverMax", { val: 1 })) : null
|
|
5399
|
+
]);
|
|
5400
|
+
return XML_DECL + el("c:chartSpace", CHART_SPACE_NS, [
|
|
5401
|
+
raw(voidEl("c:date1904", { val: 0 })),
|
|
5402
|
+
raw(voidEl("c:roundedCorners", { val: chartArea.roundedCorners ? 1 : 0 })),
|
|
5403
|
+
raw(chart),
|
|
5404
|
+
raw(chartShapeProps(chartArea.fill, chartArea.border, " ", {})),
|
|
5405
|
+
raw(el("c:externalData", { "r:id": "rId1" }, raw(voidEl("c:autoUpdate", { val: 0 })))),
|
|
5406
|
+
raw(genXmlChartMetadata(rel.opts.metadata))
|
|
5407
|
+
]);
|
|
4893
5408
|
}
|
|
4894
5409
|
/**
|
|
4895
5410
|
* Stable ts-pptx vendor GUID identifying the chart-metadata extension on `c:chartSpace/c:extLst`.
|
|
@@ -4944,7 +5459,7 @@ function genXmlChartMetadata(metadata) {
|
|
|
4944
5459
|
* @return {string} XML chart
|
|
4945
5460
|
*/
|
|
4946
5461
|
function makeChartType(chartType, data, opts, valAxisId, catAxisId) {
|
|
4947
|
-
const valFmtCode =
|
|
5462
|
+
const valFmtCode = opts.valLabelFormatCode || opts.dataTableFormatCode || opts.dataLabelFormatCode || "General";
|
|
4948
5463
|
switch (chartType) {
|
|
4949
5464
|
case "area":
|
|
4950
5465
|
case "bar":
|
|
@@ -5328,6 +5843,13 @@ function makeChartExStyleXml() {
|
|
|
5328
5843
|
//#region src/gen/chart/embed-xlsx.ts
|
|
5329
5844
|
/** MS chart-extension relationship types (chartEx style + color-style sidecar parts). */
|
|
5330
5845
|
const MS_CHART_REL = "http://schemas.microsoft.com/office/2011/relationships/";
|
|
5846
|
+
/** The SpreadsheetML namespace every part of the embedded workbook is written in. */
|
|
5847
|
+
const SML_NS = "http://schemas.openxmlformats.org/spreadsheetml/2006/main";
|
|
5848
|
+
/** OPC content types, and the prefix the four SpreadsheetML part types share. */
|
|
5849
|
+
const CT_NS = "http://schemas.openxmlformats.org/package/2006/content-types";
|
|
5850
|
+
const SML_CT = "application/vnd.openxmlformats-officedocument.spreadsheetml.";
|
|
5851
|
+
/** One `<si>` shared string carrying literal text. */
|
|
5852
|
+
const sharedString = (text) => el("si", null, raw(el("t", null, text)));
|
|
5331
5853
|
function relationship$2(id, type, target) {
|
|
5332
5854
|
return voidEl("Relationship", {
|
|
5333
5855
|
Id: id,
|
|
@@ -5340,6 +5862,17 @@ function relationships(rels) {
|
|
|
5340
5862
|
return el("Relationships", { xmlns: PACKAGE_REL_NS }, rels.map(raw));
|
|
5341
5863
|
}
|
|
5342
5864
|
/**
|
|
5865
|
+
* The embedded workbook's style sheet, captured verbatim from an Excel-authored chart workbook.
|
|
5866
|
+
* @raw-xml-asset
|
|
5867
|
+
*/
|
|
5868
|
+
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";
|
|
5869
|
+
/**
|
|
5870
|
+
* The Office theme the embedded workbook ships, captured verbatim. PowerPoint reads it when a user
|
|
5871
|
+
* opens the chart's data, so it has to be exactly the bytes Office writes.
|
|
5872
|
+
* @raw-xml-asset
|
|
5873
|
+
*/
|
|
5874
|
+
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>";
|
|
5875
|
+
/**
|
|
5343
5876
|
* Build the chart's embedded Excel workbook as a standalone OPC package and
|
|
5344
5877
|
* return its bytes — the data source PowerPoint opens when a user edits the
|
|
5345
5878
|
* chart's data. Pure (no zip side effects), so both the package write path
|
|
@@ -5354,24 +5887,108 @@ function buildEmbeddedWorksheet(chartObject) {
|
|
|
5354
5887
|
const zipExcel = new ZipWriter();
|
|
5355
5888
|
const intBubbleCols = (data.length - 1) * 2 + 1;
|
|
5356
5889
|
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
|
-
|
|
5890
|
+
{
|
|
5891
|
+
const override = (partName, contentType) => voidEl("Override", {
|
|
5892
|
+
PartName: partName,
|
|
5893
|
+
ContentType: contentType
|
|
5894
|
+
}, { openPrefix: " " });
|
|
5895
|
+
zipExcel.add("[Content_Types].xml", XML_DECL + el("Types", { xmlns: CT_NS }, [
|
|
5896
|
+
raw(voidEl("Default", {
|
|
5897
|
+
Extension: "rels",
|
|
5898
|
+
ContentType: "application/vnd.openxmlformats-package.relationships+xml"
|
|
5899
|
+
}, { openPrefix: " " })),
|
|
5900
|
+
raw(voidEl("Default", {
|
|
5901
|
+
Extension: "xml",
|
|
5902
|
+
ContentType: "application/xml"
|
|
5903
|
+
}, { openPrefix: " " })),
|
|
5904
|
+
raw(override("/xl/workbook.xml", SML_CT + "sheet.main+xml")),
|
|
5905
|
+
raw(override("/xl/worksheets/sheet1.xml", SML_CT + "worksheet+xml")),
|
|
5906
|
+
raw(override("/xl/theme/theme1.xml", "application/vnd.openxmlformats-officedocument.theme+xml")),
|
|
5907
|
+
raw(override("/xl/styles.xml", SML_CT + "styles+xml")),
|
|
5908
|
+
raw(override("/xl/sharedStrings.xml", SML_CT + "sharedStrings+xml")),
|
|
5909
|
+
raw(override("/xl/tables/table1.xml", SML_CT + "table+xml")),
|
|
5910
|
+
raw(override("/docProps/core.xml", "application/vnd.openxmlformats-package.core-properties+xml")),
|
|
5911
|
+
raw(override("/docProps/app.xml", "application/vnd.openxmlformats-officedocument.extended-properties+xml"))
|
|
5912
|
+
]) + "\n");
|
|
5913
|
+
zipExcel.add("_rels/.rels", XML_DECL + relationships([
|
|
5914
|
+
relationship$2("rId1", PACKAGE_REL_NS + "/metadata/core-properties", "docProps/core.xml"),
|
|
5915
|
+
relationship$2("rId2", OFFICE_REL + "extended-properties", "docProps/app.xml"),
|
|
5916
|
+
relationship$2("rId3", OFFICE_REL + "officeDocument", "xl/workbook.xml")
|
|
5917
|
+
]) + "\n");
|
|
5918
|
+
const headingPairs = el("vt:vector", {
|
|
5919
|
+
size: 2,
|
|
5920
|
+
baseType: "variant"
|
|
5921
|
+
}, [raw(el("vt:variant", null, raw(el("vt:lpstr", null, "Worksheets")))), raw(el("vt:variant", null, raw(el("vt:i4", null, 1))))]);
|
|
5922
|
+
zipExcel.add("docProps/app.xml", XML_DECL + el("Properties", {
|
|
5923
|
+
xmlns: "http://schemas.openxmlformats.org/officeDocument/2006/extended-properties",
|
|
5924
|
+
"xmlns:vt": "http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes"
|
|
5925
|
+
}, [
|
|
5926
|
+
raw(el("Application", null, "Microsoft Macintosh Excel")),
|
|
5927
|
+
raw(el("DocSecurity", null, 0)),
|
|
5928
|
+
raw(el("ScaleCrop", null, "false")),
|
|
5929
|
+
raw(el("HeadingPairs", null, raw(headingPairs))),
|
|
5930
|
+
raw(el("TitlesOfParts", null, raw(el("vt:vector", {
|
|
5931
|
+
size: 1,
|
|
5932
|
+
baseType: "lpstr"
|
|
5933
|
+
}, raw(el("vt:lpstr", null, "Sheet1")))))),
|
|
5934
|
+
raw(el("Company", null)),
|
|
5935
|
+
raw(el("LinksUpToDate", null, "false")),
|
|
5936
|
+
raw(el("SharedDoc", null, "false")),
|
|
5937
|
+
raw(el("HyperlinksChanged", null, "false")),
|
|
5938
|
+
raw(el("AppVersion", null, "16.0300"))
|
|
5939
|
+
]) + "\n");
|
|
5940
|
+
zipExcel.add("docProps/core.xml", XML_DECL + el("cp:coreProperties", {
|
|
5941
|
+
"xmlns:cp": "http://schemas.openxmlformats.org/package/2006/metadata/core-properties",
|
|
5942
|
+
"xmlns:dc": "http://purl.org/dc/elements/1.1/",
|
|
5943
|
+
"xmlns:dcterms": "http://purl.org/dc/terms/",
|
|
5944
|
+
"xmlns:dcmitype": "http://purl.org/dc/dcmitype/",
|
|
5945
|
+
"xmlns:xsi": "http://www.w3.org/2001/XMLSchema-instance"
|
|
5946
|
+
}, [
|
|
5947
|
+
raw(el("dc:creator", null, "TsPptx")),
|
|
5948
|
+
raw(el("cp:lastModifiedBy", null, "TsPptx")),
|
|
5949
|
+
raw(el("dcterms:created", { "xsi:type": "dcterms:W3CDTF" }, (/* @__PURE__ */ new Date()).toISOString())),
|
|
5950
|
+
raw(el("dcterms:modified", { "xsi:type": "dcterms:W3CDTF" }, (/* @__PURE__ */ new Date()).toISOString()))
|
|
5951
|
+
]));
|
|
5952
|
+
zipExcel.add("xl/_rels/workbook.xml.rels", XML_DECL + relationships([
|
|
5953
|
+
relationship$2("rId3", OFFICE_REL + "styles", "styles.xml"),
|
|
5954
|
+
relationship$2("rId2", OFFICE_REL + "theme", "theme/theme1.xml"),
|
|
5955
|
+
relationship$2("rId1", OFFICE_REL + "worksheet", "worksheets/sheet1.xml"),
|
|
5956
|
+
relationship$2("rId4", OFFICE_REL + "sharedStrings", "sharedStrings.xml")
|
|
5957
|
+
]));
|
|
5958
|
+
zipExcel.add("xl/styles.xml", XML_DECL + XLSX_STYLES_XML);
|
|
5959
|
+
zipExcel.add("xl/theme/theme1.xml", XML_DECL + XLSX_THEME_XML);
|
|
5960
|
+
zipExcel.add("xl/workbook.xml", XML_DECL + el("workbook", {
|
|
5961
|
+
xmlns: SML_NS,
|
|
5962
|
+
"xmlns:r": "http://schemas.openxmlformats.org/officeDocument/2006/relationships",
|
|
5963
|
+
"xmlns:mc": "http://schemas.openxmlformats.org/markup-compatibility/2006",
|
|
5964
|
+
"mc:Ignorable": "x15",
|
|
5965
|
+
"xmlns:x15": "http://schemas.microsoft.com/office/spreadsheetml/2010/11/main"
|
|
5966
|
+
}, [
|
|
5967
|
+
raw(voidEl("fileVersion", {
|
|
5968
|
+
appName: "xl",
|
|
5969
|
+
lastEdited: 7,
|
|
5970
|
+
lowestEdited: 6,
|
|
5971
|
+
rupBuild: 10507
|
|
5972
|
+
})),
|
|
5973
|
+
raw(voidEl("workbookPr")),
|
|
5974
|
+
raw(el("bookViews", null, raw(voidEl("workbookView", {
|
|
5975
|
+
xWindow: 0,
|
|
5976
|
+
yWindow: 500,
|
|
5977
|
+
windowWidth: 20960,
|
|
5978
|
+
windowHeight: 15960
|
|
5979
|
+
})))),
|
|
5980
|
+
raw(el("sheets", null, raw(voidEl("sheet", {
|
|
5981
|
+
name: "Sheet1",
|
|
5982
|
+
sheetId: 1,
|
|
5983
|
+
"r:id": "rId1"
|
|
5984
|
+
})))),
|
|
5985
|
+
raw(voidEl("calcPr", {
|
|
5986
|
+
calcId: 0,
|
|
5987
|
+
concurrentCalc: 0
|
|
5988
|
+
}))
|
|
5989
|
+
]) + "\n");
|
|
5990
|
+
zipExcel.add("xl/worksheets/_rels/sheet1.xml.rels", XML_DECL + relationships([relationship$2("rId1", OFFICE_REL + "table", "../tables/table1.xml")]) + "\n");
|
|
5991
|
+
}
|
|
5375
5992
|
zipExcel.add("xl/sharedStrings.xml", buildXlsxSharedStrings(chartObject, data, intBubbleCols, IS_MULTI_CAT_AXES));
|
|
5376
5993
|
zipExcel.add("xl/tables/table1.xml", buildXlsxTable(chartObject, data, intBubbleCols));
|
|
5377
5994
|
zipExcel.add("xl/worksheets/sheet1.xml", buildXlsxSheet(chartObject, data, intBubbleCols, IS_MULTI_CAT_AXES));
|
|
@@ -5382,167 +5999,201 @@ function buildEmbeddedWorksheet(chartObject) {
|
|
|
5382
5999
|
* Build the embedded workbook's `xl/sharedStrings.xml` (series names + category labels).
|
|
5383
6000
|
*/
|
|
5384
6001
|
function buildXlsxSharedStrings(chartObject, data, intBubbleCols, IS_MULTI_CAT_AXES) {
|
|
5385
|
-
|
|
5386
|
-
|
|
5387
|
-
|
|
6002
|
+
const isBubble = chartObject.opts._type === "bubble" || chartObject.opts._type === "bubble3D";
|
|
6003
|
+
const isScatter = chartObject.opts._type === "scatter";
|
|
6004
|
+
let count;
|
|
6005
|
+
let uniqueCount;
|
|
6006
|
+
let blank = "";
|
|
6007
|
+
if (isBubble) count = uniqueCount = intBubbleCols;
|
|
6008
|
+
else if (isScatter) count = uniqueCount = data.length;
|
|
5388
6009
|
else if (IS_MULTI_CAT_AXES) {
|
|
5389
6010
|
let totCount = data.length + 1;
|
|
5390
6011
|
dataLabels(data[0]).forEach((arrLabel) => totCount += arrLabel.filter((label) => label && label !== "").length);
|
|
5391
|
-
|
|
5392
|
-
|
|
6012
|
+
count = uniqueCount = totCount;
|
|
6013
|
+
blank = el("si", null, raw(voidEl("t")));
|
|
5393
6014
|
} 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;
|
|
6015
|
+
count = data.length + dataLabels(data[0]).length * firstLabelGroup(data[0]).length + dataLabels(data[0]).length;
|
|
6016
|
+
uniqueCount = data.length + dataLabels(data[0]).length * firstLabelGroup(data[0]).length + 1;
|
|
6017
|
+
blank = el("si", null, raw(el("t", { "xml:space": "preserve" })));
|
|
6018
|
+
}
|
|
6019
|
+
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("");
|
|
6020
|
+
const labels = isBubble || isScatter ? "" : dataLabels(data[0]).slice().reverse().map((labelsGroup) => labelsGroup.filter((label) => label && label !== "").map((label) => sharedString(label)).join("")).join("");
|
|
6021
|
+
return XML_DECL + el("sst", {
|
|
6022
|
+
xmlns: SML_NS,
|
|
6023
|
+
count,
|
|
6024
|
+
uniqueCount
|
|
6025
|
+
}, [
|
|
6026
|
+
raw(blank),
|
|
6027
|
+
raw(names),
|
|
6028
|
+
raw(labels)
|
|
6029
|
+
]) + "\n";
|
|
5416
6030
|
}
|
|
5417
6031
|
/**
|
|
5418
6032
|
* Build the embedded workbook's `xl/tables/table1.xml` (the data table over the sheet range).
|
|
5419
6033
|
*/
|
|
5420
6034
|
function buildXlsxTable(chartObject, data, intBubbleCols) {
|
|
5421
|
-
|
|
6035
|
+
const labelCols = dataLabels(data[0]).length;
|
|
6036
|
+
let ref;
|
|
6037
|
+
let columns;
|
|
5422
6038
|
if (chartObject.opts._type === "bubble" || chartObject.opts._type === "bubble3D") {
|
|
5423
|
-
|
|
5424
|
-
strTableXml += `<tableColumns count="${intBubbleCols}">`;
|
|
6039
|
+
ref = `A1:${getExcelColName(intBubbleCols)}${intBubbleCols}`;
|
|
5425
6040
|
let idxColLtr = 1;
|
|
5426
|
-
data.
|
|
5427
|
-
if (idx === 0)
|
|
5428
|
-
|
|
5429
|
-
|
|
5430
|
-
|
|
5431
|
-
|
|
5432
|
-
|
|
5433
|
-
|
|
6041
|
+
columns = data.map((obj, idx) => {
|
|
6042
|
+
if (idx === 0) return voidEl("tableColumn", {
|
|
6043
|
+
id: idx + 1,
|
|
6044
|
+
name: "X-Values"
|
|
6045
|
+
});
|
|
6046
|
+
const nameCol = voidEl("tableColumn", {
|
|
6047
|
+
id: idx + idxColLtr,
|
|
6048
|
+
name: obj.name
|
|
6049
|
+
});
|
|
6050
|
+
idxColLtr++;
|
|
6051
|
+
return nameCol + voidEl("tableColumn", {
|
|
6052
|
+
id: idx + idxColLtr,
|
|
6053
|
+
name: `Size${idx}`
|
|
6054
|
+
});
|
|
6055
|
+
}).join("");
|
|
5434
6056
|
} else if (chartObject.opts._type === "scatter") {
|
|
5435
|
-
|
|
5436
|
-
|
|
5437
|
-
|
|
5438
|
-
|
|
5439
|
-
});
|
|
6057
|
+
ref = `A1:${getExcelColName(data.length)}${dataValues(data[0]).length + 1}`;
|
|
6058
|
+
columns = data.map((_obj, idx) => voidEl("tableColumn", {
|
|
6059
|
+
id: idx + 1,
|
|
6060
|
+
name: `${idx === 0 ? "X-Values" : "Y-Value "}${idx}`
|
|
6061
|
+
})).join("");
|
|
5440
6062
|
} else {
|
|
5441
|
-
|
|
5442
|
-
|
|
5443
|
-
|
|
5444
|
-
|
|
5445
|
-
})
|
|
5446
|
-
|
|
5447
|
-
|
|
5448
|
-
});
|
|
6063
|
+
ref = `A1:${getExcelColName(data.length + labelCols)}${firstLabelGroup(data[0]).length + 1}`;
|
|
6064
|
+
columns = dataLabels(data[0]).map((_labelsGroup, idx) => voidEl("tableColumn", {
|
|
6065
|
+
id: idx + 1,
|
|
6066
|
+
name: `Column${idx + 1}`
|
|
6067
|
+
})).join("") + data.map((obj, idx) => voidEl("tableColumn", {
|
|
6068
|
+
id: idx + labelCols + 1,
|
|
6069
|
+
name: obj.name ?? ""
|
|
6070
|
+
})).join("");
|
|
5449
6071
|
}
|
|
5450
|
-
|
|
5451
|
-
|
|
5452
|
-
|
|
5453
|
-
|
|
6072
|
+
const columnCount = chartObject.opts._type === "bubble" || chartObject.opts._type === "bubble3D" ? intBubbleCols : chartObject.opts._type === "scatter" ? data.length : data.length + labelCols;
|
|
6073
|
+
return XML_DECL + el("table", {
|
|
6074
|
+
xmlns: SML_NS,
|
|
6075
|
+
id: 1,
|
|
6076
|
+
name: "Table1",
|
|
6077
|
+
displayName: "Table1",
|
|
6078
|
+
ref,
|
|
6079
|
+
totalsRowShown: 0
|
|
6080
|
+
}, [raw(el("tableColumns", { count: columnCount }, raw(columns))), raw(voidEl("tableStyleInfo", {
|
|
6081
|
+
showFirstColumn: 0,
|
|
6082
|
+
showLastColumn: 0,
|
|
6083
|
+
showRowStripes: 1,
|
|
6084
|
+
showColumnStripes: 0
|
|
6085
|
+
}))]);
|
|
5454
6086
|
}
|
|
5455
6087
|
/**
|
|
5456
6088
|
* Build the embedded workbook's `xl/worksheets/sheet1.xml` (header row + per-series data rows).
|
|
5457
6089
|
*/
|
|
5458
6090
|
function buildXlsxSheet(chartObject, data, intBubbleCols, IS_MULTI_CAT_AXES) {
|
|
5459
|
-
|
|
5460
|
-
|
|
5461
|
-
|
|
5462
|
-
|
|
5463
|
-
|
|
5464
|
-
|
|
5465
|
-
|
|
5466
|
-
|
|
5467
|
-
|
|
5468
|
-
|
|
5469
|
-
|
|
5470
|
-
|
|
5471
|
-
|
|
6091
|
+
const isBubble = chartObject.opts._type === "bubble" || chartObject.opts._type === "bubble3D";
|
|
6092
|
+
const isScatter = chartObject.opts._type === "scatter";
|
|
6093
|
+
const labelCols = dataLabels(data[0]).length;
|
|
6094
|
+
/** One cell. `t="s"` marks a shared-string index; without it the value is a number. */
|
|
6095
|
+
const cell = (col, row, value, shared = false) => el("c", {
|
|
6096
|
+
r: `${getExcelColName(col)}${row}`,
|
|
6097
|
+
t: shared ? "s" : void 0
|
|
6098
|
+
}, raw(el("v", null, value)));
|
|
6099
|
+
/** One row, spanning the sheet's full column count. */
|
|
6100
|
+
const sheetRow = (row, span, cells) => el("row", {
|
|
6101
|
+
r: row,
|
|
6102
|
+
spans: `1:${span}`
|
|
6103
|
+
}, raw(cells));
|
|
6104
|
+
const colCount = isBubble ? intBubbleCols : isScatter ? data.length : data.length + labelCols;
|
|
6105
|
+
let rows = "";
|
|
6106
|
+
if (isBubble) {
|
|
6107
|
+
let header = "";
|
|
6108
|
+
for (let idx = 0; idx < intBubbleCols; idx++) header += cell(idx + 1, 1, idx, true);
|
|
6109
|
+
rows += sheetRow(1, intBubbleCols, header);
|
|
5472
6110
|
dataValues(data[0]).forEach((val, idx) => {
|
|
5473
|
-
|
|
5474
|
-
strSheetXml += `<c r="A${idx + 2}"><v>${val}</v></c>`;
|
|
6111
|
+
let cells = cell(1, idx + 2, val);
|
|
5475
6112
|
let idxColLtr = 2;
|
|
5476
6113
|
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++;
|
|
6114
|
+
cells += cell(idxColLtr++, idx + 2, dataValues(data[idy])[idx] ?? "");
|
|
6115
|
+
cells += cell(idxColLtr++, idx + 2, dataSizes(data[idy])[idx] ?? "");
|
|
5481
6116
|
}
|
|
5482
|
-
|
|
6117
|
+
rows += sheetRow(idx + 2, intBubbleCols, cells);
|
|
5483
6118
|
});
|
|
5484
|
-
} else if (
|
|
5485
|
-
|
|
5486
|
-
|
|
5487
|
-
|
|
5488
|
-
strSheetXml += "</row>";
|
|
6119
|
+
} else if (isScatter) {
|
|
6120
|
+
let header = "";
|
|
6121
|
+
for (let idx = 0; idx < data.length; idx++) header += cell(idx + 1, 1, idx, true);
|
|
6122
|
+
rows += sheetRow(1, data.length, header);
|
|
5489
6123
|
dataValues(data[0]).forEach((val, idx) => {
|
|
5490
|
-
|
|
5491
|
-
|
|
5492
|
-
|
|
5493
|
-
|
|
6124
|
+
let cells = cell(1, idx + 2, val);
|
|
6125
|
+
for (let idy = 1; idy < data.length; idy++) {
|
|
6126
|
+
const yValue = dataValues(data[idy])[idx];
|
|
6127
|
+
cells += cell(idy + 1, idx + 2, yValue || yValue === 0 ? yValue : "");
|
|
6128
|
+
}
|
|
6129
|
+
rows += sheetRow(idx + 2, data.length, cells);
|
|
5494
6130
|
});
|
|
6131
|
+
} else if (!IS_MULTI_CAT_AXES) {
|
|
6132
|
+
let header = "";
|
|
6133
|
+
for (let idx = 0; idx < labelCols; idx++) header += cell(idx + 1, 1, 0, true);
|
|
6134
|
+
for (let idx = 0; idx < data.length; idx++) header += cell(idx + 1 + labelCols, 1, idx + 1, true);
|
|
6135
|
+
rows += sheetRow(1, data.length + labelCols, header);
|
|
6136
|
+
const rowCount = firstLabelGroup(data[0]).length || Math.max(0, ...data.map((series) => dataValues(series).length));
|
|
6137
|
+
for (let idx = 0; idx < rowCount; idx++) {
|
|
6138
|
+
let cells = "";
|
|
6139
|
+
for (let idx2 = labelCols - 1; idx2 >= 0; idx2--) cells += cell(labelCols - idx2, idx + 2, data.length + idx + 1, true);
|
|
6140
|
+
for (let idy = 0; idy < data.length; idy++) cells += cell(labelCols + idy + 1, idx + 2, dataValues(data[idy])[idx] ?? "");
|
|
6141
|
+
rows += sheetRow(idx + 2, data.length + labelCols, cells);
|
|
6142
|
+
}
|
|
5495
6143
|
} 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
|
-
});
|
|
6144
|
+
const TOT_SER = data.length;
|
|
6145
|
+
const TOT_CAT = firstLabelGroup(data[0]).length;
|
|
6146
|
+
const revLabelGroups = dataLabels(data[0]).slice().reverse();
|
|
6147
|
+
const ssLabelMap = /* @__PURE__ */ new Map();
|
|
6148
|
+
let ssIdx = TOT_SER + 1;
|
|
6149
|
+
revLabelGroups.forEach((labelsGroup, revLevelIdx) => {
|
|
6150
|
+
labelsGroup.forEach((label, rowIdx) => {
|
|
6151
|
+
if (label && label !== "") ssLabelMap.set(`${revLevelIdx}:${rowIdx}`, ssIdx++);
|
|
5526
6152
|
});
|
|
5527
|
-
|
|
5528
|
-
|
|
5529
|
-
|
|
5530
|
-
|
|
5531
|
-
|
|
5532
|
-
|
|
5533
|
-
|
|
5534
|
-
|
|
5535
|
-
|
|
5536
|
-
|
|
5537
|
-
|
|
5538
|
-
|
|
5539
|
-
}
|
|
6153
|
+
});
|
|
6154
|
+
let header = "";
|
|
6155
|
+
for (let col = 1; col <= labelCols; col++) header += cell(col, 1, 0, true);
|
|
6156
|
+
for (let ser = 0; ser < TOT_SER; ser++) header += cell(labelCols + ser + 1, 1, ser + 1, true);
|
|
6157
|
+
rows += sheetRow(1, TOT_SER + labelCols, header);
|
|
6158
|
+
for (let idx = 0; idx < TOT_CAT; idx++) {
|
|
6159
|
+
let cells = revLabelGroups.map((labelsGroup, idy) => {
|
|
6160
|
+
const colLabel = labelsGroup[idx];
|
|
6161
|
+
return colLabel && colLabel !== "" ? cell(idy + 1, idx + 2, ssLabelMap.get(`${idy}:${idx}`) ?? "", true) : "";
|
|
6162
|
+
}).join("");
|
|
6163
|
+
for (let idy = 0; idy < TOT_SER; idy++) cells += cell(labelCols + idy + 1, idx + 2, dataValues(data[idy])[idx] ?? "");
|
|
6164
|
+
rows += sheetRow(idx + 2, TOT_SER + labelCols, cells);
|
|
5540
6165
|
}
|
|
5541
6166
|
}
|
|
5542
|
-
|
|
5543
|
-
|
|
5544
|
-
|
|
5545
|
-
|
|
6167
|
+
const sheetView = el("sheetViews", null, raw(el("sheetView", {
|
|
6168
|
+
tabSelected: 1,
|
|
6169
|
+
workbookViewId: 0
|
|
6170
|
+
}, raw(voidEl("selection", {
|
|
6171
|
+
activeCell: "B1",
|
|
6172
|
+
sqref: "B1"
|
|
6173
|
+
})))));
|
|
6174
|
+
return XML_DECL + el("worksheet", {
|
|
6175
|
+
xmlns: SML_NS,
|
|
6176
|
+
"xmlns:r": "http://schemas.openxmlformats.org/officeDocument/2006/relationships",
|
|
6177
|
+
"xmlns:mc": "http://schemas.openxmlformats.org/markup-compatibility/2006",
|
|
6178
|
+
"mc:Ignorable": "x14ac",
|
|
6179
|
+
"xmlns:x14ac": "http://schemas.microsoft.com/office/spreadsheetml/2009/9/ac"
|
|
6180
|
+
}, [
|
|
6181
|
+
raw(voidEl("dimension", { ref: `A1:${getExcelColName(colCount)}${dataValues(data[0]).length + 1}` })),
|
|
6182
|
+
raw(sheetView),
|
|
6183
|
+
raw(voidEl("sheetFormatPr", {
|
|
6184
|
+
baseColWidth: 10,
|
|
6185
|
+
defaultRowHeight: 16
|
|
6186
|
+
})),
|
|
6187
|
+
raw(el("sheetData", null, raw(rows))),
|
|
6188
|
+
raw(voidEl("pageMargins", {
|
|
6189
|
+
left: .7,
|
|
6190
|
+
right: .7,
|
|
6191
|
+
top: .75,
|
|
6192
|
+
bottom: .75,
|
|
6193
|
+
header: .3,
|
|
6194
|
+
footer: .3
|
|
6195
|
+
}))
|
|
6196
|
+
]) + "\n";
|
|
5546
6197
|
}
|
|
5547
6198
|
/**
|
|
5548
6199
|
* Build the standalone `.rels` for a chart part: a single `rId1` relationship to
|
|
@@ -7012,17 +7663,17 @@ function fallbackPic(picId, objectName, altText, model, xf) {
|
|
|
7012
7663
|
return el("p:pic", null, [
|
|
7013
7664
|
raw(el("p:nvPicPr", null, [
|
|
7014
7665
|
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:
|
|
7666
|
+
raw(el("p:cNvPicPr", null, raw(genXmlObjectLock("a:picLocks", PICTURE_LOCK_ATTRS, {
|
|
7667
|
+
noGrp: true,
|
|
7668
|
+
noRot: true,
|
|
7669
|
+
noChangeAspect: true,
|
|
7670
|
+
noMove: true,
|
|
7671
|
+
noResize: true,
|
|
7672
|
+
noEditPoints: true,
|
|
7673
|
+
noAdjustHandles: true,
|
|
7674
|
+
noChangeArrowheads: true,
|
|
7675
|
+
noChangeShapeType: true,
|
|
7676
|
+
noCrop: true
|
|
7026
7677
|
})))),
|
|
7027
7678
|
raw(voidEl("p:nvPr"))
|
|
7028
7679
|
])),
|
|
@@ -7064,7 +7715,7 @@ function renderModel3dObject(slideItemObj, idx, x, y, cx, cy) {
|
|
|
7064
7715
|
const graphicFrame = el("p:graphicFrame", null, [
|
|
7065
7716
|
raw(el("p:nvGraphicFramePr", null, [
|
|
7066
7717
|
raw(cNvPrOpen(idx + 2, opts.objectName, altText) + "/>"),
|
|
7067
|
-
raw(el("p:cNvGraphicFramePr", null, raw(voidEl("a:graphicFrameLocks")))),
|
|
7718
|
+
raw(el("p:cNvGraphicFramePr", null, raw(genXmlObjectLock("a:graphicFrameLocks", GRAPHIC_FRAME_LOCK_ATTRS, opts.objectLock, opts.objectName) || voidEl("a:graphicFrameLocks")))),
|
|
7068
7719
|
raw(voidEl("p:nvPr"))
|
|
7069
7720
|
])),
|
|
7070
7721
|
raw(el("p:xfrm", null, [raw(voidEl("a:off", {
|
|
@@ -7355,7 +8006,7 @@ function renderTableObject(slideItemObj, idx, x, y, cx, cy, placeholderObj, item
|
|
|
7355
8006
|
let intColCnt = 0;
|
|
7356
8007
|
let tblInner = "";
|
|
7357
8008
|
let cellOpts = null;
|
|
7358
|
-
arrTabRows = (slideItemObj.arrTabRows ?? []).map((row) => [...row]);
|
|
8009
|
+
arrTabRows = withCheckedSpans((slideItemObj.arrTabRows ?? []).map((row) => [...row]));
|
|
7359
8010
|
objTabOpts = itemOpts;
|
|
7360
8011
|
intColCnt = 0;
|
|
7361
8012
|
(arrTabRows[0] ?? []).forEach((cell) => {
|
|
@@ -7639,16 +8290,16 @@ function zoomFallbackPic(picId, objectName, tile, absXf) {
|
|
|
7639
8290
|
"r:id": `rId${tile.fallbackSlideRid}`,
|
|
7640
8291
|
action: "ppaction://hlinksldjump"
|
|
7641
8292
|
}) + "</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:
|
|
8293
|
+
raw(el("p:cNvPicPr", null, raw(genXmlObjectLock("a:picLocks", PICTURE_LOCK_ATTRS, {
|
|
8294
|
+
noGrp: true,
|
|
8295
|
+
noRot: true,
|
|
8296
|
+
noChangeAspect: true,
|
|
8297
|
+
noMove: true,
|
|
8298
|
+
noResize: true,
|
|
8299
|
+
noEditPoints: true,
|
|
8300
|
+
noAdjustHandles: true,
|
|
8301
|
+
noChangeArrowheads: true,
|
|
8302
|
+
noChangeShapeType: true
|
|
7652
8303
|
})))),
|
|
7653
8304
|
raw(voidEl("p:nvPr"))
|
|
7654
8305
|
])),
|
|
@@ -7675,7 +8326,8 @@ function zoomFallbackPic(picId, objectName, tile, absXf) {
|
|
|
7675
8326
|
function renderZoomObject(slideItemObj, idx, x, y, cx, cy) {
|
|
7676
8327
|
const zoom = slideItemObj.zoom;
|
|
7677
8328
|
if (!zoom) return "";
|
|
7678
|
-
const
|
|
8329
|
+
const opts = slideItemObj.options || {};
|
|
8330
|
+
const objectName = opts.objectName;
|
|
7679
8331
|
const { uri, prefix, zm } = ZOOM_VARIANTS[zoom.variant];
|
|
7680
8332
|
const firstTile = zoom.tiles[0];
|
|
7681
8333
|
if (!firstTile) return "";
|
|
@@ -7693,7 +8345,10 @@ function renderZoomObject(slideItemObj, idx, x, y, cx, cy) {
|
|
|
7693
8345
|
const graphicFrame = el("p:graphicFrame", null, [
|
|
7694
8346
|
raw(el("p:nvGraphicFramePr", null, [
|
|
7695
8347
|
raw(cNvPrOpen(idx + 2, objectName, "") + "/>"),
|
|
7696
|
-
raw(el("p:cNvGraphicFramePr", null, raw(
|
|
8348
|
+
raw(el("p:cNvGraphicFramePr", null, raw(genXmlObjectLock("a:graphicFrameLocks", GRAPHIC_FRAME_LOCK_ATTRS, {
|
|
8349
|
+
noChangeAspect: true,
|
|
8350
|
+
...opts.objectLock
|
|
8351
|
+
}, objectName)))),
|
|
7697
8352
|
raw(voidEl("p:nvPr"))
|
|
7698
8353
|
])),
|
|
7699
8354
|
raw(el("p:xfrm", null, [raw(voidEl("a:off", {
|
|
@@ -8352,56 +9007,18 @@ function buildThemeClrScheme(scheme) {
|
|
|
8352
9007
|
return raw(el(`a:${slot}`, null, child));
|
|
8353
9008
|
}));
|
|
8354
9009
|
}
|
|
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 = [
|
|
9010
|
+
/**
|
|
9011
|
+
* The per-script theme font fallback table (`a:fontScheme`'s CT_TextFont lists), in OOXML
|
|
9012
|
+
* document order. Static Office defaults — no caller data, no escaping risk — unlike the
|
|
9013
|
+
* `<a:latin>`/`<a:ea>`/`<a:cs>` slots above.
|
|
9014
|
+
*
|
|
9015
|
+
* Forty-one of the forty-seven scripts take the same face in the major and minor lists, so the
|
|
9016
|
+
* shared table below is the whole thing and the two override maps hold the six-odd rows that
|
|
9017
|
+
* actually differ. Written out twice, ninety-four lines said less than these do, and one row
|
|
9018
|
+
* mistyped in one copy produces a theme that opens fine and paints a script in the wrong face —
|
|
9019
|
+
* a difference nobody reviewing a diff of two 47-row tables would see.
|
|
9020
|
+
*/
|
|
9021
|
+
const THEME_FONT_LIST = [
|
|
8405
9022
|
["Jpan", "游ゴシック"],
|
|
8406
9023
|
["Hang", "맑은 고딕"],
|
|
8407
9024
|
["Hans", "等线"],
|
|
@@ -8450,6 +9067,24 @@ const MINOR_FONT_LIST = [
|
|
|
8450
9067
|
["Talu", "Microsoft New Tai Lue"],
|
|
8451
9068
|
["Tfng", "Ebrima"]
|
|
8452
9069
|
];
|
|
9070
|
+
/**
|
|
9071
|
+
* The seven scripts whose *heading* face differs from the body one. Latin and CJK headings take
|
|
9072
|
+
* the Light weight; the scripts with no Light cut take a serif (or, for Khmer, a different face
|
|
9073
|
+
* entirely) where the body takes a sans. Every other script in {@link THEME_FONT_LIST} uses one
|
|
9074
|
+
* face for both.
|
|
9075
|
+
*/
|
|
9076
|
+
const MAJOR_FONT_OVERRIDES = {
|
|
9077
|
+
Jpan: "游ゴシック Light",
|
|
9078
|
+
Hans: "等线 Light",
|
|
9079
|
+
Arab: "Times New Roman",
|
|
9080
|
+
Hebr: "Times New Roman",
|
|
9081
|
+
Thai: "Angsana New",
|
|
9082
|
+
Khmr: "MoolBoran",
|
|
9083
|
+
Viet: "Times New Roman"
|
|
9084
|
+
};
|
|
9085
|
+
/** The major (heading) and minor (body) lists, both derived from the one table. */
|
|
9086
|
+
const MAJOR_FONT_LIST = THEME_FONT_LIST.map(([script, face]) => [script, MAJOR_FONT_OVERRIDES[script] ?? face]);
|
|
9087
|
+
const MINOR_FONT_LIST = THEME_FONT_LIST;
|
|
8453
9088
|
function fontListChildren(scriptFaces) {
|
|
8454
9089
|
return scriptFaces.map(([script, typeface]) => raw(voidEl("a:font", {
|
|
8455
9090
|
script,
|
|
@@ -9390,20 +10025,7 @@ function makeXmlMaster(slide, layouts) {
|
|
|
9390
10025
|
id: LAYOUT_IDX_SERIES_BASE + idx,
|
|
9391
10026
|
"r:id": `rId${slide._rels.length + idx + 1}`
|
|
9392
10027
|
})).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
|
-
});
|
|
10028
|
+
const clrMap = voidEl("p:clrMap", DEFAULT_COLOR_MAP);
|
|
9407
10029
|
const hf = voidEl("p:hf", {
|
|
9408
10030
|
sldNum: slide._slideNumberProps ? null : 0,
|
|
9409
10031
|
hdr: 0,
|
|
@@ -9671,7 +10293,7 @@ async function writePackage(source, props) {
|
|
|
9671
10293
|
* the OfficeGen project (Copyright 2013 Ziv Barber). This project is likewise MIT; the full
|
|
9672
10294
|
* license text is in `LICENSE` at the repository root.
|
|
9673
10295
|
*/
|
|
9674
|
-
const VERSION = "3.
|
|
10296
|
+
const VERSION = "3.6.0";
|
|
9675
10297
|
function standardLayoutToPresLayout(layout) {
|
|
9676
10298
|
return {
|
|
9677
10299
|
name: layout.name,
|
|
@@ -10651,6 +11273,6 @@ function textRuns(runs) {
|
|
|
10651
11273
|
return runs;
|
|
10652
11274
|
}
|
|
10653
11275
|
//#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 };
|
|
11276
|
+
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
11277
|
|
|
10656
|
-
//# sourceMappingURL=text-
|
|
11278
|
+
//# sourceMappingURL=text-CyetbF6p.js.map
|