@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
JavaScript
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