UNPKG

@syncfusion/ej2-diagrams

Version:

Feature-rich diagram control to create diagrams like flow charts, organizational charts, mind maps, and BPMN diagrams. Its rich feature set includes built-in shapes, editing, serializing, exporting, printing, overview, data binding, and automatic layouts.

855 lines 128 kB
import { PathElement } from '../core/elements/path-element'; import { ImageElement } from '../core/elements/image-element'; import { TextElement } from '../core/elements/text-element'; import { GroupableView } from '../core/containers/container'; import { rotateMatrix, identityMatrix, transformPointByMatrix } from '../primitives/matrix'; import { Size } from '../primitives/size'; import { wordBreakToString, whiteSpaceToString, textAlignToString, randomId, rotatePoint } from '../utility/base-util'; import { getUserHandlePosition, canShowCorner, getInterval, getSpaceValue, canShowControlPoints } from '../utility/diagram-util'; import { getDiagramElement, getAdornerLayer, getGridLayer, getHTMLLayer, updatePath } from '../utility/dom-util'; import { measurePath, getBackgroundLayerSvg, getBackgroundImageLayer, setAttributeSvg } from '../utility/dom-util'; import { SnapConstraints, RendererAction, FlipDirection, ConnectorConstraints } from '../enum/enum'; import { ThumbsConstraints, SelectorConstraints, ElementAction } from '../enum/enum'; import { SvgRenderer } from './svg-renderer'; import { CanvasRenderer } from './canvas-renderer'; import { processPathData, splitArrayCollection, transformPath } from '../utility/path-util'; import { isDiagramChild } from '../utility/diagram-util'; import { DiagramNativeElement } from '../core/elements/native-element'; import { DiagramHtmlElement } from '../core/elements/html-element'; import { Point } from '../primitives/point'; import { canDrawThumbs, avoidDrawSelector } from '../utility/constraints-util'; import { Diagram } from '../diagram'; import { getSegmentThumbShapeHorizontal, getSegmentThumbShapeVertical } from '../objects/dictionary/common'; /** * Renderer module is used to render basic diagram elements */ /** @private */ var DiagramRenderer = /** @class */ (function () { function DiagramRenderer(name, svgRender, isSvgMode) { /** @private */ this.renderer = null; /** @private */ this.isSvgMode = true; /** @private */ this.touchMove = undefined; this.transform = { x: 0, y: 0 }; this.diagramId = name; this.element = getDiagramElement(this.diagramId); this.svgRenderer = svgRender; this.isSvgMode = isSvgMode; this.renderer = isSvgMode ? new SvgRenderer() : new CanvasRenderer(); } /** * Method used to set the cur \ * * @param {HTMLElement} canvas - Provide the canvas . * @param {string} cursor - Provide the element . * @returns {void } Method used to set the layer .\ * @private */ DiagramRenderer.prototype.setCursor = function (canvas, cursor) { canvas.style.cursor = cursor; }; /** * Method used to set the layer \ * * @returns {void } Method used to set the layer .\ * * @private */ DiagramRenderer.prototype.setLayers = function () { this.iconSvgLayer = this.element.getElementsByClassName('e-ports-expand-layer')[0]; this.adornerSvgLayer = this.element.getElementsByClassName('e-adorner-layer')[0]; this.nativeSvgLayer = this.element.getElementsByClassName('e-native-layer')[0]; this.diagramSvgLayer = this.element.getElementsByClassName('e-diagram-layer')[0]; }; DiagramRenderer.prototype.getAdornerLayer = function () { var adornerLayer = getAdornerLayer(this.diagramId); return adornerLayer; }; DiagramRenderer.prototype.getParentSvg = function (element, targetElement, canvas) { if (this.diagramId && element && element.id) { if (element.id.split('_icon_content').length > 1 || element.id.split('_nodeport').length > 1 || (element.elementActions & ElementAction.ElementIsPort)) { return this.iconSvgLayer; } if (targetElement && targetElement === 'selector') { return this.adornerSvgLayer; } else if (element instanceof DiagramNativeElement) { return this.nativeSvgLayer; } else { return this.diagramSvgLayer; } } return canvas; }; DiagramRenderer.prototype.getParentElement = function (element, defaultParent, svgElement, indexValue) { var layerGElement = defaultParent; if (svgElement && this.diagramId && element && element.id) { if (element.id.split('_icon_content').length > 1) { layerGElement = svgElement.getElementById(this.diagramId + '_diagramExpander'); defaultParent = null; } else if (element.id.split('_nodeport').length > 1) { layerGElement = svgElement.getElementById(this.diagramId + '_diagramPorts'); } else if (element instanceof DiagramNativeElement) { layerGElement = svgElement.getElementById(this.diagramId + '_nativeLayer'); defaultParent = null; } else if (element.elementActions & ElementAction.ElementIsPort) { layerGElement = svgElement.getElementById(this.diagramId + '_diagramPorts'); defaultParent = null; } else { layerGElement = svgElement.getElementById(this.diagramId + '_diagramLayer'); } var groupElement = this.getGroupElement(element, defaultParent || layerGElement, indexValue); layerGElement = groupElement.g; if (groupElement.svg) { svgElement = groupElement.svg; } } return { g: layerGElement, svg: svgElement }; }; DiagramRenderer.prototype.getGroupElement = function (element, canvas, indexValue) { var gElement; var parentSvg = this.getParentSvg(element); var svgElement; if (canvas && parentSvg) { if (parentSvg) { gElement = parentSvg.getElementById(element.id + '_groupElement'); if (!gElement && parentSvg !== this.nativeSvgLayer) { //code added var nativeSvg = this.nativeSvgLayer; gElement = nativeSvg.getElementById(element.id + '_groupElement'); svgElement = nativeSvg; } } if (!gElement) { gElement = this.svgRenderer.createGElement('g', { id: element.id + '_groupElement' }); if (indexValue !== undefined && canvas.childNodes.length > indexValue) { canvas.insertBefore(gElement, canvas.childNodes[parseInt(indexValue.toString(), 10)]); } else { canvas.appendChild(gElement); } } } return { g: gElement, svg: svgElement }; }; /** * Method used to render the diagram element \ * * @returns {void } Method used to render the diagram element .\ * * @param {DiagramElement} element - Provide the DiagramElement value. * @param {HTMLCanvasElement | SVGElement } canvas - Provide the canvas value. * @param {HTMLElement } htmlLayer - Provide the HTMLElement value. * @param {Transforms } transform - Provide the Transforms value. * @param {SVGSVGElement} parentSvg - Provide the SVGSVGElement value. * @param {boolean } createParent - Provide the boolean value. * @param {boolean } fromPalette - Provide the boolean value. * @param {number } indexValue - Provide the indexValue value. * @param {boolean } isPreviewNode - Provide the isPreviewNode value. * @param {object } centerPoint - Provide the centerPoint value. * @param {object} portCenterPoint - Provide the portCenterPoint value. * @private */ DiagramRenderer.prototype.renderElement = function (element, canvas, htmlLayer, transform, parentSvg, createParent, fromPalette, indexValue, isPreviewNode, centerPoint, portCenterPoint) { var isElement = true; if (element instanceof GroupableView) { // eslint-disable-next-line @typescript-eslint/no-unused-vars isElement = false; element.id = element.id ? element.id : randomId(); this.renderContainer(element, canvas, htmlLayer, transform, parentSvg, createParent, fromPalette, indexValue, isPreviewNode, centerPoint, portCenterPoint); } else if (element instanceof ImageElement) { this.renderImageElement(element, canvas, transform, parentSvg, fromPalette); } else if (element instanceof PathElement) { this.renderPathElement(element, canvas, transform, parentSvg, fromPalette, isPreviewNode, portCenterPoint); } else if (element instanceof TextElement) { this.renderTextElement(element, canvas, transform, parentSvg, fromPalette, centerPoint); } else if (element instanceof DiagramNativeElement) { this.renderNativeElement(element, canvas, transform, parentSvg, fromPalette); } else if (element instanceof DiagramHtmlElement) { this.renderHTMLElement(element, canvas, htmlLayer, transform, parentSvg, fromPalette, indexValue); } else { this.renderRect(element, canvas, transform, parentSvg, isPreviewNode); } }; /** * Method used to draw the selection rectangle for the node \ * * @returns {void } Method used to draw the selection rectangle for the node .\ * * @param {number} x - Provide the DiagramElement value. * @param {number } y - Provide the SVGElement value. * @param {number } w - Provide the Transforms value. * @param {number } h - Provide the Transforms value. * @param {HTMLCanvasElement | SVGElement } canvas - Provide the Transforms value. * @param {number } t - Provide the Transforms value. * @private */ DiagramRenderer.prototype.drawSelectionRectangle = function (x, y, w, h, canvas, t) { x = (x + t.tx) * t.scale; y = (y + t.ty) * t.scale; var options = { width: w * t.scale, height: h * t.scale, x: x + 0.5, y: y + 0.5, fill: 'transparent', stroke: 'gray', angle: 0, pivotX: 0.5, pivotY: 0.5, strokeWidth: 1, dashArray: '6 3', opacity: 1, visible: true, id: canvas.id + '_selected_region' }; var adornerLayer = this.getAdornerLayer(); this.svgRenderer.updateSelectionRegion(adornerLayer, options); }; /** * Method used to render the highlighter \ * * @returns {void } Method used to render the highlighter .\ * * @param {DiagramElement} element - Provide the DiagramElement value. * @param {SVGElement } canvas - Provide the SVGElement value. * @param {Transforms } transform - Provide the Transforms value. * @private */ DiagramRenderer.prototype.renderHighlighter = function (element, canvas, transform) { var width = element.actualSize.width || 2; var height = element.actualSize.height || 2; var x = element.offsetX - width * element.pivot.x; var y = element.offsetY - height * element.pivot.y; x = (x + transform.tx) * transform.scale; y = (y + transform.ty) * transform.scale; var options = { width: width * transform.scale, height: height * transform.scale, x: x, y: y, fill: 'transparent', stroke: '#8CC63F', angle: element.rotateAngle, pivotX: element.pivot.x, pivotY: element.pivot.y, strokeWidth: 4, dashArray: '', opacity: 1, cornerRadius: 0, visible: true, id: canvas.id + '_highlighter', class: 'e-diagram-highlighter' }; this.svgRenderer.drawRectangle(canvas, options, this.diagramId, undefined, undefined, canvas); }; /** * Method used to render the node selection rectangle \ * * @returns {void } Method used to render the node selection rectangle .\ * * @param {DiagramElement} element - Provide the DiagramElement value. * @param {SVGElement } canvas - Provide the SVGElement value. * @param {Transforms } transform - Provide the Transforms value. * @param {number } isFirst - Provide the boolean value. * @private */ DiagramRenderer.prototype.renderSelectionRectangle = function (element, canvas, transform, isFirst) { var width = element.actualSize.width || 2; var height = element.actualSize.height || 2; var x = element.offsetX - width * element.pivot.x; var y = element.offsetY - height * element.pivot.y; x = (x + transform.tx) * transform.scale; y = (y + transform.ty) * transform.scale; var options = { width: width * transform.scale, height: height * transform.scale, x: x, y: y, fill: 'transparent', stroke: '#00cc00', angle: element.rotateAngle, pivotX: element.pivot.x, pivotY: element.pivot.y, strokeWidth: isFirst ? 2 : 1, dashArray: '', opacity: 1, cornerRadius: 0, visible: true, id: element.id + '_highlighter', class: isFirst ? 'e-diagram-first-selection-indicator e-diagram-selection-indicator' : 'e-diagram-selection-indicator' }; var parentSvg = this.getParentSvg(element, 'selector'); this.svgRenderer.drawRectangle(canvas, options, this.diagramId, undefined, undefined, parentSvg); }; /** * Method used to render the selection line for connector \ * * @returns {void } Method used to render the selection line for connector .\ * * @param {PathElement} element - Provide the path element of the diagram . * @param { HTMLCanvasElement | SVGElement } canvas - Provide the canvas element value. * @param { Transforms } transform - Provide the transform value. * @param { boolean } isFirst - Provide the boolean value. * @private */ DiagramRenderer.prototype.renderSelectionLine = function (element, canvas, transform, isFirst) { var options = this.getBaseAttributes(element, transform); options.data = element.absolutePath; options.id = options.id + '_highlighter'; var ariaLabel = element.description ? element.description : element.id; if (!this.isSvgMode) { options.x = element.flipOffset.x ? element.flipOffset.x : options.x; options.y = element.flipOffset.y ? element.flipOffset.y : options.y; } if (transform) { options.x = options.x * transform.scale; options.y = options.y * transform.scale; } options.stroke = '#00cc00'; options.strokeWidth = isFirst ? 2 : 1; options.class = isFirst ? 'e-diagram-first-selection-indicator e-diagram-selection-indicator' : 'e-diagram-selection-indicator'; var parentSvg = this.getParentSvg(element, 'selector'); this.svgRenderer.drawPath(canvas, options, this.diagramId, undefined, parentSvg, ariaLabel, transform.scale); }; /** * Method used to render the stack highlighter \ * * @returns {void } Method used to render the stack highlighter .\ * * @param {DiagramElement} element - Provide the DiagramElement value. * @param {SVGElement } canvas - Provide the SVGElement value. * @param {Transforms } transform - Provide the Transforms value. * @param {boolean} isVertical - Provide the Boolean value. * @param {PointModel } position - Provide the PointModel value. * @param {boolean } isUml - Provide the boolean value. * @param {boolean } isSwimlane - Provide the boolean value. * @private */ DiagramRenderer.prototype.renderStackHighlighter = function (element, canvas, transform, isVertical, position, isUml, isSwimlane) { var width = element.actualSize.width || 2; var x = element.offsetX - width * element.pivot.x; var height = element.actualSize.height || 2; var y = element.offsetY - height * element.pivot.y; x = (x + transform.tx) * transform.scale; var data; var bounds = element.bounds; var newPathString = ''; y = (y + transform.ty) * transform.scale; if (!isVertical) { var d = height * transform.scale; data = 'M 10 -10 L 0 0 Z M -10 -10 L 0 0 Z M 0 0 L 0 ' + (d) + ' Z M 0 ' + (d) + ' L -10 ' + (d + 10) + ' Z L 10 ' + (d + 10) + ' Z'; if (position.x >= element.offsetX) { //879085- swimlane helper guides not rendered properly when zoomed x += width * transform.scale; } } else { if (isUml) { var d = width * transform.scale; data = 'M 0 0 L ' + (d + 2) + ' 0 Z'; var scaleX = -bounds.x; var scaleY = -bounds.y; var arrayCollection = []; scaleX = element.actualSize.width / Number(bounds.width ? bounds.width : 1) * transform.scale; scaleY = element.actualSize.height / Number(bounds.height ? bounds.height : 1) * transform.scale; var umlData = 'M7,4 L8,4 8,7 11,7 11,8 8,8 8,11 7,11 7,8 4,8 4,7 7,7 z M7.5,0.99999994' + 'C3.9160004,1 1,3.9160004 0.99999994,7.5 1,11.084 3.9160004,14 7.5,14 11.084,14 14,11.084 14,7.5 14,' + '3.9160004 11.084,1 7.5,0.99999994 z M7.5,0 C11.636002,0 15,3.3639984 15,7.5 15,11.636002 11.636002,15 7.5,' + '15 3.3640003,15 0,11.636002 0,7.5 0,3.3639984 3.3640003,0 7.5,0 z'; arrayCollection = processPathData(umlData); arrayCollection = splitArrayCollection(arrayCollection); newPathString = transformPath(arrayCollection, scaleX + d + 2, scaleY - 8, false, bounds.x, bounds.y, 0, 0); if (position.y >= element.offsetY) { y += height; } } else { if (isSwimlane) { if (position.y >= element.offsetY) { //879085- swimlane helper guides not rendered properly when zoomed y += height * transform.scale; } } var d = width * transform.scale; data = 'M -10 -10 L 0 0 Z M -10 10 L 0 0 Z M 0 0 L ' + (d) + ' 0 Z M ' + (d) + ' 0 L ' + (d + 10) + ' 10 Z L ' + (d + 10) + ' -10 Z'; } } var options = { data: data + newPathString, width: width * transform.scale, height: height * transform.scale, x: x, y: y, fill: 'transparent', stroke: '#8CC63F', angle: element.rotateAngle, pivotX: element.pivot.x, pivotY: element.pivot.y, strokeWidth: 1, dashArray: '', opacity: 1, visible: true, id: canvas.id + '_stack_highlighter', class: 'e-diagram-highlighter' }; this.svgRenderer.drawPath(canvas, options, this.diagramId); }; /** * Method used to draw the line \ * * @returns {void } Method used to draw the line .\ * * @param {SVGElement} canvas - Provide the SVGElement value. * @param {LineAttributes } options - Provide the LineAttributes value. * @private */ DiagramRenderer.prototype.drawLine = function (canvas, options) { this.svgRenderer.drawLine(canvas, options); }; /** * Method used to draw the path \ * * @returns {void } Method used to draw the path .\ * * @param {SVGElement} canvas - Provide the canvas value. * @param {PathAttributes } options - Provide the PathAttributes value. * @private */ DiagramRenderer.prototype.drawPath = function (canvas, options) { this.svgRenderer.drawPath(canvas, options, this.diagramId); }; /** * Method used to render the resize handle \ * * @returns {void } Method used to render the resize handle .\ * * @param {DiagramElement} element - Provide the DiagramElement value. * @param {HTMLCanvasElement | SVGElement } canvas - Provide the canvas element. * @param { ThumbsConstraints } constraints - Provide the constraints value . * @param { number} currentZoom - Provide the currentZoom value. * @param { SelectorConstraints } selectorConstraints - Provide the selectorConstraints value . * @param { Transforms } transform - Provide the transform value. * @param { boolean } canMask - Provide the canMask boolean value. * @param { number } enableNode - Provide the enableNode value. * @param { boolean } nodeConstraints - Provide the nodeConstraints value. * @param { boolean } isSwimlane - Provide the isSwimlane boolean value. * @param { number } handleSize - Provide the handleSize value. * @private */ DiagramRenderer.prototype.renderResizeHandle = function (element, canvas, constraints, currentZoom, selectorConstraints, transform, canMask, enableNode, nodeConstraints, isSwimlane, handleSize) { var left = element.offsetX - element.actualSize.width * element.pivot.x; var top = element.offsetY - element.actualSize.height * element.pivot.y; var height = element.actualSize.height; var width = element.actualSize.width; if (!isSwimlane && (constraints & ThumbsConstraints.Rotate && canDrawThumbs(this.rendererActions) && (!avoidDrawSelector(this.rendererActions)))) { this.renderPivotLine(element, canvas, transform, selectorConstraints, canMask); this.renderRotateThumb(element, canvas, transform, selectorConstraints, canMask); } else { if (this.touchMove) { var rotateThumb = document.getElementById('rotateThumb'); if (rotateThumb) { rotateThumb.setAttribute('visibility', 'hidden'); } } } this.renderBorder(element, canvas, transform, enableNode, nodeConstraints, isSwimlane); var nodeWidth = element.actualSize.width * currentZoom; var nodeHeight = element.actualSize.height * currentZoom; if (!nodeConstraints && canDrawThumbs(this.rendererActions) && (!avoidDrawSelector(this.rendererActions))) { //Bug 860033: Bpmn text annotation path size not rendered properly while dragging. //Added below condition to prevent the resize thumbs for bpmn text annotation. if (!element.isTextAnnotation) { if (nodeWidth >= 40 && nodeHeight >= 40) { //Hide corners when the size is less than 40 if (selectorConstraints & SelectorConstraints.ResizeNorthWest) { this.renderCircularHandle('resizeNorthWest', element, left, top, canvas, canShowCorner(selectorConstraints, 'ResizeNorthWest'), constraints & ThumbsConstraints.ResizeNorthWest, transform, undefined, canMask, { 'aria-label': 'Thumb to resize the selected object on top left side direction' }, undefined, 'e-diagram-resize-handle e-northwest', handleSize); } if (selectorConstraints & SelectorConstraints.ResizeNorthEast) { this.renderCircularHandle('resizeNorthEast', element, left + width, top, canvas, canShowCorner(selectorConstraints, 'ResizeNorthEast'), constraints & ThumbsConstraints.ResizeNorthEast, transform, undefined, canMask, { 'aria-label': 'Thumb to resize the selected object on top right side direction' }, undefined, 'e-diagram-resize-handle e-northeast', handleSize); } if (selectorConstraints & SelectorConstraints.ResizeSouthWest) { this.renderCircularHandle('resizeSouthWest', element, left, top + height, canvas, canShowCorner(selectorConstraints, 'ResizeSouthWest'), constraints & ThumbsConstraints.ResizeSouthWest, transform, undefined, canMask, { 'aria-label': 'Thumb to resize the selected object on bottom left side direction' }, undefined, 'e-diagram-resize-handle e-southwest', handleSize); } if (selectorConstraints & SelectorConstraints.ResizeSouthEast) { this.renderCircularHandle('resizeSouthEast', element, left + width, top + height, canvas, canShowCorner(selectorConstraints, 'ResizeSouthEast'), constraints & ThumbsConstraints.ResizeSouthEast, transform, undefined, canMask, { 'aria-label': 'Thumb to resize the selected object on bottom right side direction' }, undefined, 'e-diagram-resize-handle e-southeast', handleSize); } } if (selectorConstraints & SelectorConstraints.ResizeNorth) { this.renderCircularHandle('resizeNorth', element, left + width / 2, top, canvas, canShowCorner(selectorConstraints, 'ResizeNorth'), constraints & ThumbsConstraints.ResizeNorth, transform, undefined, canMask, { 'aria-label': 'Thumb to resize the selected object on top side direction' }, undefined, 'e-diagram-resize-handle e-north', handleSize); } if (selectorConstraints & SelectorConstraints.ResizeSouth) { this.renderCircularHandle('resizeSouth', element, left + width / 2, top + height, canvas, canShowCorner(selectorConstraints, 'ResizeSouth'), constraints & ThumbsConstraints.ResizeSouth, transform, undefined, canMask, { 'aria-label': 'Thumb to resize the selected object on bottom side direction' }, undefined, 'e-diagram-resize-handle e-south', handleSize); } if (selectorConstraints & SelectorConstraints.ResizeWest) { this.renderCircularHandle('resizeWest', element, left, top + height / 2, canvas, canShowCorner(selectorConstraints, 'ResizeWest'), constraints & ThumbsConstraints.ResizeWest, transform, undefined, canMask, { 'aria-label': 'Thumb to resize the selected object on left side direction' }, undefined, 'e-diagram-resize-handle e-west', handleSize); } if (selectorConstraints & SelectorConstraints.ResizeEast) { this.renderCircularHandle('resizeEast', element, left + width, top + height / 2, canvas, canShowCorner(selectorConstraints, 'ResizeEast'), constraints & ThumbsConstraints.ResizeEast, transform, undefined, canMask, { 'aria-label': 'Thumb to resize the selected object on right side direction' }, undefined, 'e-diagram-resize-handle e-east', handleSize); } } } var selector = document.getElementById(this.diagramId + '_SelectorElement'); if (element.flippedPoint && selector) { var domElement = document.getElementById(element.id + '_groupElement'); var transform_1 = domElement.getAttribute('transform'); if (transform_1.includes('scale')) { var x = element.flippedPoint.x - element.corners.topLeft.x; var y = element.flippedPoint.y - element.corners.topLeft.y; transform_1 = "translate(" + x + "," + y + ")"; } if (transform_1) { selector.setAttribute('transform', transform_1); } } else if (selector) { selector.setAttribute('transform', ''); } }; /** * Method used to render the end point of the handle \ * * @returns {void } Method used to render the end point of the handle .\ * * @param {ConnectorModel} selector - Provide the ConnectorModel. * @param {HTMLCanvasElement | SVGElement } canvas - Provide the element. * @param { ThumbsConstraints } constraints - Provide the constraints value . * @param { SelectorConstraints} selectorConstraints - Provide the selectorConstraints value. * @param { Transforms } transform - Provide the transform value . * @param { boolean } connectedSource - Provide the connectedSource boolean value. * @param { boolean } connectedTarget - Provide the connectedTarget boolean value. * @param { boolean } isSegmentEditing - Provide the isSegmentEditing boolean value. * @param { boolean } canShowBezierPoints - Provide the canShowBezierPoints boolean value. * @param {number} handleSize - Provide the handleSize value. * @private */ DiagramRenderer.prototype.renderEndPointHandle = function (selector, canvas, constraints, selectorConstraints, transform, connectedSource, connectedTarget, isSegmentEditing, canShowBezierPoints, handleSize) { var sourcePoint = selector.sourcePoint; var targetPoint = selector.targetPoint; var wrapper = selector.wrapper; var i; var segment; this.renderCircularHandle('connectorSourceThumb', wrapper, sourcePoint.x, sourcePoint.y, canvas, canShowCorner(selectorConstraints, 'ConnectorSourceThumb'), constraints & ThumbsConstraints.ConnectorSource, transform, connectedSource, undefined, { 'aria-label': 'Thumb to move the source point of the connector' }, undefined, 'e-diagram-endpoint-handle e-sourceend', handleSize); this.renderCircularHandle('connectorTargetThumb', wrapper, targetPoint.x, targetPoint.y, canvas, canShowCorner(selectorConstraints, 'ConnectorTargetThumb'), constraints & ThumbsConstraints.ConnectorTarget, transform, connectedTarget, undefined, { 'aria-label': 'Thumb to move the target point of the connector' }, undefined, 'e-diagram-endpoint-handle e-targetend', handleSize); if (isSegmentEditing) { if ((selector.type === 'Straight') && selector.segments.length > 0) { for (i = 0; i < selector.segments.length - 1; i++) { segment = selector.segments[parseInt(i.toString(), 10)]; var className = 'e-diagram-straight-segment-handle'; this.renderCircularHandle(('segementThumb_' + (i + 1)), wrapper, segment.point.x, segment.point.y, canvas, true, constraints & ThumbsConstraints.ConnectorSource, transform, connectedSource, null, null, i, className, handleSize); } } //824805-Support to modify bezier connector segment thumb shape and style else if ((selector.type === 'Bezier') && selector.segments.length > 0) { for (i = 0; i < selector.segments.length - 1; i++) { segment = selector.segments[parseInt(i.toString(), 10)]; var className = 'e-diagram-bezier-segment-handle'; this.renderBezierHandle(('segementThumb_' + (i + 1)), wrapper, segment.point.x, segment.point.y, canvas, true, selector, transform, connectedSource, null, i, className, handleSize); } } else { // (EJ2-57115) - Added below code to check if maxSegmentThumb is zero or not if (!selector.maxSegmentThumb) { for (i = 0; i < selector.segments.length; i++) { var seg = selector.segments[parseInt(i.toString(), 10)]; this.renderOrthogonalThumbs('orthoThumb_' + (i + 1), wrapper, seg, canvas, canShowCorner(selectorConstraints, 'ConnectorSourceThumb'), transform, selector); } } else { // (EJ2-57115) - Added below code to check if maxSegmentThumb is non zero then we have ignore the rendering of // first and last segment thumb var start = selector.segments.length <= selector.maxSegmentThumb ? 0 : 1; var end = selector.segments.length <= selector.maxSegmentThumb ? selector.segments.length : selector.segments.length - 1; // (EJ2-57115) - If maxSegmentThumb is greater than or equal to 3 means then set start as second segment(1) and end as last before segment if (selector.maxSegmentThumb >= 3 && selector.segments.length === 3) { start = 1; end = selector.segments.length - 1; } // (EJ2-57115) - If segments length is greater than maxSegmentThumb + 2 means then set start as 2 start = selector.segments.length > selector.maxSegmentThumb + 2 ? 2 : start; // (EJ2-57115) - If segments length is greater than maxSegmentThumb + 2 means then set end as last before segment end = selector.segments.length > selector.maxSegmentThumb + 2 ? selector.segments.length - 2 : end; if (selector.segments.length === 1 && selector.segments[0].points.length <= 2) { start = 1; end = selector.segments.length; } for (i = start; i < end; i++) { var seg = selector.segments[parseInt(i.toString(), 10)]; this.renderOrthogonalThumbs('orthoThumb_' + (i + 1), wrapper, seg, canvas, canShowCorner(selectorConstraints, 'ConnectorSourceThumb'), transform, selector); } } } } if (selector.type === 'Bezier' && canShowBezierPoints) { var segmentCount = selector.segments.length - 1; var controlPointsVisibility = selector.bezierSettings != null ? selector.bezierSettings.controlPointsVisibility : null; for (i = 0; i <= segmentCount; i++) { var segment_1 = selector.segments[parseInt(i.toString(), 10)]; var bezierPoint = !Point.isEmptyPoint(segment_1.point1) ? segment_1.point1 : segment_1.bezierPoint1; if (controlPointsVisibility != null && (i === 0 && canShowControlPoints(controlPointsVisibility, 'Source')) || (i !== 0 && canShowControlPoints(controlPointsVisibility, 'Intermediate'))) { this.renderCircularHandle('bezierPoint_' + (i + 1) + '_1', wrapper, bezierPoint.x, bezierPoint.y, canvas, canShowCorner(selectorConstraints, 'ConnectorSourceThumb'), constraints & ThumbsConstraints.ConnectorSource, transform, undefined, undefined, { 'aria-label': 'Thumb to move the source point of the connector' }, undefined, 'e-diagram-bezier-control-handle e-source', handleSize); if (canShowCorner(selectorConstraints, 'ConnectorSourceThumb')) { this.renderBezierLine('bezierLine_' + (i + 1) + '_1', wrapper, canvas, segment_1.points[0], !Point.isEmptyPoint(segment_1.point1) ? segment_1.point1 : segment_1.bezierPoint1, transform); } } bezierPoint = !Point.isEmptyPoint(segment_1.point2) ? segment_1.point2 : segment_1.bezierPoint2; if (controlPointsVisibility != null && (i === segmentCount && canShowControlPoints(controlPointsVisibility, 'Target')) || (i !== segmentCount && canShowControlPoints(controlPointsVisibility, 'Intermediate'))) { this.renderCircularHandle('bezierPoint_' + (i + 1) + '_2', wrapper, bezierPoint.x, bezierPoint.y, canvas, canShowCorner(selectorConstraints, 'ConnectorTargetThumb'), constraints & ThumbsConstraints.ConnectorTarget, transform, undefined, undefined, { 'aria-label': 'Thumb to move the target point of the connector' }, undefined, 'e-diagram-bezier-control-handle e-target', handleSize); if (canShowCorner(selectorConstraints, 'ConnectorTargetThumb')) { this.renderBezierLine('bezierLine_' + (i + 1) + '_2', wrapper, canvas, segment_1.points[1], !Point.isEmptyPoint(segment_1.point2) ? segment_1.point2 : segment_1.bezierPoint2, transform); } } } } }; /** * Method used to render the orthogonal thumb \ * * @returns {void } Method used to render the orthogonal thumb .\ * * @param {string} id - Provide the id for the element. * @param {DiagramElement } selector - Provide the selector element. * @param { OrthogonalSegment } segment - Provide the segment value . * @param { HTMLCanvasElement | SVGElement } canvas - Provide the canvas element value. * @param { boolean } visibility - Provide the visibility value . * @param { Transforms } t - Provide the Transforms value. * @param { ConnectorModel } connector - Provide the connector value. * @private */ DiagramRenderer.prototype.renderOrthogonalThumbs = function (id, selector, segment, canvas, visibility, t, connector) { var orientation; var visible; var length; var j = 0; var direction; // (EJ2-57115) - Added below code to check if maxSegmentThumb is zero or not if (!connector.maxSegmentThumb) { for (j = 0; j < segment.points.length - 1; j++) { length = Point.distancePoints(segment.points[parseInt(j.toString(), 10)], segment.points[j + 1]); orientation = (segment.points[parseInt(j.toString(), 10)].y.toFixed(2) === segment.points[j + 1].y.toFixed(2)) ? 'horizontal' : 'vertical'; //850501-Added below code to check the direction of the segments direction = Point.direction(segment.points[parseInt(j.toString(), 10)], segment.points[j + 1]); visible = (length >= 50 && segment.allowDrag) ? true : false; this.renderOrthogonalThumb((id + '_' + (j + 1)), selector, (((segment.points[parseInt(j.toString(), 10)].x + segment.points[j + 1].x) / 2)), (((segment.points[parseInt(j.toString(), 10)].y + segment.points[j + 1].y) / 2)), canvas, visible, orientation, t, connector, direction); } } else { // (EJ2-57115) - Added below code to check if maxSegmentThumb greater then 3 means then we have ignore the rendering of // first and last segment thumb // Set the start value as 1 if segment points is greater than 3 var start = segment.points.length < 3 ? 0 : 1; // set the end value as segment.points.length - 2 if segment points is greater then 3 var end = segment.points.length < 3 ? segment.points.length - 1 : segment.points.length - 2; start = connector.segments.length === 1 ? start : 0; end = connector.segments.length === 1 ? end : segment.points.length - 1; for (j = start; j < end; j++) { length = Point.distancePoints(segment.points[parseInt(j.toString(), 10)], segment.points[j + 1]); orientation = (segment.points[parseInt(j.toString(), 10)].y.toFixed(2) === segment.points[j + 1].y.toFixed(2)) ? 'horizontal' : 'vertical'; visible = (length >= 50 && segment.allowDrag) ? true : false; this.renderOrthogonalThumb((id + '_' + (j + 1)), selector, (((segment.points[parseInt(j.toString(), 10)].x + segment.points[j + 1].x) / 2)), (((segment.points[parseInt(j.toString(), 10)].y + segment.points[j + 1].y) / 2)), canvas, visible, orientation, t, connector, direction); } } }; /** * Method used to render the orthogonal thumb \ * * @returns {void } Method used to render the orthogonal thumb .\ * * @param {string} id - Provide the id for the element. * @param {DiagramElement } selector - Provide the selector element. * @param { Transforms } x - Provide the x value . * @param { Transforms } y - Provide the y value. * @param { HTMLCanvasElement | SVGElement } canvas - Provide the canvas element. * @param { boolean } visible - Provide the visible boolean value. * @param { string } orientation - Provide the orientation value. * @param { Transforms } t - Provide the Transforms value. * @param { ConnectorModel } connector - Provide the connector value. * @param { string } direction - Provide the direction of the segment. * @private */ DiagramRenderer.prototype.renderOrthogonalThumb = function (id, selector, x, y, canvas, visible, orientation, t, connector, direction) { var path; var segmentThumbAngle = 0; var diagramElement = document.getElementById(this.diagramId); var instance = 'ej2_instances'; var diagram; if (diagramElement) { diagram = diagramElement["" + instance][0]; } //824805-Support to modify connector segment thumb shape and style based on constraints var inheritsegmentThumbShape = (connector.constraints & ConnectorConstraints.InheritSegmentThumbShape); var segmentThumbShape = inheritsegmentThumbShape ? diagram.segmentThumbShape : connector.segmentThumbShape; //850501-Added below code to modify connector segment thumb size based on constraints var inheritSegmentThumbSize = (connector.constraints & ConnectorConstraints.InheritSegmentThumbSize); var segmentThumbSize = inheritSegmentThumbSize ? diagram.segmentThumbSize : connector.segmentThumbSize; if (orientation === 'horizontal') { path = getSegmentThumbShapeHorizontal(segmentThumbShape); } else { path = getSegmentThumbShapeVertical(segmentThumbShape); } //850501-Added the below code to change the angles of the segmentThumbShape(arrows) based on the direction if (segmentThumbShape === 'Arrow' || segmentThumbShape === 'DoubleArrow' || segmentThumbShape === 'OpenArrow') { switch (direction) { case 'Bottom': case 'Right': segmentThumbAngle = 180; break; default: segmentThumbAngle = 0; } } else if (segmentThumbShape === 'Fletch' || segmentThumbShape === 'OpenFetch' || segmentThumbShape === 'IndentedArrow' || segmentThumbShape === 'OutdentedArrow') { switch (direction) { case 'Bottom': segmentThumbAngle = -90; break; case 'Top': segmentThumbAngle = 90; break; case 'Right': segmentThumbAngle = 180; break; default: segmentThumbAngle = 0; } } var options = { x: ((x + t.tx) * t.scale) - segmentThumbSize / 2, y: ((y + t.ty) * t.scale) - segmentThumbSize / 2, angle: segmentThumbAngle, fill: '#e2e2e2', stroke: 'black', strokeWidth: 1, dashArray: '', data: path, width: segmentThumbSize, height: segmentThumbSize, pivotX: 0.5, pivotY: 0.5, opacity: 1, visible: visible, id: id, class: 'e-diagram-ortho-segment-handle' }; //850501-Added the below code to adjust size for the segment thumb shape based on the size given var absoluteBounds = measurePath(options.data); var desiredSize = new Size(options.width, options.height); var pathElement = new PathElement(); options.data = pathElement.updatePath(options.data, absoluteBounds, desiredSize); //Bug 914365: Node is not resizable using touch interaction //Added below code to update the element if it is already rendered during touch move interaction if (this.touchMove) { var thumb = document.getElementById(id); if (thumb) { this.updateSegmentPosition(thumb, options); } else { this.svgRenderer.drawPath(canvas, options, this.diagramId); } } else { this.svgRenderer.drawPath(canvas, options, this.diagramId); } }; /** * Method used to render the pivot line line\ * * @returns {void } Method used to render the pivot line line .\ * * @param {DiagramElement} element - Provide the diagram element value. * @param { HTMLCanvasElement | SVGElement } canvas - Provide the canvas element. * @param { Transforms } transform - Provide the transform value . * @param { SelectorConstraints } selectorConstraints - Provide the selector constraints value. * @param { boolean } canMask - Provide the canMask boolean value. * @private */ DiagramRenderer.prototype.renderPivotLine = function (element, canvas, transform, selectorConstraints, canMask) { var wrapper = element; var dashArray = '2,3'; var visible = (selectorConstraints & SelectorConstraints.Rotate) ? true : false; if (canMask) { visible = false; } var options = this.getBaseAttributes(wrapper, transform); options.fill = 'None'; options.stroke = 'black'; options.strokeWidth = 1; options.dashArray = dashArray; options.visible = visible; var scale = transform.scale; options.x *= scale; options.y *= scale; options.width *= scale; options.height *= scale; options.id = 'pivotLine'; options.class = 'e-diagram-pivot-line'; var startPoint = { x: wrapper.actualSize.width * wrapper.pivot.x * scale, y: -20 }; var endPoint = { x: wrapper.actualSize.width * wrapper.pivot.x * scale, y: 0 }; options.startPoint = startPoint; options.endPoint = endPoint; this.svgRenderer.drawLine(canvas, options); }; /** * Method used to render the bezier line for the connector \ * * @returns {void } Method used to render the bezier line for the connector .\ * * @param {string} id - Provide the id value for the bezier line. * @param { DiagramElement } wrapper - Provide the wrapper for the element. * @param { HTMLCanvasElement | SVGElement } canvas - Provide the canvas element . * @param { PointModel } start - Provide the pointmodel value. * @param { PointModel } end - Provide the pointmodel value. * @param { Transforms } transform - Provide the itransform value . * @private */ DiagramRenderer.prototype.renderBezierLine = function (id, wrapper, canvas, start, end, transform) { var dashArray = '3,3'; var options = this.getBaseAttributes(wrapper, transform); options.id = id; options.stroke = 'black'; options.strokeWidth = 1; options.dashArray = dashArray; options.fill = 'None'; options.class = 'e-diagram-bezier-control-line'; options.x = 0; options.y = 0; var scale = transform.scale; var x1 = (start.x + transform.tx) * scale; var y1 = (start.y + transform.ty) * scale; var x2 = (end.x + transform.tx) * scale; var y2 = (end.y + transform.ty) * scale; var startPoint = { x: x1, y: y1 }; var endPoint = { x: x2, y: y2 }; options.startPoint = startPoint; options.endPoint = endPoint; this.svgRenderer.drawLine(canvas, options); }; /** * Method used to render the circular handle for the node element \ * * @returns {void } Method used to render the circular handle for the node element .\ * * @param {string} id - Provide the id value. * @param { DiagramElement } selector - Provide the selector element value. * @param { number } cx - Provide cx value . * @param { number } cy - Provide cx value. * @param { HTMLCanvasElement | SVGElement } canvas - Provide the canvas element. * @param { boolean } visible - Provide the visible property for the handle . * @param { number } enableSelector - Provide the value for the enableSelector . * @param { Transforms } t - Provide the transform value . * @param { boolean } connected - Provide the connected boolean value . * @param { boolean } canMask - Provide the canMask boolean value . * @param { Object } ariaLabel - Provide the label properties . * @param { number } count - Provide the count value . * @param { string } className - Provide the class name for this element . * @param { number } handleSize - Provide the handle size value . * * @private */ // Feature (EJ2-44346) Provide support to increase the size of the resize thumb DiagramRenderer.prototype.renderCircularHandle = function (id, selector, cx, cy, canvas, visible, enableSelector, t, connected, canMask, ariaLabel, count, className, handleSize) { var wrapper = selector; var newPoint = { x: cx, y: cy }; if (wrapper.rotateAngle !== 0 || wrapper.parentTransform !== 0) { var matrix = identityMatrix(); rotateMatrix(matrix, wrapper.rotateAngle + wrapper.parentTransform, wrapper.offsetX, wrapper.offsetY); newPoint = transformPointByMatrix(matrix, newPoint); } var options = this.getBaseAttributes(wrapper); options.stroke = 'black'; options.strokeWidth = 1; if (count !== undefined) { options.id = 'segmentEnd_' + count; options.fill = '#e2e2e2'; } else { options.fill = connected ? '#8CC63F' : 'white'; } options.cornerRadius = handleSize / 2; options.angle = selector.rotateAngle; options.id = id; options.visible = visible; options.class = className; options.width = handleSize; options.height = handleSize; // EJ2-65895 - Added below code to calculate the rect x and y if node pivot is not equal to 0.5 options.x = (newPoint.x + t.tx) * t.scale; options.y = (newPoint.y + t.ty) * t.scale; options.x = options.x - options.width / 2; options.y = options.y - options.height / 2; if (connected) { options.class += ' e-connected'; } if (canMask) { options.visible = false; } //Bug 914365: Node is not resiz