diff --git a/demos/common/demos.js b/demos/common/demos.js index 220ed4df3..e1d31d24c 100644 --- a/demos/common/demos.js +++ b/demos/common/demos.js @@ -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 // ======== ----------------------------------------------------------------------------------- diff --git a/src/core-interfaces.ts b/src/core-interfaces.ts index b8ab70612..520f6d46f 100644 --- a/src/core-interfaces.ts +++ b/src/core-interfaces.ts @@ -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 { @@ -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' diff --git a/src/gen-objects.ts b/src/gen-objects.ts index b66e6edd9..ad23c7f57 100644 --- a/src/gen-objects.ts +++ b/src/gen-objects.ts @@ -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, @@ -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 @@ -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 diff --git a/src/gen-xml.ts b/src/gen-xml.ts index 080536fde..fa1240a64 100644 --- a/src/gen-xml.ts +++ b/src/gen-xml.ts @@ -199,7 +199,7 @@ function slideObjectToXml(slide: ISlideLib | ISlideLayout): string { ' ' + ' ' + ' ' - // + ' '; + // + ' '; // 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) // @@ -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 += '' + 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 += ''; + strSlideXml += ''; + 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 += '' + + // B: Assign Starting and Ending shape for connections ====================== + if (sourceId !== null) { + strSlideXml += ''; + } + if (targetId !== null) { + strSlideXml += ''; + } + strSlideXml += ''; + strSlideXml += ''; + } else { + // 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 += `` + strSlideXml += '' : '/>') + strSlideXml += `${slideItemObj.type === 'placeholder' ? genXmlPlaceholder(slideItemObj) : genXmlPlaceholder(placeholderObj)}` + strSlideXml += '' + } + strSlideXml += '' strSlideXml += `` strSlideXml += `` strSlideXml += `` @@ -524,7 +538,11 @@ function slideObjectToXml(slide: ISlideLib | ISlideLayout): string { strSlideXml += genXmlTextBody(slideItemObj) // LAST: Close SHAPE ======================================================= - strSlideXml += '' + if (slideItemObj.options.line.isConnector) { + strSlideXml += '' + } else { + strSlideXml += '' + } break case SLIDE_OBJECT_TYPES.image: