@jsamuel1/pptxgenjs 4.1.1 → 4.1.2
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/pptxgen.bundle.js +26 -26
- package/dist/pptxgen.bundle.js.map +1 -1
- package/dist/pptxgen.cjs.js +195 -20
- package/dist/pptxgen.es.js +195 -20
- package/dist/pptxgen.min.js +31 -31
- package/dist/pptxgen.min.js.map +1 -1
- package/package.json +1 -1
package/dist/pptxgen.cjs.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/* PptxGenJS 4.1.
|
|
1
|
+
/* PptxGenJS 4.1.1 @ 2026-06-07T21:17:30.867Z */
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
4
|
var JSZip = require('jszip');
|
|
@@ -581,6 +581,7 @@ var MASTER_OBJECTS;
|
|
|
581
581
|
var SLIDE_OBJECT_TYPES;
|
|
582
582
|
(function (SLIDE_OBJECT_TYPES) {
|
|
583
583
|
SLIDE_OBJECT_TYPES["chart"] = "chart";
|
|
584
|
+
SLIDE_OBJECT_TYPES["group"] = "group";
|
|
584
585
|
SLIDE_OBJECT_TYPES["hyperlink"] = "hyperlink";
|
|
585
586
|
SLIDE_OBJECT_TYPES["image"] = "image";
|
|
586
587
|
SLIDE_OBJECT_TYPES["media"] = "media";
|
|
@@ -2480,6 +2481,90 @@ function addShapeDefinition(target, shapeName, opts) {
|
|
|
2480
2481
|
// LAST: Add object to slide
|
|
2481
2482
|
target._slideObjects.push(newObject);
|
|
2482
2483
|
}
|
|
2484
|
+
/**
|
|
2485
|
+
* Feature 7: Adds a rounded-rectangle callout/badge to a slide definition.
|
|
2486
|
+
* Thin sugar over `addTextDefinition` with `shape:'roundRect'`, centred text, and a
|
|
2487
|
+
* corner-radius `adj` value computed from `cornerRadius` (inches) per:
|
|
2488
|
+
* `adj = Math.round((cornerRadius / (h / 2)) * 50000)`.
|
|
2489
|
+
* @param {PresSlide} target slide object that the callout should be added to
|
|
2490
|
+
* @param {CalloutProps} opts callout options
|
|
2491
|
+
*/
|
|
2492
|
+
function addCalloutDefinition(target, opts) {
|
|
2493
|
+
const options = typeof opts === 'object' ? opts : {};
|
|
2494
|
+
const h = options.h !== undefined ? Number(options.h) : 0.4;
|
|
2495
|
+
const w = options.w !== undefined ? options.w : 1.5;
|
|
2496
|
+
const cornerRadius = options.cornerRadius !== undefined ? options.cornerRadius : 0.1;
|
|
2497
|
+
// Map inches -> OOXML `adj` (percentage of half-shortest-side × 1000). Guard divide-by-zero.
|
|
2498
|
+
const calloutAdj = h > 0 ? Math.round((cornerRadius / (h / 2)) * 50000) : 0;
|
|
2499
|
+
const fill = options.fill !== undefined ? options.fill : '7C3AED';
|
|
2500
|
+
const textOpts = {
|
|
2501
|
+
shape: SHAPE_TYPE.ROUNDED_RECTANGLE,
|
|
2502
|
+
x: options.x !== undefined ? options.x : 1,
|
|
2503
|
+
y: options.y !== undefined ? options.y : 1,
|
|
2504
|
+
w,
|
|
2505
|
+
h,
|
|
2506
|
+
fill: typeof fill === 'string' ? { color: fill } : fill,
|
|
2507
|
+
color: options.fontColor !== undefined ? options.fontColor : 'FFFFFF',
|
|
2508
|
+
fontSize: options.fontSize !== undefined ? options.fontSize : 12,
|
|
2509
|
+
bold: options.fontBold !== undefined ? options.fontBold : true,
|
|
2510
|
+
align: options.align || 'center',
|
|
2511
|
+
valign: options.valign || 'middle',
|
|
2512
|
+
_calloutAdj: calloutAdj,
|
|
2513
|
+
};
|
|
2514
|
+
if (options.objectName)
|
|
2515
|
+
textOpts.objectName = options.objectName;
|
|
2516
|
+
addTextDefinition(target, [{ text: options.text || '', options: null }], textOpts, false);
|
|
2517
|
+
}
|
|
2518
|
+
/**
|
|
2519
|
+
* Feature 6: Adds a shape group to a slide definition and returns a group handle.
|
|
2520
|
+
* The group emits a `<p:grpSp>` whose `<a:xfrm>` carries the absolute position/size plus
|
|
2521
|
+
* `chOff="0,0"`/`chExt` equal to the extent — so child shapes/text use coordinates relative
|
|
2522
|
+
* to the group origin (1:1 scale). Children are added via the returned object's
|
|
2523
|
+
* `addShape()` / `addText()`, which reuse the existing shape/text intake but push onto the
|
|
2524
|
+
* group's private child array instead of the slide.
|
|
2525
|
+
* @param {PresSlide} target slide the group should be added to
|
|
2526
|
+
* @param {GroupProps} opts group position/size options
|
|
2527
|
+
* @return {SlideGroup} group handle exposing `addShape` / `addText`
|
|
2528
|
+
*/
|
|
2529
|
+
function addGroupDefinition(target, opts) {
|
|
2530
|
+
const options = typeof opts === 'object' ? opts : {};
|
|
2531
|
+
const grpObjects = [];
|
|
2532
|
+
const groupObj = {
|
|
2533
|
+
_type: SLIDE_OBJECT_TYPES.group,
|
|
2534
|
+
options: {
|
|
2535
|
+
x: options.x !== undefined ? options.x : 0,
|
|
2536
|
+
y: options.y !== undefined ? options.y : 0,
|
|
2537
|
+
w: options.w !== undefined ? options.w : 0,
|
|
2538
|
+
h: options.h !== undefined ? options.h : 0,
|
|
2539
|
+
objectName: options.objectName ? encodeXmlEntities(options.objectName) : `Group ${target._slideObjects.filter(obj => obj._type === SLIDE_OBJECT_TYPES.group).length + 1}`,
|
|
2540
|
+
},
|
|
2541
|
+
_grpObjects: grpObjects,
|
|
2542
|
+
};
|
|
2543
|
+
target._slideObjects.push(groupObj);
|
|
2544
|
+
// Proxy target: existing intake fns push onto the group's child array but reuse the parent
|
|
2545
|
+
// slide's rels/layout/color so child shapes/text render identically to top-level ones.
|
|
2546
|
+
const childTarget = {
|
|
2547
|
+
_slideObjects: grpObjects,
|
|
2548
|
+
_rels: target._rels,
|
|
2549
|
+
_relsChart: target._relsChart,
|
|
2550
|
+
_relsMedia: target._relsMedia,
|
|
2551
|
+
_slideLayout: target._slideLayout,
|
|
2552
|
+
_presLayout: target._presLayout,
|
|
2553
|
+
color: target.color,
|
|
2554
|
+
};
|
|
2555
|
+
const group = {
|
|
2556
|
+
addShape(shapeName, shapeOpts) {
|
|
2557
|
+
addShapeDefinition(childTarget, shapeName, (shapeOpts || {}));
|
|
2558
|
+
return group;
|
|
2559
|
+
},
|
|
2560
|
+
addText(text, textOpts) {
|
|
2561
|
+
const textParam = typeof text === 'string' || typeof text === 'number' ? [{ text, options: textOpts }] : text;
|
|
2562
|
+
addTextDefinition(childTarget, textParam, (textOpts || {}), false);
|
|
2563
|
+
return group;
|
|
2564
|
+
},
|
|
2565
|
+
};
|
|
2566
|
+
return group;
|
|
2567
|
+
}
|
|
2483
2568
|
/**
|
|
2484
2569
|
* Adds a table object to a slide definition.
|
|
2485
2570
|
* @param {PresSlide} target - slide object that the table should be added to
|
|
@@ -3163,6 +3248,27 @@ class Slide {
|
|
|
3163
3248
|
addShapeDefinition(this, shapeName, options);
|
|
3164
3249
|
return this;
|
|
3165
3250
|
}
|
|
3251
|
+
/**
|
|
3252
|
+
* Add a shape group to Slide (Feature 6).
|
|
3253
|
+
* Returns a group handle whose `addShape()`/`addText()` use coordinates relative to the
|
|
3254
|
+
* group origin; the group emits a `<p:grpSp>` with an absolute `<a:xfrm>` + `chOff`/`chExt`.
|
|
3255
|
+
* @param {GroupProps} options - group position/size options
|
|
3256
|
+
* @return {SlideGroup} group handle exposing `addShape` / `addText`
|
|
3257
|
+
*/
|
|
3258
|
+
addGroup(options) {
|
|
3259
|
+
return addGroupDefinition(this, options);
|
|
3260
|
+
}
|
|
3261
|
+
/**
|
|
3262
|
+
* Add a rounded-rectangle callout/badge to Slide (Feature 7).
|
|
3263
|
+
* Sugar over `addShape('roundRect', …)` with centred text and an `adj`
|
|
3264
|
+
* corner-radius derived from `cornerRadius` (inches).
|
|
3265
|
+
* @param {CalloutProps} options - callout options
|
|
3266
|
+
* @return {Slide} this Slide
|
|
3267
|
+
*/
|
|
3268
|
+
addCallout(options) {
|
|
3269
|
+
addCalloutDefinition(this, options);
|
|
3270
|
+
return this;
|
|
3271
|
+
}
|
|
3166
3272
|
/**
|
|
3167
3273
|
* Add table to Slide
|
|
3168
3274
|
* @param {TableRow[]} tableRows - table rows
|
|
@@ -5796,7 +5902,11 @@ function slideObjectToXml(slide) {
|
|
|
5796
5902
|
}
|
|
5797
5903
|
else {
|
|
5798
5904
|
strSlideXml += '<a:prstGeom prst="' + slideItemObj.shape + '"><a:avLst>';
|
|
5799
|
-
if (slideItemObj.options.
|
|
5905
|
+
if (slideItemObj.options._calloutAdj !== undefined && slideItemObj.options._calloutAdj !== null) {
|
|
5906
|
+
// Feature 7: addCallout() supplies a pre-computed `adj` value; emit it verbatim.
|
|
5907
|
+
strSlideXml += `<a:gd name="adj" fmla="val ${slideItemObj.options._calloutAdj}"/>`;
|
|
5908
|
+
}
|
|
5909
|
+
else if (slideItemObj.options.rectRadius) {
|
|
5800
5910
|
strSlideXml += `<a:gd name="adj" fmla="val ${Math.round((slideItemObj.options.rectRadius * EMU * 100000) / Math.min(cx, cy))}"/>`;
|
|
5801
5911
|
}
|
|
5802
5912
|
else if (slideItemObj.options.angleRange) {
|
|
@@ -5826,23 +5936,33 @@ function slideObjectToXml(slide) {
|
|
|
5826
5936
|
// FUTURE: `endArrowSize` < a: headEnd type = "arrow" w = "lg" len = "lg" /> 'sm' | 'med' | 'lg'(values are 1 - 9, making a 3x3 grid of w / len possibilities)
|
|
5827
5937
|
strSlideXml += '</a:ln>';
|
|
5828
5938
|
}
|
|
5829
|
-
// EFFECTS > SHADOW: REF: @see http://officeopenxml.com/drwSp-effects.php
|
|
5830
|
-
|
|
5831
|
-
|
|
5832
|
-
|
|
5833
|
-
const
|
|
5834
|
-
|
|
5835
|
-
|
|
5836
|
-
|
|
5837
|
-
|
|
5838
|
-
|
|
5839
|
-
|
|
5840
|
-
|
|
5841
|
-
|
|
5842
|
-
|
|
5843
|
-
|
|
5844
|
-
|
|
5845
|
-
|
|
5939
|
+
// EFFECTS > SHADOW + GLOW (Feature 10): REF: @see http://officeopenxml.com/drwSp-effects.php
|
|
5940
|
+
// Both effects share a single <a:effectLst>; emit it once if either is present.
|
|
5941
|
+
{
|
|
5942
|
+
const hasShadow = !!(slideItemObj.options.shadow && slideItemObj.options.shadow.type !== 'none');
|
|
5943
|
+
const hasGlow = !!slideItemObj.options.glow;
|
|
5944
|
+
if (hasShadow || hasGlow) {
|
|
5945
|
+
strSlideXml += '<a:effectLst>';
|
|
5946
|
+
if (hasShadow) {
|
|
5947
|
+
// derive emit-time values into locals so we don't mutate the user's options.shadow
|
|
5948
|
+
// (re-emission would otherwise re-convert pt→EMU and produce absurd values).
|
|
5949
|
+
const sh = slideItemObj.options.shadow;
|
|
5950
|
+
const shadowType = sh.type || 'outer';
|
|
5951
|
+
const shadowBlur = valToPts(sh.blur || 8);
|
|
5952
|
+
const shadowOffset = valToPts(sh.offset || 4);
|
|
5953
|
+
const shadowAngle = Math.round((sh.angle || 270) * 60000);
|
|
5954
|
+
const shadowOpacity = Math.round((sh.opacity || 0.75) * 100000);
|
|
5955
|
+
const shadowColor = sh.color || DEF_TEXT_SHADOW.color;
|
|
5956
|
+
strSlideXml += `<a:${shadowType}Shdw ${shadowType === 'outer' ? 'sx="100000" sy="100000" kx="0" ky="0" algn="bl" rotWithShape="0"' : ''} blurRad="${shadowBlur}" dist="${shadowOffset}" dir="${shadowAngle}">`;
|
|
5957
|
+
strSlideXml += `<a:srgbClr val="${shadowColor}">`;
|
|
5958
|
+
strSlideXml += `<a:alpha val="${shadowOpacity}"/></a:srgbClr>`;
|
|
5959
|
+
strSlideXml += `</a:${shadowType}Shdw>`;
|
|
5960
|
+
}
|
|
5961
|
+
if (hasGlow) {
|
|
5962
|
+
strSlideXml += createGlowElement(slideItemObj.options.glow, DEF_TEXT_GLOW);
|
|
5963
|
+
}
|
|
5964
|
+
strSlideXml += '</a:effectLst>';
|
|
5965
|
+
}
|
|
5846
5966
|
}
|
|
5847
5967
|
/* TODO: FUTURE: Text wrapping (copied from MS-PPTX export)
|
|
5848
5968
|
// Commented out b/c i'm not even sure this works - current code produces text that wraps in shapes and textboxes, so...
|
|
@@ -5990,6 +6110,20 @@ function slideObjectToXml(slide) {
|
|
|
5990
6110
|
strSlideXml += ' </a:graphic>';
|
|
5991
6111
|
strSlideXml += '</p:graphicFrame>';
|
|
5992
6112
|
break;
|
|
6113
|
+
case SLIDE_OBJECT_TYPES.group:
|
|
6114
|
+
// Feature 6: nested shape group. The `<a:xfrm>` carries the absolute position/size;
|
|
6115
|
+
// `chOff="0,0"` + `chExt`=ext gives a 1:1 child coordinate space, so children use
|
|
6116
|
+
// coordinates relative to the group origin. Children reuse the standard shape/text
|
|
6117
|
+
// emitters via `genGroupChildrenXml`.
|
|
6118
|
+
strSlideXml += '<p:grpSp>';
|
|
6119
|
+
strSlideXml += `<p:nvGrpSpPr><p:cNvPr id="${idx + 2}" name="${slideItemObj.options.objectName || `Group ${idx + 1}`}"/><p:cNvGrpSpPr/><p:nvPr/></p:nvGrpSpPr>`;
|
|
6120
|
+
strSlideXml += `<p:grpSpPr><a:xfrm${locationAttr}>`;
|
|
6121
|
+
strSlideXml += `<a:off x="${x}" y="${y}"/><a:ext cx="${cx}" cy="${cy}"/>`;
|
|
6122
|
+
strSlideXml += `<a:chOff x="0" y="0"/><a:chExt cx="${cx}" cy="${cy}"/>`;
|
|
6123
|
+
strSlideXml += '</a:xfrm></p:grpSpPr>';
|
|
6124
|
+
strSlideXml += genGroupChildrenXml(slide, slideItemObj._grpObjects, idx);
|
|
6125
|
+
strSlideXml += '</p:grpSp>';
|
|
6126
|
+
break;
|
|
5993
6127
|
default:
|
|
5994
6128
|
strSlideXml += '';
|
|
5995
6129
|
break;
|
|
@@ -6061,6 +6195,47 @@ function slideObjectToXml(slide) {
|
|
|
6061
6195
|
// LAST: Return
|
|
6062
6196
|
return strSlideXml;
|
|
6063
6197
|
}
|
|
6198
|
+
/**
|
|
6199
|
+
* Feature 6: Render a shape group's child objects as the inner markup of a `<p:grpSp>`.
|
|
6200
|
+
* Reuses the full slide emitter (`slideObjectToXml`) on the same slide with its object list
|
|
6201
|
+
* temporarily swapped to the group's children (and slide-number footer suppressed), then
|
|
6202
|
+
* extracts just the `<p:spTree>` child markup (everything after the root `</p:grpSpPr>` up to
|
|
6203
|
+
* `</p:spTree>`). Child `<p:cNvPr>` ids are offset to stay unique within the slide part so
|
|
6204
|
+
* PowerPoint does not flag the file for repair.
|
|
6205
|
+
* @param {PresSlide | SlideLayout} slide - parent slide (provides layout/rels/presLayout)
|
|
6206
|
+
* @param {ISlideObject[]} grpObjects - the group's child slide objects
|
|
6207
|
+
* @param {number} groupIdx - the group's index within the slide (used to namespace child ids)
|
|
6208
|
+
* @return {string} child markup to nest inside `<p:grpSp>`
|
|
6209
|
+
*/
|
|
6210
|
+
function genGroupChildrenXml(slide, grpObjects, groupIdx) {
|
|
6211
|
+
if (!grpObjects || grpObjects.length === 0)
|
|
6212
|
+
return '';
|
|
6213
|
+
// Temporarily render the children through the normal slide pipeline. Background is emitted
|
|
6214
|
+
// before `<p:spTree>` (outside the extracted region) so it is harmless; the slide-number
|
|
6215
|
+
// footer is emitted inside `<p:spTree>`, so suppress it during the recursive render.
|
|
6216
|
+
const savedObjects = slide._slideObjects;
|
|
6217
|
+
const savedSlideNum = slide._slideNumberProps;
|
|
6218
|
+
slide._slideObjects = grpObjects;
|
|
6219
|
+
slide._slideNumberProps = null;
|
|
6220
|
+
let fullXml;
|
|
6221
|
+
try {
|
|
6222
|
+
fullXml = slideObjectToXml(slide);
|
|
6223
|
+
}
|
|
6224
|
+
finally {
|
|
6225
|
+
slide._slideObjects = savedObjects;
|
|
6226
|
+
slide._slideNumberProps = savedSlideNum;
|
|
6227
|
+
}
|
|
6228
|
+
const startMarker = '</p:grpSpPr>';
|
|
6229
|
+
const startIdx = fullXml.indexOf(startMarker);
|
|
6230
|
+
const endIdx = fullXml.lastIndexOf('</p:spTree>');
|
|
6231
|
+
if (startIdx === -1 || endIdx === -1 || endIdx <= startIdx)
|
|
6232
|
+
return '';
|
|
6233
|
+
let childXml = fullXml.substring(startIdx + startMarker.length, endIdx);
|
|
6234
|
+
// Keep child cNvPr ids unique within the slide part (avoid PowerPoint "needs repair").
|
|
6235
|
+
const idBase = (groupIdx + 1) * 1000;
|
|
6236
|
+
childXml = childXml.replace(/<p:cNvPr id="(\d+)"/g, (_m, n) => `<p:cNvPr id="${idBase + Number(n)}"`);
|
|
6237
|
+
return childXml;
|
|
6238
|
+
}
|
|
6064
6239
|
/**
|
|
6065
6240
|
* Transforms slide relations to XML string.
|
|
6066
6241
|
* Extra relations that are not dynamic can be passed using the 2nd arg (e.g. theme relation in master file).
|
|
@@ -7396,7 +7571,7 @@ function makeXmlViewProps() {
|
|
|
7396
7571
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
7397
7572
|
* SOFTWARE.
|
|
7398
7573
|
*/
|
|
7399
|
-
const VERSION = '4.
|
|
7574
|
+
const VERSION = '4.1.1';
|
|
7400
7575
|
class PptxGenJS {
|
|
7401
7576
|
set layout(value) {
|
|
7402
7577
|
const newLayout = this.LAYOUTS[value];
|
package/dist/pptxgen.es.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/* PptxGenJS 4.1.
|
|
1
|
+
/* PptxGenJS 4.1.1 @ 2026-06-07T21:17:30.873Z */
|
|
2
2
|
import JSZip from 'jszip';
|
|
3
3
|
|
|
4
4
|
/******************************************************************************
|
|
@@ -579,6 +579,7 @@ var MASTER_OBJECTS;
|
|
|
579
579
|
var SLIDE_OBJECT_TYPES;
|
|
580
580
|
(function (SLIDE_OBJECT_TYPES) {
|
|
581
581
|
SLIDE_OBJECT_TYPES["chart"] = "chart";
|
|
582
|
+
SLIDE_OBJECT_TYPES["group"] = "group";
|
|
582
583
|
SLIDE_OBJECT_TYPES["hyperlink"] = "hyperlink";
|
|
583
584
|
SLIDE_OBJECT_TYPES["image"] = "image";
|
|
584
585
|
SLIDE_OBJECT_TYPES["media"] = "media";
|
|
@@ -2478,6 +2479,90 @@ function addShapeDefinition(target, shapeName, opts) {
|
|
|
2478
2479
|
// LAST: Add object to slide
|
|
2479
2480
|
target._slideObjects.push(newObject);
|
|
2480
2481
|
}
|
|
2482
|
+
/**
|
|
2483
|
+
* Feature 7: Adds a rounded-rectangle callout/badge to a slide definition.
|
|
2484
|
+
* Thin sugar over `addTextDefinition` with `shape:'roundRect'`, centred text, and a
|
|
2485
|
+
* corner-radius `adj` value computed from `cornerRadius` (inches) per:
|
|
2486
|
+
* `adj = Math.round((cornerRadius / (h / 2)) * 50000)`.
|
|
2487
|
+
* @param {PresSlide} target slide object that the callout should be added to
|
|
2488
|
+
* @param {CalloutProps} opts callout options
|
|
2489
|
+
*/
|
|
2490
|
+
function addCalloutDefinition(target, opts) {
|
|
2491
|
+
const options = typeof opts === 'object' ? opts : {};
|
|
2492
|
+
const h = options.h !== undefined ? Number(options.h) : 0.4;
|
|
2493
|
+
const w = options.w !== undefined ? options.w : 1.5;
|
|
2494
|
+
const cornerRadius = options.cornerRadius !== undefined ? options.cornerRadius : 0.1;
|
|
2495
|
+
// Map inches -> OOXML `adj` (percentage of half-shortest-side × 1000). Guard divide-by-zero.
|
|
2496
|
+
const calloutAdj = h > 0 ? Math.round((cornerRadius / (h / 2)) * 50000) : 0;
|
|
2497
|
+
const fill = options.fill !== undefined ? options.fill : '7C3AED';
|
|
2498
|
+
const textOpts = {
|
|
2499
|
+
shape: SHAPE_TYPE.ROUNDED_RECTANGLE,
|
|
2500
|
+
x: options.x !== undefined ? options.x : 1,
|
|
2501
|
+
y: options.y !== undefined ? options.y : 1,
|
|
2502
|
+
w,
|
|
2503
|
+
h,
|
|
2504
|
+
fill: typeof fill === 'string' ? { color: fill } : fill,
|
|
2505
|
+
color: options.fontColor !== undefined ? options.fontColor : 'FFFFFF',
|
|
2506
|
+
fontSize: options.fontSize !== undefined ? options.fontSize : 12,
|
|
2507
|
+
bold: options.fontBold !== undefined ? options.fontBold : true,
|
|
2508
|
+
align: options.align || 'center',
|
|
2509
|
+
valign: options.valign || 'middle',
|
|
2510
|
+
_calloutAdj: calloutAdj,
|
|
2511
|
+
};
|
|
2512
|
+
if (options.objectName)
|
|
2513
|
+
textOpts.objectName = options.objectName;
|
|
2514
|
+
addTextDefinition(target, [{ text: options.text || '', options: null }], textOpts, false);
|
|
2515
|
+
}
|
|
2516
|
+
/**
|
|
2517
|
+
* Feature 6: Adds a shape group to a slide definition and returns a group handle.
|
|
2518
|
+
* The group emits a `<p:grpSp>` whose `<a:xfrm>` carries the absolute position/size plus
|
|
2519
|
+
* `chOff="0,0"`/`chExt` equal to the extent — so child shapes/text use coordinates relative
|
|
2520
|
+
* to the group origin (1:1 scale). Children are added via the returned object's
|
|
2521
|
+
* `addShape()` / `addText()`, which reuse the existing shape/text intake but push onto the
|
|
2522
|
+
* group's private child array instead of the slide.
|
|
2523
|
+
* @param {PresSlide} target slide the group should be added to
|
|
2524
|
+
* @param {GroupProps} opts group position/size options
|
|
2525
|
+
* @return {SlideGroup} group handle exposing `addShape` / `addText`
|
|
2526
|
+
*/
|
|
2527
|
+
function addGroupDefinition(target, opts) {
|
|
2528
|
+
const options = typeof opts === 'object' ? opts : {};
|
|
2529
|
+
const grpObjects = [];
|
|
2530
|
+
const groupObj = {
|
|
2531
|
+
_type: SLIDE_OBJECT_TYPES.group,
|
|
2532
|
+
options: {
|
|
2533
|
+
x: options.x !== undefined ? options.x : 0,
|
|
2534
|
+
y: options.y !== undefined ? options.y : 0,
|
|
2535
|
+
w: options.w !== undefined ? options.w : 0,
|
|
2536
|
+
h: options.h !== undefined ? options.h : 0,
|
|
2537
|
+
objectName: options.objectName ? encodeXmlEntities(options.objectName) : `Group ${target._slideObjects.filter(obj => obj._type === SLIDE_OBJECT_TYPES.group).length + 1}`,
|
|
2538
|
+
},
|
|
2539
|
+
_grpObjects: grpObjects,
|
|
2540
|
+
};
|
|
2541
|
+
target._slideObjects.push(groupObj);
|
|
2542
|
+
// Proxy target: existing intake fns push onto the group's child array but reuse the parent
|
|
2543
|
+
// slide's rels/layout/color so child shapes/text render identically to top-level ones.
|
|
2544
|
+
const childTarget = {
|
|
2545
|
+
_slideObjects: grpObjects,
|
|
2546
|
+
_rels: target._rels,
|
|
2547
|
+
_relsChart: target._relsChart,
|
|
2548
|
+
_relsMedia: target._relsMedia,
|
|
2549
|
+
_slideLayout: target._slideLayout,
|
|
2550
|
+
_presLayout: target._presLayout,
|
|
2551
|
+
color: target.color,
|
|
2552
|
+
};
|
|
2553
|
+
const group = {
|
|
2554
|
+
addShape(shapeName, shapeOpts) {
|
|
2555
|
+
addShapeDefinition(childTarget, shapeName, (shapeOpts || {}));
|
|
2556
|
+
return group;
|
|
2557
|
+
},
|
|
2558
|
+
addText(text, textOpts) {
|
|
2559
|
+
const textParam = typeof text === 'string' || typeof text === 'number' ? [{ text, options: textOpts }] : text;
|
|
2560
|
+
addTextDefinition(childTarget, textParam, (textOpts || {}), false);
|
|
2561
|
+
return group;
|
|
2562
|
+
},
|
|
2563
|
+
};
|
|
2564
|
+
return group;
|
|
2565
|
+
}
|
|
2481
2566
|
/**
|
|
2482
2567
|
* Adds a table object to a slide definition.
|
|
2483
2568
|
* @param {PresSlide} target - slide object that the table should be added to
|
|
@@ -3161,6 +3246,27 @@ class Slide {
|
|
|
3161
3246
|
addShapeDefinition(this, shapeName, options);
|
|
3162
3247
|
return this;
|
|
3163
3248
|
}
|
|
3249
|
+
/**
|
|
3250
|
+
* Add a shape group to Slide (Feature 6).
|
|
3251
|
+
* Returns a group handle whose `addShape()`/`addText()` use coordinates relative to the
|
|
3252
|
+
* group origin; the group emits a `<p:grpSp>` with an absolute `<a:xfrm>` + `chOff`/`chExt`.
|
|
3253
|
+
* @param {GroupProps} options - group position/size options
|
|
3254
|
+
* @return {SlideGroup} group handle exposing `addShape` / `addText`
|
|
3255
|
+
*/
|
|
3256
|
+
addGroup(options) {
|
|
3257
|
+
return addGroupDefinition(this, options);
|
|
3258
|
+
}
|
|
3259
|
+
/**
|
|
3260
|
+
* Add a rounded-rectangle callout/badge to Slide (Feature 7).
|
|
3261
|
+
* Sugar over `addShape('roundRect', …)` with centred text and an `adj`
|
|
3262
|
+
* corner-radius derived from `cornerRadius` (inches).
|
|
3263
|
+
* @param {CalloutProps} options - callout options
|
|
3264
|
+
* @return {Slide} this Slide
|
|
3265
|
+
*/
|
|
3266
|
+
addCallout(options) {
|
|
3267
|
+
addCalloutDefinition(this, options);
|
|
3268
|
+
return this;
|
|
3269
|
+
}
|
|
3164
3270
|
/**
|
|
3165
3271
|
* Add table to Slide
|
|
3166
3272
|
* @param {TableRow[]} tableRows - table rows
|
|
@@ -5794,7 +5900,11 @@ function slideObjectToXml(slide) {
|
|
|
5794
5900
|
}
|
|
5795
5901
|
else {
|
|
5796
5902
|
strSlideXml += '<a:prstGeom prst="' + slideItemObj.shape + '"><a:avLst>';
|
|
5797
|
-
if (slideItemObj.options.
|
|
5903
|
+
if (slideItemObj.options._calloutAdj !== undefined && slideItemObj.options._calloutAdj !== null) {
|
|
5904
|
+
// Feature 7: addCallout() supplies a pre-computed `adj` value; emit it verbatim.
|
|
5905
|
+
strSlideXml += `<a:gd name="adj" fmla="val ${slideItemObj.options._calloutAdj}"/>`;
|
|
5906
|
+
}
|
|
5907
|
+
else if (slideItemObj.options.rectRadius) {
|
|
5798
5908
|
strSlideXml += `<a:gd name="adj" fmla="val ${Math.round((slideItemObj.options.rectRadius * EMU * 100000) / Math.min(cx, cy))}"/>`;
|
|
5799
5909
|
}
|
|
5800
5910
|
else if (slideItemObj.options.angleRange) {
|
|
@@ -5824,23 +5934,33 @@ function slideObjectToXml(slide) {
|
|
|
5824
5934
|
// FUTURE: `endArrowSize` < a: headEnd type = "arrow" w = "lg" len = "lg" /> 'sm' | 'med' | 'lg'(values are 1 - 9, making a 3x3 grid of w / len possibilities)
|
|
5825
5935
|
strSlideXml += '</a:ln>';
|
|
5826
5936
|
}
|
|
5827
|
-
// EFFECTS > SHADOW: REF: @see http://officeopenxml.com/drwSp-effects.php
|
|
5828
|
-
|
|
5829
|
-
|
|
5830
|
-
|
|
5831
|
-
const
|
|
5832
|
-
|
|
5833
|
-
|
|
5834
|
-
|
|
5835
|
-
|
|
5836
|
-
|
|
5837
|
-
|
|
5838
|
-
|
|
5839
|
-
|
|
5840
|
-
|
|
5841
|
-
|
|
5842
|
-
|
|
5843
|
-
|
|
5937
|
+
// EFFECTS > SHADOW + GLOW (Feature 10): REF: @see http://officeopenxml.com/drwSp-effects.php
|
|
5938
|
+
// Both effects share a single <a:effectLst>; emit it once if either is present.
|
|
5939
|
+
{
|
|
5940
|
+
const hasShadow = !!(slideItemObj.options.shadow && slideItemObj.options.shadow.type !== 'none');
|
|
5941
|
+
const hasGlow = !!slideItemObj.options.glow;
|
|
5942
|
+
if (hasShadow || hasGlow) {
|
|
5943
|
+
strSlideXml += '<a:effectLst>';
|
|
5944
|
+
if (hasShadow) {
|
|
5945
|
+
// derive emit-time values into locals so we don't mutate the user's options.shadow
|
|
5946
|
+
// (re-emission would otherwise re-convert pt→EMU and produce absurd values).
|
|
5947
|
+
const sh = slideItemObj.options.shadow;
|
|
5948
|
+
const shadowType = sh.type || 'outer';
|
|
5949
|
+
const shadowBlur = valToPts(sh.blur || 8);
|
|
5950
|
+
const shadowOffset = valToPts(sh.offset || 4);
|
|
5951
|
+
const shadowAngle = Math.round((sh.angle || 270) * 60000);
|
|
5952
|
+
const shadowOpacity = Math.round((sh.opacity || 0.75) * 100000);
|
|
5953
|
+
const shadowColor = sh.color || DEF_TEXT_SHADOW.color;
|
|
5954
|
+
strSlideXml += `<a:${shadowType}Shdw ${shadowType === 'outer' ? 'sx="100000" sy="100000" kx="0" ky="0" algn="bl" rotWithShape="0"' : ''} blurRad="${shadowBlur}" dist="${shadowOffset}" dir="${shadowAngle}">`;
|
|
5955
|
+
strSlideXml += `<a:srgbClr val="${shadowColor}">`;
|
|
5956
|
+
strSlideXml += `<a:alpha val="${shadowOpacity}"/></a:srgbClr>`;
|
|
5957
|
+
strSlideXml += `</a:${shadowType}Shdw>`;
|
|
5958
|
+
}
|
|
5959
|
+
if (hasGlow) {
|
|
5960
|
+
strSlideXml += createGlowElement(slideItemObj.options.glow, DEF_TEXT_GLOW);
|
|
5961
|
+
}
|
|
5962
|
+
strSlideXml += '</a:effectLst>';
|
|
5963
|
+
}
|
|
5844
5964
|
}
|
|
5845
5965
|
/* TODO: FUTURE: Text wrapping (copied from MS-PPTX export)
|
|
5846
5966
|
// Commented out b/c i'm not even sure this works - current code produces text that wraps in shapes and textboxes, so...
|
|
@@ -5988,6 +6108,20 @@ function slideObjectToXml(slide) {
|
|
|
5988
6108
|
strSlideXml += ' </a:graphic>';
|
|
5989
6109
|
strSlideXml += '</p:graphicFrame>';
|
|
5990
6110
|
break;
|
|
6111
|
+
case SLIDE_OBJECT_TYPES.group:
|
|
6112
|
+
// Feature 6: nested shape group. The `<a:xfrm>` carries the absolute position/size;
|
|
6113
|
+
// `chOff="0,0"` + `chExt`=ext gives a 1:1 child coordinate space, so children use
|
|
6114
|
+
// coordinates relative to the group origin. Children reuse the standard shape/text
|
|
6115
|
+
// emitters via `genGroupChildrenXml`.
|
|
6116
|
+
strSlideXml += '<p:grpSp>';
|
|
6117
|
+
strSlideXml += `<p:nvGrpSpPr><p:cNvPr id="${idx + 2}" name="${slideItemObj.options.objectName || `Group ${idx + 1}`}"/><p:cNvGrpSpPr/><p:nvPr/></p:nvGrpSpPr>`;
|
|
6118
|
+
strSlideXml += `<p:grpSpPr><a:xfrm${locationAttr}>`;
|
|
6119
|
+
strSlideXml += `<a:off x="${x}" y="${y}"/><a:ext cx="${cx}" cy="${cy}"/>`;
|
|
6120
|
+
strSlideXml += `<a:chOff x="0" y="0"/><a:chExt cx="${cx}" cy="${cy}"/>`;
|
|
6121
|
+
strSlideXml += '</a:xfrm></p:grpSpPr>';
|
|
6122
|
+
strSlideXml += genGroupChildrenXml(slide, slideItemObj._grpObjects, idx);
|
|
6123
|
+
strSlideXml += '</p:grpSp>';
|
|
6124
|
+
break;
|
|
5991
6125
|
default:
|
|
5992
6126
|
strSlideXml += '';
|
|
5993
6127
|
break;
|
|
@@ -6059,6 +6193,47 @@ function slideObjectToXml(slide) {
|
|
|
6059
6193
|
// LAST: Return
|
|
6060
6194
|
return strSlideXml;
|
|
6061
6195
|
}
|
|
6196
|
+
/**
|
|
6197
|
+
* Feature 6: Render a shape group's child objects as the inner markup of a `<p:grpSp>`.
|
|
6198
|
+
* Reuses the full slide emitter (`slideObjectToXml`) on the same slide with its object list
|
|
6199
|
+
* temporarily swapped to the group's children (and slide-number footer suppressed), then
|
|
6200
|
+
* extracts just the `<p:spTree>` child markup (everything after the root `</p:grpSpPr>` up to
|
|
6201
|
+
* `</p:spTree>`). Child `<p:cNvPr>` ids are offset to stay unique within the slide part so
|
|
6202
|
+
* PowerPoint does not flag the file for repair.
|
|
6203
|
+
* @param {PresSlide | SlideLayout} slide - parent slide (provides layout/rels/presLayout)
|
|
6204
|
+
* @param {ISlideObject[]} grpObjects - the group's child slide objects
|
|
6205
|
+
* @param {number} groupIdx - the group's index within the slide (used to namespace child ids)
|
|
6206
|
+
* @return {string} child markup to nest inside `<p:grpSp>`
|
|
6207
|
+
*/
|
|
6208
|
+
function genGroupChildrenXml(slide, grpObjects, groupIdx) {
|
|
6209
|
+
if (!grpObjects || grpObjects.length === 0)
|
|
6210
|
+
return '';
|
|
6211
|
+
// Temporarily render the children through the normal slide pipeline. Background is emitted
|
|
6212
|
+
// before `<p:spTree>` (outside the extracted region) so it is harmless; the slide-number
|
|
6213
|
+
// footer is emitted inside `<p:spTree>`, so suppress it during the recursive render.
|
|
6214
|
+
const savedObjects = slide._slideObjects;
|
|
6215
|
+
const savedSlideNum = slide._slideNumberProps;
|
|
6216
|
+
slide._slideObjects = grpObjects;
|
|
6217
|
+
slide._slideNumberProps = null;
|
|
6218
|
+
let fullXml;
|
|
6219
|
+
try {
|
|
6220
|
+
fullXml = slideObjectToXml(slide);
|
|
6221
|
+
}
|
|
6222
|
+
finally {
|
|
6223
|
+
slide._slideObjects = savedObjects;
|
|
6224
|
+
slide._slideNumberProps = savedSlideNum;
|
|
6225
|
+
}
|
|
6226
|
+
const startMarker = '</p:grpSpPr>';
|
|
6227
|
+
const startIdx = fullXml.indexOf(startMarker);
|
|
6228
|
+
const endIdx = fullXml.lastIndexOf('</p:spTree>');
|
|
6229
|
+
if (startIdx === -1 || endIdx === -1 || endIdx <= startIdx)
|
|
6230
|
+
return '';
|
|
6231
|
+
let childXml = fullXml.substring(startIdx + startMarker.length, endIdx);
|
|
6232
|
+
// Keep child cNvPr ids unique within the slide part (avoid PowerPoint "needs repair").
|
|
6233
|
+
const idBase = (groupIdx + 1) * 1000;
|
|
6234
|
+
childXml = childXml.replace(/<p:cNvPr id="(\d+)"/g, (_m, n) => `<p:cNvPr id="${idBase + Number(n)}"`);
|
|
6235
|
+
return childXml;
|
|
6236
|
+
}
|
|
6062
6237
|
/**
|
|
6063
6238
|
* Transforms slide relations to XML string.
|
|
6064
6239
|
* Extra relations that are not dynamic can be passed using the 2nd arg (e.g. theme relation in master file).
|
|
@@ -7394,7 +7569,7 @@ function makeXmlViewProps() {
|
|
|
7394
7569
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
7395
7570
|
* SOFTWARE.
|
|
7396
7571
|
*/
|
|
7397
|
-
const VERSION = '4.
|
|
7572
|
+
const VERSION = '4.1.1';
|
|
7398
7573
|
class PptxGenJS {
|
|
7399
7574
|
set layout(value) {
|
|
7400
7575
|
const newLayout = this.LAYOUTS[value];
|