@shbernal/pptxgenjs 5.2.0 → 5.3.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/{browser-DraPrTLD.js → browser-CzGC6NnM.js} +3 -3
- package/dist/{browser-DraPrTLD.js.map → browser-CzGC6NnM.js.map} +1 -1
- package/dist/browser.d.ts +3 -3
- package/dist/browser.js +4 -4
- package/dist/{core-interfaces-vUc0ElZs.js → core-interfaces-BFXQk67T.js} +30 -9
- package/dist/core-interfaces-BFXQk67T.js.map +1 -0
- package/dist/core.d.ts +2 -2
- package/dist/core.js +3 -3
- package/dist/index.d.ts +2 -2
- package/dist/index.js +4 -4
- package/dist/inspect.js +1 -1
- package/dist/node.d.ts +3 -3
- package/dist/node.js +4 -4
- package/dist/{pptxgen--5RWzhb4.js → pptxgen-B-mAxCRC.js} +655 -211
- package/dist/pptxgen-B-mAxCRC.js.map +1 -0
- package/dist/{pptxgen-DzBNFPxG.d.ts → pptxgen-Clv3zz3l.d.ts} +2 -2
- package/dist/{pptxgen-DzBNFPxG.d.ts.map → pptxgen-Clv3zz3l.d.ts.map} +1 -1
- package/dist/standalone.d.ts +288 -30
- package/dist/standalone.d.ts.map +1 -1
- package/dist/standalone.js +724 -215
- package/dist/standalone.js.map +1 -1
- package/dist/units-BMrBTU0-.js +106 -0
- package/dist/units-BMrBTU0-.js.map +1 -0
- package/dist/{units-y594YyBo.d.ts → units-BPRPrYRg.d.ts} +289 -31
- package/dist/units-BPRPrYRg.d.ts.map +1 -0
- package/package.json +1 -1
- package/dist/core-interfaces-vUc0ElZs.js.map +0 -1
- package/dist/pptxgen--5RWzhb4.js.map +0 -1
- package/dist/units-DmzbVUNp.js +0 -62
- package/dist/units-DmzbVUNp.js.map +0 -1
- package/dist/units-y594YyBo.d.ts.map +0 -1
package/dist/standalone.js
CHANGED
|
@@ -3137,6 +3137,10 @@ while (n === a[++i] && n === a[++i] && n === a[++i] && n === a[++i] && n === a[+
|
|
|
3137
3137
|
const EMU_PER_INCH = 914400;
|
|
3138
3138
|
const EMU_PER_POINT = 12700;
|
|
3139
3139
|
const POINTS_PER_INCH = 72;
|
|
3140
|
+
/** A bare number larger than this (in inches) is almost certainly a mistake — likely a raw EMU
|
|
3141
|
+
* value passed where inches are expected. We interpret it as inches (the documented contract) but
|
|
3142
|
+
* warn, pointing at the explicit `"<n>emu"` form. ~1000in is far beyond any real slide. */
|
|
3143
|
+
const IMPLAUSIBLE_INCHES = 1e3;
|
|
3140
3144
|
function inchesToEmu(inches) {
|
|
3141
3145
|
assertFiniteNumber(inches, "inches");
|
|
3142
3146
|
return Math.round(inches * EMU_PER_INCH);
|
|
@@ -3150,6 +3154,46 @@ function pixelsToEmu(pixels, dpi) {
|
|
|
3150
3154
|
assertPositiveFiniteNumber(dpi, "dpi");
|
|
3151
3155
|
return inchesToEmu(pixels / dpi);
|
|
3152
3156
|
}
|
|
3157
|
+
/**
|
|
3158
|
+
* Resolve a percentage of an axis length to EMU.
|
|
3159
|
+
* @param percent - percentage value (e.g. `50` for 50%)
|
|
3160
|
+
* @param axisEmu - the axis length in EMU (slide width for x/w, height for y/h)
|
|
3161
|
+
*/
|
|
3162
|
+
function percentToEmu(percent, axisEmu) {
|
|
3163
|
+
assertFiniteNumber(percent, "percent");
|
|
3164
|
+
assertFiniteNumber(axisEmu, "axisEmu");
|
|
3165
|
+
return Math.round(percent / 100 * axisEmu);
|
|
3166
|
+
}
|
|
3167
|
+
/**
|
|
3168
|
+
* The single user-coordinate → EMU boundary. Convert each user-supplied coordinate exactly once.
|
|
3169
|
+
*
|
|
3170
|
+
* Accepts (see {@link Coord}):
|
|
3171
|
+
* - a bare `number` → **always inches** (the documented unit); no magnitude guessing
|
|
3172
|
+
* - `"<n>%"` → percentage of `axisEmu`
|
|
3173
|
+
* - `"<n>in"` / `"<n>pt"` / `"<n>emu"` → explicit units (the escape hatch for non-inch values)
|
|
3174
|
+
*
|
|
3175
|
+
* Throws on non-finite or unparseable input rather than silently emitting a degenerate 0-size.
|
|
3176
|
+
* @param value - user coordinate
|
|
3177
|
+
* @param axisEmu - axis length in EMU, used only to resolve percentages
|
|
3178
|
+
*/
|
|
3179
|
+
function coordToEmu(value, axisEmu) {
|
|
3180
|
+
if (typeof value === "number") {
|
|
3181
|
+
assertFiniteNumber(value, "coordinate");
|
|
3182
|
+
if (Math.abs(value) > IMPLAUSIBLE_INCHES) console.warn(`PptxGenJS: coordinate ${value} interpreted as ${value} inches. A bare number is always inches; if you meant EMU, pass it as a string like "${Math.round(value)}emu".`);
|
|
3183
|
+
return inchesToEmu(value);
|
|
3184
|
+
}
|
|
3185
|
+
const match = /^\s*(-?\d*\.?\d+)\s*(%|in|pt|emu)\s*$/.exec(value);
|
|
3186
|
+
if (!match) throw new Error(`PptxGenJS: invalid coordinate "${value}". Expected a number (inches) or a string like "50%", "5in", "72pt", or "914400emu".`);
|
|
3187
|
+
const n = Number(match[1]);
|
|
3188
|
+
switch (match[2]) {
|
|
3189
|
+
case "%": return percentToEmu(n, axisEmu);
|
|
3190
|
+
case "in": return inchesToEmu(n);
|
|
3191
|
+
case "pt": return pointsToEmu(n);
|
|
3192
|
+
default:
|
|
3193
|
+
assertFiniteNumber(n, "coordinate");
|
|
3194
|
+
return Math.round(n);
|
|
3195
|
+
}
|
|
3196
|
+
}
|
|
3153
3197
|
function emuToInches(emu) {
|
|
3154
3198
|
assertFiniteNumber(emu, "emu");
|
|
3155
3199
|
return emu / EMU_PER_INCH;
|
|
@@ -3433,7 +3477,7 @@ let ShapeType = /* @__PURE__ */ function(ShapeType) {
|
|
|
3433
3477
|
ShapeType["flowChartSort"] = "flowChartSort";
|
|
3434
3478
|
ShapeType["flowChartSummingJunction"] = "flowChartSummingJunction";
|
|
3435
3479
|
ShapeType["flowChartTerminator"] = "flowChartTerminator";
|
|
3436
|
-
ShapeType["
|
|
3480
|
+
ShapeType["foldedCorner"] = "foldedCorner";
|
|
3437
3481
|
ShapeType["frame"] = "frame";
|
|
3438
3482
|
ShapeType["funnel"] = "funnel";
|
|
3439
3483
|
ShapeType["gear6"] = "gear6";
|
|
@@ -3636,7 +3680,7 @@ let SHAPE_TYPE = /* @__PURE__ */ function(SHAPE_TYPE) {
|
|
|
3636
3680
|
SHAPE_TYPE["FLOWCHART_STORED_DATA"] = "flowChartOnlineStorage";
|
|
3637
3681
|
SHAPE_TYPE["FLOWCHART_SUMMING_JUNCTION"] = "flowChartSummingJunction";
|
|
3638
3682
|
SHAPE_TYPE["FLOWCHART_TERMINATOR"] = "flowChartTerminator";
|
|
3639
|
-
SHAPE_TYPE["FOLDED_CORNER"] = "
|
|
3683
|
+
SHAPE_TYPE["FOLDED_CORNER"] = "foldedCorner";
|
|
3640
3684
|
SHAPE_TYPE["FRAME"] = "frame";
|
|
3641
3685
|
SHAPE_TYPE["FUNNEL"] = "funnel";
|
|
3642
3686
|
SHAPE_TYPE["GEAR_6"] = "gear6";
|
|
@@ -3671,10 +3715,6 @@ let SHAPE_TYPE = /* @__PURE__ */ function(SHAPE_TYPE) {
|
|
|
3671
3715
|
SHAPE_TYPE["LINE_CALLOUT_3_ACCENT_BAR"] = "accentCallout3";
|
|
3672
3716
|
SHAPE_TYPE["LINE_CALLOUT_3_BORDER_AND_ACCENT_BAR"] = "accentBorderCallout3";
|
|
3673
3717
|
SHAPE_TYPE["LINE_CALLOUT_3_NO_BORDER"] = "callout3";
|
|
3674
|
-
SHAPE_TYPE["LINE_CALLOUT_4"] = "borderCallout4";
|
|
3675
|
-
SHAPE_TYPE["LINE_CALLOUT_4_ACCENT_BAR"] = "accentCallout3=4";
|
|
3676
|
-
SHAPE_TYPE["LINE_CALLOUT_4_BORDER_AND_ACCENT_BAR"] = "accentBorderCallout4";
|
|
3677
|
-
SHAPE_TYPE["LINE_CALLOUT_4_NO_BORDER"] = "callout4";
|
|
3678
3718
|
SHAPE_TYPE["LINE"] = "line";
|
|
3679
3719
|
SHAPE_TYPE["LINE_INVERSE"] = "lineInv";
|
|
3680
3720
|
SHAPE_TYPE["MATH_DIVIDE"] = "mathDivide";
|
|
@@ -3742,6 +3782,31 @@ let SHAPE_TYPE = /* @__PURE__ */ function(SHAPE_TYPE) {
|
|
|
3742
3782
|
SHAPE_TYPE["WAVE"] = "wave";
|
|
3743
3783
|
return SHAPE_TYPE;
|
|
3744
3784
|
}({});
|
|
3785
|
+
/**
|
|
3786
|
+
* Valid ECMA-376 `ST_ShapeType` presets that are not surfaced with a friendly
|
|
3787
|
+
* `SHAPE_TYPE` name. They are still legal geometries PowerPoint renders, so the
|
|
3788
|
+
* preset-validation set must accept them.
|
|
3789
|
+
*/
|
|
3790
|
+
const EXTRA_SHAPE_PRESETS = [
|
|
3791
|
+
"straightConnector1",
|
|
3792
|
+
"bentConnector2",
|
|
3793
|
+
"bentConnector3",
|
|
3794
|
+
"bentConnector4",
|
|
3795
|
+
"bentConnector5",
|
|
3796
|
+
"curvedConnector2",
|
|
3797
|
+
"curvedConnector3",
|
|
3798
|
+
"curvedConnector4",
|
|
3799
|
+
"curvedConnector5"
|
|
3800
|
+
];
|
|
3801
|
+
/**
|
|
3802
|
+
* Every shape geometry name PptxGenJS can serialize without corrupting the
|
|
3803
|
+
* package: the OOXML preset geometries (`ST_ShapeType` — `SHAPE_TYPE` values
|
|
3804
|
+
* plus the unexposed connectors above) and `custGeom` (freeform paths, emitted
|
|
3805
|
+
* as `<a:custGeom>` rather than `<a:prstGeom>`). Used to reject bogus presets
|
|
3806
|
+
* before they become an invalid `<a:prstGeom prst="...">` that triggers
|
|
3807
|
+
* PowerPoint's "needs repair" dialog and drops the shape.
|
|
3808
|
+
*/
|
|
3809
|
+
const VALID_SHAPE_PRESETS = new Set([...Object.values(SHAPE_TYPE), ...EXTRA_SHAPE_PRESETS]);
|
|
3745
3810
|
let CHART_TYPE = /* @__PURE__ */ function(CHART_TYPE) {
|
|
3746
3811
|
CHART_TYPE["AREA"] = "area";
|
|
3747
3812
|
CHART_TYPE["BAR"] = "bar";
|
|
@@ -3910,27 +3975,20 @@ const IMG_PLAYBTN = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAB4AAAAVnCAYAA
|
|
|
3910
3975
|
* PptxGenJS: Utility Methods
|
|
3911
3976
|
*/
|
|
3912
3977
|
/**
|
|
3913
|
-
*
|
|
3914
|
-
* -
|
|
3915
|
-
*
|
|
3916
|
-
* -
|
|
3917
|
-
* -
|
|
3918
|
-
* @param {
|
|
3919
|
-
* @param {'X' | 'Y'} xyDir -
|
|
3920
|
-
* @param {PresLayout} layout - presentation layout
|
|
3921
|
-
* @returns {
|
|
3978
|
+
* Resolve a user `Coord` (x/y/w/h) to EMU — the single user-coordinate → EMU boundary.
|
|
3979
|
+
* - bare `number` → **inches** (no magnitude guessing); `"<n>%"` → percent of the slide axis;
|
|
3980
|
+
* `"<n>in"`/`"<n>pt"`/`"<n>emu"` → explicit units (see {@link Coord} / {@link coordToEmu})
|
|
3981
|
+
* - `null`/`undefined` → 0 (callers may omit a coordinate)
|
|
3982
|
+
* - throws on a non-finite number rather than silently collapsing the object to zero size
|
|
3983
|
+
* @param {Coord|null|undefined} size - user coordinate
|
|
3984
|
+
* @param {'X' | 'Y'} xyDir - axis (selects slide width vs height for percentages)
|
|
3985
|
+
* @param {PresLayout} layout - presentation layout (EMU dimensions)
|
|
3986
|
+
* @returns {Emu} resolved EMU value
|
|
3922
3987
|
*/
|
|
3923
3988
|
function getSmartParseNumber(size, xyDir, layout) {
|
|
3924
|
-
if (
|
|
3989
|
+
if (size === null || size === void 0) return 0;
|
|
3925
3990
|
if (typeof size === "number" && !isFinite(size)) throw new Error(`Invalid ${xyDir || "coordinate"} value: expected a finite number but received ${String(size)}. This usually means a layout dimension was read from a missing property (e.g. \`layout.width\` returning \`undefined\`). Use \`slide.width\`/\`slide.height\` or \`STANDARD_LAYOUTS.<NAME>.width\`/\`.height\` (inches).`);
|
|
3926
|
-
|
|
3927
|
-
if (typeof size === "number" && size >= 100) return size;
|
|
3928
|
-
if (typeof size === "string" && size.includes("%")) {
|
|
3929
|
-
if (xyDir && xyDir === "X") return Math.round(parseFloat(size) / 100 * layout.width);
|
|
3930
|
-
if (xyDir && xyDir === "Y") return Math.round(parseFloat(size) / 100 * layout.height);
|
|
3931
|
-
return Math.round(parseFloat(size) / 100 * layout.width);
|
|
3932
|
-
}
|
|
3933
|
-
return 0;
|
|
3991
|
+
return coordToEmu(size, xyDir === "Y" ? layout.height : layout.width);
|
|
3934
3992
|
}
|
|
3935
3993
|
/**
|
|
3936
3994
|
* Basic UUID Generator Adapted
|
|
@@ -4003,14 +4061,16 @@ function getDuplicateObjectNames(names) {
|
|
|
4003
4061
|
return Array.from(dupes);
|
|
4004
4062
|
}
|
|
4005
4063
|
/**
|
|
4006
|
-
* Convert inches into EMU
|
|
4007
|
-
*
|
|
4008
|
-
* @
|
|
4064
|
+
* Convert inches into EMU.
|
|
4065
|
+
* - accepts a number (inches) or a numeric/`"<n>in"` string
|
|
4066
|
+
* - no magnitude guessing: values are always treated as inches (use {@link coordToEmu} for
|
|
4067
|
+
* user coordinates that may carry other units)
|
|
4068
|
+
* @param {number|string} inches - inches as number or string
|
|
4069
|
+
* @returns {Emu} EMU value
|
|
4009
4070
|
*/
|
|
4010
4071
|
function inch2Emu(inches) {
|
|
4011
|
-
if (typeof inches === "number" && inches > 100) return inches;
|
|
4012
4072
|
if (typeof inches === "string") inches = Number(inches.replace(/in*/gi, ""));
|
|
4013
|
-
return
|
|
4073
|
+
return inchesToEmu(inches);
|
|
4014
4074
|
}
|
|
4015
4075
|
/**
|
|
4016
4076
|
* Convert `pt` into points (using `ONEPT`)
|
|
@@ -4022,6 +4082,33 @@ function valToPts(pt) {
|
|
|
4022
4082
|
return isNaN(points) ? 0 : Math.round(points * ONEPT);
|
|
4023
4083
|
}
|
|
4024
4084
|
/**
|
|
4085
|
+
* Convert a transparency percentage (0-100) into a schema-valid `<a:alpha>` value
|
|
4086
|
+
* (ST_PositiveFixedPercentage, 0-100000). Out-of-range transparency yields an
|
|
4087
|
+
* alpha that PowerPoint rejects as needing repair, so clamp into range and warn.
|
|
4088
|
+
*/
|
|
4089
|
+
function transparencyToAlpha(transparency) {
|
|
4090
|
+
const pct = Math.min(100, Math.max(0, transparency));
|
|
4091
|
+
if (pct !== transparency) console.warn(`Warning: transparency ${transparency} is outside the valid range 0-100; using ${pct}.`);
|
|
4092
|
+
return Math.round((100 - pct) * 1e3);
|
|
4093
|
+
}
|
|
4094
|
+
/** Convert an opacity (0-1) into a schema-valid `<a:alpha>` value (0-100000); clamps + warns on out-of-range input. */
|
|
4095
|
+
function opacityToAlpha(opacity) {
|
|
4096
|
+
const o = Math.min(1, Math.max(0, opacity));
|
|
4097
|
+
if (o !== opacity) console.warn(`Warning: opacity ${opacity} is outside the valid range 0-1; using ${o}.`);
|
|
4098
|
+
return Math.round(o * 1e5);
|
|
4099
|
+
}
|
|
4100
|
+
/**
|
|
4101
|
+
* Convert a line width (points) to EMU clamped into ST_LineWidth (0..20116800 EMU,
|
|
4102
|
+
* i.e. 0-1584pt). Out-of-range widths make PowerPoint report the package as needing
|
|
4103
|
+
* repair, so clamp into range and warn.
|
|
4104
|
+
*/
|
|
4105
|
+
function lineWidthToEmu(widthPts) {
|
|
4106
|
+
const raw = valToPts(widthPts);
|
|
4107
|
+
const clamped = Math.min(20116800, Math.max(0, raw));
|
|
4108
|
+
if (clamped !== raw) console.warn(`Warning: line width ${widthPts} is outside the valid range 0-1584pt; using ${clamped / ONEPT}.`);
|
|
4109
|
+
return clamped;
|
|
4110
|
+
}
|
|
4111
|
+
/**
|
|
4025
4112
|
* Convert degrees (0..360) to PowerPoint `rot` value
|
|
4026
4113
|
* @param {number} d degrees
|
|
4027
4114
|
* @returns {number} calculated `rot` value
|
|
@@ -4069,8 +4156,10 @@ function createColorElement(colorStr, innerElements) {
|
|
|
4069
4156
|
}
|
|
4070
4157
|
let colorVal = (colorStr || "").replace("#", "");
|
|
4071
4158
|
if (/^[0-9a-fA-F]{8}$/.test(colorVal)) {
|
|
4072
|
-
|
|
4073
|
-
|
|
4159
|
+
if (!innerElements?.includes("<a:alpha")) {
|
|
4160
|
+
const alphaHex = colorVal.slice(6, 8);
|
|
4161
|
+
innerElements = `<a:alpha val="${Math.round(parseInt(alphaHex, 16) / 255 * 1e5)}"/>${innerElements || ""}`;
|
|
4162
|
+
}
|
|
4074
4163
|
colorVal = colorVal.slice(0, 6);
|
|
4075
4164
|
}
|
|
4076
4165
|
if (!REGEX_HEX_COLOR.test(colorVal) && colorVal !== "bg1" && colorVal !== "bg2" && colorVal !== "tx1" && colorVal !== "tx2" && colorVal !== "accent1" && colorVal !== "accent2" && colorVal !== "accent3" && colorVal !== "accent4" && colorVal !== "accent5" && colorVal !== "accent6") {
|
|
@@ -4096,12 +4185,38 @@ function createGlowElement(options, defaults) {
|
|
|
4096
4185
|
};
|
|
4097
4186
|
const size = Math.round(opts.size * ONEPT);
|
|
4098
4187
|
const color = opts.color || "000000";
|
|
4099
|
-
const opacity =
|
|
4188
|
+
const opacity = opacityToAlpha(opts.opacity ?? 0);
|
|
4100
4189
|
strXml += `<a:glow rad="${size}">`;
|
|
4101
4190
|
strXml += createColorElement(color, `<a:alpha val="${opacity}"/>`);
|
|
4102
4191
|
strXml += "</a:glow>";
|
|
4103
4192
|
return strXml;
|
|
4104
4193
|
}
|
|
4194
|
+
/**
|
|
4195
|
+
* Creates an `a:outerShdw`/`a:innerShdw` element for a text run or shape.
|
|
4196
|
+
* Returns the shadow element only (no wrapping `a:effectLst`) so callers can
|
|
4197
|
+
* combine it with other effects (e.g. glow) inside a single `a:effectLst`.
|
|
4198
|
+
* @param {ShadowProps} options shadow properties
|
|
4199
|
+
* @param {ShadowProps} defaults defaults for unspecified properties in `options`
|
|
4200
|
+
* @see http://officeopenxml.com/drwSp-effects.php
|
|
4201
|
+
* @returns {string} XML string, or '' when type is 'none'
|
|
4202
|
+
*/
|
|
4203
|
+
function createShadowElement$1(options, defaults) {
|
|
4204
|
+
const opts = {
|
|
4205
|
+
...defaults,
|
|
4206
|
+
...options
|
|
4207
|
+
};
|
|
4208
|
+
if (opts.type === "none") return "";
|
|
4209
|
+
const type = opts.type || "outer";
|
|
4210
|
+
const blur = valToPts(opts.blur ?? 0);
|
|
4211
|
+
const offset = valToPts(opts.offset ?? 0);
|
|
4212
|
+
const angle = Math.round((opts.angle ?? 0) * 6e4);
|
|
4213
|
+
const opacity = Math.round((opts.opacity ?? .75) * 1e5);
|
|
4214
|
+
const color = opts.color || "000000";
|
|
4215
|
+
let strXml = `<a:${type}Shdw ${type === "outer" ? "sx=\"100000\" sy=\"100000\" kx=\"0\" ky=\"0\" algn=\"bl\" rotWithShape=\"0\" " : ""}blurRad="${blur}" dist="${offset}" dir="${angle}">`;
|
|
4216
|
+
strXml += createColorElement(color, `<a:alpha val="${opacity}"/>`);
|
|
4217
|
+
strXml += `</a:${type}Shdw>`;
|
|
4218
|
+
return strXml;
|
|
4219
|
+
}
|
|
4105
4220
|
function boolToXml(value) {
|
|
4106
4221
|
return value ? "1" : "0";
|
|
4107
4222
|
}
|
|
@@ -4112,8 +4227,8 @@ function normalizeGradientAngle(angle) {
|
|
|
4112
4227
|
}
|
|
4113
4228
|
function gradientStopColorAdjustments(stop) {
|
|
4114
4229
|
let internalElements = "";
|
|
4115
|
-
if (stop.alpha) internalElements += `<a:alpha val="${
|
|
4116
|
-
if (stop.transparency) internalElements += `<a:alpha val="${
|
|
4230
|
+
if (stop.alpha) internalElements += `<a:alpha val="${transparencyToAlpha(stop.alpha)}"/>`;
|
|
4231
|
+
if (stop.transparency) internalElements += `<a:alpha val="${transparencyToAlpha(stop.transparency)}"/>`;
|
|
4117
4232
|
return internalElements;
|
|
4118
4233
|
}
|
|
4119
4234
|
function normalizeGradientStops(stops) {
|
|
@@ -4163,6 +4278,17 @@ function genXmlPatternFill(pattern) {
|
|
|
4163
4278
|
* @param {Color | ShapeFillProps | ShapeLineProps} props fill props
|
|
4164
4279
|
* @returns XML string
|
|
4165
4280
|
*/
|
|
4281
|
+
/**
|
|
4282
|
+
* Map a friendly `LineCap` value to the OOXML `cap` attribute value (`flat`/`sq`/`rnd`).
|
|
4283
|
+
* @param {LineCap} [lineCap] - line cap style (defaults to `flat`)
|
|
4284
|
+
* @returns {string} value for the `cap` attribute on `<a:ln>`
|
|
4285
|
+
*/
|
|
4286
|
+
function createLineCap(lineCap) {
|
|
4287
|
+
if (!lineCap || lineCap === "flat") return "flat";
|
|
4288
|
+
else if (lineCap === "square") return "sq";
|
|
4289
|
+
else if (lineCap === "round") return "rnd";
|
|
4290
|
+
else throw new Error(`Invalid line cap: ${String(lineCap)}`);
|
|
4291
|
+
}
|
|
4166
4292
|
function genXmlColorSelection(props) {
|
|
4167
4293
|
let fillType = "solid";
|
|
4168
4294
|
let colorVal = "";
|
|
@@ -4173,8 +4299,8 @@ function genXmlColorSelection(props) {
|
|
|
4173
4299
|
else {
|
|
4174
4300
|
if (props.type) fillType = props.type;
|
|
4175
4301
|
if (props.color) colorVal = props.color;
|
|
4176
|
-
if (props.alpha) internalElements += `<a:alpha val="${
|
|
4177
|
-
if (props.transparency) internalElements += `<a:alpha val="${
|
|
4302
|
+
if (props.alpha) internalElements += `<a:alpha val="${transparencyToAlpha(props.alpha)}"/>`;
|
|
4303
|
+
if (props.transparency) internalElements += `<a:alpha val="${transparencyToAlpha(props.transparency)}"/>`;
|
|
4178
4304
|
}
|
|
4179
4305
|
switch (fillType) {
|
|
4180
4306
|
case "solid":
|
|
@@ -4768,6 +4894,28 @@ function getSlidesForTableRows(tableRows = [], tableProps = {}, presLayout, mast
|
|
|
4768
4894
|
return tableRowSlides;
|
|
4769
4895
|
}
|
|
4770
4896
|
/**
|
|
4897
|
+
* Convert a computed CSS border (width string + color string) from `getComputedStyle` into a
|
|
4898
|
+
* pptx `BorderProps`.
|
|
4899
|
+
*
|
|
4900
|
+
* Preserves *fractional* widths: a hairline CSS border such as `0.5px` must not be rounded to
|
|
4901
|
+
* `0pt` and silently vanish — the table serializer (`valToPts`) emits fractional points just
|
|
4902
|
+
* fine, so there is no reason to integer-round here (upstream gitbrent/PptxGenJS#1235). A
|
|
4903
|
+
* computed width of `0` (or a non-finite value) yields `{ type: 'none' }` so we never emit a
|
|
4904
|
+
* zero-width line.
|
|
4905
|
+
* @param {string} widthStr - computed `border-<side>-width`, e.g. `"0.5px"`
|
|
4906
|
+
* @param {string} colorStr - computed `border-<side>-color`, e.g. `"rgb(102, 102, 102)"`
|
|
4907
|
+
* @returns {BorderProps} border props for the cell side
|
|
4908
|
+
*/
|
|
4909
|
+
function htmlBorderToProps(widthStr, colorStr) {
|
|
4910
|
+
const pt = Number(String(widthStr).replace("px", ""));
|
|
4911
|
+
if (!isFinite(pt) || pt <= 0) return { type: "none" };
|
|
4912
|
+
const arrRGB = String(colorStr).replace(/\s+/gi, "").replace("rgba(", "").replace("rgb(", "").replace(")", "").split(",");
|
|
4913
|
+
return {
|
|
4914
|
+
pt,
|
|
4915
|
+
color: rgbToHex(Number(arrRGB[0]), Number(arrRGB[1]), Number(arrRGB[2]))
|
|
4916
|
+
};
|
|
4917
|
+
}
|
|
4918
|
+
/**
|
|
4771
4919
|
* Reproduces an HTML table as a PowerPoint table - including column widths, style, etc. - creates 1 or more slides as needed
|
|
4772
4920
|
* @param {TableToSlidesHost} pptx - pptxgenjs instance
|
|
4773
4921
|
* @param {string} tabEleId - HTMLElementID of the table
|
|
@@ -4915,12 +5063,8 @@ function genTableToSlides(pptx, tabEleId, options = {}, masterSlide) {
|
|
|
4915
5063
|
"bottom",
|
|
4916
5064
|
"left"
|
|
4917
5065
|
].forEach((val, idxb) => {
|
|
4918
|
-
const
|
|
4919
|
-
|
|
4920
|
-
cellBorder[idxb] = {
|
|
4921
|
-
pt: intBorderW,
|
|
4922
|
-
color: rgbToHex(Number(arrRGB[0]), Number(arrRGB[1]), Number(arrRGB[2]))
|
|
4923
|
-
};
|
|
5066
|
+
const style = window.getComputedStyle(cell);
|
|
5067
|
+
cellBorder[idxb] = htmlBorderToProps(style.getPropertyValue("border-" + val + "-width"), style.getPropertyValue("border-" + val + "-color"));
|
|
4924
5068
|
});
|
|
4925
5069
|
cellOpts.border = cellBorder;
|
|
4926
5070
|
}
|
|
@@ -4990,6 +5134,8 @@ function genTableToSlides(pptx, tabEleId, options = {}, masterSlide) {
|
|
|
4990
5134
|
*/
|
|
4991
5135
|
/** counter for included charts (used for index in their filenames) */
|
|
4992
5136
|
let _chartCounter = 0;
|
|
5137
|
+
/** DPI PowerPoint assumes when sizing an inserted raster image (natural pixels / 96 == inches) */
|
|
5138
|
+
const IMAGE_NATURAL_DPI = 96;
|
|
4993
5139
|
function normalizeBorderTuple(border) {
|
|
4994
5140
|
return Array.isArray(border) ? border : [
|
|
4995
5141
|
border,
|
|
@@ -5026,6 +5172,26 @@ function createSlideMaster(props, target) {
|
|
|
5026
5172
|
if (props.slideNumber && typeof props.slideNumber === "object") target._slideNumberProps = props.slideNumber;
|
|
5027
5173
|
}
|
|
5028
5174
|
/**
|
|
5175
|
+
* Round and clamp an integer chart percentage/angle option into a schema-valid range.
|
|
5176
|
+
*
|
|
5177
|
+
* Several chart attributes are bounded integer types whose out-of-range values make
|
|
5178
|
+
* PowerPoint report the package as needing repair: `<c:overlap>` (ST_Overlap, -100..100),
|
|
5179
|
+
* `<c:gapWidth>`/`<c:gapDepth>` (ST_GapAmount, 0..500), `<c:holeSize>` (ST_HoleSize, 10..90)
|
|
5180
|
+
* and `<c:firstSliceAng>` (ST_FirstSliceAng, 0..360). Missing/non-numeric input returns
|
|
5181
|
+
* `undefined` so the caller can apply its own default; an out-of-range value is clamped
|
|
5182
|
+
* and a warning is emitted (per the library's warn-rather-than-degrade policy).
|
|
5183
|
+
* @param value - caller-supplied option value
|
|
5184
|
+
* @param min - inclusive lower bound
|
|
5185
|
+
* @param max - inclusive upper bound
|
|
5186
|
+
* @param name - option name, for the warning message
|
|
5187
|
+
*/
|
|
5188
|
+
function clampChartPct(value, min, max, name) {
|
|
5189
|
+
if (typeof value !== "number" || isNaN(value)) return void 0;
|
|
5190
|
+
const clamped = Math.min(max, Math.max(min, Math.round(value)));
|
|
5191
|
+
if (clamped !== value) console.warn(`Warning: ${name} ${value} is outside the valid range ${min}-${max}; using ${clamped}.`);
|
|
5192
|
+
return clamped;
|
|
5193
|
+
}
|
|
5194
|
+
/**
|
|
5029
5195
|
* Generate the chart based on input data.
|
|
5030
5196
|
* OOXML Chart Spec: ISO/IEC 29500-1:2016(E)
|
|
5031
5197
|
*
|
|
@@ -5197,7 +5363,13 @@ function addChartDefinition(target, type, data, opt) {
|
|
|
5197
5363
|
"marker",
|
|
5198
5364
|
"filled"
|
|
5199
5365
|
].includes(options.radarStyle || "")) options.radarStyle = "standard";
|
|
5200
|
-
|
|
5366
|
+
{
|
|
5367
|
+
const rawSymbolSize = options.lineDataSymbolSize;
|
|
5368
|
+
const hasSymbolSize = rawSymbolSize != null && !isNaN(rawSymbolSize);
|
|
5369
|
+
const symbolSize = Math.min(72, Math.max(2, Math.round(hasSymbolSize ? rawSymbolSize : 6)));
|
|
5370
|
+
if (hasSymbolSize && symbolSize !== rawSymbolSize) console.warn(`Warning: lineDataSymbolSize ${rawSymbolSize} is outside the valid marker size range (integer 2-72); using ${symbolSize}.`);
|
|
5371
|
+
options.lineDataSymbolSize = symbolSize;
|
|
5372
|
+
}
|
|
5201
5373
|
options.lineDataSymbolLineSize = options.lineDataSymbolLineSize && !isNaN(options.lineDataSymbolLineSize) ? valToPts(options.lineDataSymbolLineSize) : valToPts(.75);
|
|
5202
5374
|
const chartLayout = options.layout;
|
|
5203
5375
|
if (chartLayout) [
|
|
@@ -5247,8 +5419,11 @@ function addChartDefinition(target, type, data, opt) {
|
|
|
5247
5419
|
options.v3DRotY = typeof options.v3DRotY === "number" && !isNaN(options.v3DRotY) && options.v3DRotY >= 0 && options.v3DRotY <= 360 ? options.v3DRotY : 30;
|
|
5248
5420
|
options.v3DRAngAx = options.v3DRAngAx || !options.v3DRAngAx ? options.v3DRAngAx : true;
|
|
5249
5421
|
options.v3DPerspective = typeof options.v3DPerspective === "number" && !isNaN(options.v3DPerspective) && options.v3DPerspective >= 0 && options.v3DPerspective <= 240 ? options.v3DPerspective : 30;
|
|
5250
|
-
options.barGapWidthPct =
|
|
5251
|
-
options.barGapDepthPct =
|
|
5422
|
+
options.barGapWidthPct = clampChartPct(options.barGapWidthPct, 0, 500, "barGapWidthPct") ?? 150;
|
|
5423
|
+
options.barGapDepthPct = clampChartPct(options.barGapDepthPct, 0, 500, "barGapDepthPct") ?? 150;
|
|
5424
|
+
options.barOverlapPct = clampChartPct(options.barOverlapPct, -100, 100, "barOverlapPct");
|
|
5425
|
+
options.holeSize = clampChartPct(options.holeSize, 10, 90, "holeSize");
|
|
5426
|
+
options.firstSliceAng = clampChartPct(options.firstSliceAng, 0, 360, "firstSliceAng");
|
|
5252
5427
|
options.chartColors = Array.isArray(options.chartColors) ? options.chartColors : options._type === "pie" || options._type === "doughnut" ? PIECHART_COLORS : BARCHART_COLORS;
|
|
5253
5428
|
options.chartColorsOpacity = options.chartColorsOpacity && !isNaN(options.chartColorsOpacity) ? options.chartColorsOpacity : void 0;
|
|
5254
5429
|
options.border = options.border && typeof options.border === "object" ? options.border : void 0;
|
|
@@ -5337,16 +5512,29 @@ function addImageDefinition(target, opt) {
|
|
|
5337
5512
|
else if (strImageData?.toLowerCase().includes("image/svg+xml")) strImgExtn = "svg";
|
|
5338
5513
|
newObject._type = "image";
|
|
5339
5514
|
newObject.image = strImagePath || "preencoded.png";
|
|
5515
|
+
let defWidth = intWidth;
|
|
5516
|
+
let defHeight = intHeight;
|
|
5517
|
+
if ((!intWidth || !intHeight) && strImageData && strImgExtn !== "svg") {
|
|
5518
|
+
const natural = getImageSizeFromBase64(strImageData);
|
|
5519
|
+
if (natural) {
|
|
5520
|
+
if (!intWidth && !intHeight) {
|
|
5521
|
+
defWidth = natural.w / IMAGE_NATURAL_DPI;
|
|
5522
|
+
defHeight = natural.h / IMAGE_NATURAL_DPI;
|
|
5523
|
+
} else if (typeof intWidth === "number" && intWidth && !intHeight) defHeight = intWidth * (natural.h / natural.w);
|
|
5524
|
+
else if (typeof intHeight === "number" && intHeight && !intWidth) defWidth = intHeight * (natural.w / natural.h);
|
|
5525
|
+
}
|
|
5526
|
+
}
|
|
5340
5527
|
const objectOptions = {
|
|
5341
5528
|
x: intPosX || 0,
|
|
5342
5529
|
y: intPosY || 0,
|
|
5343
|
-
w:
|
|
5344
|
-
h:
|
|
5530
|
+
w: defWidth || 1,
|
|
5531
|
+
h: defHeight || 1,
|
|
5345
5532
|
altText: opt.altText || "",
|
|
5346
5533
|
rounding: typeof opt.rounding === "boolean" ? opt.rounding : false,
|
|
5347
5534
|
shape: opt.shape,
|
|
5348
5535
|
points: opt.points,
|
|
5349
5536
|
rectRadius: opt.rectRadius,
|
|
5537
|
+
shapeAdjust: opt.shapeAdjust,
|
|
5350
5538
|
sizing,
|
|
5351
5539
|
placeholder: opt.placeholder,
|
|
5352
5540
|
rotate: opt.rotate || 0,
|
|
@@ -5355,6 +5543,7 @@ function addImageDefinition(target, opt) {
|
|
|
5355
5543
|
transparency: opt.transparency || 0,
|
|
5356
5544
|
duotone: opt.duotone,
|
|
5357
5545
|
objectName,
|
|
5546
|
+
objectLock: opt.objectLock,
|
|
5358
5547
|
shadow: correctShadowOptions(opt.shadow)
|
|
5359
5548
|
};
|
|
5360
5549
|
newObject.options = objectOptions;
|
|
@@ -5384,7 +5573,10 @@ function addImageDefinition(target, opt) {
|
|
|
5384
5573
|
});
|
|
5385
5574
|
newObject.imageRid = imageRelId + 1;
|
|
5386
5575
|
} else {
|
|
5387
|
-
const dupeItem = target._relsMedia.find((item) =>
|
|
5576
|
+
const dupeItem = target._relsMedia.find((item) => {
|
|
5577
|
+
if (item.isDuplicate || !item.Target || item.type !== "image/" + strImgExtn) return false;
|
|
5578
|
+
return strImagePath ? item.path === strImagePath : !!strImageData && item.data === strImageData;
|
|
5579
|
+
});
|
|
5388
5580
|
target._relsMedia.push({
|
|
5389
5581
|
path: strImagePath || "preencoded." + strImgExtn,
|
|
5390
5582
|
type: "image/" + strImgExtn,
|
|
@@ -5442,6 +5634,7 @@ function addMediaDefinition(target, opt) {
|
|
|
5442
5634
|
slideData.options.h = intSizeY;
|
|
5443
5635
|
slideData.options.objectName = objectName;
|
|
5444
5636
|
if (opt.altText) slideData.options.altText = opt.altText;
|
|
5637
|
+
if (opt.objectLock) slideData.options.objectLock = opt.objectLock;
|
|
5445
5638
|
/**
|
|
5446
5639
|
* NOTE:
|
|
5447
5640
|
* - rId starts at 2 (hence the intRels+1 below) as slideLayout.xml is rId=1!
|
|
@@ -5471,7 +5664,10 @@ function addMediaDefinition(target, opt) {
|
|
|
5471
5664
|
Target: `../media/image-${target._slideNum}-${target._relsMedia.length + 1}.png`
|
|
5472
5665
|
});
|
|
5473
5666
|
} else {
|
|
5474
|
-
const dupeItem = target._relsMedia.find((item) =>
|
|
5667
|
+
const dupeItem = target._relsMedia.find((item) => {
|
|
5668
|
+
if (item.isDuplicate || !item.Target || item.type !== strType + "/" + strExtn) return false;
|
|
5669
|
+
return strPath ? item.path === strPath : !!strData && item.data === strData;
|
|
5670
|
+
});
|
|
5475
5671
|
const relId1 = getNewRelId(target);
|
|
5476
5672
|
target._relsMedia.push({
|
|
5477
5673
|
path: strPath || "preencoded" + strExtn,
|
|
@@ -5536,12 +5732,14 @@ function addShapeDefinition(target, shapeName, opts) {
|
|
|
5536
5732
|
const options = typeof opts === "object" ? opts : {};
|
|
5537
5733
|
options.line = options.line || { type: "none" };
|
|
5538
5734
|
options.shadow = correctShadowOptions(options.shadow);
|
|
5735
|
+
const resolvedShapeName = typeof shapeName === "string" && SHAPE_NAME_ALIASES[shapeName] ? SHAPE_NAME_ALIASES[shapeName] : shapeName;
|
|
5539
5736
|
const newObject = {
|
|
5540
5737
|
_type: "text",
|
|
5541
|
-
shape:
|
|
5738
|
+
shape: resolvedShapeName || "rect",
|
|
5542
5739
|
options
|
|
5543
5740
|
};
|
|
5544
5741
|
if (!shapeName) throw new Error("Missing/Invalid shape parameter! Example: `addShape(pptxgen.shapes.LINE, {x:1, y:1, w:1, h:1});`");
|
|
5742
|
+
if (!VALID_SHAPE_PRESETS.has(resolvedShapeName)) throw new Error(`Invalid shape "${String(shapeName)}"! Use a value from \`pptxgen.shapes.*\` (e.g. \`pptxgen.shapes.RECTANGLE\`). PowerPoint can't render unknown preset geometries and will drop the shape during repair.`);
|
|
5545
5743
|
const newLineOpts = {
|
|
5546
5744
|
type: options.line.type || "solid",
|
|
5547
5745
|
color: options.line.color || "333333",
|
|
@@ -5638,9 +5836,8 @@ function addTableDefinition(target, tableRows, options, slideLayout, presLayout,
|
|
|
5638
5836
|
}
|
|
5639
5837
|
arrRows.push(newRow);
|
|
5640
5838
|
});
|
|
5641
|
-
|
|
5642
|
-
|
|
5643
|
-
if (opt.h) opt.h = getSmartParseNumber(opt.h, "Y", presLayout);
|
|
5839
|
+
if (opt.x === void 0 || opt.x === null) opt.x = .5;
|
|
5840
|
+
if (opt.y === void 0 || opt.y === null) opt.y = .5;
|
|
5644
5841
|
opt.fontSize = opt.fontSize || 12;
|
|
5645
5842
|
opt.margin = opt.margin === 0 || opt.margin ? opt.margin : DEF_CELL_MARGIN_IN;
|
|
5646
5843
|
if (typeof opt.margin === "number") opt.margin = [
|
|
@@ -5709,12 +5906,7 @@ function addTableDefinition(target, tableRows, options, slideLayout, presLayout,
|
|
|
5709
5906
|
console.warn("addTable: mismatch: (colW.length != data.length) Therefore, defaulting to evenly distributed col widths.");
|
|
5710
5907
|
opt.colW = void 0;
|
|
5711
5908
|
}
|
|
5712
|
-
} else if (opt.w) opt.w =
|
|
5713
|
-
else opt.w = Math.floor((presLayout._sizeW || presLayout.width) / EMU - arrTableMargin[1] - arrTableMargin[3]);
|
|
5714
|
-
if (opt.x && opt.x < 20) opt.x = inch2Emu(opt.x);
|
|
5715
|
-
if (opt.y && opt.y < 20) opt.y = inch2Emu(opt.y);
|
|
5716
|
-
if (opt.w && typeof opt.w === "number" && opt.w < 20) opt.w = inch2Emu(opt.w);
|
|
5717
|
-
if (opt.h && typeof opt.h === "number" && opt.h < 20) opt.h = inch2Emu(opt.h);
|
|
5909
|
+
} else if (opt.w) {} else opt.w = Math.floor((presLayout._sizeW || presLayout.width) / EMU - arrTableMargin[1] - arrTableMargin[3]);
|
|
5718
5910
|
arrRows.forEach((row) => {
|
|
5719
5911
|
row.forEach((cell, idy) => {
|
|
5720
5912
|
if (typeof cell === "number" || typeof cell === "string") row[idy] = {
|
|
@@ -5742,7 +5934,7 @@ function addTableDefinition(target, tableRows, options, slideLayout, presLayout,
|
|
|
5742
5934
|
if (opt.autoPageRepeatHeader) opt._arrObjTabHeadRows = arrRows.filter((_row, idx) => idx < (opt.autoPageHeaderRows || 1));
|
|
5743
5935
|
getSlidesForTableRows(arrRows, opt, presLayout, slideLayout).forEach((slide, idx) => {
|
|
5744
5936
|
if (!getSlide(target._slideNum + idx)) slides.push(addSlide({ masterName: slideLayout?._name || void 0 }));
|
|
5745
|
-
if (idx > 0) opt.y =
|
|
5937
|
+
if (idx > 0) opt.y = opt.autoPageSlideStartY || opt.newSlideStartY || arrTableMargin[0];
|
|
5746
5938
|
{
|
|
5747
5939
|
const newSlide = getSlide(target._slideNum + idx);
|
|
5748
5940
|
opt.autoPage = false;
|
|
@@ -5814,6 +6006,10 @@ function addTextDefinition(target, text, opts, isPlaceholder) {
|
|
|
5814
6006
|
itemOpts._bodyProp.anchor = !itemOpts.placeholder ? "ctr" : void 0;
|
|
5815
6007
|
itemOpts._bodyProp.vert = itemOpts.vert;
|
|
5816
6008
|
itemOpts._bodyProp.wrap = typeof itemOpts.wrap === "boolean" ? itemOpts.wrap : true;
|
|
6009
|
+
if (itemOpts.columns !== void 0) if (typeof itemOpts.columns !== "number" || isNaN(itemOpts.columns) || itemOpts.columns < 1 || itemOpts.columns > 16) console.warn("Warning: text `columns` must be a number 1-16 (ignoring value)");
|
|
6010
|
+
else itemOpts._bodyProp.numCol = Math.round(itemOpts.columns);
|
|
6011
|
+
if (itemOpts.columnSpacing !== void 0) if (typeof itemOpts.columnSpacing !== "number" || isNaN(itemOpts.columnSpacing) || itemOpts.columnSpacing < 0) console.warn("Warning: text `columnSpacing` must be a number >= 0 (ignoring value)");
|
|
6012
|
+
else itemOpts._bodyProp.spcCol = valToPts(itemOpts.columnSpacing);
|
|
5817
6013
|
if (itemOpts.inset && !isNaN(Number(itemOpts.inset)) || itemOpts.inset === 0) {
|
|
5818
6014
|
itemOpts._bodyProp.lIns = inch2Emu(itemOpts.inset);
|
|
5819
6015
|
itemOpts._bodyProp.rIns = inch2Emu(itemOpts.inset);
|
|
@@ -6323,6 +6519,22 @@ async function createExcelWorksheet(chartObject, zip) {
|
|
|
6323
6519
|
});
|
|
6324
6520
|
}
|
|
6325
6521
|
/**
|
|
6522
|
+
* Emit the `<a:latin>/<a:ea>/<a:cs>` font trio for a chart text run.
|
|
6523
|
+
*
|
|
6524
|
+
* In DrawingML run properties a typeface applies only to the script class of
|
|
6525
|
+
* its element: `<a:latin>` covers Latin/ASCII, `<a:ea>` covers East Asian, and
|
|
6526
|
+
* `<a:cs>` covers complex scripts. Emitting `<a:latin>` alone leaves East Asian
|
|
6527
|
+
* (e.g. Chinese) and complex-script glyphs falling back to the theme font, so a
|
|
6528
|
+
* user-specified font never takes effect for that text — most visibly on
|
|
6529
|
+
* PowerPoint for Mac. Stamping the same typeface onto all three classes is what
|
|
6530
|
+
* choosing a font in PowerPoint's UI does (upstream gitbrent/PptxGenJS#1420).
|
|
6531
|
+
* @param {string} typeface - font face name
|
|
6532
|
+
* @return {string} `<a:latin/><a:ea/><a:cs/>` XML
|
|
6533
|
+
*/
|
|
6534
|
+
function createChartTextFonts(typeface) {
|
|
6535
|
+
return `<a:latin typeface="${typeface}"/><a:ea typeface="${typeface}"/><a:cs typeface="${typeface}"/>`;
|
|
6536
|
+
}
|
|
6537
|
+
/**
|
|
6326
6538
|
* Main entry point method for create charts
|
|
6327
6539
|
* @see: http://www.datypic.com/sc/ooxml/s-dml-chart.xsd.html
|
|
6328
6540
|
* @param {ISlideRelChart} rel - chart object
|
|
@@ -6332,6 +6544,10 @@ function makeXmlCharts(rel) {
|
|
|
6332
6544
|
let strXml = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>";
|
|
6333
6545
|
let usesSecondaryValAxis = false;
|
|
6334
6546
|
let usesSecondaryCatAxis = false;
|
|
6547
|
+
let primaryCatAxisValType = null;
|
|
6548
|
+
let secondaryCatAxisValType = null;
|
|
6549
|
+
let primaryCatAxisHasCategoryChart = false;
|
|
6550
|
+
let secondaryCatAxisHasCategoryChart = false;
|
|
6335
6551
|
strXml += "<c:chartSpace xmlns:c=\"http://schemas.openxmlformats.org/drawingml/2006/chart\" xmlns:a=\"http://schemas.openxmlformats.org/drawingml/2006/main\" xmlns:r=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships\">";
|
|
6336
6552
|
strXml += "<c:date1904 val=\"0\"/>";
|
|
6337
6553
|
strXml += `<c:roundedCorners val="${rel.opts.chartArea.roundedCorners ? "1" : "0"}"/>`;
|
|
@@ -6344,6 +6560,8 @@ function makeXmlCharts(rel) {
|
|
|
6344
6560
|
fontSize: rel.opts.titleFontSize || 18,
|
|
6345
6561
|
titleAlign: rel.opts.titleAlign,
|
|
6346
6562
|
titleBold: rel.opts.titleBold,
|
|
6563
|
+
titleItalic: rel.opts.titleItalic,
|
|
6564
|
+
titleUnderline: rel.opts.titleUnderline,
|
|
6347
6565
|
titlePos: rel.opts.titlePos,
|
|
6348
6566
|
titleRotate: rel.opts.titleRotate
|
|
6349
6567
|
}, rel.opts.x, rel.opts.y);
|
|
@@ -6376,18 +6594,37 @@ function makeXmlCharts(rel) {
|
|
|
6376
6594
|
const catAxisId = options.secondaryCatAxis ? AXIS_ID_CATEGORY_SECONDARY : AXIS_ID_CATEGORY_PRIMARY;
|
|
6377
6595
|
usesSecondaryValAxis = usesSecondaryValAxis || options.secondaryValAxis;
|
|
6378
6596
|
usesSecondaryCatAxis = usesSecondaryCatAxis || options.secondaryCatAxis;
|
|
6597
|
+
const usesValueXAxis = type.type === "scatter" || type.type === "bubble" || type.type === "bubble3D";
|
|
6598
|
+
if (options.secondaryCatAxis) if (usesValueXAxis) secondaryCatAxisValType = type.type;
|
|
6599
|
+
else secondaryCatAxisHasCategoryChart = true;
|
|
6600
|
+
else if (usesValueXAxis) primaryCatAxisValType = type.type;
|
|
6601
|
+
else primaryCatAxisHasCategoryChart = true;
|
|
6379
6602
|
strXml += makeChartType(type.type, type.data, options, valAxisId, catAxisId);
|
|
6380
6603
|
});
|
|
6381
6604
|
else strXml += makeChartType(rel.opts._type, rel.data, rel.opts, AXIS_ID_VALUE_PRIMARY, AXIS_ID_CATEGORY_PRIMARY);
|
|
6382
6605
|
if (rel.opts._type !== "pie" && rel.opts._type !== "doughnut") {
|
|
6383
6606
|
if (rel.opts.valAxes && rel.opts.valAxes.length > 1 && !usesSecondaryValAxis) throw new Error("Secondary axis must be used by one of the multiple charts");
|
|
6607
|
+
const comboCatAxisType = (isSecondary) => {
|
|
6608
|
+
const valType = isSecondary ? secondaryCatAxisValType : primaryCatAxisValType;
|
|
6609
|
+
const hasCategoryChart = isSecondary ? secondaryCatAxisHasCategoryChart : primaryCatAxisHasCategoryChart;
|
|
6610
|
+
if (!valType) return {};
|
|
6611
|
+
if (hasCategoryChart) {
|
|
6612
|
+
console.warn(`A category-based chart and a scatter/bubble chart cannot share the same ${isSecondary ? "secondary" : "primary"} category axis; emitting a category axis. Put the scatter/bubble series on a separate axis.`);
|
|
6613
|
+
return {};
|
|
6614
|
+
}
|
|
6615
|
+
return { _type: valType };
|
|
6616
|
+
};
|
|
6384
6617
|
if (rel.opts.catAxes) {
|
|
6385
6618
|
if (!rel.opts.valAxes || rel.opts.valAxes.length !== rel.opts.catAxes.length) throw new Error("There must be the same number of value and category axes.");
|
|
6386
6619
|
strXml += makeCatAxis({
|
|
6387
6620
|
...rel.opts,
|
|
6388
|
-
...rel.opts.catAxes[0]
|
|
6621
|
+
...rel.opts.catAxes[0],
|
|
6622
|
+
...comboCatAxisType(false)
|
|
6389
6623
|
}, AXIS_ID_CATEGORY_PRIMARY, AXIS_ID_VALUE_PRIMARY);
|
|
6390
|
-
} else strXml += makeCatAxis(
|
|
6624
|
+
} else strXml += makeCatAxis({
|
|
6625
|
+
...rel.opts,
|
|
6626
|
+
...comboCatAxisType(false)
|
|
6627
|
+
}, AXIS_ID_CATEGORY_PRIMARY, AXIS_ID_VALUE_PRIMARY);
|
|
6391
6628
|
if (rel.opts.valAxes) {
|
|
6392
6629
|
strXml += makeValAxis({
|
|
6393
6630
|
...rel.opts,
|
|
@@ -6404,9 +6641,13 @@ function makeXmlCharts(rel) {
|
|
|
6404
6641
|
}
|
|
6405
6642
|
if (rel.opts?.catAxes && rel.opts?.catAxes[1]) strXml += makeCatAxis({
|
|
6406
6643
|
...rel.opts,
|
|
6407
|
-
...rel.opts.catAxes[1]
|
|
6644
|
+
...rel.opts.catAxes[1],
|
|
6645
|
+
...comboCatAxisType(true)
|
|
6646
|
+
}, AXIS_ID_CATEGORY_SECONDARY, AXIS_ID_VALUE_SECONDARY);
|
|
6647
|
+
else if (usesSecondaryCatAxis && (!rel.opts.catAxes || !rel.opts.catAxes[1])) strXml += makeCatAxis({
|
|
6648
|
+
...rel.opts,
|
|
6649
|
+
...comboCatAxisType(true)
|
|
6408
6650
|
}, AXIS_ID_CATEGORY_SECONDARY, AXIS_ID_VALUE_SECONDARY);
|
|
6409
|
-
else if (usesSecondaryCatAxis && (!rel.opts.catAxes || !rel.opts.catAxes[1])) strXml += makeCatAxis(rel.opts, AXIS_ID_CATEGORY_SECONDARY, AXIS_ID_VALUE_SECONDARY);
|
|
6410
6651
|
}
|
|
6411
6652
|
if (rel.opts.showDataTable) {
|
|
6412
6653
|
strXml += "<c:dTable>";
|
|
@@ -6461,8 +6702,7 @@ function makeXmlCharts(rel) {
|
|
|
6461
6702
|
strXml += " <a:pPr>";
|
|
6462
6703
|
strXml += rel.opts.legendFontSize ? `<a:defRPr sz="${Math.round(Number(rel.opts.legendFontSize) * 100)}">` : "<a:defRPr>";
|
|
6463
6704
|
if (rel.opts.legendColor) strXml += genXmlColorSelection(rel.opts.legendColor);
|
|
6464
|
-
if (rel.opts.legendFontFace) strXml +=
|
|
6465
|
-
if (rel.opts.legendFontFace) strXml += "<a:cs typeface=\"" + rel.opts.legendFontFace + "\"/>";
|
|
6705
|
+
if (rel.opts.legendFontFace) strXml += createChartTextFonts(rel.opts.legendFontFace);
|
|
6466
6706
|
strXml += " </a:defRPr>";
|
|
6467
6707
|
strXml += " </a:pPr>";
|
|
6468
6708
|
strXml += " <a:endParaRPr lang=\"en-US\"/>";
|
|
@@ -6500,6 +6740,7 @@ function makeChartType(chartType, data, opts, valAxisId, catAxisId) {
|
|
|
6500
6740
|
let idxColLtr = 1;
|
|
6501
6741
|
let optsChartData;
|
|
6502
6742
|
let strXml = "";
|
|
6743
|
+
const valFmtCode = encodeXmlEntities(opts.valLabelFormatCode || opts.dataTableFormatCode || opts.dataLabelFormatCode || "General");
|
|
6503
6744
|
switch (chartType) {
|
|
6504
6745
|
case "area":
|
|
6505
6746
|
case "bar":
|
|
@@ -6543,7 +6784,7 @@ function makeChartType(chartType, data, opts, valAxisId, catAxisId) {
|
|
|
6543
6784
|
} else if (opts.dataBorder) strXml += `<a:ln w="${valToPts(opts.dataBorder.pt)}" cap="${createLineCap(opts.lineCap)}"><a:solidFill>${createColorElement(opts.dataBorder.color)}</a:solidFill><a:prstDash val="solid"/><a:round/></a:ln>`;
|
|
6544
6785
|
strXml += createShadowElement(opts.shadow, DEF_SHAPE_SHADOW);
|
|
6545
6786
|
strXml += " </c:spPr>";
|
|
6546
|
-
if (chartType
|
|
6787
|
+
if (chartType === "bar" || chartType === "bar3D") strXml += " <c:invertIfNegative val=\"0\"/>";
|
|
6547
6788
|
if (chartType === "line" || chartType === "radar") {
|
|
6548
6789
|
strXml += "<c:marker>";
|
|
6549
6790
|
strXml += " <c:symbol val=\"" + opts.lineDataSymbol + "\"/>";
|
|
@@ -6558,6 +6799,10 @@ function makeChartType(chartType, data, opts, valAxisId, catAxisId) {
|
|
|
6558
6799
|
strXml += " </c:spPr>";
|
|
6559
6800
|
strXml += "</c:marker>";
|
|
6560
6801
|
}
|
|
6802
|
+
{
|
|
6803
|
+
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;
|
|
6804
|
+
strXml += makeSeriesDataPointsXml(chartType, obj, opts, barVaryColors);
|
|
6805
|
+
}
|
|
6561
6806
|
if (chartType !== "radar") {
|
|
6562
6807
|
const lblColor = seriesOverride?.dataLabelColor ?? opts.dataLabelColor ?? "000000";
|
|
6563
6808
|
const lblBold = seriesOverride?.dataLabelFontBold ?? opts.dataLabelFontBold ?? false;
|
|
@@ -6565,12 +6810,15 @@ function makeChartType(chartType, data, opts, valAxisId, catAxisId) {
|
|
|
6565
6810
|
const lblSize = seriesOverride?.dataLabelFontSize ?? opts.dataLabelFontSize ?? 12;
|
|
6566
6811
|
const lblFace = seriesOverride?.dataLabelFontFace ?? opts.dataLabelFontFace ?? "Arial";
|
|
6567
6812
|
strXml += "<c:dLbls>";
|
|
6813
|
+
if (obj.customLabels?.length) obj.customLabels.forEach((lbl, idx) => {
|
|
6814
|
+
if (lbl) strXml += makeCustomDLblXml(idx, lbl, opts);
|
|
6815
|
+
});
|
|
6568
6816
|
strXml += `<c:numFmt formatCode="${encodeXmlEntities(opts.dataLabelFormatCode) || "General"}" sourceLinked="0"/>`;
|
|
6569
6817
|
if (opts.dataLabelBkgrdColors) strXml += `<c:spPr><a:solidFill>${createColorElement(seriesColor)}</a:solidFill></c:spPr>`;
|
|
6570
6818
|
strXml += "<c:txPr><a:bodyPr/><a:lstStyle/><a:p><a:pPr>";
|
|
6571
6819
|
strXml += `<a:defRPr b="${lblBold ? 1 : 0}" i="${lblItalic ? 1 : 0}" strike="noStrike" sz="${Math.round(lblSize * 100)}" u="none">`;
|
|
6572
6820
|
strXml += `<a:solidFill>${createColorElement(lblColor)}</a:solidFill>`;
|
|
6573
|
-
strXml +=
|
|
6821
|
+
strXml += createChartTextFonts(lblFace);
|
|
6574
6822
|
strXml += "</a:defRPr></a:pPr></a:p></c:txPr>";
|
|
6575
6823
|
if (opts.dataLabelPosition) strXml += `<c:dLblPos val="${opts.dataLabelPosition}"/>`;
|
|
6576
6824
|
strXml += "<c:showLegendKey val=\"0\"/>";
|
|
@@ -6579,29 +6827,6 @@ function makeChartType(chartType, data, opts, valAxisId, catAxisId) {
|
|
|
6579
6827
|
strXml += `<c:showLeaderLines val="${opts.showLeaderLines ? "1" : "0"}"/>`;
|
|
6580
6828
|
strXml += "</c:dLbls>";
|
|
6581
6829
|
}
|
|
6582
|
-
if ((chartType === "bar" || chartType === "bar3D") && data.length === 1 && (opts.chartColors && opts.chartColors !== BARCHART_COLORS && opts.chartColors.length > 1 || opts.invertedColors?.length)) obj.values.forEach((value, index) => {
|
|
6583
|
-
const arrColors = value < 0 ? opts.invertedColors || opts.chartColors || BARCHART_COLORS : opts.chartColors || [];
|
|
6584
|
-
strXml += " <c:dPt>";
|
|
6585
|
-
strXml += ` <c:idx val="${index}"/>`;
|
|
6586
|
-
strXml += " <c:invertIfNegative val=\"0\"/>";
|
|
6587
|
-
strXml += " <c:bubble3D val=\"0\"/>";
|
|
6588
|
-
strXml += " <c:spPr>";
|
|
6589
|
-
if (opts.lineSize === 0) strXml += "<a:ln><a:noFill/></a:ln>";
|
|
6590
|
-
else if (chartType === "bar") {
|
|
6591
|
-
strXml += "<a:solidFill>";
|
|
6592
|
-
strXml += " <a:srgbClr val=\"" + arrColors[index % arrColors.length] + "\"/>";
|
|
6593
|
-
strXml += "</a:solidFill>";
|
|
6594
|
-
} else {
|
|
6595
|
-
strXml += "<a:ln>";
|
|
6596
|
-
strXml += " <a:solidFill>";
|
|
6597
|
-
strXml += " <a:srgbClr val=\"" + arrColors[index % arrColors.length] + "\"/>";
|
|
6598
|
-
strXml += " </a:solidFill>";
|
|
6599
|
-
strXml += "</a:ln>";
|
|
6600
|
-
}
|
|
6601
|
-
strXml += createShadowElement(opts.shadow, DEF_SHAPE_SHADOW);
|
|
6602
|
-
strXml += " </c:spPr>";
|
|
6603
|
-
strXml += " </c:dPt>";
|
|
6604
|
-
});
|
|
6605
6830
|
strXml += "<c:cat>";
|
|
6606
6831
|
if (opts.catLabelFormatCode) {
|
|
6607
6832
|
strXml += " <c:numRef>";
|
|
@@ -6638,10 +6863,10 @@ function makeChartType(chartType, data, opts, valAxisId, catAxisId) {
|
|
|
6638
6863
|
strXml += " <c:numRef>";
|
|
6639
6864
|
strXml += `<c:f>Sheet1!$${getExcelColName(obj._dataIndex + obj.labels.length + 1)}$2:$${getExcelColName(obj._dataIndex + obj.labels.length + 1)}$${obj.labels[0].length + 1}</c:f>`;
|
|
6640
6865
|
strXml += " <c:numCache>";
|
|
6641
|
-
strXml += " <c:formatCode>" +
|
|
6866
|
+
strXml += " <c:formatCode>" + valFmtCode + "</c:formatCode>";
|
|
6642
6867
|
strXml += ` <c:ptCount val="${obj.labels[0].length}"/>`;
|
|
6643
6868
|
obj.values.forEach((value, idx) => {
|
|
6644
|
-
|
|
6869
|
+
strXml += numCachePt(idx, value);
|
|
6645
6870
|
});
|
|
6646
6871
|
strXml += " </c:numCache>";
|
|
6647
6872
|
strXml += " </c:numRef>";
|
|
@@ -6657,7 +6882,7 @@ function makeChartType(chartType, data, opts, valAxisId, catAxisId) {
|
|
|
6657
6882
|
strXml += " <a:p><a:pPr>";
|
|
6658
6883
|
strXml += ` <a:defRPr b="${opts.dataLabelFontBold ? 1 : 0}" i="${opts.dataLabelFontItalic ? 1 : 0}" strike="noStrike" sz="${Math.round((opts.dataLabelFontSize || 12) * 100)}" u="none">`;
|
|
6659
6884
|
strXml += " <a:solidFill>" + createColorElement(opts.dataLabelColor || "000000") + "</a:solidFill>";
|
|
6660
|
-
strXml += "
|
|
6885
|
+
strXml += " " + createChartTextFonts(opts.dataLabelFontFace || "Arial");
|
|
6661
6886
|
strXml += " </a:defRPr>";
|
|
6662
6887
|
strXml += " </a:pPr></a:p>";
|
|
6663
6888
|
strXml += " </c:txPr>";
|
|
@@ -6673,6 +6898,7 @@ function makeChartType(chartType, data, opts, valAxisId, catAxisId) {
|
|
|
6673
6898
|
if (chartType === "bar") {
|
|
6674
6899
|
strXml += ` <c:gapWidth val="${opts.barGapWidthPct}"/>`;
|
|
6675
6900
|
strXml += ` <c:overlap val="${opts.barOverlapPct != null ? opts.barOverlapPct : (opts.barGrouping || "").includes("tacked") ? 100 : 0}"/>`;
|
|
6901
|
+
strXml += createSerLinesElement(opts.barSeriesLine);
|
|
6676
6902
|
} else if (chartType === "bar3D") {
|
|
6677
6903
|
strXml += ` <c:gapWidth val="${opts.barGapWidthPct}"/>`;
|
|
6678
6904
|
strXml += ` <c:gapDepth val="${opts.barGapDepthPct}"/>`;
|
|
@@ -6724,6 +6950,10 @@ function makeChartType(chartType, data, opts, valAxisId, catAxisId) {
|
|
|
6724
6950
|
strXml += "<a:effectLst/>";
|
|
6725
6951
|
strXml += "</c:spPr>";
|
|
6726
6952
|
strXml += "</c:marker>";
|
|
6953
|
+
{
|
|
6954
|
+
const scatterVaryColors = data.length === 1 && opts.chartColors !== BARCHART_COLORS ? opts.chartColors || BARCHART_COLORS : null;
|
|
6955
|
+
strXml += makeSeriesDataPointsXml(chartType, obj, opts, scatterVaryColors);
|
|
6956
|
+
}
|
|
6727
6957
|
if (opts.showLabel) {
|
|
6728
6958
|
const chartUuid = getUuid("-xxxx-xxxx-xxxx-xxxxxxxxxxxx");
|
|
6729
6959
|
if (obj.labels[0] && (opts.dataLabelFormatScatter === "custom" || opts.dataLabelFormatScatter === "customXY")) {
|
|
@@ -6742,13 +6972,13 @@ function makeChartType(chartType, data, opts, valAxisId, catAxisId) {
|
|
|
6742
6972
|
strXml += " <a:pPr>";
|
|
6743
6973
|
strXml += ` <a:defRPr sz="${Math.round((opts.dataLabelFontSize || 12) * 100)}" b="${opts.dataLabelFontBold ? "1" : "0"}" i="${opts.dataLabelFontItalic ? "1" : "0"}" u="none" strike="noStrike">`;
|
|
6744
6974
|
strXml += " <a:solidFill>" + createColorElement(opts.dataLabelColor || "000000") + "</a:solidFill>";
|
|
6745
|
-
strXml +=
|
|
6975
|
+
strXml += " " + createChartTextFonts(opts.dataLabelFontFace || "Arial");
|
|
6746
6976
|
strXml += " </a:defRPr>";
|
|
6747
6977
|
strXml += " </a:pPr>";
|
|
6748
6978
|
strXml += " <a:r>";
|
|
6749
6979
|
strXml += ` <a:rPr lang="${opts.lang || "en-US"}" sz="${Math.round((opts.dataLabelFontSize || 12) * 100)}" b="${opts.dataLabelFontBold ? "1" : "0"}" i="${opts.dataLabelFontItalic ? "1" : "0"}" u="none" strike="noStrike" dirty="0">`;
|
|
6750
6980
|
strXml += " <a:solidFill>" + createColorElement(opts.dataLabelColor || "000000") + "</a:solidFill>";
|
|
6751
|
-
strXml +=
|
|
6981
|
+
strXml += " " + createChartTextFonts(opts.dataLabelFontFace || "Arial");
|
|
6752
6982
|
strXml += " </a:rPr>";
|
|
6753
6983
|
strXml += " <a:t>" + encodeXmlEntities(label) + "</a:t>";
|
|
6754
6984
|
strXml += " </a:r>";
|
|
@@ -6828,7 +7058,7 @@ function makeChartType(chartType, data, opts, valAxisId, catAxisId) {
|
|
|
6828
7058
|
strXml += " <a:pPr>";
|
|
6829
7059
|
strXml += ` <a:defRPr sz="${Math.round((opts.dataLabelFontSize || 12) * 100)}" b="${opts.dataLabelFontBold ? "1" : "0"}" i="${opts.dataLabelFontItalic ? "1" : "0"}" u="none" strike="noStrike">`;
|
|
6830
7060
|
strXml += " <a:solidFill>" + createColorElement(opts.dataLabelColor || "000000") + "</a:solidFill>";
|
|
6831
|
-
strXml +=
|
|
7061
|
+
strXml += " " + createChartTextFonts(opts.dataLabelFontFace || "Arial");
|
|
6832
7062
|
strXml += " </a:defRPr>";
|
|
6833
7063
|
strXml += " </a:pPr>";
|
|
6834
7064
|
strXml += ` <a:endParaRPr lang="${opts.lang || "en-US"}"/>`;
|
|
@@ -6849,31 +7079,14 @@ function makeChartType(chartType, data, opts, valAxisId, catAxisId) {
|
|
|
6849
7079
|
strXml += "</c:dLbls>";
|
|
6850
7080
|
}
|
|
6851
7081
|
}
|
|
6852
|
-
if (data.length === 1 && opts.chartColors !== BARCHART_COLORS) obj.values.forEach((value, index) => {
|
|
6853
|
-
const arrColors = value < 0 ? opts.invertedColors || opts.chartColors || BARCHART_COLORS : opts.chartColors || [];
|
|
6854
|
-
strXml += " <c:dPt>";
|
|
6855
|
-
strXml += ` <c:idx val="${index}"/>`;
|
|
6856
|
-
strXml += " <c:invertIfNegative val=\"0\"/>";
|
|
6857
|
-
strXml += " <c:bubble3D val=\"0\"/>";
|
|
6858
|
-
strXml += " <c:spPr>";
|
|
6859
|
-
if (opts.lineSize === 0) strXml += "<a:ln><a:noFill/></a:ln>";
|
|
6860
|
-
else {
|
|
6861
|
-
strXml += "<a:solidFill>";
|
|
6862
|
-
strXml += " <a:srgbClr val=\"" + arrColors[index % arrColors.length] + "\"/>";
|
|
6863
|
-
strXml += "</a:solidFill>";
|
|
6864
|
-
}
|
|
6865
|
-
strXml += createShadowElement(opts.shadow, DEF_SHAPE_SHADOW);
|
|
6866
|
-
strXml += " </c:spPr>";
|
|
6867
|
-
strXml += " </c:dPt>";
|
|
6868
|
-
});
|
|
6869
7082
|
strXml += "<c:xVal>";
|
|
6870
7083
|
strXml += " <c:numRef>";
|
|
6871
7084
|
strXml += ` <c:f>Sheet1!$A$2:$A$${data[0].values.length + 1}</c:f>`;
|
|
6872
7085
|
strXml += " <c:numCache>";
|
|
6873
|
-
strXml += " <c:formatCode>
|
|
7086
|
+
strXml += " <c:formatCode>" + valFmtCode + "</c:formatCode>";
|
|
6874
7087
|
strXml += ` <c:ptCount val="${data[0].values.length}"/>`;
|
|
6875
7088
|
data[0].values.forEach((value, idx) => {
|
|
6876
|
-
|
|
7089
|
+
strXml += numCachePt(idx, value);
|
|
6877
7090
|
});
|
|
6878
7091
|
strXml += " </c:numCache>";
|
|
6879
7092
|
strXml += " </c:numRef>";
|
|
@@ -6882,10 +7095,10 @@ function makeChartType(chartType, data, opts, valAxisId, catAxisId) {
|
|
|
6882
7095
|
strXml += " <c:numRef>";
|
|
6883
7096
|
strXml += ` <c:f>Sheet1!$${getExcelColName(idx + 2)}$2:$${getExcelColName(idx + 2)}$${data[0].values.length + 1}</c:f>`;
|
|
6884
7097
|
strXml += " <c:numCache>";
|
|
6885
|
-
strXml += " <c:formatCode>
|
|
7098
|
+
strXml += " <c:formatCode>" + valFmtCode + "</c:formatCode>";
|
|
6886
7099
|
strXml += ` <c:ptCount val="${data[0].values.length}"/>`;
|
|
6887
7100
|
data[0].values.forEach((_value, idx) => {
|
|
6888
|
-
|
|
7101
|
+
strXml += numCachePt(idx, obj.values[idx]);
|
|
6889
7102
|
});
|
|
6890
7103
|
strXml += " </c:numCache>";
|
|
6891
7104
|
strXml += " </c:numRef>";
|
|
@@ -6901,7 +7114,7 @@ function makeChartType(chartType, data, opts, valAxisId, catAxisId) {
|
|
|
6901
7114
|
strXml += " <a:p><a:pPr>";
|
|
6902
7115
|
strXml += ` <a:defRPr b="${opts.dataLabelFontBold ? "1" : "0"}" i="${opts.dataLabelFontItalic ? "1" : "0"}" strike="noStrike" sz="${Math.round((opts.dataLabelFontSize || 12) * 100)}" u="none">`;
|
|
6903
7116
|
strXml += " <a:solidFill>" + createColorElement(opts.dataLabelColor || "000000") + "</a:solidFill>";
|
|
6904
|
-
strXml += "
|
|
7117
|
+
strXml += " " + createChartTextFonts(opts.dataLabelFontFace || "Arial");
|
|
6905
7118
|
strXml += " </a:defRPr>";
|
|
6906
7119
|
strXml += " </a:pPr></a:p>";
|
|
6907
7120
|
strXml += " </c:txPr>";
|
|
@@ -6951,10 +7164,10 @@ function makeChartType(chartType, data, opts, valAxisId, catAxisId) {
|
|
|
6951
7164
|
strXml += " <c:numRef>";
|
|
6952
7165
|
strXml += ` <c:f>Sheet1!$A$2:$A$${data[0].values.length + 1}</c:f>`;
|
|
6953
7166
|
strXml += " <c:numCache>";
|
|
6954
|
-
strXml += " <c:formatCode>
|
|
7167
|
+
strXml += " <c:formatCode>" + valFmtCode + "</c:formatCode>";
|
|
6955
7168
|
strXml += ` <c:ptCount val="${data[0].values.length}"/>`;
|
|
6956
7169
|
data[0].values.forEach((value, idx) => {
|
|
6957
|
-
strXml +=
|
|
7170
|
+
strXml += numCachePt(idx, value);
|
|
6958
7171
|
});
|
|
6959
7172
|
strXml += " </c:numCache>";
|
|
6960
7173
|
strXml += " </c:numRef>";
|
|
@@ -6964,10 +7177,10 @@ function makeChartType(chartType, data, opts, valAxisId, catAxisId) {
|
|
|
6964
7177
|
strXml += `<c:f>Sheet1!$${getExcelColName(idxColLtr + 1)}$2:$${getExcelColName(idxColLtr + 1)}$${data[0].values.length + 1}</c:f>`;
|
|
6965
7178
|
idxColLtr++;
|
|
6966
7179
|
strXml += " <c:numCache>";
|
|
6967
|
-
strXml += " <c:formatCode>
|
|
7180
|
+
strXml += " <c:formatCode>" + valFmtCode + "</c:formatCode>";
|
|
6968
7181
|
strXml += ` <c:ptCount val="${data[0].values.length}"/>`;
|
|
6969
7182
|
data[0].values.forEach((_value, idx) => {
|
|
6970
|
-
strXml +=
|
|
7183
|
+
strXml += numCachePt(idx, obj.values[idx]);
|
|
6971
7184
|
});
|
|
6972
7185
|
strXml += " </c:numCache>";
|
|
6973
7186
|
strXml += " </c:numRef>";
|
|
@@ -6980,7 +7193,7 @@ function makeChartType(chartType, data, opts, valAxisId, catAxisId) {
|
|
|
6980
7193
|
strXml += " <c:formatCode>General</c:formatCode>";
|
|
6981
7194
|
strXml += ` <c:ptCount val="${obj.sizes.length}"/>`;
|
|
6982
7195
|
obj.sizes.forEach((value, idx) => {
|
|
6983
|
-
strXml +=
|
|
7196
|
+
strXml += numCachePt(idx, value);
|
|
6984
7197
|
});
|
|
6985
7198
|
strXml += " </c:numCache>";
|
|
6986
7199
|
strXml += " </c:numRef>";
|
|
@@ -6993,12 +7206,12 @@ function makeChartType(chartType, data, opts, valAxisId, catAxisId) {
|
|
|
6993
7206
|
strXml += "<c:txPr><a:bodyPr/><a:lstStyle/><a:p><a:pPr>";
|
|
6994
7207
|
strXml += `<a:defRPr b="${opts.dataLabelFontBold ? 1 : 0}" i="${opts.dataLabelFontItalic ? 1 : 0}" strike="noStrike" sz="${Math.round(Math.round(opts.dataLabelFontSize || 12) * 100)}" u="none">`;
|
|
6995
7208
|
strXml += `<a:solidFill>${createColorElement(opts.dataLabelColor || "000000")}</a:solidFill>`;
|
|
6996
|
-
strXml +=
|
|
7209
|
+
strXml += createChartTextFonts(opts.dataLabelFontFace || "Arial");
|
|
6997
7210
|
strXml += "</a:defRPr></a:pPr></a:p></c:txPr>";
|
|
6998
7211
|
if (opts.dataLabelPosition) strXml += `<c:dLblPos val="${opts.dataLabelPosition}"/>`;
|
|
6999
7212
|
strXml += "<c:showLegendKey val=\"0\"/>";
|
|
7000
7213
|
strXml += `<c:showVal val="${opts.showValue ? "1" : "0"}"/>`;
|
|
7001
|
-
strXml += `<c:showCatName val="0"/><c:showSerName val="${opts.showSerName ? "1" : "0"}"/><c:showPercent val="0"/><c:showBubbleSize val="0"/>`;
|
|
7214
|
+
strXml += `<c:showCatName val="0"/><c:showSerName val="${opts.showSerName ? "1" : "0"}"/><c:showPercent val="0"/><c:showBubbleSize val="${opts.showBubbleSize ? "1" : "0"}"/>`;
|
|
7002
7215
|
strXml += "<c:extLst>";
|
|
7003
7216
|
strXml += " <c:ext uri=\"{CE6537A1-D6FC-4f65-9D91-7224C49458BB}\" xmlns:c15=\"http://schemas.microsoft.com/office/drawing/2012/chart\">";
|
|
7004
7217
|
strXml += " <c15:showLeaderLines val=\"" + (opts.showLeaderLines ? "1" : "0") + "\"/>";
|
|
@@ -7032,33 +7245,37 @@ function makeChartType(chartType, data, opts, valAxisId, catAxisId) {
|
|
|
7032
7245
|
else strXml += createShadowElement(opts.shadow, DEF_SHAPE_SHADOW);
|
|
7033
7246
|
strXml += " </c:spPr>";
|
|
7034
7247
|
optsChartData.labels[0].forEach((_label, idx) => {
|
|
7248
|
+
const ptStyle = optsChartData.pointStyles?.[idx];
|
|
7035
7249
|
strXml += "<c:dPt>";
|
|
7036
7250
|
strXml += ` <c:idx val="${idx}"/>`;
|
|
7037
7251
|
strXml += " <c:bubble3D val=\"0\"/>";
|
|
7038
7252
|
strXml += " <c:spPr>";
|
|
7039
|
-
strXml += `<a:solidFill>${createColorElement(opts.chartColors[idx + 1 > opts.chartColors.length ? Math.floor(Math.random() * opts.chartColors.length) : idx])}</a:solidFill>`;
|
|
7040
|
-
if (
|
|
7253
|
+
strXml += `<a:solidFill>${createColorElement(ptStyle?.fill || opts.chartColors[idx + 1 > opts.chartColors.length ? Math.floor(Math.random() * opts.chartColors.length) : idx])}</a:solidFill>`;
|
|
7254
|
+
if (ptStyle?.border) strXml += createChartBorderLine(ptStyle.border);
|
|
7255
|
+
else if (opts.dataBorder) strXml += `<a:ln w="${valToPts(opts.dataBorder.pt)}" cap="flat"><a:solidFill>${createColorElement(opts.dataBorder.color)}</a:solidFill><a:prstDash val="solid"/><a:round/></a:ln>`;
|
|
7041
7256
|
strXml += createShadowElement(opts.shadow, DEF_SHAPE_SHADOW);
|
|
7042
7257
|
strXml += " </c:spPr>";
|
|
7043
7258
|
strXml += "</c:dPt>";
|
|
7044
7259
|
});
|
|
7045
7260
|
strXml += "<c:dLbls>";
|
|
7046
7261
|
optsChartData.labels[0].forEach((_label, idx) => {
|
|
7262
|
+
const customLbl = optsChartData.customLabels?.[idx];
|
|
7047
7263
|
strXml += "<c:dLbl>";
|
|
7048
7264
|
strXml += ` <c:idx val="${idx}"/>`;
|
|
7265
|
+
if (customLbl) strXml += `<c:tx><c:rich><a:bodyPr/><a:lstStyle/><a:p><a:r><a:rPr lang="${opts.lang || "en-US"}" dirty="0"/><a:t>${encodeXmlEntities(customLbl)}</a:t></a:r></a:p></c:rich></c:tx>`;
|
|
7049
7266
|
strXml += ` <c:numFmt formatCode="${encodeXmlEntities(opts.dataLabelFormatCode) || "General"}" sourceLinked="0"/>`;
|
|
7050
7267
|
strXml += " <c:spPr/><c:txPr>";
|
|
7051
7268
|
strXml += " <a:bodyPr/><a:lstStyle/>";
|
|
7052
7269
|
strXml += " <a:p><a:pPr>";
|
|
7053
7270
|
strXml += ` <a:defRPr sz="${Math.round((opts.dataLabelFontSize || 12) * 100)}" b="${opts.dataLabelFontBold ? 1 : 0}" i="${opts.dataLabelFontItalic ? 1 : 0}" u="none" strike="noStrike">`;
|
|
7054
7271
|
strXml += " <a:solidFill>" + createColorElement(opts.dataLabelColor || "000000") + "</a:solidFill>";
|
|
7055
|
-
strXml +=
|
|
7272
|
+
strXml += " " + createChartTextFonts(opts.dataLabelFontFace || "Arial");
|
|
7056
7273
|
strXml += " </a:defRPr>";
|
|
7057
7274
|
strXml += " </a:pPr></a:p>";
|
|
7058
7275
|
strXml += " </c:txPr>";
|
|
7059
7276
|
if (chartType === "pie" && opts.dataLabelPosition) strXml += `<c:dLblPos val="${opts.dataLabelPosition}"/>`;
|
|
7060
7277
|
strXml += " <c:showLegendKey val=\"0\"/>";
|
|
7061
|
-
strXml += " <c:showVal val=\"" + (opts.showValue ? "1" : "0") + "\"/>";
|
|
7278
|
+
strXml += " <c:showVal val=\"" + (customLbl ? "0" : opts.showValue ? "1" : "0") + "\"/>";
|
|
7062
7279
|
strXml += " <c:showCatName val=\"" + (opts.showLabel ? "1" : "0") + "\"/>";
|
|
7063
7280
|
strXml += " <c:showSerName val=\"" + (opts.showSerName ? "1" : "0") + "\"/>";
|
|
7064
7281
|
strXml += " <c:showPercent val=\"" + (opts.showPercent ? "1" : "0") + "\"/>";
|
|
@@ -7073,7 +7290,7 @@ function makeChartType(chartType, data, opts, valAxisId, catAxisId) {
|
|
|
7073
7290
|
strXml += " <a:pPr>";
|
|
7074
7291
|
strXml += ` <a:defRPr sz="${Math.round((opts.dataLabelFontSize || 12) * 100)}" b="${opts.dataLabelFontBold ? "1" : "0"}" i="${opts.dataLabelFontItalic ? "1" : "0"}" u="none" strike="noStrike">`;
|
|
7075
7292
|
strXml += " <a:solidFill>" + createColorElement(opts.dataLabelColor || "000000") + "</a:solidFill>";
|
|
7076
|
-
strXml +=
|
|
7293
|
+
strXml += " " + createChartTextFonts(opts.dataLabelFontFace || "Arial");
|
|
7077
7294
|
strXml += " </a:defRPr>";
|
|
7078
7295
|
strXml += " </a:pPr>";
|
|
7079
7296
|
strXml += " </a:p>";
|
|
@@ -7102,6 +7319,7 @@ function makeChartType(chartType, data, opts, valAxisId, catAxisId) {
|
|
|
7102
7319
|
strXml += " <c:numRef>";
|
|
7103
7320
|
strXml += ` <c:f>Sheet1!$B$2:$B$${optsChartData.labels[0].length + 1}</c:f>`;
|
|
7104
7321
|
strXml += " <c:numCache>";
|
|
7322
|
+
strXml += " <c:formatCode>" + valFmtCode + "</c:formatCode>";
|
|
7105
7323
|
strXml += ` <c:ptCount val="${optsChartData.labels[0].length}"/>`;
|
|
7106
7324
|
optsChartData.values.forEach((value, idx) => {
|
|
7107
7325
|
strXml += `<c:pt idx="${idx}"><c:v>${value || value === 0 ? value : ""}</c:v></c:pt>`;
|
|
@@ -7177,7 +7395,7 @@ function makeCatAxis(opts, axisId, valAxisId) {
|
|
|
7177
7395
|
strXml += " <a:pPr>";
|
|
7178
7396
|
strXml += ` <a:defRPr sz="${Math.round((opts.catAxisLabelFontSize || 12) * 100)}" b="${opts.catAxisLabelFontBold ? 1 : 0}" i="${opts.catAxisLabelFontItalic ? 1 : 0}" u="none" strike="noStrike">`;
|
|
7179
7397
|
strXml += " <a:solidFill>" + createColorElement(opts.catAxisLabelColor || "000000") + "</a:solidFill>";
|
|
7180
|
-
strXml += "
|
|
7398
|
+
strXml += " " + createChartTextFonts(opts.catAxisLabelFontFace || "Arial");
|
|
7181
7399
|
strXml += " </a:defRPr>";
|
|
7182
7400
|
strXml += " </a:pPr>";
|
|
7183
7401
|
strXml += " <a:endParaRPr lang=\"" + (opts.lang || "en-US") + "\"/>";
|
|
@@ -7270,7 +7488,7 @@ function makeValAxis(opts, valAxisId) {
|
|
|
7270
7488
|
strXml += " <a:pPr>";
|
|
7271
7489
|
strXml += ` <a:defRPr sz="${Math.round((opts.valAxisLabelFontSize || 12) * 100)}" b="${opts.valAxisLabelFontBold ? 1 : 0}" i="${opts.valAxisLabelFontItalic ? 1 : 0}" u="none" strike="noStrike">`;
|
|
7272
7490
|
strXml += " <a:solidFill>" + createColorElement(opts.valAxisLabelColor || "000000") + "</a:solidFill>";
|
|
7273
|
-
strXml += "
|
|
7491
|
+
strXml += " " + createChartTextFonts(opts.valAxisLabelFontFace || "Arial");
|
|
7274
7492
|
strXml += " </a:defRPr>";
|
|
7275
7493
|
strXml += " </a:pPr>";
|
|
7276
7494
|
strXml += " <a:endParaRPr lang=\"" + (opts.lang || "en-US") + "\"/>";
|
|
@@ -7326,7 +7544,7 @@ function makeSerAxis(opts, axisId, valAxisId) {
|
|
|
7326
7544
|
strXml += " <a:pPr>";
|
|
7327
7545
|
strXml += ` <a:defRPr sz="${Math.round((opts.serAxisLabelFontSize || 12) * 100)}" b="${opts.serAxisLabelFontBold ? "1" : "0"}" i="${opts.serAxisLabelFontItalic ? "1" : "0"}" u="none" strike="noStrike">`;
|
|
7328
7546
|
strXml += ` <a:solidFill>${createColorElement(opts.serAxisLabelColor || "000000")}</a:solidFill>`;
|
|
7329
|
-
strXml +=
|
|
7547
|
+
strXml += " " + createChartTextFonts(opts.serAxisLabelFontFace || "Arial");
|
|
7330
7548
|
strXml += " </a:defRPr>";
|
|
7331
7549
|
strXml += " </a:pPr>";
|
|
7332
7550
|
strXml += " <a:endParaRPr lang=\"" + (opts.lang || "en-US") + "\"/>";
|
|
@@ -7366,17 +7584,31 @@ function genXmlTitle(opts, chartX, chartY) {
|
|
|
7366
7584
|
const rotate = opts.titleRotate ? `<a:bodyPr rot="${convertRotationDegrees(opts.titleRotate)}"/>` : "<a:bodyPr/>";
|
|
7367
7585
|
const sizeAttr = opts.fontSize ? `sz="${Math.round(opts.fontSize * 100)}"` : "";
|
|
7368
7586
|
const titleBold = opts.titleBold ? 1 : 0;
|
|
7587
|
+
const titleItalic = opts.titleItalic ? 1 : 0;
|
|
7588
|
+
const titleUnderline = opts.titleUnderline ? "sng" : "none";
|
|
7369
7589
|
let layout = "<c:layout/>";
|
|
7370
|
-
|
|
7371
|
-
|
|
7372
|
-
|
|
7373
|
-
let
|
|
7374
|
-
|
|
7375
|
-
if (
|
|
7376
|
-
|
|
7377
|
-
|
|
7378
|
-
|
|
7379
|
-
|
|
7590
|
+
const hasX = opts.titlePos && typeof opts.titlePos.x === "number";
|
|
7591
|
+
const hasY = opts.titlePos && typeof opts.titlePos.y === "number";
|
|
7592
|
+
if (hasX || hasY) {
|
|
7593
|
+
let modes = "";
|
|
7594
|
+
let vals = "";
|
|
7595
|
+
if (hasX) {
|
|
7596
|
+
const totalX = opts.titlePos.x + chartX;
|
|
7597
|
+
let valX = totalX === 0 ? 0 : totalX * (totalX / 5) / 10;
|
|
7598
|
+
if (valX >= 1) valX = valX / 10;
|
|
7599
|
+
if (valX >= .1) valX = valX / 10;
|
|
7600
|
+
modes += "<c:xMode val=\"edge\"/>";
|
|
7601
|
+
vals += `<c:x val="${valX}"/>`;
|
|
7602
|
+
}
|
|
7603
|
+
if (hasY) {
|
|
7604
|
+
const totalY = opts.titlePos.y + chartY;
|
|
7605
|
+
let valY = totalY === 0 ? 0 : totalY * (totalY / 5) / 10;
|
|
7606
|
+
if (valY >= 1) valY = valY / 10;
|
|
7607
|
+
if (valY >= .1) valY = valY / 10;
|
|
7608
|
+
modes += "<c:yMode val=\"edge\"/>";
|
|
7609
|
+
vals += `<c:y val="${valY}"/>`;
|
|
7610
|
+
}
|
|
7611
|
+
layout = `<c:layout><c:manualLayout>${modes}${vals}</c:manualLayout></c:layout>`;
|
|
7380
7612
|
}
|
|
7381
7613
|
return `<c:title>
|
|
7382
7614
|
<c:tx>
|
|
@@ -7385,15 +7617,15 @@ function genXmlTitle(opts, chartX, chartY) {
|
|
|
7385
7617
|
<a:lstStyle/>
|
|
7386
7618
|
<a:p>
|
|
7387
7619
|
${align}
|
|
7388
|
-
<a:defRPr ${sizeAttr} b="${titleBold}" i="
|
|
7620
|
+
<a:defRPr ${sizeAttr} b="${titleBold}" i="${titleItalic}" u="${titleUnderline}" strike="noStrike">
|
|
7389
7621
|
<a:solidFill>${createColorElement(opts.color || "000000")}</a:solidFill>
|
|
7390
|
-
|
|
7622
|
+
${createChartTextFonts(opts.fontFace || "Arial")}
|
|
7391
7623
|
</a:defRPr>
|
|
7392
7624
|
</a:pPr>
|
|
7393
7625
|
<a:r>
|
|
7394
|
-
<a:rPr ${sizeAttr} b="${titleBold}" i="
|
|
7626
|
+
<a:rPr ${sizeAttr} b="${titleBold}" i="${titleItalic}" u="${titleUnderline}" strike="noStrike">
|
|
7395
7627
|
<a:solidFill>${createColorElement(opts.color || "000000")}</a:solidFill>
|
|
7396
|
-
|
|
7628
|
+
${createChartTextFonts(opts.fontFace || "Arial")}
|
|
7397
7629
|
</a:rPr>
|
|
7398
7630
|
<a:t>${encodeXmlEntities(opts.title) || ""}</a:t>
|
|
7399
7631
|
</a:r>
|
|
@@ -7467,11 +7699,105 @@ function createGridLineElement(glOpts) {
|
|
|
7467
7699
|
strXml += "</c:majorGridlines>";
|
|
7468
7700
|
return strXml;
|
|
7469
7701
|
}
|
|
7470
|
-
|
|
7471
|
-
|
|
7472
|
-
|
|
7473
|
-
|
|
7474
|
-
|
|
7702
|
+
/**
|
|
7703
|
+
* Build a `<c:pt>` numeric-cache data point, or '' to leave a gap.
|
|
7704
|
+
*
|
|
7705
|
+
* `<c:v>` inside a `<c:numCache>` is an `xsd:double`; emitting `NaN`, `Infinity`
|
|
7706
|
+
* or an empty string yields an invalid value that makes PowerPoint report the
|
|
7707
|
+
* package as needing repair. Null/undefined are intentional gaps and are skipped
|
|
7708
|
+
* silently (a sparse, idx-keyed cache is valid); other non-finite numbers are
|
|
7709
|
+
* skipped with a warning, per the library's "warn rather than emit a degenerate
|
|
7710
|
+
* result" policy.
|
|
7711
|
+
* @param idx - zero-based data-point index (emitted as `idx`)
|
|
7712
|
+
* @param value - numeric value (or null/undefined gap)
|
|
7713
|
+
*/
|
|
7714
|
+
function numCachePt(idx, value) {
|
|
7715
|
+
if (value == null) return "";
|
|
7716
|
+
if (!Number.isFinite(value)) {
|
|
7717
|
+
console.warn(`Warning: chart value "${value}" at index ${idx} is not a finite number; data point omitted.`);
|
|
7718
|
+
return "";
|
|
7719
|
+
}
|
|
7720
|
+
return `<c:pt idx="${idx}"><c:v>${value}</c:v></c:pt>`;
|
|
7721
|
+
}
|
|
7722
|
+
/**
|
|
7723
|
+
* Build a `<c:serLines>` ("Series Lines") element for a bar chart.
|
|
7724
|
+
* @param opt - `true` for PowerPoint automatic styling, an {@link OptsChartGridLine}
|
|
7725
|
+
* to customize the line, or falsy / `{ style: 'none' }` to omit the element.
|
|
7726
|
+
*/
|
|
7727
|
+
function createSerLinesElement(opt) {
|
|
7728
|
+
if (!opt) return "";
|
|
7729
|
+
if (opt === true) return "<c:serLines/>";
|
|
7730
|
+
if (opt.style === "none") return "";
|
|
7731
|
+
let strXml = "<c:serLines><c:spPr>";
|
|
7732
|
+
strXml += `<a:ln w="${valToPts(opt.size || DEF_CHART_GRIDLINE.size)}" cap="${createLineCap(opt.cap || DEF_CHART_GRIDLINE.cap)}">`;
|
|
7733
|
+
strXml += `<a:solidFill><a:srgbClr val="${opt.color || DEF_CHART_GRIDLINE.color}"/></a:solidFill>`;
|
|
7734
|
+
strXml += `<a:prstDash val="${opt.style || DEF_CHART_GRIDLINE.style}"/><a:round/>`;
|
|
7735
|
+
strXml += "</a:ln></c:spPr></c:serLines>";
|
|
7736
|
+
return strXml;
|
|
7737
|
+
}
|
|
7738
|
+
function makeCustomDLblXml(idx, text, opts) {
|
|
7739
|
+
const sz = Math.round((opts.dataLabelFontSize || 12) * 100);
|
|
7740
|
+
const bold = opts.dataLabelFontBold ? "1" : "0";
|
|
7741
|
+
const italic = opts.dataLabelFontItalic ? "1" : "0";
|
|
7742
|
+
const color = createColorElement(opts.dataLabelColor || "000000");
|
|
7743
|
+
const face = opts.dataLabelFontFace || "Arial";
|
|
7744
|
+
const lang = opts.lang || "en-US";
|
|
7745
|
+
return `<c:dLbl><c:idx val="${idx}"/><c:tx><c:rich><a:bodyPr/><a:lstStyle/><a:p><a:pPr><a:defRPr sz="${sz}" b="${bold}" i="${italic}" u="none" strike="noStrike"><a:solidFill>${color}</a:solidFill>${createChartTextFonts(face)}</a:defRPr></a:pPr><a:r><a:rPr lang="${lang}" sz="${sz}" b="${bold}" i="${italic}" u="none" strike="noStrike" dirty="0"><a:solidFill>${color}</a:solidFill>${createChartTextFonts(face)}</a:rPr><a:t>${encodeXmlEntities(text)}</a:t></a:r></a:p></c:rich></c:tx><c:showLegendKey val="0"/><c:showVal val="0"/><c:showCatName val="0"/><c:showSerName val="0"/><c:showPercent val="0"/><c:showBubbleSize val="0"/></c:dLbl>`;
|
|
7746
|
+
}
|
|
7747
|
+
/**
|
|
7748
|
+
* Build an `<a:ln>` border element from a per-data-point `BorderProps`.
|
|
7749
|
+
* @param border - point border style (`type`, `color`, `pt`)
|
|
7750
|
+
*/
|
|
7751
|
+
function createChartBorderLine(border) {
|
|
7752
|
+
if (border.type === "none") return "<a:ln><a:noFill/></a:ln>";
|
|
7753
|
+
const dash = border.type === "dash" ? "dash" : "solid";
|
|
7754
|
+
return `<a:ln w="${valToPts(border.pt ?? 1)}" cap="flat"><a:solidFill>${createColorElement(border.color || "666666")}</a:solidFill><a:prstDash val="${dash}"/><a:round/></a:ln>`;
|
|
7755
|
+
}
|
|
7756
|
+
/**
|
|
7757
|
+
* Build `<c:dPt>` entries for a series in the bar/line/area/scatter loops.
|
|
7758
|
+
*
|
|
7759
|
+
* Merges two sources into a single `c:dPt` per index so we never emit a
|
|
7760
|
+
* duplicate `<c:idx>` (which corrupts the chart):
|
|
7761
|
+
* - legacy single-series color-vary fills (bar/scatter), supplied via `varyColors`
|
|
7762
|
+
* - per-point `pointStyles` border/fill overrides
|
|
7763
|
+
*
|
|
7764
|
+
* Must be emitted in schema position *before* `c:dLbls` (CT_*Ser order).
|
|
7765
|
+
* RADAR is skipped: extra per-point markup historically corrupts the chart.
|
|
7766
|
+
*
|
|
7767
|
+
* @param chartType - series chart type
|
|
7768
|
+
* @param obj - series data (reads `values`, `pointStyles`)
|
|
7769
|
+
* @param opts - chart options (fill/shadow/lineSize context)
|
|
7770
|
+
* @param varyColors - color array when single-series color-vary applies, else `null`
|
|
7771
|
+
*/
|
|
7772
|
+
function makeSeriesDataPointsXml(chartType, obj, opts, varyColors) {
|
|
7773
|
+
if (chartType === "radar") return "";
|
|
7774
|
+
const pointStyles = obj.pointStyles;
|
|
7775
|
+
if (!varyColors && !pointStyles?.length) return "";
|
|
7776
|
+
const isBar = chartType === "bar" || chartType === "bar3D";
|
|
7777
|
+
const isScatter = chartType === "scatter";
|
|
7778
|
+
let xml = "";
|
|
7779
|
+
obj.values.forEach((value, index) => {
|
|
7780
|
+
const ptStyle = pointStyles?.[index];
|
|
7781
|
+
const arrColors = varyColors ? value < 0 ? opts.invertedColors || opts.chartColors || BARCHART_COLORS : varyColors : null;
|
|
7782
|
+
const fillColor = ptStyle?.fill || (arrColors ? arrColors[index % arrColors.length] : null);
|
|
7783
|
+
const border = ptStyle?.border;
|
|
7784
|
+
if (!fillColor && !border) return;
|
|
7785
|
+
xml += "<c:dPt>";
|
|
7786
|
+
xml += `<c:idx val="${index}"/>`;
|
|
7787
|
+
if (isBar) xml += "<c:invertIfNegative val=\"0\"/>";
|
|
7788
|
+
xml += "<c:bubble3D val=\"0\"/>";
|
|
7789
|
+
xml += "<c:spPr>";
|
|
7790
|
+
if ((isBar || isScatter) && opts.lineSize === 0 && !border && !ptStyle?.fill) xml += "<a:ln><a:noFill/></a:ln>";
|
|
7791
|
+
else {
|
|
7792
|
+
if (fillColor) if (chartType === "bar3D") xml += `<a:ln><a:solidFill>${createColorElement(fillColor)}</a:solidFill></a:ln>`;
|
|
7793
|
+
else xml += `<a:solidFill>${createColorElement(fillColor)}</a:solidFill>`;
|
|
7794
|
+
if (border) xml += createChartBorderLine(border);
|
|
7795
|
+
}
|
|
7796
|
+
xml += createShadowElement(opts.shadow, DEF_SHAPE_SHADOW);
|
|
7797
|
+
xml += "</c:spPr>";
|
|
7798
|
+
xml += "</c:dPt>";
|
|
7799
|
+
});
|
|
7800
|
+
return xml;
|
|
7475
7801
|
}
|
|
7476
7802
|
//#endregion
|
|
7477
7803
|
//#region src/gen-media.ts
|
|
@@ -7520,6 +7846,37 @@ function encodeSlideMediaRels(layout, runtime) {
|
|
|
7520
7846
|
/**
|
|
7521
7847
|
* PptxGenJS: XML Generation
|
|
7522
7848
|
*/
|
|
7849
|
+
const _warnedTextRangeMsgs = /* @__PURE__ */ new Set();
|
|
7850
|
+
function warnTextRangeOnce(msg) {
|
|
7851
|
+
if (_warnedTextRangeMsgs.has(msg)) return;
|
|
7852
|
+
_warnedTextRangeMsgs.add(msg);
|
|
7853
|
+
console.warn(msg);
|
|
7854
|
+
}
|
|
7855
|
+
/**
|
|
7856
|
+
* Clamp a font size (points) into ST_TextFontSize (1-4000pt) and return it in
|
|
7857
|
+
* hundredths of a point for the `sz` attribute. Out-of-range sizes make
|
|
7858
|
+
* PowerPoint report the package as needing repair (e.g. `sz` > 400000 or < 100).
|
|
7859
|
+
*/
|
|
7860
|
+
function clampFontSizeSz(fontSizePts) {
|
|
7861
|
+
const raw = Math.round(fontSizePts * 100);
|
|
7862
|
+
const clamped = Math.min(4e5, Math.max(100, raw));
|
|
7863
|
+
if (clamped !== raw) warnTextRangeOnce(`Warning: fontSize ${fontSizePts} is outside the valid range 1-4000pt; using ${clamped / 100}.`);
|
|
7864
|
+
return clamped;
|
|
7865
|
+
}
|
|
7866
|
+
/** Clamp character spacing (points) into ST_TextPoint (-4000..4000pt); returns hundredths for the `spc` attribute. */
|
|
7867
|
+
function clampCharSpacingSpc(charSpacingPts) {
|
|
7868
|
+
const raw = Math.round(charSpacingPts * 100);
|
|
7869
|
+
const clamped = Math.min(4e5, Math.max(-4e5, raw));
|
|
7870
|
+
if (clamped !== raw) warnTextRangeOnce(`Warning: charSpacing ${charSpacingPts} is outside the valid range -4000..4000pt; using ${clamped / 100}.`);
|
|
7871
|
+
return clamped;
|
|
7872
|
+
}
|
|
7873
|
+
/** Clamp line spacing (points) into ST_TextSpacingPoint (0..1584pt); returns hundredths for `<a:spcPts val>`. */
|
|
7874
|
+
function clampLineSpacingPts(lineSpacingPts) {
|
|
7875
|
+
const raw = Math.round(lineSpacingPts * 100);
|
|
7876
|
+
const clamped = Math.min(158400, Math.max(0, raw));
|
|
7877
|
+
if (clamped !== raw) warnTextRangeOnce(`Warning: lineSpacing ${lineSpacingPts} is outside the valid range 0-1584pt; using ${clamped / 100}.`);
|
|
7878
|
+
return clamped;
|
|
7879
|
+
}
|
|
7523
7880
|
const ImageSizingXml = {
|
|
7524
7881
|
cover: function(imgSize, boxDim) {
|
|
7525
7882
|
const imgRatio = imgSize.h / imgSize.w;
|
|
@@ -7566,23 +7923,90 @@ const ImageSizingXml = {
|
|
|
7566
7923
|
* @return {string} `<a:prstGeom>` XML
|
|
7567
7924
|
*/
|
|
7568
7925
|
const RECT_RADIUS_ADJ1_SHAPES = new Set(["round2SameRect", "round2DiagRect"]);
|
|
7926
|
+
const SHAPE_LOCK_ATTRS = [
|
|
7927
|
+
"noGrp",
|
|
7928
|
+
"noSelect",
|
|
7929
|
+
"noRot",
|
|
7930
|
+
"noChangeAspect",
|
|
7931
|
+
"noMove",
|
|
7932
|
+
"noResize",
|
|
7933
|
+
"noEditPoints",
|
|
7934
|
+
"noAdjustHandles",
|
|
7935
|
+
"noChangeArrowheads",
|
|
7936
|
+
"noChangeShapeType",
|
|
7937
|
+
"noTextEdit"
|
|
7938
|
+
];
|
|
7939
|
+
const PICTURE_LOCK_ATTRS = [
|
|
7940
|
+
"noGrp",
|
|
7941
|
+
"noSelect",
|
|
7942
|
+
"noRot",
|
|
7943
|
+
"noChangeAspect",
|
|
7944
|
+
"noMove",
|
|
7945
|
+
"noResize",
|
|
7946
|
+
"noEditPoints",
|
|
7947
|
+
"noAdjustHandles",
|
|
7948
|
+
"noChangeArrowheads",
|
|
7949
|
+
"noChangeShapeType",
|
|
7950
|
+
"noCrop"
|
|
7951
|
+
];
|
|
7952
|
+
const GRAPHIC_FRAME_LOCK_ATTRS = [
|
|
7953
|
+
"noGrp",
|
|
7954
|
+
"noDrilldown",
|
|
7955
|
+
"noSelect",
|
|
7956
|
+
"noChangeAspect",
|
|
7957
|
+
"noMove",
|
|
7958
|
+
"noResize"
|
|
7959
|
+
];
|
|
7960
|
+
/**
|
|
7961
|
+
* Serialize an object-lock element (`a:spLocks` / `a:picLocks` / `a:graphicFrameLocks`).
|
|
7962
|
+
* Only flags set to `true` AND valid for this element type are emitted; a flag set on an
|
|
7963
|
+
* unsupported element type is dropped with a warning (silent coercion is a footgun).
|
|
7964
|
+
* @param tag - locking element tag, e.g. `'a:spLocks'`
|
|
7965
|
+
* @param allowed - attribute names this element type supports, in desired emit order
|
|
7966
|
+
* @param locks - merged lock flags (callers fold any hard-coded default in first)
|
|
7967
|
+
* @param objectName - for the warning message
|
|
7968
|
+
* @returns the locking element string, or `''` when no applicable flag is set
|
|
7969
|
+
*/
|
|
7970
|
+
function genXmlObjectLock(tag, allowed, locks, objectName) {
|
|
7971
|
+
if (!locks) return "";
|
|
7972
|
+
const lockMap = locks;
|
|
7973
|
+
for (const key of Object.keys(lockMap)) if (lockMap[key] && !allowed.includes(key)) console.warn(`Warning: objectLock.${key} is not supported on <${tag}> (object "${objectName ?? ""}") and was ignored.`);
|
|
7974
|
+
const attrs = allowed.filter((name) => lockMap[name] === true).map((name) => `${name}="1"`);
|
|
7975
|
+
return attrs.length > 0 ? `<${tag} ${attrs.join(" ")}/>` : "";
|
|
7976
|
+
}
|
|
7569
7977
|
function genXmlPresetGeom(shapeName, options, cx, cy) {
|
|
7570
|
-
|
|
7978
|
+
if (!VALID_SHAPE_PRESETS.has(shapeName)) throw new Error(`Invalid shape "${String(shapeName)}"! Use a value from \`pptxgen.shapes.*\` (e.g. \`pptxgen.shapes.RECTANGLE\`). PowerPoint can't render unknown preset geometries and will drop the shape during repair.`);
|
|
7979
|
+
let avLst = "";
|
|
7980
|
+
const emittedAdjNames = /* @__PURE__ */ new Set();
|
|
7981
|
+
const emitGuide = (name, fmlaVal) => {
|
|
7982
|
+
avLst += `<a:gd name="${name}" fmla="val ${fmlaVal}"/>`;
|
|
7983
|
+
emittedAdjNames.add(name);
|
|
7984
|
+
};
|
|
7571
7985
|
if (options.rectRadius) {
|
|
7572
7986
|
const adjVal = Math.round(options.rectRadius * EMU * 1e5 / Math.min(cx, cy));
|
|
7573
7987
|
if (RECT_RADIUS_ADJ1_SHAPES.has(shapeName)) {
|
|
7574
|
-
|
|
7575
|
-
|
|
7576
|
-
} else
|
|
7988
|
+
emitGuide("adj1", adjVal);
|
|
7989
|
+
emitGuide("adj2", 0);
|
|
7990
|
+
} else emitGuide("adj", adjVal);
|
|
7577
7991
|
} else if (options.angleRange) {
|
|
7578
7992
|
for (let i = 0; i < 2; i++) {
|
|
7579
7993
|
const angle = options.angleRange[i];
|
|
7580
|
-
|
|
7994
|
+
emitGuide(`adj${i + 1}`, convertRotationDegrees(angle));
|
|
7581
7995
|
}
|
|
7582
|
-
if (options.arcThicknessRatio)
|
|
7996
|
+
if (options.arcThicknessRatio) emitGuide("adj3", Math.round(options.arcThicknessRatio * 5e4));
|
|
7583
7997
|
}
|
|
7584
|
-
|
|
7585
|
-
|
|
7998
|
+
if (options.shapeAdjust) (Array.isArray(options.shapeAdjust) ? options.shapeAdjust : [options.shapeAdjust]).forEach((adj) => {
|
|
7999
|
+
if (!adj || typeof adj.name !== "string" || adj.name.length === 0 || typeof adj.value !== "number" || !isFinite(adj.value)) {
|
|
8000
|
+
console.warn(`Warning: shapeAdjust entry ${JSON.stringify(adj)} is invalid (needs { name:string, value:number }) and was ignored.`);
|
|
8001
|
+
return;
|
|
8002
|
+
}
|
|
8003
|
+
if (emittedAdjNames.has(adj.name)) {
|
|
8004
|
+
console.warn(`Warning: shapeAdjust "${adj.name}" was ignored because rectRadius/angleRange already set that handle.`);
|
|
8005
|
+
return;
|
|
8006
|
+
}
|
|
8007
|
+
emitGuide(adj.name, Math.round(adj.value * 1e5));
|
|
8008
|
+
});
|
|
8009
|
+
return `<a:prstGeom prst="${shapeName}"><a:avLst>${avLst}</a:avLst></a:prstGeom>`;
|
|
7586
8010
|
}
|
|
7587
8011
|
/**
|
|
7588
8012
|
* Emit an `<a:custGeom>` for a freeform path built from `points`.
|
|
@@ -7635,6 +8059,45 @@ function genXmlCustGeom(points, cx, cy, layout) {
|
|
|
7635
8059
|
}
|
|
7636
8060
|
const PLACEHOLDER_TYPE_MAP = PLACEHOLDER_TYPES;
|
|
7637
8061
|
/**
|
|
8062
|
+
* Emit the `<a:lnL>/<a:lnR>/<a:lnT>/<a:lnB>` border children of an `<a:tcPr>` for a table cell.
|
|
8063
|
+
* Shared by normal cells and the dummy span (`_hmerge`/`_vmerge`) cells so a merged region's
|
|
8064
|
+
* outer edges render with the same border as its origin cell (Issue #680).
|
|
8065
|
+
* @param {BorderProps[]} cellBorder - 4-tuple of border props in [top, right, bottom, left] order
|
|
8066
|
+
* @return {string} concatenated border element XML, in the LRTB document order PowerPoint expects
|
|
8067
|
+
*/
|
|
8068
|
+
function genTableCellBorderXml(cellBorder) {
|
|
8069
|
+
let strXml = "";
|
|
8070
|
+
[
|
|
8071
|
+
{
|
|
8072
|
+
idx: 3,
|
|
8073
|
+
name: "lnL"
|
|
8074
|
+
},
|
|
8075
|
+
{
|
|
8076
|
+
idx: 1,
|
|
8077
|
+
name: "lnR"
|
|
8078
|
+
},
|
|
8079
|
+
{
|
|
8080
|
+
idx: 0,
|
|
8081
|
+
name: "lnT"
|
|
8082
|
+
},
|
|
8083
|
+
{
|
|
8084
|
+
idx: 2,
|
|
8085
|
+
name: "lnB"
|
|
8086
|
+
}
|
|
8087
|
+
].forEach((obj) => {
|
|
8088
|
+
const border = cellBorder[obj.idx];
|
|
8089
|
+
if (!border) return;
|
|
8090
|
+
const cap = createLineCap(border.cap);
|
|
8091
|
+
if (border.type !== "none") {
|
|
8092
|
+
strXml += `<a:${obj.name} w="${valToPts(border.pt)}" cap="${cap}" cmpd="sng" algn="ctr">`;
|
|
8093
|
+
strXml += `<a:solidFill>${createColorElement(border.color)}</a:solidFill>`;
|
|
8094
|
+
strXml += `<a:prstDash val="${border.type === "dash" ? "sysDash" : "solid"}"/><a:round/><a:headEnd type="none" w="med" len="med"/><a:tailEnd type="none" w="med" len="med"/>`;
|
|
8095
|
+
strXml += `</a:${obj.name}>`;
|
|
8096
|
+
} else strXml += `<a:${obj.name} w="0" cap="${cap}" cmpd="sng" algn="ctr"><a:noFill/></a:${obj.name}>`;
|
|
8097
|
+
});
|
|
8098
|
+
return strXml;
|
|
8099
|
+
}
|
|
8100
|
+
/**
|
|
7638
8101
|
* Transforms a slide or slideLayout to resulting XML string - Creates `ppt/slide*.xml`
|
|
7639
8102
|
* @param {PresSlideInternal|SlideLayoutInternal} slideObject - slide object created within createSlideObject
|
|
7640
8103
|
* @return {string} XML string with <p:cSld> as the root
|
|
@@ -7693,7 +8156,10 @@ function slideObjectToXml(slide) {
|
|
|
7693
8156
|
intColCnt += cellOpts?.colspan ? Number(cellOpts.colspan) : 1;
|
|
7694
8157
|
});
|
|
7695
8158
|
strXml = `<p:graphicFrame><p:nvGraphicFramePr><p:cNvPr id="${intTableNum * slide._slideNum + 1}" name="${slideItemObj.options.objectName}" descr="${encodeXmlEntities(slideItemObj.options.altText || "")}"/>`;
|
|
7696
|
-
strXml +=
|
|
8159
|
+
strXml += `<p:cNvGraphicFramePr>${genXmlObjectLock("a:graphicFrameLocks", GRAPHIC_FRAME_LOCK_ATTRS, {
|
|
8160
|
+
noGrp: true,
|
|
8161
|
+
...slideItemObj.options.objectLock
|
|
8162
|
+
}, slideItemObj.options.objectName)}</p:cNvGraphicFramePr> <p:nvPr><p:extLst><p:ext uri="{D42A27DB-BD31-4B8C-83A1-F6EECF244321}"><p14:modId xmlns:p14="http://schemas.microsoft.com/office/powerpoint/2010/main" val="1579011935"/></p:ext></p:extLst></p:nvPr></p:nvGraphicFramePr>`;
|
|
7697
8163
|
strXml += `<p:xfrm><a:off x="${x || (x === 0 ? 0 : EMU)}" y="${y || (y === 0 ? 0 : EMU)}"/><a:ext cx="${cx || (cx === 0 ? 0 : EMU)}" cy="${cy || EMU}"/></p:xfrm>`;
|
|
7698
8164
|
{
|
|
7699
8165
|
const tblPrAttrs = (objTabOpts.hasHeader ? " firstRow=\"1\"" : "") + (objTabOpts.hasFooter ? " lastRow=\"1\"" : "") + (objTabOpts.hasBandedRows ? " bandRow=\"1\"" : "") + (objTabOpts.hasBandedColumns ? " bandCol=\"1\"" : "") + (objTabOpts.hasFirstColumn ? " firstCol=\"1\"" : "") + (objTabOpts.hasLastColumn ? " lastCol=\"1\"" : "");
|
|
@@ -7725,7 +8191,8 @@ function slideObjectToXml(slide) {
|
|
|
7725
8191
|
return {
|
|
7726
8192
|
_type: "tablecell",
|
|
7727
8193
|
options: { rowspan },
|
|
7728
|
-
_hmerge: true
|
|
8194
|
+
_hmerge: true,
|
|
8195
|
+
_spanOrigin: cell
|
|
7729
8196
|
};
|
|
7730
8197
|
});
|
|
7731
8198
|
cells.splice(cIdx + 1, 0, ...vMergeCells);
|
|
@@ -7741,12 +8208,14 @@ function slideObjectToXml(slide) {
|
|
|
7741
8208
|
const colspan = cell.options?.colspan;
|
|
7742
8209
|
const _hmerge = cell._hmerge;
|
|
7743
8210
|
if (rowspan && rowspan > 1) {
|
|
8211
|
+
const _spanOrigin = cell._spanOrigin || cell;
|
|
7744
8212
|
const hMergeCell = {
|
|
7745
8213
|
_type: "tablecell",
|
|
7746
8214
|
options: { colspan },
|
|
7747
8215
|
_rowContinue: rowspan - 1,
|
|
7748
8216
|
_vmerge: true,
|
|
7749
|
-
_hmerge
|
|
8217
|
+
_hmerge,
|
|
8218
|
+
_spanOrigin
|
|
7750
8219
|
};
|
|
7751
8220
|
nextRow.splice(cIdx, 0, hMergeCell);
|
|
7752
8221
|
}
|
|
@@ -7756,7 +8225,7 @@ function slideObjectToXml(slide) {
|
|
|
7756
8225
|
let intRowH = 0;
|
|
7757
8226
|
if (Array.isArray(objTabOpts.rowH) && objTabOpts.rowH[rIdx]) intRowH = inch2Emu(Number(objTabOpts.rowH[rIdx]));
|
|
7758
8227
|
else if (objTabOpts.rowH && !isNaN(Number(objTabOpts.rowH))) intRowH = inch2Emu(Number(objTabOpts.rowH));
|
|
7759
|
-
else if (slideItemObj.options.cy || slideItemObj.options.h) intRowH = Math.round((slideItemObj.options.h ?
|
|
8228
|
+
else if (slideItemObj.options.cy || slideItemObj.options.h) intRowH = Math.round((slideItemObj.options.h ? cy : typeof slideItemObj.options.cy === "number" ? slideItemObj.options.cy : 1) / arrTabRows.length);
|
|
7760
8229
|
strXml += `<a:tr h="${intRowH}">`;
|
|
7761
8230
|
cells.forEach((cellObj) => {
|
|
7762
8231
|
const cell = cellObj;
|
|
@@ -7769,7 +8238,17 @@ function slideObjectToXml(slide) {
|
|
|
7769
8238
|
let cellSpanAttrStr = Object.entries(cellSpanAttrs).filter(([, v]) => !!v).map(([k, v]) => `${String(k)}="${String(v)}"`).join(" ");
|
|
7770
8239
|
if (cellSpanAttrStr) cellSpanAttrStr = " " + cellSpanAttrStr;
|
|
7771
8240
|
if (cell._hmerge || cell._vmerge) {
|
|
7772
|
-
|
|
8241
|
+
const origin = cell._spanOrigin;
|
|
8242
|
+
let spanPrXml = "";
|
|
8243
|
+
if (origin) {
|
|
8244
|
+
const originOpts = origin.options || {};
|
|
8245
|
+
const originBorder = Array.isArray(originOpts.border) ? originOpts.border : null;
|
|
8246
|
+
if (originBorder) spanPrXml += genTableCellBorderXml(originBorder);
|
|
8247
|
+
let spanFill = origin._optImp?.fill?.color ? origin._optImp.fill.color : origin._optImp?.fill && typeof origin._optImp.fill === "string" ? origin._optImp.fill : "";
|
|
8248
|
+
spanFill = spanFill || originOpts.fill ? originOpts.fill : "";
|
|
8249
|
+
if (spanFill) spanPrXml += genXmlColorSelection(spanFill);
|
|
8250
|
+
}
|
|
8251
|
+
strXml += `<a:tc${cellSpanAttrStr}><a:tcPr>${spanPrXml}</a:tcPr></a:tc>`;
|
|
7773
8252
|
return;
|
|
7774
8253
|
}
|
|
7775
8254
|
const cellOpts = cell.options || {};
|
|
@@ -7813,32 +8292,7 @@ function slideObjectToXml(slide) {
|
|
|
7813
8292
|
else cellMarginXml = ` marL="${inch2Emu(cellMargin[3])}" marR="${inch2Emu(cellMargin[1])}" marT="${inch2Emu(cellMargin[0])}" marB="${inch2Emu(cellMargin[2])}"`;
|
|
7814
8293
|
strXml += `<a:tc${cellSpanAttrStr}>${genXmlTextBody(cell)}<a:tcPr${cellMarginXml}${cellValign}${cellTextDir}>`;
|
|
7815
8294
|
const cellBorder = Array.isArray(cellOpts.border) ? cellOpts.border : null;
|
|
7816
|
-
if (cellBorder)
|
|
7817
|
-
{
|
|
7818
|
-
idx: 3,
|
|
7819
|
-
name: "lnL"
|
|
7820
|
-
},
|
|
7821
|
-
{
|
|
7822
|
-
idx: 1,
|
|
7823
|
-
name: "lnR"
|
|
7824
|
-
},
|
|
7825
|
-
{
|
|
7826
|
-
idx: 0,
|
|
7827
|
-
name: "lnT"
|
|
7828
|
-
},
|
|
7829
|
-
{
|
|
7830
|
-
idx: 2,
|
|
7831
|
-
name: "lnB"
|
|
7832
|
-
}
|
|
7833
|
-
].forEach((obj) => {
|
|
7834
|
-
const border = cellBorder[obj.idx];
|
|
7835
|
-
if (border.type !== "none") {
|
|
7836
|
-
strXml += `<a:${obj.name} w="${valToPts(border.pt)}" cap="flat" cmpd="sng" algn="ctr">`;
|
|
7837
|
-
strXml += `<a:solidFill>${createColorElement(border.color)}</a:solidFill>`;
|
|
7838
|
-
strXml += `<a:prstDash val="${border.type === "dash" ? "sysDash" : "solid"}"/><a:round/><a:headEnd type="none" w="med" len="med"/><a:tailEnd type="none" w="med" len="med"/>`;
|
|
7839
|
-
strXml += `</a:${obj.name}>`;
|
|
7840
|
-
} else strXml += `<a:${obj.name} w="0" cap="flat" cmpd="sng" algn="ctr"><a:noFill/></a:${obj.name}>`;
|
|
7841
|
-
});
|
|
8295
|
+
if (cellBorder) strXml += genTableCellBorderXml(cellBorder);
|
|
7842
8296
|
strXml += cellFill;
|
|
7843
8297
|
strXml += " </a:tcPr>";
|
|
7844
8298
|
strXml += " </a:tc>";
|
|
@@ -7857,10 +8311,10 @@ function slideObjectToXml(slide) {
|
|
|
7857
8311
|
if (!slideItemObj.options.line && cy === 0) cy = EMU * .3;
|
|
7858
8312
|
if (!slideItemObj.options._bodyProp) slideItemObj.options._bodyProp = {};
|
|
7859
8313
|
if (slideItemObj.options.margin && Array.isArray(slideItemObj.options.margin)) {
|
|
7860
|
-
slideItemObj.options._bodyProp.
|
|
8314
|
+
slideItemObj.options._bodyProp.tIns = valToPts(slideItemObj.options.margin[0] || 0);
|
|
7861
8315
|
slideItemObj.options._bodyProp.rIns = valToPts(slideItemObj.options.margin[1] || 0);
|
|
7862
8316
|
slideItemObj.options._bodyProp.bIns = valToPts(slideItemObj.options.margin[2] || 0);
|
|
7863
|
-
slideItemObj.options._bodyProp.
|
|
8317
|
+
slideItemObj.options._bodyProp.lIns = valToPts(slideItemObj.options.margin[3] || 0);
|
|
7864
8318
|
} else if (typeof slideItemObj.options.margin === "number") {
|
|
7865
8319
|
slideItemObj.options._bodyProp.lIns = valToPts(slideItemObj.options.margin);
|
|
7866
8320
|
slideItemObj.options._bodyProp.rIns = valToPts(slideItemObj.options.margin);
|
|
@@ -7872,7 +8326,11 @@ function slideObjectToXml(slide) {
|
|
|
7872
8326
|
if (slideItemObj.options.hyperlink?.url) strSlideXml += `<a:hlinkClick r:id="rId${slideItemObj.options.hyperlink._rId}" tooltip="${slideItemObj.options.hyperlink.tooltip ? encodeXmlEntities(slideItemObj.options.hyperlink.tooltip) : ""}"/>`;
|
|
7873
8327
|
if (slideItemObj.options.hyperlink?.slide) strSlideXml += `<a:hlinkClick r:id="rId${slideItemObj.options.hyperlink._rId}" tooltip="${slideItemObj.options.hyperlink.tooltip ? encodeXmlEntities(slideItemObj.options.hyperlink.tooltip) : ""}" action="ppaction://hlinksldjump"/>`;
|
|
7874
8328
|
strSlideXml += "</p:cNvPr>";
|
|
7875
|
-
|
|
8329
|
+
{
|
|
8330
|
+
const spLockXml = genXmlObjectLock("a:spLocks", SHAPE_LOCK_ATTRS, slideItemObj.options.objectLock, slideItemObj.options.objectName);
|
|
8331
|
+
strSlideXml += "<p:cNvSpPr" + (slideItemObj.options?.isTextBox ? " txBox=\"1\"" : "");
|
|
8332
|
+
strSlideXml += spLockXml ? `>${spLockXml}</p:cNvSpPr>` : "/>";
|
|
8333
|
+
}
|
|
7876
8334
|
strSlideXml += `<p:nvPr>${slideItemObj._type === "placeholder" ? genXmlPlaceholder(slideItemObj) : genXmlPlaceholder(placeholderObj)}</p:nvPr>`;
|
|
7877
8335
|
strSlideXml += "</p:nvSpPr><p:spPr>";
|
|
7878
8336
|
strSlideXml += `<a:xfrm${locationAttr}>`;
|
|
@@ -7882,7 +8340,8 @@ function slideObjectToXml(slide) {
|
|
|
7882
8340
|
else strSlideXml += genXmlPresetGeom(slideItemObj.shape, slideItemObj.options, cx, cy);
|
|
7883
8341
|
strSlideXml += slideItemObj.options.fill ? genXmlColorSelection(slideItemObj.options.fill) : "<a:noFill/>";
|
|
7884
8342
|
if (slideItemObj.options.line) {
|
|
7885
|
-
|
|
8343
|
+
const lnAttrs = (slideItemObj.options.line.width ? ` w="${lineWidthToEmu(slideItemObj.options.line.width)}"` : "") + (slideItemObj.options.line.cap ? ` cap="${createLineCap(slideItemObj.options.line.cap)}"` : "");
|
|
8344
|
+
strSlideXml += `<a:ln${lnAttrs}>`;
|
|
7886
8345
|
if (slideItemObj.options.line.color) strSlideXml += genXmlColorSelection(slideItemObj.options.line);
|
|
7887
8346
|
if (slideItemObj.options.line.dashType) strSlideXml += `<a:prstDash val="${slideItemObj.options.line.dashType}"/>`;
|
|
7888
8347
|
if (slideItemObj.options.line.beginArrowType) strSlideXml += `<a:headEnd type="${slideItemObj.options.line.beginArrowType}"/>`;
|
|
@@ -7915,7 +8374,10 @@ function slideObjectToXml(slide) {
|
|
|
7915
8374
|
if (slideItemObj.hyperlink?.url) strSlideXml += `<a:hlinkClick r:id="rId${slideItemObj.hyperlink._rId}" tooltip="${slideItemObj.hyperlink.tooltip ? encodeXmlEntities(slideItemObj.hyperlink.tooltip) : ""}"/>`;
|
|
7916
8375
|
if (slideItemObj.hyperlink?.slide) strSlideXml += `<a:hlinkClick r:id="rId${slideItemObj.hyperlink._rId}" tooltip="${slideItemObj.hyperlink.tooltip ? encodeXmlEntities(slideItemObj.hyperlink.tooltip) : ""}" action="ppaction://hlinksldjump"/>`;
|
|
7917
8376
|
strSlideXml += " </p:cNvPr>";
|
|
7918
|
-
strSlideXml +=
|
|
8377
|
+
strSlideXml += ` <p:cNvPicPr>${genXmlObjectLock("a:picLocks", PICTURE_LOCK_ATTRS, {
|
|
8378
|
+
noChangeAspect: true,
|
|
8379
|
+
...slideItemObj.options.objectLock
|
|
8380
|
+
}, slideItemObj.options.objectName)}</p:cNvPicPr>`;
|
|
7919
8381
|
strSlideXml += " <p:nvPr>" + genXmlPlaceholder(placeholderObj) + "</p:nvPr>";
|
|
7920
8382
|
strSlideXml += " </p:nvPicPr>";
|
|
7921
8383
|
strSlideXml += "<p:blipFill>";
|
|
@@ -7990,7 +8452,7 @@ function slideObjectToXml(slide) {
|
|
|
7990
8452
|
strSlideXml += "<p:pic>";
|
|
7991
8453
|
strSlideXml += " <p:nvPicPr>";
|
|
7992
8454
|
strSlideXml += `<p:cNvPr id="${slideItemObj.mediaRid + 2}" name="${slideItemObj.options.objectName}" descr="${encodeXmlEntities(slideItemObj.options.altText || "")}"/>`;
|
|
7993
|
-
strSlideXml +=
|
|
8455
|
+
strSlideXml += ` <p:cNvPicPr>${genXmlObjectLock("a:picLocks", PICTURE_LOCK_ATTRS, slideItemObj.options.objectLock, slideItemObj.options.objectName)}</p:cNvPicPr>`;
|
|
7994
8456
|
strSlideXml += " <p:nvPr>";
|
|
7995
8457
|
strSlideXml += ` <a:videoFile r:link="rId${slideItemObj.mediaRid}"/>`;
|
|
7996
8458
|
strSlideXml += " </p:nvPr>";
|
|
@@ -8005,7 +8467,10 @@ function slideObjectToXml(slide) {
|
|
|
8005
8467
|
strSlideXml += "<p:pic>";
|
|
8006
8468
|
strSlideXml += " <p:nvPicPr>";
|
|
8007
8469
|
strSlideXml += `<p:cNvPr id="${slideItemObj.mediaRid + 2}" name="${slideItemObj.options.objectName}" descr="${encodeXmlEntities(slideItemObj.options.altText || "")}"><a:hlinkClick r:id="" action="ppaction://media"/></p:cNvPr>`;
|
|
8008
|
-
strSlideXml +=
|
|
8470
|
+
strSlideXml += ` <p:cNvPicPr>${genXmlObjectLock("a:picLocks", PICTURE_LOCK_ATTRS, {
|
|
8471
|
+
noChangeAspect: true,
|
|
8472
|
+
...slideItemObj.options.objectLock
|
|
8473
|
+
}, slideItemObj.options.objectName)}</p:cNvPicPr>`;
|
|
8009
8474
|
strSlideXml += " <p:nvPr>";
|
|
8010
8475
|
strSlideXml += ` <a:videoFile r:link="rId${slideItemObj.mediaRid}"/>`;
|
|
8011
8476
|
strSlideXml += " <p:extLst>";
|
|
@@ -8069,7 +8534,7 @@ function slideObjectToXml(slide) {
|
|
|
8069
8534
|
strSlideXml += "/>";
|
|
8070
8535
|
strSlideXml += " <a:lstStyle><a:lvl1pPr>";
|
|
8071
8536
|
if (slide._slideNumberProps.fontFace || slide._slideNumberProps.fontSize || slide._slideNumberProps.color) {
|
|
8072
|
-
strSlideXml += `<a:defRPr sz="${
|
|
8537
|
+
strSlideXml += `<a:defRPr sz="${clampFontSizeSz(slide._slideNumberProps.fontSize || 12)}">`;
|
|
8073
8538
|
if (slide._slideNumberProps.color) strSlideXml += genXmlColorSelection(slide._slideNumberProps.color);
|
|
8074
8539
|
if (slide._slideNumberProps.fontFace) strSlideXml += `<a:latin typeface="${slide._slideNumberProps.fontFace}"/><a:ea typeface="${slide._slideNumberProps.fontFace}"/><a:cs typeface="${slide._slideNumberProps.fontFace}"/>`;
|
|
8075
8540
|
strSlideXml += "</a:defRPr>";
|
|
@@ -8158,7 +8623,7 @@ function genXmlParagraphProperties(textObj, isDefault) {
|
|
|
8158
8623
|
paragraphPropXml += "";
|
|
8159
8624
|
break;
|
|
8160
8625
|
}
|
|
8161
|
-
if (textObj.options.lineSpacing) strXmlLnSpc = `<a:lnSpc><a:spcPts val="${
|
|
8626
|
+
if (textObj.options.lineSpacing) strXmlLnSpc = `<a:lnSpc><a:spcPts val="${clampLineSpacingPts(textObj.options.lineSpacing)}"/></a:lnSpc>`;
|
|
8162
8627
|
else if (textObj.options.lineSpacingMultiple) strXmlLnSpc = `<a:lnSpc><a:spcPct val="${Math.round(textObj.options.lineSpacingMultiple * 1e5)}"/></a:lnSpc>`;
|
|
8163
8628
|
if (textObj.options.indentLevel && !isNaN(Number(textObj.options.indentLevel)) && textObj.options.indentLevel > 0) paragraphPropXml += ` lvl="${textObj.options.indentLevel}"`;
|
|
8164
8629
|
if (textObj.options.paraSpaceBefore && !isNaN(Number(textObj.options.paraSpaceBefore)) && textObj.options.paraSpaceBefore > 0) strXmlParaSpc += `<a:spcBef><a:spcPts val="${Math.round(textObj.options.paraSpaceBefore * 100)}"/></a:spcBef>`;
|
|
@@ -8212,7 +8677,7 @@ function genXmlTextRunProperties(opts, isDefault) {
|
|
|
8212
8677
|
let runProps = "";
|
|
8213
8678
|
const runPropsTag = isDefault ? "a:defRPr" : "a:rPr";
|
|
8214
8679
|
runProps += "<" + runPropsTag + " lang=\"" + (opts.lang ? opts.lang : "en-US") + "\"" + (opts.lang ? " altLang=\"en-US\"" : "");
|
|
8215
|
-
runProps += opts.fontSize ? ` sz="${
|
|
8680
|
+
runProps += opts.fontSize ? ` sz="${clampFontSizeSz(opts.fontSize)}"` : "";
|
|
8216
8681
|
runProps += opts?.bold ? ` b="${opts.bold ? "1" : "0"}"` : "";
|
|
8217
8682
|
runProps += opts?.italic ? ` i="${opts.italic ? "1" : "0"}"` : "";
|
|
8218
8683
|
runProps += opts?.strike ? ` strike="${typeof opts.strike === "string" ? opts.strike : "sngStrike"}"` : "";
|
|
@@ -8223,17 +8688,23 @@ function genXmlTextRunProperties(opts, isDefault) {
|
|
|
8223
8688
|
if (opts.baseline) runProps += ` baseline="${Math.round(opts.baseline * 50)}"`;
|
|
8224
8689
|
else if (opts.subscript) runProps += " baseline=\"-40000\"";
|
|
8225
8690
|
else if (opts.superscript) runProps += " baseline=\"30000\"";
|
|
8226
|
-
runProps += opts.charSpacing ? ` spc="${
|
|
8691
|
+
runProps += opts.charSpacing ? ` spc="${clampCharSpacingSpc(opts.charSpacing)}" kern="0"` : "";
|
|
8227
8692
|
runProps += " dirty=\"0\">";
|
|
8228
|
-
|
|
8229
|
-
|
|
8693
|
+
const hasShadow = !!opts.shadow && opts.shadow.type !== "none";
|
|
8694
|
+
if (opts.color || opts.fontFace || opts.outline || opts.glow || hasShadow || typeof opts.underline === "object" && opts.underline.color) {
|
|
8695
|
+
if (opts.outline && typeof opts.outline === "object") runProps += `<a:ln w="${lineWidthToEmu(opts.outline.size || .75)}">${genXmlColorSelection(opts.outline.color || "FFFFFF")}</a:ln>`;
|
|
8230
8696
|
if (opts.color) runProps += genXmlColorSelection({
|
|
8231
8697
|
color: opts.color,
|
|
8232
8698
|
transparency: opts.transparency
|
|
8233
8699
|
});
|
|
8700
|
+
if (opts.glow || hasShadow) {
|
|
8701
|
+
runProps += "<a:effectLst>";
|
|
8702
|
+
if (opts.glow) runProps += createGlowElement(opts.glow, DEF_TEXT_GLOW);
|
|
8703
|
+
if (hasShadow) runProps += createShadowElement$1(opts.shadow, DEF_TEXT_SHADOW);
|
|
8704
|
+
runProps += "</a:effectLst>";
|
|
8705
|
+
}
|
|
8234
8706
|
if (opts.highlight) runProps += `<a:highlight>${createColorElement(opts.highlight)}</a:highlight>`;
|
|
8235
8707
|
if (typeof opts.underline === "object" && opts.underline.color) runProps += `<a:uFill>${genXmlColorSelection(opts.underline.color)}</a:uFill>`;
|
|
8236
|
-
if (opts.glow) runProps += `<a:effectLst>${createGlowElement(opts.glow, DEF_TEXT_GLOW)}</a:effectLst>`;
|
|
8237
8708
|
if (opts.fontFace) runProps += `<a:latin typeface="${opts.fontFace}" pitchFamily="34" charset="0"/><a:ea typeface="${opts.fontFace}" pitchFamily="34" charset="-122"/><a:cs typeface="${opts.fontFace}" pitchFamily="34" charset="-120"/>`;
|
|
8238
8709
|
}
|
|
8239
8710
|
if (opts.hyperlink) {
|
|
@@ -8263,6 +8734,28 @@ function genXmlTextRun(textObj) {
|
|
|
8263
8734
|
return `<a:r>${genXmlTextRunProperties(textObj.options, false)}<a:t>${encodeXmlEntities(String(textObj.text))}</a:t></a:r>`;
|
|
8264
8735
|
}
|
|
8265
8736
|
/**
|
|
8737
|
+
* Builds `<a:normAutofit>` with explicit fontScale/lnSpcReduction for "shrink text on overflow"
|
|
8738
|
+
* @param {TextFitShrinkProps} fit - shrink fit options
|
|
8739
|
+
* @return {string} XML string (`<a:normAutofit .../>`)
|
|
8740
|
+
* @see ECMA-376 CT_TextNormAutofit (attributes in 1000ths of a percent)
|
|
8741
|
+
*/
|
|
8742
|
+
function genXmlNormAutofit(fit) {
|
|
8743
|
+
let attrs = "";
|
|
8744
|
+
const pct = (val, name) => {
|
|
8745
|
+
if (val === void 0 || val === null) return null;
|
|
8746
|
+
if (typeof val !== "number" || isNaN(val) || val < 0 || val > 100) {
|
|
8747
|
+
console.warn(`Warning: fit.${name} must be a number between 0 and 100 (percent); received ${String(val)} - attribute ignored.`);
|
|
8748
|
+
return null;
|
|
8749
|
+
}
|
|
8750
|
+
return Math.round(val * 1e3);
|
|
8751
|
+
};
|
|
8752
|
+
const fontScale = pct(fit.fontScale, "fontScale");
|
|
8753
|
+
if (fontScale !== null) attrs += ` fontScale="${fontScale}"`;
|
|
8754
|
+
const lnSpcReduction = pct(fit.lnSpcReduction, "lnSpcReduction");
|
|
8755
|
+
if (lnSpcReduction !== null) attrs += ` lnSpcReduction="${lnSpcReduction}"`;
|
|
8756
|
+
return `<a:normAutofit${attrs}/>`;
|
|
8757
|
+
}
|
|
8758
|
+
/**
|
|
8266
8759
|
* Builds `<a:bodyPr></a:bodyPr>` tag for "genXmlTextBody()"
|
|
8267
8760
|
* @param {ISlideObject | TableCell} slideObject - various options
|
|
8268
8761
|
* @return {string} XML string
|
|
@@ -8275,6 +8768,8 @@ function genXmlBodyProperties(slideObject) {
|
|
|
8275
8768
|
if (slideObject.options._bodyProp.tIns || slideObject.options._bodyProp.tIns === 0) bodyProperties += ` tIns="${slideObject.options._bodyProp.tIns}"`;
|
|
8276
8769
|
if (slideObject.options._bodyProp.rIns || slideObject.options._bodyProp.rIns === 0) bodyProperties += ` rIns="${slideObject.options._bodyProp.rIns}"`;
|
|
8277
8770
|
if (slideObject.options._bodyProp.bIns || slideObject.options._bodyProp.bIns === 0) bodyProperties += ` bIns="${slideObject.options._bodyProp.bIns}"`;
|
|
8771
|
+
if (slideObject.options._bodyProp.numCol) bodyProperties += ` numCol="${slideObject.options._bodyProp.numCol}"`;
|
|
8772
|
+
if (slideObject.options._bodyProp.spcCol) bodyProperties += ` spcCol="${slideObject.options._bodyProp.spcCol}"`;
|
|
8278
8773
|
bodyProperties += " rtlCol=\"0\"";
|
|
8279
8774
|
if (slideObject.options._bodyProp.anchor) bodyProperties += " anchor=\"" + slideObject.options._bodyProp.anchor + "\"";
|
|
8280
8775
|
if (slideObject.options._bodyProp.vert) bodyProperties += " vert=\"" + slideObject.options._bodyProp.vert + "\"";
|
|
@@ -8285,9 +8780,11 @@ function genXmlBodyProperties(slideObject) {
|
|
|
8285
8780
|
* @see: http://www.datypic.com/sc/ooxml/g-a_EG_TextAutofit.html
|
|
8286
8781
|
*/
|
|
8287
8782
|
if (slideObject.options.fit) {
|
|
8288
|
-
|
|
8289
|
-
|
|
8290
|
-
else if (
|
|
8783
|
+
const fit = slideObject.options.fit;
|
|
8784
|
+
if (fit === "none") bodyProperties += "";
|
|
8785
|
+
else if (fit === "shrink") bodyProperties += "<a:normAutofit/>";
|
|
8786
|
+
else if (fit === "resize") bodyProperties += "<a:spAutoFit/>";
|
|
8787
|
+
else if (typeof fit === "object" && fit.type === "shrink") bodyProperties += genXmlNormAutofit(fit);
|
|
8291
8788
|
}
|
|
8292
8789
|
if (slideObject.options.shrinkText) bodyProperties += "<a:normAutofit/>";
|
|
8293
8790
|
bodyProperties += slideObject.options._bodyProp.autoFit ? "<a:spAutoFit/>" : "";
|
|
@@ -8423,13 +8920,13 @@ function genXmlTextBody(slideObj) {
|
|
|
8423
8920
|
}
|
|
8424
8921
|
});
|
|
8425
8922
|
if (slideObj._type === "tablecell" && (opts.fontSize || opts.fontFace)) if (opts.fontFace) {
|
|
8426
|
-
strSlideXml += `<a:endParaRPr lang="${opts.lang || "en-US"}"` + (opts.fontSize ? ` sz="${
|
|
8923
|
+
strSlideXml += `<a:endParaRPr lang="${opts.lang || "en-US"}"` + (opts.fontSize ? ` sz="${clampFontSizeSz(opts.fontSize)}"` : "") + " dirty=\"0\">";
|
|
8427
8924
|
strSlideXml += `<a:latin typeface="${opts.fontFace}" charset="0"/>`;
|
|
8428
8925
|
strSlideXml += `<a:ea typeface="${opts.fontFace}" charset="0"/>`;
|
|
8429
8926
|
strSlideXml += `<a:cs typeface="${opts.fontFace}" charset="0"/>`;
|
|
8430
8927
|
strSlideXml += "</a:endParaRPr>";
|
|
8431
|
-
} else strSlideXml += `<a:endParaRPr lang="${opts.lang || "en-US"}"` + (opts.fontSize ? ` sz="${
|
|
8432
|
-
else if (reqsClosingFontSize) strSlideXml += `<a:endParaRPr lang="${opts.lang || "en-US"}"` + (opts.fontSize ? ` sz="${
|
|
8928
|
+
} else strSlideXml += `<a:endParaRPr lang="${opts.lang || "en-US"}"` + (opts.fontSize ? ` sz="${clampFontSizeSz(opts.fontSize)}"` : "") + " dirty=\"0\"/>";
|
|
8929
|
+
else if (reqsClosingFontSize) strSlideXml += `<a:endParaRPr lang="${opts.lang || "en-US"}"` + (opts.fontSize ? ` sz="${clampFontSizeSz(opts.fontSize)}"` : "") + " dirty=\"0\"/>";
|
|
8433
8930
|
else strSlideXml += `<a:endParaRPr lang="${opts.lang || "en-US"}" dirty="0"/>`;
|
|
8434
8931
|
strSlideXml += "</a:p>";
|
|
8435
8932
|
});
|
|
@@ -8905,7 +9402,7 @@ function genXmlTableStyleBorders(border) {
|
|
|
8905
9402
|
xml += `<a:${side}>`;
|
|
8906
9403
|
if (b.type === "none") xml += "<a:ln><a:noFill/></a:ln>";
|
|
8907
9404
|
else {
|
|
8908
|
-
xml += `<a:ln w="${
|
|
9405
|
+
xml += `<a:ln w="${lineWidthToEmu(b.pt ?? 1)}" cap="flat" cmpd="sng" algn="ctr">`;
|
|
8909
9406
|
xml += `<a:solidFill>${createColorElement(b.color ?? "666666")}</a:solidFill>`;
|
|
8910
9407
|
xml += `<a:prstDash val="${b.type === "dash" ? "sysDash" : "solid"}"/>`;
|
|
8911
9408
|
xml += "</a:ln>";
|
|
@@ -8983,7 +9480,7 @@ function makeXmlViewProps() {
|
|
|
8983
9480
|
* @see https://docs.microsoft.com/en-us/office/open-xml/structure-of-a-presentationml-document
|
|
8984
9481
|
* @see https://docs.microsoft.com/en-us/previous-versions/office/developer/office-2010/hh273476(v=office.14)
|
|
8985
9482
|
*/
|
|
8986
|
-
const VERSION = "5.
|
|
9483
|
+
const VERSION = "5.3.0";
|
|
8987
9484
|
function standardLayoutToPresLayout(layout) {
|
|
8988
9485
|
return {
|
|
8989
9486
|
name: layout.name,
|
|
@@ -9315,6 +9812,18 @@ var PptxGenJS$1 = class {
|
|
|
9315
9812
|
});
|
|
9316
9813
|
arrMediaPromises = arrMediaPromises.concat(encodeSlideMediaRels(this._masterSlide, this._runtime));
|
|
9317
9814
|
return await Promise.all(arrMediaPromises).then(async () => {
|
|
9815
|
+
const canonicalMediaTargets = /* @__PURE__ */ new Map();
|
|
9816
|
+
for (const target of [
|
|
9817
|
+
...this._slides,
|
|
9818
|
+
...this._slideLayouts,
|
|
9819
|
+
this._masterSlide
|
|
9820
|
+
]) for (const rel of target._relsMedia || []) {
|
|
9821
|
+
if (rel.type === "online" || rel.type === "hyperlink" || typeof rel.data !== "string" || !rel.data) continue;
|
|
9822
|
+
const key = (rel.extn || "") + "\0" + rel.data;
|
|
9823
|
+
const canonical = canonicalMediaTargets.get(key);
|
|
9824
|
+
if (canonical) rel.Target = canonical;
|
|
9825
|
+
else canonicalMediaTargets.set(key, rel.Target);
|
|
9826
|
+
}
|
|
9318
9827
|
this._slides.forEach((slide) => {
|
|
9319
9828
|
if (slide._slideLayout) addPlaceholdersToSlideLayouts(slide);
|
|
9320
9829
|
});
|
|
@@ -9666,6 +10175,6 @@ var PptxGenJS = class extends PptxGenJS$1 {
|
|
|
9666
10175
|
}
|
|
9667
10176
|
};
|
|
9668
10177
|
//#endregion
|
|
9669
|
-
export { AXIS_ID_CATEGORY_PRIMARY, AXIS_ID_CATEGORY_SECONDARY, AXIS_ID_SERIES_PRIMARY, AXIS_ID_VALUE_PRIMARY, AXIS_ID_VALUE_SECONDARY, AlignH, AlignV, BARCHART_COLORS, BULLET_TYPES, CHART_TYPE, CRLF, ChartType, DEF_BULLET_MARGIN, DEF_CELL_BORDER, DEF_CELL_MARGIN_IN, DEF_CELL_MARGIN_PT, DEF_CHART_BORDER, DEF_CHART_GRIDLINE, DEF_FONT_COLOR, DEF_FONT_SIZE, DEF_FONT_TITLE_SIZE, DEF_PRES_LAYOUT, DEF_PRES_LAYOUT_NAME, DEF_SHAPE_LINE_COLOR, DEF_SHAPE_SHADOW, DEF_SLIDE_BKGD, DEF_SLIDE_MARGIN_IN, DEF_TEXT_GLOW, DEF_TEXT_SHADOW, EMU, EMU_PER_INCH, EMU_PER_POINT, IMG_BROKEN, IMG_PLAYBTN, IMG_SVG_PLACEHOLDER, LAYOUT_IDX_SERIES_BASE, LETTERS, LINEH_MODIFIER, MASTER_OBJECTS, ONEPT, OutputType, PIECHART_COLORS, PLACEHOLDER_TYPES, POINTS_PER_INCH, PptxGenJS, PptxGenJS as Presentation, PptxGenJS as default, REGEX_HEX_COLOR, SCHEME_COLOR_NAMES, SHAPE_TYPE, SLDNUMFLDID, SLIDE_OBJECT_TYPES, STANDARD_LAYOUTS, SchemeColor, ShapeType, TABLE_STYLE, TEXT_HALIGN, TEXT_VALIGN, emuToInches, emuToPixels, emuToPoints, inchesToEmu, pixelsToEmu, pointsToEmu, textRun, textRuns };
|
|
10178
|
+
export { AXIS_ID_CATEGORY_PRIMARY, AXIS_ID_CATEGORY_SECONDARY, AXIS_ID_SERIES_PRIMARY, AXIS_ID_VALUE_PRIMARY, AXIS_ID_VALUE_SECONDARY, AlignH, AlignV, BARCHART_COLORS, BULLET_TYPES, CHART_TYPE, CRLF, ChartType, DEF_BULLET_MARGIN, DEF_CELL_BORDER, DEF_CELL_MARGIN_IN, DEF_CELL_MARGIN_PT, DEF_CHART_BORDER, DEF_CHART_GRIDLINE, DEF_FONT_COLOR, DEF_FONT_SIZE, DEF_FONT_TITLE_SIZE, DEF_PRES_LAYOUT, DEF_PRES_LAYOUT_NAME, DEF_SHAPE_LINE_COLOR, DEF_SHAPE_SHADOW, DEF_SLIDE_BKGD, DEF_SLIDE_MARGIN_IN, DEF_TEXT_GLOW, DEF_TEXT_SHADOW, EMU, EMU_PER_INCH, EMU_PER_POINT, IMG_BROKEN, IMG_PLAYBTN, IMG_SVG_PLACEHOLDER, LAYOUT_IDX_SERIES_BASE, LETTERS, LINEH_MODIFIER, MASTER_OBJECTS, ONEPT, OutputType, PIECHART_COLORS, PLACEHOLDER_TYPES, POINTS_PER_INCH, PptxGenJS, PptxGenJS as Presentation, PptxGenJS as default, REGEX_HEX_COLOR, SCHEME_COLOR_NAMES, SHAPE_TYPE, SLDNUMFLDID, SLIDE_OBJECT_TYPES, STANDARD_LAYOUTS, SchemeColor, ShapeType, TABLE_STYLE, TEXT_HALIGN, TEXT_VALIGN, VALID_SHAPE_PRESETS, coordToEmu, emuToInches, emuToPixels, emuToPoints, inchesToEmu, percentToEmu, pixelsToEmu, pointsToEmu, textRun, textRuns };
|
|
9670
10179
|
|
|
9671
10180
|
//# sourceMappingURL=standalone.js.map
|