Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 13 additions & 10 deletions demos/common/demos.js
Original file line number Diff line number Diff line change
Expand Up @@ -2632,20 +2632,23 @@ function genSlides_Shape(pptx) {
slide.addTable( [ [{ text:'Shape Examples 1: Misc Shape Types (no text)', options:gOptsTextL },gOptsTextR] ], gOptsTabOpts );

//slide.addShape(pptx.shapes.RECTANGLE, { x:0.5, y:0.8, w:12.5,h:0.5, fill:'F9F9F9' });
slide.addShape(pptx.shapes.RECTANGLE, { x: 0.5, y: 0.8, w: 1.5, h: 3.0, fill: { color: 'FF0000' }, line: { type: 'none' } });
slide.addShape(pptx.shapes.RECTANGLE, { x: 3.0, y: 0.7, w: 1.5, h: 3.0, fill: { color: 'F38E00' }, rotate: 45 });
slide.addShape(pptx.shapes.RECTANGLE, { x: 0.5, y: 0.8, w: 1.5, h: 1.0, fill: { color: 'FF0000' }, line: { type: 'none' } });
slide.addShape(pptx.shapes.RECTANGLE, { x: 3.0, y: 0.7, w: 1.5, h: 1.0, fill: { color: 'F38E00' }, rotate: 45 });
slide.addShape(pptx.shapes.OVAL, { x: 5.4, y: 0.8, w: 3.0, h: 1.5, fill: { type: 'solid', color: '0088CC' } });
slide.addShape(pptx.shapes.OVAL, { x: 7.7, y: 1.4, w: 3.0, h: 1.5, fill: { color: 'FF00CC' }, rotate: 90 }); // TEST: no type
slide.addShape(pptx.shapes.ROUNDED_RECTANGLE, { x:10 , y:2.5, w:3.0, h:1.5, r:0.2, fill:'00FF00', line:'000000', lineSize:1 }); // TEST: DEPRECATED: `fill`,`line`,`lineSize`
slide.addShape(pptx.shapes.RECTANGLE, { sId: 1, x: 0.5, y: 2, w: 1.5, h: 1.5, fill: { color: 'F0F8FF' }}); // for connector demo
slide.addShape(pptx.shapes.RECTANGLE, { sId: 2, x: 3.0, y: 2, w: 1.5, h: 1.5, fill: { color: 'F38E00' }}); // for connector demo
//
slide.addShape(pptx.shapes.LINE, { x: 4.2, y: 4.4, w: 5.0, h: 0.0, line: { color: 'FF0000', width: 1, dashType: 'lgDash' } });
slide.addShape(pptx.shapes.LINE, { x: 4.2, y: 4.8, w: 5.0, h: 0.0, line: { color: 'FF0000', width: 2, dashType: 'dashDot' }, lineHead: 'arrow' }); // TEST: DEPRECATED: lineHead
slide.addShape(pptx.shapes.LINE, { x: 4.2, y: 5.2, w: 5.0, h: 0.0, line: { color: 'FF0000', width: 3, endArrowType: 'triangle' } });
slide.addShape(pptx.shapes.LINE, { x: 4.2, y: 5.6, w: 5.0, h: 0.0, line: { color: 'FF0000', width: 4, beginArrowType: 'diamond', endArrowType: 'oval' } });
slide.addShape(pptx.shapes.LINE, { x: 5.7, y: 3.3, w: 2.5, h: 0.0, line: { width: 1 }, rotate: (360 - 45) }); // DIAGONAL Line // TEST:no line.color
//
slide.addShape(pptx.shapes.RIGHT_TRIANGLE, { x: 0.4, y: 4.3, w: 6.0, h: 3.0, fill: { color: '0088CC' }, line: { color: '000000', width: 3 }, shapeName:'First Right Triangle' });
slide.addShape(pptx.shapes.RIGHT_TRIANGLE, { x: 7.0, y: 4.3, w: 6.0, h: 3.0, fill: { color: '0088CC' }, line: { color: '000000', width: 2 }, flipH: true });
slide.addShape(pptx.shapes.LINE, { x: 4.2, y: 4.4, w: 5.0, h: 0.0, line: { color: 'FF0000', size: 1, dashType: 'lgDash' } });
slide.addShape(pptx.shapes.LINE, { x: 4.2, y: 4.8, w: 5.0, h: 0.0, line: { color: 'FF0000', size: 2, dashType: 'dashDot' }, lineHead: 'arrow' }); // TEST: DEPRECATED: lineHead
slide.addShape(pptx.shapes.LINE, { x: 4.2, y: 5.2, w: 5.0, h: 0.0, line: { color: 'FF0000', size: 3, endArrowType: 'triangle' } });
slide.addShape(pptx.shapes.LINE, { x: 4.2, y: 5.6, w: 5.0, h: 0.0, line: { color: 'FF0000', size: 4, beginArrowType: 'diamond', endArrowType: 'oval' } });
slide.addShape(pptx.shapes.LINE, { x: 5.7, y: 3.3, w: 2.5, h: 0.0, line: { size: 1 }, rotate: (360 - 45) }); // DIAGONAL Line // TEST:no line.color
slide.addShape(pptx.shapes.LINE, { sId: 3, x: 2, y: 1, w: 1, h: 0.0, line: { size: 1, sourceId: 1, targetId: 2, sourceAnchorPos: 0, targetAnchorPos: 1 } }); // connector test start pos 0 / end pos 1
//
slide.addShape(pptx.shapes.RIGHT_TRIANGLE, { x: 0.4, y: 4.3, w: 6.0, h: 3.0, fill: { color: '0088CC' }, line: { color: '000000', size: 3 } });
slide.addShape(pptx.shapes.RIGHT_TRIANGLE, { x: 7.0, y: 4.3, w: 6.0, h: 3.0, fill: { color: '0088CC' }, line: { color: '000000', size: 2 }, flipH: true });

// SLIDE 2: Misc Shape Types with Text
// ======== -----------------------------------------------------------------------------------
Expand Down
26 changes: 26 additions & 0 deletions src/core-interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,28 @@ export interface ShapeLine extends ShapeFill {
* @deprecated v3.3.0 - use `arrowTypeEnd`
*/
pt?: 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
}
// used by: chart, slide, table, text
export interface TextOptions {
Expand Down Expand Up @@ -431,6 +453,10 @@ export interface MediaOpts extends PositionOptions, OptsDataOrPath {
// shapes =========================================================================================

export interface ShapeOptions extends PositionOptions {
/**
* id of shape
*/
sId?: Number
/**
* Horizontal alignment
* @default 'left'
Expand Down
8 changes: 8 additions & 0 deletions src/gen-objects.ts
Original file line number Diff line number Diff line change
Expand Up @@ -579,6 +579,7 @@ export function addNotesDefinition(target: ISlideLib, notes: string) {
export function addShapeDefinition(target: ISlideLib, shapeName: SHAPE_NAME, opts: ShapeOptions) {
let options = typeof opts === 'object' ? opts : {}
options.line = options.line || ({ type: 'none' } as ShapeLine)
options.sId = options.sId || (options.sId === 0 ? 0 : null)
let newObject: ISlideObject = {
type: SLIDE_OBJECT_TYPES.text,
shape: shapeName || SHAPE_TYPE.RECTANGLE,
Expand All @@ -598,6 +599,12 @@ export function addShapeDefinition(target: ISlideLib, shapeName: SHAPE_NAME, opt
dashType: options.line.dashType || 'solid',
beginArrowType: options.line.beginArrowType || null,
endArrowType: options.line.endArrowType || null,
// Handle connectors related options
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),
}
if (typeof options.line === 'object' && options.line.type !== 'none') options.line = newLineOpts

Expand Down Expand Up @@ -930,6 +937,7 @@ export function addTextDefinition(target: ISlideLib, text: string | IText[], opt
dashType: opt.line.dashType || 'solid',
beginArrowType: opt.line.beginArrowType || null,
endArrowType: opt.line.endArrowType || null,
// NOTE: Ignoring connector options since you cannot add text to connectors - Tom Choi - June 2020
}
if (typeof opt.line === 'object') opt.line = newLineOpts

Expand Down
78 changes: 48 additions & 30 deletions src/gen-xml.ts
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,7 @@ function slideObjectToXml(slide: ISlideLib | ISlideLayout): string {
' <a:graphicData uri="http://schemas.openxmlformats.org/drawingml/2006/table">' +
' <a:tbl>' +
' <a:tblPr/>'
// + ' <a:tblPr bandRow="1"/>';
// + ' <a:tblPr bandRow="1"/>';
// TODO: Support banded rows, first/last row, etc.
// NOTE: Banding, etc. only shows when using a table style! (or set alt row color if banding)
// <a:tblPr firstCol="0" firstRow="0" lastCol="0" lastRow="0" bandCol="0" bandRow="1">
Expand Down Expand Up @@ -430,37 +430,51 @@ function slideObjectToXml(slide: ISlideLib | ISlideLayout): string {
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)
slideItemObj.options.bodyProp.lIns = Math.round(slideItemObj.options.margin * ONEPT)
slideItemObj.options.bodyProp.rIns = Math.round(slideItemObj.options.margin * ONEPT)
slideItemObj.options.bodyProp.bIns = Math.round(slideItemObj.options.margin * ONEPT)
slideItemObj.options.bodyProp.tIns = Math.round(slideItemObj.options.margin * ONEPT)
}

// A: Start SHAPE =======================================================
strSlideXml += '<p:sp>'
if (slideItemObj.options.line.isConnector) {
// convert user defined sId of sourceId and targetId to 'id' of shape
// 3.1: Handle connector line
let sourceId = null
let targetId = null
if (slideItemObj.options.line.sourceId != null) {
sourceId = slide.data.findIndex(d => d.options.sId === slideItemObj.options.line.sourceId)
sourceId = sourceId + 2
}
if (slideItemObj.options.line.targetId != null) {
targetId = slide.data.findIndex((d) => d.options.sId === slideItemObj.options.line.targetId)
targetId = targetId + 2
}
// A: Start Connector =======================================================
strSlideXml += '<p:cxnSp>';
strSlideXml += '<p:nvCxnSpPr><p:cNvPr id="'+ (idx + 2) +'" name="Connector '+ (idx + 1) +'"/>';
strSlideXml += '<p:cNvCxnSpPr>';

// B: The addition of the "txBox" attribute is the sole determiner of if an object is a shape or textbox
strSlideXml += `<p:nvSpPr><p:cNvPr id="${idx + 2}" name="${shapeName}">`
// <Hyperlink>
if (slideItemObj.options.hyperlink && slideItemObj.options.hyperlink.url)
strSlideXml +=
'<a:hlinkClick r:id="rId' +
slideItemObj.options.hyperlink.rId +
'" tooltip="' +
(slideItemObj.options.hyperlink.tooltip ? encodeXmlEntities(slideItemObj.options.hyperlink.tooltip) : '') +
'"/>'
if (slideItemObj.options.hyperlink && 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"/>'
// </Hyperlink>
strSlideXml += '</p:cNvPr>'
strSlideXml += '<p:cNvSpPr' + (slideItemObj.options && slideItemObj.options.isTextBox ? ' txBox="1"/>' : '/>')
strSlideXml += `<p:nvPr>${slideItemObj.type === 'placeholder' ? genXmlPlaceholder(slideItemObj) : genXmlPlaceholder(placeholderObj)}</p:nvPr>`
strSlideXml += '</p:nvSpPr><p:spPr>'

// B: Assign Starting and Ending shape for connections ======================
if (sourceId !== null) {
strSlideXml += '<a:stCxn id="' + sourceId + '" idx="' + slideItemObj.options.line.sourceAnchorPos + '"/>';
}
if (targetId !== null) {
strSlideXml += '<a:endCxn id="' + targetId + '" idx="' + slideItemObj.options.line.targetAnchorPos + '"/>';
}
strSlideXml += '</p:cNvCxnSpPr><p:nvPr/>';
strSlideXml += '</p:nvCxnSpPr>';
} else {
// A: Start SHAPE =======================================================
strSlideXml += '<p:sp>'

// B: The addition of the "txBox" attribute is the sole determiner of if an object is a shape or textbox
strSlideXml += `<p:nvSpPr><p:cNvPr id="${idx + 2}" name="Object${idx + 1}"/>`
strSlideXml += '<p:cNvSpPr' + (slideItemObj.options && slideItemObj.options.isTextBox ? ' txBox="1"/>' : '/>')
strSlideXml += `<p:nvPr>${slideItemObj.type === 'placeholder' ? genXmlPlaceholder(slideItemObj) : genXmlPlaceholder(placeholderObj)}</p:nvPr>`
strSlideXml += '</p:nvSpPr>'
}
strSlideXml += '<p:spPr>'
strSlideXml += `<a:xfrm${locationAttr}>`
strSlideXml += `<a:off x="${x}" y="${y}"/>`
strSlideXml += `<a:ext cx="${cx}" cy="${cy}"/></a:xfrm>`
Expand Down Expand Up @@ -524,7 +538,11 @@ function slideObjectToXml(slide: ISlideLib | ISlideLayout): string {
strSlideXml += genXmlTextBody(slideItemObj)

// LAST: Close SHAPE =======================================================
strSlideXml += '</p:sp>'
if (slideItemObj.options.line.isConnector) {
strSlideXml += '</p:cxnSp>'
} else {
strSlideXml += '</p:sp>'
}
break

case SLIDE_OBJECT_TYPES.image:
Expand Down