diff --git a/demos/modules/demo_shape.mjs b/demos/modules/demo_shape.mjs
index c921998c2..c5bb2d583 100644
--- a/demos/modules/demo_shape.mjs
+++ b/demos/modules/demo_shape.mjs
@@ -96,6 +96,7 @@ function genSlide01(pptx) {
});
slide.addShape(pptx.shapes.RIGHT_TRIANGLE, {
+ sId: 20,
x: 0.4,
y: 4.3,
w: 6.0,
@@ -105,6 +106,7 @@ function genSlide01(pptx) {
shapeName: "First Right Triangle",
});
slide.addShape(pptx.shapes.RIGHT_TRIANGLE, {
+ sId: 21,
x: 7.0,
y: 4.3,
w: 6.0,
@@ -113,6 +115,22 @@ function genSlide01(pptx) {
line: { color: pptx.colors.ACCENT1, width: 2 },
flipH: true,
});
+
+ slide.addShape(pptx.shapes.LINE, {
+ x: 3108960,
+ y: 5303520,
+ w: 6035040,
+ h: 0,
+ line: {
+ width: 2, color: "000000",
+ sourceId: 20,
+ targetId: 21,
+ sourceAnchorPos: 5, // on rectangel pptx.anchor.TOP , pptx.anchor.BOTTOM , pptx.anchor.LEFT or pptx.anchor.RIGHT
+ targetAnchorPos: 5 // could be used instead
+ }
+ });
+
+
}
/**
@@ -251,6 +269,7 @@ function genSlide02(pptx) {
slide.addText("RIGHT-TRIANGLE", {
shape: pptx.shapes.RIGHT_TRIANGLE,
align: "center",
+ sId: 20,
x: 0.4,
y: 4.3,
w: 6,
@@ -261,6 +280,7 @@ function genSlide02(pptx) {
slide.addText("HYPERLINK-SHAPE", {
shape: pptx.shapes.RIGHT_TRIANGLE,
align: "center",
+ sId: 21,
x: 7.0,
y: 4.3,
w: 6,
@@ -270,4 +290,18 @@ function genSlide02(pptx) {
flipH: true,
hyperlink: { url: "https://github.com/gitbrent/pptxgenjs", tooltip: "Visit Homepage" },
});
+ slide.addShape(pptx.shapes.LINE, {
+ x: 3108960,
+ y: 5303520,
+ w: 6035040,
+ h: 0,
+ line: {
+ width: 2, color: "000000",
+ sourceId: 20,
+ targetId: 21,
+ sourceAnchorPos: 5, // on rectangel pptx.anchor.TOP , pptx.anchor.BOTTOM , pptx.anchor.LEFT or pptx.anchor.RIGHT
+ targetAnchorPos: 5 // could be used instead
+ }
+ });
+ slide.addText("Connected lines do not support text", {x:4.5,y:6})
}
diff --git a/src/core-enums.ts b/src/core-enums.ts
index 8a4950d3e..d31791d69 100644
--- a/src/core-enums.ts
+++ b/src/core-enums.ts
@@ -321,6 +321,13 @@ export enum AlignV {
'bottom' = 'bottom',
}
+export enum ANCHOR{
+ "TOP" = 0,
+ "LEFT" = 1,
+ "BOTTOM" = 2,
+ "RIGHT" = 3
+}
+
export enum SHAPE_TYPE {
ACTION_BUTTON_BACK_OR_PREVIOUS = 'actionButtonBackPrevious',
ACTION_BUTTON_BEGINNING = 'actionButtonBeginning',
diff --git a/src/core-interfaces.ts b/src/core-interfaces.ts
index bf41a113f..c10baf1c5 100644
--- a/src/core-interfaces.ts
+++ b/src/core-interfaces.ts
@@ -16,6 +16,12 @@ import { CHART_NAME, PLACEHOLDER_TYPE, SHAPE_NAME, SLIDE_OBJECT_TYPES, TEXT_HALI
* @example '75%' // coordinate as percentage of slide size
*/
export type Coord = number | string
+
+export type IDCoord = {
+ id:number
+ posistion: PositionProps
+}
+
export type PositionProps = {
/**
* Horizontal position
@@ -238,6 +244,32 @@ export interface ShapeLineProps extends ShapeFillProps {
* @deprecated v3.3.0 - use `width`
*/
size?: number
+ /**
+ * Set line shape to be connector
+ * @default false
+ */
+ isConnector?: boolean
+ /**
+ * connected source shape id
+ */
+ sourceId?: number
+ /**
+ * connected target shape id
+ */
+ targetId?: number
+ /**
+ * source shape connection position (dependent on available connection points on a shape)
+ */
+ sourceAnchorPos?: number
+ /**
+ * target shape connection position (dependent on available connection points on a shape)
+ */
+ targetAnchorPos?: number
+ /**
+ * adjustments to the curve
+ */
+ curveadjust?: number[]
+
}
// used by: chart, slide, table, text
export interface TextBaseProps {
@@ -263,80 +295,80 @@ export interface TextBaseProps {
* @default false
*/
bullet?:
- | boolean
- | {
- /**
- * Bullet type
- * @default bullet
- */
- type?: 'bullet' | 'number'
- /**
- * Bullet character code (unicode)
- * @since v3.3.0
- * @example '25BA' // 'BLACK RIGHT-POINTING POINTER' (U+25BA)
- */
- characterCode?: string
- /**
- * Indentation (space between bullet and text) (points)
- * @since v3.3.0
- * @default 27 // DEF_BULLET_MARGIN
- * @example 10 // Indents text 10 points from bullet
- */
- indent?: number
- /**
- * Number type
- * @since v3.3.0
- * @example 'romanLcParenR' // roman numerals lower-case with paranthesis right
- */
- numberType?:
- | 'alphaLcParenBoth'
- | 'alphaLcParenR'
- | 'alphaLcPeriod'
- | 'alphaUcParenBoth'
- | 'alphaUcParenR'
- | 'alphaUcPeriod'
- | 'arabicParenBoth'
- | 'arabicParenR'
- | 'arabicPeriod'
- | 'arabicPlain'
- | 'romanLcParenBoth'
- | 'romanLcParenR'
- | 'romanLcPeriod'
- | 'romanUcParenBoth'
- | 'romanUcParenR'
- | 'romanUcPeriod'
- /**
- * Number bullets start at
- * @since v3.3.0
- * @default 1
- * @example 10 // numbered bullets start with 10
- */
- numberStartAt?: number
+ | boolean
+ | {
+ /**
+ * Bullet type
+ * @default bullet
+ */
+ type?: 'bullet' | 'number'
+ /**
+ * Bullet character code (unicode)
+ * @since v3.3.0
+ * @example '25BA' // 'BLACK RIGHT-POINTING POINTER' (U+25BA)
+ */
+ characterCode?: string
+ /**
+ * Indentation (space between bullet and text) (points)
+ * @since v3.3.0
+ * @default 27 // DEF_BULLET_MARGIN
+ * @example 10 // Indents text 10 points from bullet
+ */
+ indent?: number
+ /**
+ * Number type
+ * @since v3.3.0
+ * @example 'romanLcParenR' // roman numerals lower-case with paranthesis right
+ */
+ numberType?:
+ | 'alphaLcParenBoth'
+ | 'alphaLcParenR'
+ | 'alphaLcPeriod'
+ | 'alphaUcParenBoth'
+ | 'alphaUcParenR'
+ | 'alphaUcPeriod'
+ | 'arabicParenBoth'
+ | 'arabicParenR'
+ | 'arabicPeriod'
+ | 'arabicPlain'
+ | 'romanLcParenBoth'
+ | 'romanLcParenR'
+ | 'romanLcPeriod'
+ | 'romanUcParenBoth'
+ | 'romanUcParenR'
+ | 'romanUcPeriod'
+ /**
+ * Number bullets start at
+ * @since v3.3.0
+ * @default 1
+ * @example 10 // numbered bullets start with 10
+ */
+ numberStartAt?: number
- // DEPRECATED
+ // DEPRECATED
- /**
- * Bullet code (unicode)
- * @deprecated v3.3.0 - use `characterCode`
- */
- code?: string
- /**
- * Margin between bullet and text
- * @since v3.2.1
- * @deplrecated v3.3.0 - use `indent`
- */
- marginPt?: number
- /**
- * Number to start with (only applies to type:number)
- * @deprecated v3.3.0 - use `numberStartAt`
- */
- startAt?: number
- /**
- * Number type
- * @deprecated v3.3.0 - use `numberType`
- */
- style?: string
- }
+ /**
+ * Bullet code (unicode)
+ * @deprecated v3.3.0 - use `characterCode`
+ */
+ code?: string
+ /**
+ * Margin between bullet and text
+ * @since v3.2.1
+ * @deplrecated v3.3.0 - use `indent`
+ */
+ marginPt?: number
+ /**
+ * Number to start with (only applies to type:number)
+ * @deprecated v3.3.0 - use `numberStartAt`
+ */
+ startAt?: number
+ /**
+ * Number type
+ * @deprecated v3.3.0 - use `numberType`
+ */
+ style?: string
+ }
/**
* Text color
* - `HexColor` or `ThemeColor`
@@ -390,23 +422,23 @@ export interface TextBaseProps {
*/
underline?: {
style?:
- | 'dash'
- | 'dashHeavy'
- | 'dashLong'
- | 'dashLongHeavy'
- | 'dbl'
- | 'dotDash'
- | 'dotDashHeave'
- | 'dotDotDash'
- | 'dotDotDashHeavy'
- | 'dotted'
- | 'dottedHeavy'
- | 'heavy'
- | 'none'
- | 'sng'
- | 'wavy'
- | 'wavyDbl'
- | 'wavyHeavy'
+ | 'dash'
+ | 'dashHeavy'
+ | 'dashLong'
+ | 'dashLongHeavy'
+ | 'dbl'
+ | 'dotDash'
+ | 'dotDashHeave'
+ | 'dotDotDash'
+ | 'dotDotDashHeavy'
+ | 'dotted'
+ | 'dottedHeavy'
+ | 'heavy'
+ | 'none'
+ | 'sng'
+ | 'wavy'
+ | 'wavyDbl'
+ | 'wavyHeavy'
color?: Color
}
/**
@@ -632,6 +664,10 @@ export interface ShapeProps extends PositionProps {
* @depreacted v3.3.0
*/
lineTail?: 'arrow' | 'diamond' | 'none' | 'oval' | 'stealth' | 'triangle'
+ /**
+ * id of shape
+ */
+ sId?: number
}
// tables =========================================================================================
@@ -1335,20 +1371,20 @@ export interface IChartPropsTitle extends TextBaseProps {
}
export interface IChartOpts
extends IChartPropsAxisCat,
- IChartPropsAxisSer,
- IChartPropsAxisVal,
- IChartPropsBase,
- IChartPropsChartBar,
- IChartPropsChartDoughnut,
- IChartPropsChartLine,
- IChartPropsChartPie,
- IChartPropsChartRadar,
- IChartPropsDataLabel,
- IChartPropsDataTable,
- IChartPropsLegend,
- IChartPropsTitle,
- OptsChartGridLine,
- PositionProps {
+ IChartPropsAxisSer,
+ IChartPropsAxisVal,
+ IChartPropsBase,
+ IChartPropsChartBar,
+ IChartPropsChartDoughnut,
+ IChartPropsChartLine,
+ IChartPropsChartPie,
+ IChartPropsChartRadar,
+ IChartPropsDataLabel,
+ IChartPropsDataTable,
+ IChartPropsLegend,
+ IChartPropsTitle,
+ OptsChartGridLine,
+ PositionProps {
/**
* Alt Text value ("How would you describe this object and its contents to someone who is blind?")
* - PowerPoint: [right-click on a chart] > "Edit Alt Text..."
@@ -1487,15 +1523,15 @@ export interface SlideMasterProps {
| { rect: {} }
| { text: TextProps }
| {
- placeholder: {
- options: PlaceholderProps
- /**
- * Text to be shown in placeholder (shown until user focuses textbox or adds text)
- * - Leave blank to have powerpoint show default phrase (ex: "Click to add title")
- */
- text?: string
- }
- }
+ placeholder: {
+ options: PlaceholderProps
+ /**
+ * Text to be shown in placeholder (shown until user focuses textbox or adds text)
+ * - Leave blank to have powerpoint show default phrase (ex: "Click to add title")
+ */
+ text?: string
+ }
+ }
)[]
slideNumber?: SlideNumberProps
diff --git a/src/gen-objects.ts b/src/gen-objects.ts
index e20cd18ec..10d945698 100644
--- a/src/gen-objects.ts
+++ b/src/gen-objects.ts
@@ -640,6 +640,12 @@ export function addShapeDefinition(target: PresSlide, shapeName: SHAPE_NAME, opt
dashType: options.line.dashType || 'solid',
beginArrowType: options.line.beginArrowType || null,
endArrowType: options.line.endArrowType || null,
+ sourceId: options.line.sourceId || null,
+ targetId: options.line.targetId || null,
+ sourceAnchorPos: options.line.sourceAnchorPos || (options.line.sourceAnchorPos === 0 ? 0 : null),
+ targetAnchorPos: options.line.targetAnchorPos || (options.line.targetAnchorPos === 0 ? 0 : null),
+ isConnector: options.line && (options.line.sourceId != null || options.line.targetId != null),
+ curveadjust: options.line.curveadjust || null
}
if (typeof options.line === 'object' && options.line.type !== 'none') options.line = newLineOpts
diff --git a/src/gen-xml.ts b/src/gen-xml.ts
index eebfee559..145fac282 100644
--- a/src/gen-xml.ts
+++ b/src/gen-xml.ts
@@ -3,6 +3,7 @@
*/
import {
+ ANCHOR,
BULLET_TYPES,
CRLF,
DEF_BULLET_MARGIN,
@@ -18,6 +19,7 @@ import {
} from './core-enums'
import {
IChartOpts,
+ IDCoord,
ImageProps,
IPresentationProps,
ISlideObject,
@@ -79,6 +81,23 @@ let imageSizingXml = {
},
}
+/**
+ * this function finds the elements of a list based on its id
+ * it is only really used for finding shapes in the coordinates list
+ * this is so the program can caluclate the posistion of connecting lines by itself
+ * @param {IDCoord[]} list
+ * @param {number} id
+ */
+
+function FindById(list: IDCoord[], id: number): IDCoord {
+ for (const element of list) {
+ if (element.id == id) {
+ return element
+ }
+ }
+ console.error("no element in list matching id")
+}
+
/**
* Transforms a slide or slideLayout to resulting XML string - Creates `ppt/slide*.xml`
* @param {PresSlide|SlideLayout} slideObject - slide object created within createSlideObject
@@ -104,8 +123,43 @@ function slideObjectToXml(slide: PresSlide | SlideLayout): string {
strSlideXml += ''
strSlideXml += ''
+ let IDs: number[] = []
+ let coordinates: IDCoord[] = []
+
// STEP 3: Loop over all Slide.data objects and add them to this slide
slide._slideObjects.forEach((slideItemObj: ISlideObject, idx: number) => {
+ if (slideItemObj.options != undefined) {
+ if (slideItemObj.options.sId != undefined) {
+ if (IDs.indexOf(slideItemObj.options.sId) > -1) {
+ throw "ID is already in use, object / shape id cannot be the same for multiple objects / shapes";
+ } else {
+ IDs.push(slideItemObj.options.sId);
+ }
+
+ } else {
+ if (IDs.indexOf(idx + 2) > -1) {
+ throw "an sID used matched an automatically generated ID try using a higher number";
+ } else {
+ IDs.push(idx + 2);
+ }
+
+ }
+ }
+
+
+
+ if (slideItemObj.options != undefined) {
+ coordinates.push({
+ id: IDs.at(-1),
+ posistion: {
+ x: slideItemObj.options.x,
+ y: slideItemObj.options.y,
+ w: slideItemObj.options.w,
+ h: slideItemObj.options.h
+ }
+ })
+ }
+
let x = 0,
y = 0,
cx = getSmartParseNumber('75%', 'X', slide._presLayout),
@@ -127,10 +181,107 @@ function slideObjectToXml(slide: PresSlide | SlideLayout): string {
// A: Set option vars
slideItemObj.options = slideItemObj.options || {}
- if (typeof slideItemObj.options.x !== 'undefined') x = getSmartParseNumber(slideItemObj.options.x, 'X', slide._presLayout)
- if (typeof slideItemObj.options.y !== 'undefined') y = getSmartParseNumber(slideItemObj.options.y, 'Y', slide._presLayout)
- if (typeof slideItemObj.options.w !== 'undefined') cx = getSmartParseNumber(slideItemObj.options.w, 'X', slide._presLayout)
- if (typeof slideItemObj.options.h !== 'undefined') cy = getSmartParseNumber(slideItemObj.options.h, 'Y', slide._presLayout)
+ //calculates the coordinates for connecting lines, only works for squares with number posistions ( so no percentages)
+ if (slideItemObj.options.line != undefined) {
+ if (slideItemObj.options.line.isConnector) {
+ const source = FindById(coordinates, slideItemObj.options.line.sourceId);
+ const target = FindById(coordinates, slideItemObj.options.line.targetId);
+
+
+ let deltaX = 0;
+ let deltaY = 0;
+ //this does not work for triangle because anchorpoint is outside the enum!!!!
+ switch (slideItemObj.options.line.sourceAnchorPos) {
+ case ANCHOR.TOP:
+ deltaX = Number(source.posistion.w) / 2;
+ x = Number(source.posistion.x) + deltaX;
+ y = Number(source.posistion.y)
+ break;
+ case ANCHOR.BOTTOM:
+ deltaX = Number(source.posistion.w) / 2;
+ x = Number(source.posistion.x) + deltaX;
+ deltaY = Number(source.posistion.h)
+ y = Number(source.posistion.y) + deltaY
+ break;
+ case ANCHOR.LEFT:
+ deltaY = Number(source.posistion.h) / 2;
+ y = Number(source.posistion.y) + deltaY;
+ x = Number(source.posistion.x);
+ break;
+ case ANCHOR.RIGHT:
+ deltaY = Number(source.posistion.h) / 2;
+ y = Number(source.posistion.y) + deltaY;
+ deltaX = Number(source.posistion.w)
+ x = Number(source.posistion.x) + deltaX;
+ break;
+ }
+
+ let tx = 0;
+ let ty = 0;
+
+ switch (slideItemObj.options.line.targetAnchorPos) {
+ case ANCHOR.TOP:
+ deltaX = Number(target.posistion.w) / 2;
+ tx = Number(target.posistion.x) + deltaX;
+ ty = Number(target.posistion.y)
+ break;
+ case ANCHOR.BOTTOM:
+ deltaX = Number(target.posistion.w) / 2;
+ tx = Number(target.posistion.x) + deltaX;
+ deltaY = Number(target.posistion.h)
+ ty = Number(target.posistion.y) + deltaY
+ break;
+ case ANCHOR.LEFT:
+ deltaY = Number(target.posistion.h) / 2;
+ ty = Number(target.posistion.y) + deltaY;
+ tx = Number(target.posistion.x);
+ break;
+ case ANCHOR.RIGHT:
+ deltaY = Number(target.posistion.h) / 2;
+ ty = Number(target.posistion.y) + deltaY;
+ deltaX = Number(target.posistion.w)
+ tx = Number(target.posistion.x) + deltaX;
+ break;
+ }
+
+ if (tx > x) {
+ cx = tx - x
+
+ slideItemObj.options.flipH = false;
+ } else {
+ slideItemObj.options.flipH = true;
+ cx = x - tx
+ x = tx;
+ }
+ if (ty > y) {
+ cy = ty - y;
+ slideItemObj.options.flipV = false;
+ } else {
+ cy = y - ty
+ y = ty;
+ slideItemObj.options.flipV = true;
+ }
+
+ x = getSmartParseNumber(x, "X", slide._presLayout);
+ y = getSmartParseNumber(y, "Y", slide._presLayout);
+ cx = getSmartParseNumber(cx, "X", slide._presLayout);
+ cy = getSmartParseNumber(cy, "X", slide._presLayout);
+
+
+ } else {
+ if (typeof slideItemObj.options.x !== 'undefined') x = getSmartParseNumber(slideItemObj.options.x, 'X', slide._presLayout)
+ if (typeof slideItemObj.options.y !== 'undefined') y = getSmartParseNumber(slideItemObj.options.y, 'Y', slide._presLayout)
+ if (typeof slideItemObj.options.w !== 'undefined') cx = getSmartParseNumber(slideItemObj.options.w, 'X', slide._presLayout)
+ if (typeof slideItemObj.options.h !== 'undefined') cy = getSmartParseNumber(slideItemObj.options.h, 'Y', slide._presLayout)
+ }
+ } else {
+ if (typeof slideItemObj.options.x !== 'undefined') x = getSmartParseNumber(slideItemObj.options.x, 'X', slide._presLayout)
+ if (typeof slideItemObj.options.y !== 'undefined') y = getSmartParseNumber(slideItemObj.options.y, 'Y', slide._presLayout)
+ if (typeof slideItemObj.options.w !== 'undefined') cx = getSmartParseNumber(slideItemObj.options.w, 'X', slide._presLayout)
+ if (typeof slideItemObj.options.h !== 'undefined') cy = getSmartParseNumber(slideItemObj.options.h, 'Y', slide._presLayout)
+ }
+
+
// If using a placeholder then inherit it's position
if (placeholderObj) {
@@ -168,9 +319,8 @@ function slideObjectToXml(slide: PresSlide | SlideLayout): string {
'' +
' ' +
''
- strXml += ``
+ strXml += ``
strXml += ''
// + ' ';
// TODO: Support banded rows, first/last row, etc.
@@ -208,7 +358,7 @@ function slideObjectToXml(slide: PresSlide | SlideLayout): string {
// We have to build an actual grid now
/*
EX: (A0:rowspan=3, B1:rowspan=2, C1:colspan=2)
-
+
/------|------|------|------\
| A0 | B0 | C0 | D0 |
| | B1 | C1 | |
@@ -217,7 +367,7 @@ function slideObjectToXml(slide: PresSlide | SlideLayout): string {
*/
// A: add _hmerge cell for colspan. should reserve rowspan
arrTabRows.forEach(cells => {
- for (let cIdx = 0; cIdx < cells.length; ) {
+ for (let cIdx = 0; cIdx < cells.length;) {
let cell = cells[cIdx]
let colspan = cell.options?.colspan
let rowspan = cell.options?.rowspan
@@ -256,7 +406,7 @@ function slideObjectToXml(slide: PresSlide | SlideLayout): string {
else if (slideItemObj.options.cy || slideItemObj.options.h)
intRowH = Math.round(
(slideItemObj.options.h ? inch2Emu(slideItemObj.options.h) : typeof slideItemObj.options.cy === 'number' ? slideItemObj.options.cy : 1) /
- arrTabRows.length
+ arrTabRows.length
)
// B: Start row
@@ -289,30 +439,30 @@ function slideObjectToXml(slide: PresSlide | SlideLayout): string {
let cellOpts = cell.options || ({} as TableCell['options'])
cell.options = cellOpts
- // B: Inherit some options from table when cell options dont exist
- // @see: http://officeopenxml.com/drwTableCellProperties-alignment.php
- ;['align', 'bold', 'border', 'color', 'fill', 'fontFace', 'fontSize', 'margin', 'underline', 'valign'].forEach(name => {
- if (objTabOpts[name] && !cellOpts[name] && cellOpts[name] !== 0) cellOpts[name] = objTabOpts[name]
- })
+ // B: Inherit some options from table when cell options dont exist
+ // @see: http://officeopenxml.com/drwTableCellProperties-alignment.php
+ ;['align', 'bold', 'border', 'color', 'fill', 'fontFace', 'fontSize', 'margin', 'underline', 'valign'].forEach(name => {
+ if (objTabOpts[name] && !cellOpts[name] && cellOpts[name] !== 0) cellOpts[name] = objTabOpts[name]
+ })
let cellValign = cellOpts.valign
? ' anchor="' +
- cellOpts.valign
- .replace(/^c$/i, 'ctr')
- .replace(/^m$/i, 'ctr')
- .replace('center', 'ctr')
- .replace('middle', 'ctr')
- .replace('top', 't')
- .replace('btm', 'b')
- .replace('bottom', 'b') +
- '"'
+ cellOpts.valign
+ .replace(/^c$/i, 'ctr')
+ .replace(/^m$/i, 'ctr')
+ .replace('center', 'ctr')
+ .replace('middle', 'ctr')
+ .replace('top', 't')
+ .replace('btm', 'b')
+ .replace('bottom', 'b') +
+ '"'
: ''
let fillColor =
cell._optImp && cell._optImp.fill && cell._optImp.fill.color
? cell._optImp.fill.color
: cell._optImp && cell._optImp.fill && typeof cell._optImp.fill === 'string'
- ? cell._optImp.fill
- : ''
+ ? cell._optImp.fill
+ : ''
fillColor =
fillColor || (cellOpts.fill && cellOpts.fill.color) ? cellOpts.fill.color : cellOpts.fill && typeof cellOpts.fill === 'string' ? cellOpts.fill : ''
let cellFill = fillColor ? `${createColorElement(fillColor)}` : ''
@@ -353,9 +503,8 @@ function slideObjectToXml(slide: PresSlide | SlideLayout): string {
if (cellOpts.border[obj.idx].type !== 'none') {
strXml += ``
strXml += `${createColorElement(cellOpts.border[obj.idx].color)}`
- strXml += ``
+ strXml += ``
strXml += ``
} else {
strXml += ``
@@ -388,117 +537,50 @@ function slideObjectToXml(slide: PresSlide | SlideLayout): string {
case SLIDE_OBJECT_TYPES.text:
case SLIDE_OBJECT_TYPES.placeholder:
- let shapeName = slideItemObj.options.shapeName ? encodeXmlEntities(slideItemObj.options.shapeName) : `Object${idx + 1}`
-
- // Lines can have zero cy, but text should not
- if (!slideItemObj.options.line && cy === 0) cy = EMU * 0.3
-
- // Margin/Padding/Inset for textboxes
- if (!slideItemObj.options._bodyProp) slideItemObj.options._bodyProp = {}
- if (slideItemObj.options.margin && Array.isArray(slideItemObj.options.margin)) {
- slideItemObj.options._bodyProp.lIns = valToPts(slideItemObj.options.margin[0] || 0)
- slideItemObj.options._bodyProp.rIns = valToPts(slideItemObj.options.margin[1] || 0)
- slideItemObj.options._bodyProp.bIns = valToPts(slideItemObj.options.margin[2] || 0)
- slideItemObj.options._bodyProp.tIns = valToPts(slideItemObj.options.margin[3] || 0)
- } else if (typeof slideItemObj.options.margin === 'number') {
- slideItemObj.options._bodyProp.lIns = valToPts(slideItemObj.options.margin)
- slideItemObj.options._bodyProp.rIns = valToPts(slideItemObj.options.margin)
- slideItemObj.options._bodyProp.bIns = valToPts(slideItemObj.options.margin)
- slideItemObj.options._bodyProp.tIns = valToPts(slideItemObj.options.margin)
- }
+ if (slideItemObj.options.line.isConnector) {
+ let shapeName = slideItemObj.options.shapeName ? encodeXmlEntities(slideItemObj.options.shapeName) : `Object${idx + 1}`
+
+ // Lines can have zero cy, but text should not
+ if (!slideItemObj.options.line && cy === 0) cy = EMU * 0.3
+
+ // Margin/Padding/Inset for textboxes
+ if (!slideItemObj.options._bodyProp) slideItemObj.options._bodyProp = {}
+ if (slideItemObj.options.margin && Array.isArray(slideItemObj.options.margin)) {
+ slideItemObj.options._bodyProp.lIns = valToPts(slideItemObj.options.margin[0] || 0)
+ slideItemObj.options._bodyProp.rIns = valToPts(slideItemObj.options.margin[1] || 0)
+ slideItemObj.options._bodyProp.bIns = valToPts(slideItemObj.options.margin[2] || 0)
+ slideItemObj.options._bodyProp.tIns = valToPts(slideItemObj.options.margin[3] || 0)
+ } else if (typeof slideItemObj.options.margin === 'number') {
+ slideItemObj.options._bodyProp.lIns = valToPts(slideItemObj.options.margin)
+ slideItemObj.options._bodyProp.rIns = valToPts(slideItemObj.options.margin)
+ slideItemObj.options._bodyProp.bIns = valToPts(slideItemObj.options.margin)
+ slideItemObj.options._bodyProp.tIns = valToPts(slideItemObj.options.margin)
+ }
- // A: Start SHAPE =======================================================
- strSlideXml += ''
+ // A: Start SHAPE =======================================================
+ strSlideXml += ''
- // B: The addition of the "txBox" attribute is the sole determiner of if an object is a shape or textbox
- strSlideXml += ``
- //
- if (slideItemObj.options.hyperlink && slideItemObj.options.hyperlink.url)
- strSlideXml +=
- ''
- if (slideItemObj.options.hyperlink && slideItemObj.options.hyperlink.slide)
- strSlideXml +=
- ''
- //
- strSlideXml += ''
- strSlideXml += '' : '/>')
- strSlideXml += `${slideItemObj._type === 'placeholder' ? genXmlPlaceholder(slideItemObj) : genXmlPlaceholder(placeholderObj)}`
- strSlideXml += ''
- strSlideXml += ``
- strSlideXml += ``
- strSlideXml += ``
-
- if (slideItemObj.shape === 'custGeom') {
- strSlideXml += ''
- strSlideXml += ''
- strSlideXml += ''
- strSlideXml += ''
- strSlideXml += ''
- strSlideXml += ''
- strSlideXml += ''
-
- strSlideXml += ''
- strSlideXml += ``
-
- slideItemObj.options.points?.map((point, i) => {
- if ('curve' in point) {
- switch (point.curve.type) {
- case 'arc':
- strSlideXml += ``
- break
- case 'cubic':
- strSlideXml += `
-
-
-
- `
- break
- case 'quadratic':
- strSlideXml += `
-
-
- `
- break
- default:
- break
- }
- } else if ('close' in point) {
- strSlideXml += ``
- } else if (point.moveTo || i === 0) {
- strSlideXml += ``
- } else {
- strSlideXml += ``
- }
- })
+ // B: The addition of the "txBox" attribute is the sole determiner of if an object is a shape or textbox
+ if (slideItemObj.options.sId != undefined) {
+ strSlideXml += ``
+ }
+ else {
+ strSlideXml += ``
+ }
+ strSlideXml += ''
+ //TODO add idx feature
+ strSlideXml += `
+
+
+ ` ;
+ strSlideXml += ''
+ strSlideXml += ''
+ strSlideXml += ``
+ strSlideXml += ``
+ strSlideXml += ``
- strSlideXml += ''
- strSlideXml += ''
- strSlideXml += ''
- } else {
strSlideXml += ''
- if (slideItemObj.options.rectRadius) {
- strSlideXml += ``
- } else if (slideItemObj.options.angleRange) {
+ if (slideItemObj.options.angleRange) {
for (let i = 0; i < 2; i++) {
const angle = slideItemObj.options.angleRange[i]
strSlideXml += ``
@@ -508,61 +590,243 @@ function slideObjectToXml(slide: PresSlide | SlideLayout): string {
strSlideXml += ``
}
}
+
+ if (slideItemObj.options.line.curveadjust) {
+ let i = 1
+ for (const adjustments in slideItemObj.options.line.curveadjust) {
+ strSlideXml += ``
+ i++
+ }
+
+ }
+
+
strSlideXml += ''
- }
- // Option: FILL
- strSlideXml += slideItemObj.options.fill ? genXmlColorSelection(slideItemObj.options.fill) : ''
-
- // shape Type: LINE: line color
- if (slideItemObj.options.line) {
- strSlideXml += slideItemObj.options.line.width ? `` : ''
- if (slideItemObj.options.line.color) strSlideXml += genXmlColorSelection(slideItemObj.options.line)
- if (slideItemObj.options.line.dashType) strSlideXml += ``
- if (slideItemObj.options.line.beginArrowType) strSlideXml += ``
- if (slideItemObj.options.line.endArrowType) strSlideXml += ``
- // 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)
- strSlideXml += ''
- }
- // EFFECTS > SHADOW: REF: @see http://officeopenxml.com/drwSp-effects.php
- if (slideItemObj.options.shadow) {
- slideItemObj.options.shadow.type = slideItemObj.options.shadow.type || 'outer'
- slideItemObj.options.shadow.blur = valToPts(slideItemObj.options.shadow.blur || 8)
- slideItemObj.options.shadow.offset = valToPts(slideItemObj.options.shadow.offset || 4)
- slideItemObj.options.shadow.angle = Math.round((slideItemObj.options.shadow.angle || 270) * 60000)
- slideItemObj.options.shadow.opacity = Math.round((slideItemObj.options.shadow.opacity || 0.75) * 100000)
- slideItemObj.options.shadow.color = slideItemObj.options.shadow.color || DEF_TEXT_SHADOW.color
-
- strSlideXml += ''
- strSlideXml += ''
- strSlideXml += ''
- strSlideXml += ''
- strSlideXml += ''
- strSlideXml += ''
- }
+ // Option: FILL
+ strSlideXml += slideItemObj.options.fill ? genXmlColorSelection(slideItemObj.options.fill) : ''
- /* TODO: FUTURE: Text wrapping (copied from MS-PPTX export)
- // Commented out b/c i'm not even sure this works - current code produces text that wraps in shapes and textboxes, so...
- if ( slideItemObj.options.textWrap ) {
- strSlideXml += ''
- + ''
- + ''
- + ''
- + '';
+ // shape Type: LINE: line color
+ if (slideItemObj.options.line) {
+ strSlideXml += slideItemObj.options.line.width ? `` : ''
+ if (slideItemObj.options.line.color) strSlideXml += genXmlColorSelection(slideItemObj.options.line)
+ if (slideItemObj.options.line.dashType) strSlideXml += ``
+ if (slideItemObj.options.line.beginArrowType) strSlideXml += ``
+ if (slideItemObj.options.line.endArrowType) strSlideXml += ``
+ // 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)
+ strSlideXml += ''
}
- */
- // B: Close shape Properties
- strSlideXml += ''
+ // EFFECTS > SHADOW: REF: @see http://officeopenxml.com/drwSp-effects.php
+ if (slideItemObj.options.shadow) {
+ slideItemObj.options.shadow.type = slideItemObj.options.shadow.type || 'outer'
+ slideItemObj.options.shadow.blur = valToPts(slideItemObj.options.shadow.blur || 8)
+ slideItemObj.options.shadow.offset = valToPts(slideItemObj.options.shadow.offset || 4)
+ slideItemObj.options.shadow.angle = Math.round((slideItemObj.options.shadow.angle || 270) * 60000)
+ slideItemObj.options.shadow.opacity = Math.round((slideItemObj.options.shadow.opacity || 0.75) * 100000)
+ slideItemObj.options.shadow.color = slideItemObj.options.shadow.color || DEF_TEXT_SHADOW.color
+
+ strSlideXml += ''
+ strSlideXml += ''
+ strSlideXml += ''
+ strSlideXml += ''
+ strSlideXml += ''
+ strSlideXml += ''
+ }
+
+ // B: Close shape Properties
+ strSlideXml += ''
+
+ // C: Add formatted text (text body "bodyPr")
+ strSlideXml += genXmlTextBody(slideItemObj)
+
+ // LAST: Close SHAPE =======================================================
+ strSlideXml += ''
+ } else {
+ let shapeName = slideItemObj.options.shapeName ? encodeXmlEntities(slideItemObj.options.shapeName) : `Object${idx + 1}`
+
+ // Lines can have zero cy, but text should not
+ if (!slideItemObj.options.line && cy === 0) cy = EMU * 0.3
+
+ // Margin/Padding/Inset for textboxes
+ if (!slideItemObj.options._bodyProp) slideItemObj.options._bodyProp = {}
+ if (slideItemObj.options.margin && Array.isArray(slideItemObj.options.margin)) {
+ slideItemObj.options._bodyProp.lIns = valToPts(slideItemObj.options.margin[0] || 0)
+ slideItemObj.options._bodyProp.rIns = valToPts(slideItemObj.options.margin[1] || 0)
+ slideItemObj.options._bodyProp.bIns = valToPts(slideItemObj.options.margin[2] || 0)
+ slideItemObj.options._bodyProp.tIns = valToPts(slideItemObj.options.margin[3] || 0)
+ } else if (typeof slideItemObj.options.margin === 'number') {
+ slideItemObj.options._bodyProp.lIns = valToPts(slideItemObj.options.margin)
+ slideItemObj.options._bodyProp.rIns = valToPts(slideItemObj.options.margin)
+ slideItemObj.options._bodyProp.bIns = valToPts(slideItemObj.options.margin)
+ slideItemObj.options._bodyProp.tIns = valToPts(slideItemObj.options.margin)
+ }
+
+ // A: Start SHAPE =======================================================
+ strSlideXml += ''
+
+ // B: The addition of the "txBox" attribute is the sole determiner of if an object is a shape or textbox
+ if (slideItemObj.options.sId != undefined) {
+ strSlideXml += ``
+ }
+ else {
+ strSlideXml += ``
+ }
+ //
+ if (slideItemObj.options.hyperlink && slideItemObj.options.hyperlink.url)
+ strSlideXml +=
+ ''
+ if (slideItemObj.options.hyperlink && slideItemObj.options.hyperlink.slide)
+ strSlideXml +=
+ ''
+ //
+ strSlideXml += ''
+ strSlideXml += '' : '/>')
+ strSlideXml += `${slideItemObj._type === 'placeholder' ? genXmlPlaceholder(slideItemObj) : genXmlPlaceholder(placeholderObj)}`
+ strSlideXml += ''
+ strSlideXml += ``
+ strSlideXml += ``
+ strSlideXml += ``
+
+ if (slideItemObj.shape === 'custGeom') {
+ strSlideXml += ''
+ strSlideXml += ''
+ strSlideXml += ''
+ strSlideXml += ''
+ strSlideXml += ''
+ strSlideXml += ''
+ strSlideXml += ''
+
+ strSlideXml += ''
+ strSlideXml += ``
+
+ slideItemObj.options.points?.map((point, i) => {
+ if ('curve' in point) {
+ switch (point.curve.type) {
+ case 'arc':
+ strSlideXml += ``
+ break
+ case 'cubic':
+ strSlideXml += `
+
+
+
+ `
+ break
+ case 'quadratic':
+ strSlideXml += `
+
+
+ `
+ break
+ default:
+ break
+ }
+ } else if ('close' in point) {
+ strSlideXml += ``
+ } else if (point.moveTo || i === 0) {
+ strSlideXml += ``
+ } else {
+ strSlideXml += ``
+ }
+ })
+
+ strSlideXml += ''
+ strSlideXml += ''
+ strSlideXml += ''
+ } else {
+ strSlideXml += ''
+ if (slideItemObj.options.rectRadius) {
+ strSlideXml += ``
+ } else if (slideItemObj.options.angleRange) {
+ for (let i = 0; i < 2; i++) {
+ const angle = slideItemObj.options.angleRange[i]
+ strSlideXml += ``
+ }
+
+ if (slideItemObj.options.arcThicknessRatio) {
+ strSlideXml += ``
+ }
+ }
+ strSlideXml += ''
+ }
+
+ // Option: FILL
+ strSlideXml += slideItemObj.options.fill ? genXmlColorSelection(slideItemObj.options.fill) : ''
+
+ // shape Type: LINE: line color
+ if (slideItemObj.options.line) {
+ strSlideXml += slideItemObj.options.line.width ? `` : ''
+ if (slideItemObj.options.line.color) strSlideXml += genXmlColorSelection(slideItemObj.options.line)
+ if (slideItemObj.options.line.dashType) strSlideXml += ``
+ if (slideItemObj.options.line.beginArrowType) strSlideXml += ``
+ if (slideItemObj.options.line.endArrowType) strSlideXml += ``
+ // 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)
+ strSlideXml += ''
+ }
+
+ // EFFECTS > SHADOW: REF: @see http://officeopenxml.com/drwSp-effects.php
+ if (slideItemObj.options.shadow) {
+ slideItemObj.options.shadow.type = slideItemObj.options.shadow.type || 'outer'
+ slideItemObj.options.shadow.blur = valToPts(slideItemObj.options.shadow.blur || 8)
+ slideItemObj.options.shadow.offset = valToPts(slideItemObj.options.shadow.offset || 4)
+ slideItemObj.options.shadow.angle = Math.round((slideItemObj.options.shadow.angle || 270) * 60000)
+ slideItemObj.options.shadow.opacity = Math.round((slideItemObj.options.shadow.opacity || 0.75) * 100000)
+ slideItemObj.options.shadow.color = slideItemObj.options.shadow.color || DEF_TEXT_SHADOW.color
+
+ strSlideXml += ''
+ strSlideXml += ''
+ strSlideXml += ''
+ strSlideXml += ''
+ strSlideXml += ''
+ strSlideXml += ''
+ }
+
+ /* TODO: FUTURE: Text wrapping (copied from MS-PPTX export)
+ // Commented out b/c i'm not even sure this works - current code produces text that wraps in shapes and textboxes, so...
+ if ( slideItemObj.options.textWrap ) {
+ strSlideXml += ''
+ + ''
+ + ''
+ + ''
+ + '';
+ }
+ */
- // C: Add formatted text (text body "bodyPr")
- strSlideXml += genXmlTextBody(slideItemObj)
+ // B: Close shape Properties
+ strSlideXml += ''
- // LAST: Close SHAPE =======================================================
- strSlideXml += ''
+ // C: Add formatted text (text body "bodyPr")
+ strSlideXml += genXmlTextBody(slideItemObj)
+
+ // LAST: Close SHAPE =======================================================
+ strSlideXml += ''
+ }
break
case SLIDE_OBJECT_TYPES.image:
@@ -574,15 +838,17 @@ function slideObjectToXml(slide: PresSlide | SlideLayout): string {
strSlideXml += ''
strSlideXml += ' '
- strSlideXml += ``
+ if (slideItemObj.options.sId != undefined) {
+ strSlideXml += ``
+ } else {
+ strSlideXml += ``
+ }
if (slideItemObj.hyperlink && slideItemObj.hyperlink.url)
- strSlideXml += ``
+ strSlideXml += ``
if (slideItemObj.hyperlink && slideItemObj.hyperlink.slide)
- strSlideXml += ``
+ strSlideXml += ``
strSlideXml += ' '
strSlideXml += ' '
strSlideXml += ' ' + genXmlPlaceholder(placeholderObj) + ''
@@ -683,7 +949,11 @@ function slideObjectToXml(slide: PresSlide | SlideLayout): string {
let chartOpts = slideItemObj.options as IChartOpts
strSlideXml += ''
strSlideXml += ' '
- strSlideXml += ` `
+ if (slideItemObj.options.sId != undefined) {
+ strSlideXml += ` `
+ } else {
+ strSlideXml += ` `
+ }
strSlideXml += ' '
strSlideXml += ` ${genXmlPlaceholder(placeholderObj)}`
strSlideXml += ' '
@@ -812,41 +1082,41 @@ function slideObjectRelationsToXml(slide: PresSlide | SlideLayout, defaultRels:
''
}
})
- ;(slide._relsChart || []).forEach((rel: ISlideRelChart) => {
- lastRid = Math.max(lastRid, rel.rId)
- strXml += ''
- })
- ;(slide._relsMedia || []).forEach((rel: ISlideRelMedia) => {
- lastRid = Math.max(lastRid, rel.rId)
- if (rel.type.toLowerCase().indexOf('image') > -1) {
- strXml += ''
- } else if (rel.type.toLowerCase().indexOf('audio') > -1) {
- // As media has *TWO* rel entries per item, check for first one, if found add second rel with alt style
- if (strXml.indexOf(' Target="' + rel.Target + '"') > -1)
- strXml += ''
- else
- strXml +=
- ''
- } else if (rel.type.toLowerCase().indexOf('video') > -1) {
- // As media has *TWO* rel entries per item, check for first one, if found add second rel with alt style
- if (strXml.indexOf(' Target="' + rel.Target + '"') > -1)
- strXml += ''
- else
- strXml +=
- ''
- } else if (rel.type.toLowerCase().indexOf('online') > -1) {
- // As media has *TWO* rel entries per item, check for first one, if found add second rel with alt style
- if (strXml.indexOf(' Target="' + rel.Target + '"') > -1)
- strXml += ''
- else
- strXml +=
- ''
- }
- })
+ ; (slide._relsChart || []).forEach((rel: ISlideRelChart) => {
+ lastRid = Math.max(lastRid, rel.rId)
+ strXml += ''
+ })
+ ; (slide._relsMedia || []).forEach((rel: ISlideRelMedia) => {
+ lastRid = Math.max(lastRid, rel.rId)
+ if (rel.type.toLowerCase().indexOf('image') > -1) {
+ strXml += ''
+ } else if (rel.type.toLowerCase().indexOf('audio') > -1) {
+ // As media has *TWO* rel entries per item, check for first one, if found add second rel with alt style
+ if (strXml.indexOf(' Target="' + rel.Target + '"') > -1)
+ strXml += ''
+ else
+ strXml +=
+ ''
+ } else if (rel.type.toLowerCase().indexOf('video') > -1) {
+ // As media has *TWO* rel entries per item, check for first one, if found add second rel with alt style
+ if (strXml.indexOf(' Target="' + rel.Target + '"') > -1)
+ strXml += ''
+ else
+ strXml +=
+ ''
+ } else if (rel.type.toLowerCase().indexOf('online') > -1) {
+ // As media has *TWO* rel entries per item, check for first one, if found add second rel with alt style
+ if (strXml.indexOf(' Target="' + rel.Target + '"') > -1)
+ strXml += ''
+ else
+ strXml +=
+ ''
+ }
+ })
// STEP 2: Add default rels
defaultRels.forEach((rel, idx) => {
@@ -923,12 +1193,10 @@ function genXmlParagraphProperties(textObj: ISlideObject | TextProps, isDefault:
if (textObj.options.bullet.type) {
if (textObj.options.bullet.type.toString().toLowerCase() === 'number') {
- paragraphPropXml += ` marL="${
- textObj.options.indentLevel && textObj.options.indentLevel > 0 ? bulletMarL + bulletMarL * textObj.options.indentLevel : bulletMarL
- }" indent="-${bulletMarL}"`
- strXmlBullet = ``
+ paragraphPropXml += ` marL="${textObj.options.indentLevel && textObj.options.indentLevel > 0 ? bulletMarL + bulletMarL * textObj.options.indentLevel : bulletMarL
+ }" indent="-${bulletMarL}"`
+ strXmlBullet = ``
}
} else if (textObj.options.bullet.characterCode) {
let bulletCode = `${textObj.options.bullet.characterCode};`
@@ -939,9 +1207,8 @@ function genXmlParagraphProperties(textObj: ISlideObject | TextProps, isDefault:
bulletCode = BULLET_TYPES['DEFAULT']
}
- paragraphPropXml += ` marL="${
- textObj.options.indentLevel && textObj.options.indentLevel > 0 ? bulletMarL + bulletMarL * textObj.options.indentLevel : bulletMarL
- }" indent="-${bulletMarL}"`
+ paragraphPropXml += ` marL="${textObj.options.indentLevel && textObj.options.indentLevel > 0 ? bulletMarL + bulletMarL * textObj.options.indentLevel : bulletMarL
+ }" indent="-${bulletMarL}"`
strXmlBullet = ''
} else if (textObj.options.bullet.code) {
// @deprecated `bullet.code` v3.3.0
@@ -953,20 +1220,17 @@ function genXmlParagraphProperties(textObj: ISlideObject | TextProps, isDefault:
bulletCode = BULLET_TYPES['DEFAULT']
}
- paragraphPropXml += ` marL="${
- textObj.options.indentLevel && textObj.options.indentLevel > 0 ? bulletMarL + bulletMarL * textObj.options.indentLevel : bulletMarL
- }" indent="-${bulletMarL}"`
+ paragraphPropXml += ` marL="${textObj.options.indentLevel && textObj.options.indentLevel > 0 ? bulletMarL + bulletMarL * textObj.options.indentLevel : bulletMarL
+ }" indent="-${bulletMarL}"`
strXmlBullet = ''
} else {
- paragraphPropXml += ` marL="${
- textObj.options.indentLevel && textObj.options.indentLevel > 0 ? bulletMarL + bulletMarL * textObj.options.indentLevel : bulletMarL
- }" indent="-${bulletMarL}"`
+ paragraphPropXml += ` marL="${textObj.options.indentLevel && textObj.options.indentLevel > 0 ? bulletMarL + bulletMarL * textObj.options.indentLevel : bulletMarL
+ }" indent="-${bulletMarL}"`
strXmlBullet = ``
}
} else if (textObj.options.bullet === true) {
- paragraphPropXml += ` marL="${
- textObj.options.indentLevel && textObj.options.indentLevel > 0 ? bulletMarL + bulletMarL * textObj.options.indentLevel : bulletMarL
- }" indent="-${bulletMarL}"`
+ paragraphPropXml += ` marL="${textObj.options.indentLevel && textObj.options.indentLevel > 0 ? bulletMarL + bulletMarL * textObj.options.indentLevel : bulletMarL
+ }" indent="-${bulletMarL}"`
strXmlBullet = ``
} else if (textObj.options.bullet === false) {
// We only add this when the user explicitely asks for no bullet, otherwise, it can override the master defaults!
@@ -1045,13 +1309,11 @@ function genXmlTextRunProperties(opts: ObjectOptions | TextPropsOptions, isDefau
else if (!opts.hyperlink.url && !opts.hyperlink.slide) throw new Error("ERROR: 'hyperlink requires either `url` or `slide`'")
else if (opts.hyperlink.url) {
//runProps += ''+ genXmlColorSelection('0000FF') +''; // Breaks PPT2010! (Issue#74)
- runProps += `' : '/>'}`
+ runProps += `' : '/>'}`
} else if (opts.hyperlink.slide) {
- runProps += `' : '/>'}`
+ runProps += `' : '/>'}`
}
if (opts.color) {
runProps += ' '
@@ -1419,7 +1681,7 @@ export function makeXmlContTypes(slides: PresSlide[], slideLayouts: SlideLayout[
strXml += '' // NOTE: Hard-Code this extension as it wont be created in loop below (as extn !== type)
strXml += '' // NOTE: Hard-Code this extension as it wont be created in loop below (as extn !== type)
slides.forEach(slide => {
- ;(slide._relsMedia || []).forEach(rel => {
+ ; (slide._relsMedia || []).forEach(rel => {
if (rel.type !== 'image' && rel.type !== 'online' && rel.type !== 'chart' && rel.extn !== 'm4v' && strXml.indexOf(rel.type) === -1) {
strXml += ''
}
@@ -1455,9 +1717,9 @@ export function makeXmlContTypes(slides: PresSlide[], slideLayouts: SlideLayout[
''
- ;(layout._relsChart || []).forEach(rel => {
- strXml += ' '
- })
+ ; (layout._relsChart || []).forEach(rel => {
+ strXml += ' '
+ })
})
// STEP 5: Add notes slide(s)
diff --git a/src/pptxgen.ts b/src/pptxgen.ts
index 427b29095..5a99143b2 100644
--- a/src/pptxgen.ts
+++ b/src/pptxgen.ts
@@ -76,6 +76,7 @@ import {
SchemeColor,
ShapeType,
WRITE_OUTPUT_TYPE,
+ ANCHOR
} from './core-enums'
import {
AddSlideProps,
@@ -282,6 +283,10 @@ export default class PptxGenJS implements IPresentationProps {
public get shapes(): typeof SHAPE_TYPE {
return this._shapes
}
+ private _anchor = ANCHOR
+ public get anchor(): typeof ANCHOR {
+ return this._anchor
+ }
constructor() {
// Set available layouts