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.

1,005 lines (1,004 loc) 47.7 kB
import { Point } from './../primitives/point'; import { Size } from './../primitives/size'; import { pathSegmentCollection, processPathData } from './../utility/path-util'; import { setAttributeSvg, setChildPosition } from './../utility/dom-util'; import { overFlow, wordBreakToString, cornersPointsBeforeRotation } from './../utility/base-util'; import { CanvasRenderer } from './../rendering/canvas-renderer'; import { DiagramNativeElement } from '../core/elements/native-element'; import { createSvgElement, createHtmlElement, getBackgroundLayerSvg } from '../utility/dom-util'; import { removeGradient, checkBrowserInfo } from '../utility/diagram-util'; import { Diagram } from '../diagram'; /** * SVG Renderer */ /** @private */ var SvgRenderer = /** @class */ (function () { function SvgRenderer() { } /** * Draw the shawdow for the rectangle shape in diagram \ * * @returns {void} Draw the shawdow for the rectangle shape in diagram .\ * * @param { SVGElement} options - Provide the base attributes . * @param { RectAttributes} canvas - Provide the canvas values . * @param { string} collection - Provide the collection value. * @param { boolean} parentSvg - Provide the parent SVG values . * @private */ SvgRenderer.prototype.renderShadow = function (options, canvas, collection, parentSvg) { if (collection === void 0) { collection = null; } var pointModel = { x: 0, y: 0 }; var point = Point.transform(pointModel, options.shadow.angle, options.shadow.distance); //const tX: number = options.x + point.x; const tY: number = options.y + point.y; //let pivotX: number = tX + options.width * options.pivotX; //let pivotY: number = tY + options.height * options.pivotY; var type; var shadowElement; if (parentSvg) { shadowElement = parentSvg.getElementById(canvas.id + '_shadow'); } if (!shadowElement) { type = collection ? 'path' : 'rect'; shadowElement = document.createElementNS('http://www.w3.org/2000/svg', type); canvas.appendChild(shadowElement); } //972592: Corner radius is not applied to shadow var attr = { 'id': canvas.id + '_shadow', 'fill': options.shadow.color, 'stroke': options.shadow.color, 'opacity': options.shadow.opacity.toString(), 'transform': 'rotate(' + options.angle + ',' + (options.x + options.width * options.pivotX) + ',' + (options.y + options.height * options.pivotY) + ')' + 'translate(' + (options.x + point.x) + ',' + (options.y + point.y) + ')', 'rx': options.cornerRadius || 0, 'ry': options.cornerRadius || 0, 'stroke-dasharray': options.dashArray }; if (parentSvg) { var svgContainer = parentSvg.getElementById(canvas.id); if (svgContainer) { svgContainer.insertBefore(shadowElement, svgContainer.firstChild); } } setAttributeSvg(shadowElement, attr); if (!collection) { setAttributeSvg(shadowElement, { 'width': options.width, 'height': options.height }); } else if (collection) { this.renderPath(shadowElement, options, collection); } }; /** * Return the dashed array values \ * * @returns {number[]} Return the dashed array values .\ * @param { SVGElement} dashArray - Return the dashed array values . * @private */ // eslint-disable-next-line @typescript-eslint/no-unused-vars SvgRenderer.prototype.parseDashArray = function (dashArray) { var dashes = []; return dashes; }; /** * Draw the Rectangle for the diagram \ * * @returns {void} Draw the Rectangle for the diagram .\ * * @param { SVGElement} svg - Provide the SVG . * @param { RectAttributes} options - Provide the Rect attributes . * @param { string} diagramId - Provide the diagram id . * @param { boolean} onlyRect - Provide the boolean attribute for the shawdow rendering . * @param { boolean} isSelector - Provide the selector possobilities . * @param { SVGSVGElement} parentSvg - Provide the parent svg element . * @param { Object} ariaLabel - Provide the Arial label attributes . * @param { boolean} isCircularHandle - Provide the boolean attribute for the circular handle . * @param { number} enableSelector - Provide the selector possobilities . * @private */ SvgRenderer.prototype.drawRectangle = function (svg, options, diagramId, onlyRect, isSelector, parentSvg, ariaLabel, isCircularHandle, enableSelector) { if (options.shadow && !onlyRect) { this.renderShadow(options, svg, undefined, parentSvg); } var id; if (options.id === svg.id) { id = options.id + '_container'; } else { id = options.id; } var rect; if (parentSvg) { rect = parentSvg.getElementById(id); } if (!rect || isSelector) { rect = document.createElementNS('http://www.w3.org/2000/svg', 'rect'); svg.appendChild(rect); } var shadowElement; if (parentSvg && !options.shadow) { shadowElement = parentSvg.getElementById(options.id + '_groupElement_shadow'); if (shadowElement) { shadowElement.parentNode.removeChild(shadowElement); } } if (parentSvg) { shadowElement = parentSvg.getElementById(options.id + '_groupElement_shadow'); if (shadowElement) { shadowElement.style.visibility = options.visible ? 'visible' : 'hidden'; } } var attr; // EJ2-65895 - Added below code to calculate the transform to render the circular handle if (isCircularHandle) { attr = { 'id': id, 'x': options.x.toString(), 'y': options.y.toString(), 'width': options.width.toString(), 'height': options.height.toString(), 'visibility': options.visible ? 'visible' : 'hidden', 'transform': 'rotate(' + options.angle + ',' + (options.x + options.width / 2) + ',' + (options.y + options.height / 2) + ')', 'rx': options.cornerRadius || 0, 'ry': options.cornerRadius || 0, 'opacity': options.opacity }; } else { var x = options.x, y = options.y, width = options.width, height = options.height, visible = options.visible, angle = options.angle, pivotX = options.pivotX, pivotY = options.pivotY, _a = options.cornerRadius, cornerRadius = _a === void 0 ? 0 : _a, _b = options.opacity, opacity = _b === void 0 ? 1 : _b; var centerX = x + width * pivotX; var centerY = y + height * pivotY; attr = { id: id, x: x + '', y: y + '', width: width + '', height: height + '', visibility: visible ? 'visible' : 'hidden', transform: "rotate(" + angle + "," + centerX + "," + centerY + ")", rx: cornerRadius, ry: cornerRadius, opacity: opacity }; } if (ariaLabel) { // BLAZ-24062: Adding 'aria-label' without role attribute it causes violation in accessibility test attr['role'] = 'img'; attr['aria-label'] = ariaLabel; } var classval = options.class || ''; if (!enableSelector) { if (classval.includes('e-diagram-resize-handle') || classval.includes('e-diagram-endpoint-handle') || classval.includes('e-diagram-bezier-control-handle')) { classval += ' e-disabled'; } } if (options.class) { attr['class'] = classval; } var poiterEvents = 'pointer-events'; if (!ariaLabel) { attr["" + poiterEvents] = 'none'; } setAttributeSvg(rect, attr); this.setSvgStyle(rect, options, diagramId); }; /** * Update the diagram selection region \ * * @returns {void} Update the diagram selection region .\ * * @param { SVGElement} gElement - Provide the element type. * @param { RectAttributes} options - Provide the Rect attributes . * @private */ SvgRenderer.prototype.updateSelectionRegion = function (gElement, options) { var rect; rect = gElement.parentNode.getElementById(options.id); var attr = { 'id': options.id, 'x': options.x.toString(), 'y': options.y.toString(), 'width': options.width.toString(), 'height': options.height.toString(), 'transform': 'rotate(' + options.angle + ',' + (options.x + options.width * options.pivotX) + ',' + (options.y + options.height * options.pivotY) + ')', class: 'e-diagram-selected-region' }; if (!rect) { rect = document.createElementNS('http://www.w3.org/2000/svg', 'rect'); gElement.appendChild(rect); } this.setSvgStyle(rect, options); setAttributeSvg(rect, attr); }; /** * Create the g element for the diagram \ * * @returns {SVGGElement} Create the g element for the diagram .\ * * @param { SVGElement} elementType - Provide the element type. * @param { Object} attribute - Provide the attributes for the g element. * @private */ SvgRenderer.prototype.createGElement = function (elementType, attribute) { var gElement = createSvgElement(elementType, attribute); return gElement; }; /** * Draw the line for the diagram\ * * @returns {void} Draw the line for the diagram .\ * * @param { SVGElement} gElement - Provide the g element . * @param { LineAttributes} options - Provide the line element attributes . * @private */ SvgRenderer.prototype.drawLine = function (gElement, options) { var line = document.createElementNS('http://www.w3.org/2000/svg', 'line'); this.setSvgStyle(line, options); var pivotX = options.x + options.width * options.pivotX; var pivotY = options.y + options.height * options.pivotY; //const kk: string = ''; var attr = { 'id': options.id, 'x1': options.startPoint.x + options.x, 'y1': options.startPoint.y + options.y, 'x2': options.endPoint.x + options.x, 'y2': options.endPoint.y + options.y, 'stroke': options.stroke, 'stroke-width': options.strokeWidth.toString(), 'opacity': options.opacity.toString(), 'transform': 'rotate(' + options.angle + ' ' + pivotX + ' ' + pivotY + ')', 'visibility': options.visible ? 'visible' : 'hidden' }; if (options.class) { attr['class'] = options.class; } setAttributeSvg(line, attr); gElement.appendChild(line); }; /** * Draw the circle for the diagram\ * * @returns {void} Draw the circle for the diagram .\ * * @param { SVGElement} gElement - Provide the g element . * @param { CircleAttributes} options - Provide the circle element attributes . * @param {string} enableSelector - Provide the selector constraints string . * @param {Object} ariaLabel - Provide arial label value . * @private */ SvgRenderer.prototype.drawCircle = function (gElement, options, enableSelector, ariaLabel) { var circle = document.createElementNS('http://www.w3.org/2000/svg', 'circle'); this.setSvgStyle(circle, options); var classval = options.class || ''; if (!enableSelector) { classval += ' e-disabled'; } var attr = { 'id': options.id, 'cx': options.centerX, 'cy': options.centerY, 'r': options.radius, 'visibility': options.visible ? 'visible' : 'hidden', 'class': classval }; if (ariaLabel) { // BLAZ-24062: Adding 'aria-label' without role attribute it causes violation in accessibility test attr['role'] = 'img'; attr['aria-label'] = ariaLabel; } circle.style.display = options.visible ? 'block' : 'none'; setAttributeSvg(circle, attr); gElement.appendChild(circle); }; /** * Draw the path element for the diagram\ * * @returns {void} Draw the path element for the diagram .\ * * @param { SVGElement} svg - Provide the SVG element . * @param { PathAttributes} options - Provide the path element attributes . * @param {string} diagramId - Provide the diagram id . * @param {boolean} isSelector - Provide selector boolean value . * @param {SVGSVGElement} parentSvg - Provide the parent SVG element . * @param {Object} ariaLabel - Provide arial label value . * @param {number} scale - Provide the scale value . * @private */ SvgRenderer.prototype.drawPath = function (svg, options, diagramId, isSelector, parentSvg, ariaLabel, scale) { // eslint-disable-next-line @typescript-eslint/no-unused-vars var x = Math.floor((Math.random() * 10) + 1); //const id: string = svg.id + '_shape' + x.toString(); var collection = []; collection = processPathData(options.data); collection = pathSegmentCollection(collection); if (options.shadow) { this.renderShadow(options, svg, collection, parentSvg); } var shadowElement; if (parentSvg && !options.shadow) { shadowElement = parentSvg.getElementById(options.id + '_groupElement_shadow'); if (shadowElement) { shadowElement.parentNode.removeChild(shadowElement); } } if (parentSvg) { shadowElement = parentSvg.getElementById(options.id + '_groupElement_shadow'); if (shadowElement) { shadowElement.style.visibility = options.visible ? 'visible' : 'hidden'; } } var path; if (parentSvg) { path = parentSvg.getElementById(options.id); } if (!path || isSelector) { path = document.createElementNS('http://www.w3.org/2000/svg', 'path'); // Check if the parent of the SVG element has the ID 'diagram_nativeLayer' if (svg.parentElement && svg.parentElement.id === 'diagram_nativeLayer') { // Create a new 'g' element with the ID based on path.id + '_groupElement' var groupElement = document.createElementNS('http://www.w3.org/2000/svg', 'g'); groupElement.id = options.id + "_groupElement"; // Append the 'g' element as a child of the SVG element svg.appendChild(groupElement); // Append the path as a child of the newly created 'g' element groupElement.appendChild(path); } else { // If the parent is not 'diagram_nativeLayer', append the path directly to the SVG svg.appendChild(path); } } this.renderPath(path, options, collection); var attr = {}; if (scale) { attr = { 'id': options.id, 'transform': 'rotate(' + options.angle + ',' + (options.x + options.width * options.pivotX) + ',' + (options.y + options.height * options.pivotY) + ')' + 'translate(' + (options.x) + ',' + (options.y) + '),scale(' + scale + ')', 'visibility': options.visible ? 'visible' : 'hidden', 'opacity': options.opacity }; } else { attr = { 'id': options.id, 'transform': 'rotate(' + options.angle + ',' + (options.x + options.width * options.pivotX) + ',' + (options.y + options.height * options.pivotY) + ')' + 'translate(' + (options.x) + ',' + (options.y) + ')', 'visibility': options.visible ? 'visible' : 'hidden', 'opacity': options.opacity }; } if (ariaLabel) { // BLAZ-24062: Adding 'aria-label' without role attribute it causes violation in accessibility test attr['role'] = 'img'; attr['aria-label'] = ariaLabel; } if (options.class) { attr['class'] = options.class; } setAttributeSvg(path, attr); this.setSvgStyle(path, options, diagramId); }; /** * Draw the path element for the diagram\ * * @returns {void} Draw the path element for the diagram .\ * * @param { SVGElement} svg - Provide the SVG element . * @param {PathAttributes} options - Provide the path element attributes . * @param {Object[]} collection - Provide the parent SVG element . * @private */ SvgRenderer.prototype.renderPath = function (svg, options, collection) { var x1; var y1; var x2; var y2; var x; var y; var length; var i; var segments = collection; var d = ''; for (x = 0, y = 0, i = 0, length = segments.length; i < length; ++i) { var obj = segments[parseInt(i.toString(), 10)]; var segment = obj; var char = segment.command; if ('x1' in segment) { x1 = segment.x1; } if ('x2' in segment) { x2 = segment.x2; } if ('y1' in segment) { y1 = segment.y1; } if ('y2' in segment) { y2 = segment.y2; } if ('x' in segment) { x = segment.x; } if ('y' in segment) { y = segment.y; } switch (char) { case 'M': d = d + 'M' + x.toString() + ',' + y.toString() + ' '; break; case 'L': d = d + 'L' + x.toString() + ',' + y.toString() + ' '; break; case 'C': d = d + 'C' + x1.toString() + ',' + y1.toString() + ',' + x2.toString() + ',' + y2.toString() + ','; d += x.toString() + ',' + y.toString() + ' '; break; case 'Q': d = d + 'Q' + x1.toString() + ',' + y1.toString() + ',' + x.toString() + ',' + y.toString() + ' '; break; case 'A': d = d + 'A' + segment.r1.toString() + ',' + segment.r2.toString() + ',' + segment.angle.toString() + ','; d += segment.largeArc.toString() + ',' + segment.sweep + ',' + x.toString() + ',' + y.toString() + ' '; break; case 'Z': case 'z': d = d + 'Z' + ' '; break; } } svg.setAttribute('d', d); }; SvgRenderer.prototype.setSvgFontStyle = function (text, options) { text.style.fontStyle = options.italic ? 'italic' : 'normal'; text.style.fontWeight = options.bold ? 'bold' : 'normal'; text.style.fontSize = options.fontSize.toString() + 'px'; text.style.fontFamily = options.fontFamily; }; /** * Draw the text element for the diagram\ * * @returns {void} Draw the text element for the diagram .\ * * @param { SVGElement} canvas - Provide the SVG element . * @param {TextAttributes} options - Provide the text element attributes . * @param {SVGSVGElement} parentSvg - Provide the parent SVG element . * @param {Object} ariaLabel - Provide the label properties . * @param {string} diagramId - Provide the diagram id . * @param {number} scaleValue - Provide the scale value . * @param {any} renderer - Provide the renderer value . * @private */ SvgRenderer.prototype.drawText = function (canvas, options, parentSvg, ariaLabel, diagramId, scaleValue, renderer) { if (options.content !== undefined) { var parentNode = renderer.groupElement; var textNode = void 0; var childNodes = void 0; var wrapBounds = void 0; var position = void 0; var child = void 0; var tspanElement = void 0; var offsetX = 0; var offsetY = 0; var i = 0; var text = void 0; var nodeContent = void 0; if (parentSvg) { text = parentSvg.getElementById(options.id + '_text'); } if (text) { if (options.doWrap) { while (text.firstChild) { text.removeChild(text.firstChild); } } } else { options.doWrap = true; text = document.createElementNS('http://www.w3.org/2000/svg', 'text'); if (options.whiteSpace === 'pre-wrap') { text.setAttributeNS('http://www.w3.org/XML/1998/namespace', 'xml:space', 'preserve'); } if (parentNode) { nodeContent = document.getElementById(parentNode.id + '_content_groupElement'); } if (nodeContent && parentNode && parentNode.children && parentNode.children[0] instanceof DiagramNativeElement) { var textTag = this.createGElement('g', { id: ariaLabel + '_groupElement' }); nodeContent.appendChild(textTag); textTag.appendChild(text); } else { canvas.appendChild(text); } } var pivotX = options.x + options.width * options.pivotX; var pivotY = options.y + options.height * options.pivotY; var childNodesHeight = 0; if (options.doWrap || options.textOverflow !== 'Wrap') { //(EJ2-70658)- Node annotation disappear, while giving same id for annotation in two different diagrams //Added the below code for removing the extra span element that added when we double click the text annotation node while (text.firstChild) { text.removeChild(text.firstChild); } this.setSvgStyle(text, options, diagramId); this.setSvgFontStyle(text, options); textNode = document.createTextNode(options.content); childNodes = options.childNodes; wrapBounds = options.wrapBounds; position = this.svgLabelAlign(options, wrapBounds, childNodes); if (wrapBounds.width > options.width && options.textOverflow !== 'Wrap' && options.textWrapping === 'NoWrap') { childNodes[0].text = overFlow(options.content, options); } for (i = 0; i < childNodes.length; i++) { tspanElement = document.createElementNS('http://www.w3.org/2000/svg', 'tspan'); textNode = document.createTextNode(childNodes[parseInt(i.toString(), 10)].text); child = childNodes[parseInt(i.toString(), 10)]; child.x = setChildPosition(child, childNodes, i, options); if (options.textAlign === 'justify' || options.textAlign === 'left') { offsetX = 0; } else { offsetX = position.x + child.x - wrapBounds.x; } offsetY = position.y + child.dy * (i) + ((options.fontSize) * 0.8); if ((options.textOverflow === 'Clip' || options.textOverflow === 'Ellipsis') && (options.textWrapping === 'WrapWithOverflow' || options.textWrapping === 'Wrap') && parentNode) { var size = (options.isHorizontalLane) ? parentNode.actualSize.width : parentNode.actualSize.height; if (offsetY < size) { if (options.textOverflow === 'Ellipsis' && childNodes[i + 1]) { var temp = childNodes[i + 1]; var y = position.y + temp.dy * (i + 1) + ((options.fontSize) * 0.8); if (y > size) { child.text = child.text.slice(0, child.text.length - 3); child.text = child.text.concat('...'); textNode.data = child.text; } } //EJ2-863489 - Node annotation textAlign "Justify" option is not working correctly this.alignText(text, tspanElement, child, textNode, offsetX, offsetY, i, options, childNodes); childNodesHeight += child.dy; } else { break; } } else { //EJ2-863489 - Node annotation textAlign "Justify" option is not working correctly this.alignText(text, tspanElement, child, textNode, offsetX, offsetY, i, options, childNodes); } } } if (childNodesHeight && options.isHorizontalLane) { pivotX = options.parentOffsetX + options.pivotX; pivotY = options.parentOffsetY + options.pivotY; options.y = options.parentOffsetY - childNodesHeight * options.pivotY + 0.5; } if (options.textDecoration && options.textDecoration === 'LineThrough') { options.textDecoration = wordBreakToString(options.textDecoration); } var attr = { 'id': options.id + '_text', 'fill': options.color, 'visibility': options.visible ? 'visible' : 'hidden', 'text-decoration': options.textDecoration, 'transform': 'rotate(' + options.angle + ',' + (pivotX) + ',' + (pivotY) + ')' + 'translate(' + (options.x) + ',' + (options.y) + ')', 'opacity': options.opacity }; if (ariaLabel) { // BLAZ-24062: Adding 'aria-label' without role attribute it causes violation in accessibility test attr['role'] = 'img'; attr['aria-label'] = ariaLabel; } setAttributeSvg(text, attr); } }; SvgRenderer.prototype.alignText = function (text, tspanElement, child, textNode, offsetX, offsetY, i, options, childNodes) { //EJ2-863489 - Node annotation textAlign "Justify" option is not working correctly if (options.textAlign !== 'justify') { this.setText(text, tspanElement, child, textNode, offsetX, offsetY, options); } else { if (i !== childNodes.length - 1) { var textlength = options.width; var adjustlen = 'spacing'; this.setText(text, tspanElement, child, textNode, offsetX, offsetY, options, textlength, adjustlen); } else { this.setText(text, tspanElement, child, textNode, offsetX, offsetY, options); } } }; SvgRenderer.prototype.setText = function (text, tspanElement, child, textNode, offsetX, offsetY, options, textlength, adjustlen) { var x = offsetX.toString(); var y = offsetY.toString(); var attrs = { x: x, y: y }; if (options.textAlign === 'justify') { attrs.textLength = (textlength || 0).toString(); attrs.lengthAdjust = adjustlen || 'spacing'; } setAttributeSvg(tspanElement, attrs); text.setAttribute('fill', child.text); tspanElement.appendChild(textNode); text.appendChild(tspanElement); }; /** * Draw the image element for the diagram\ * * @returns {void} Draw the image element for the diagram . * @param { SVGElement | HTMLCanvasElement} canvas - Provide the SVG element . * @param {ImageAttributes} obj - Provide the image attributes . * @param {SVGSVGElement} parentSvg - Provide the parent SVG element . * @param {boolean} fromPalette - Provide the pointer event value . * @private */ // eslint-disable-next-line @typescript-eslint/no-unused-vars SvgRenderer.prototype.drawImage = function (canvas, obj, parentSvg, fromPalette) { ///const id: string = obj.id + '_image'; var image; if (parentSvg) { image = parentSvg.getElementById(obj.id + 'image'); } if (!image) { image = document.createElementNS('http://www.w3.org/2000/svg', 'image'); canvas.appendChild(image); } var imageObj = new Image(); imageObj.src = obj.source; var scale = obj.scale !== 'None' ? obj.scale : ''; //Removed isBlazor code var imgAlign = obj.alignment; var aspectRatio = imgAlign.charAt(0).toLowerCase() + imgAlign.slice(1); if (scale !== 'Stretch') { aspectRatio += ' ' + scale.charAt(0).toLowerCase() + scale.slice(1); } var attr = { 'id': obj.id + 'image', 'x': obj.x.toString(), 'y': obj.y.toString(), 'transform': 'rotate(' + obj.angle + ',' + (obj.x + obj.width * obj.pivotX) + ',' + (obj.y + obj.height * obj.pivotY) + ')', 'width': obj.width.toString(), 'visibility': obj.visible ? 'visible' : 'hidden', 'height': obj.height.toString(), 'preserveAspectRatio': aspectRatio, //832073 - Opacity when set to Zero for image node is not working - opacity value of 1 is already set as default 'opacity': obj.opacity.toString() }; setAttributeSvg(image, attr); image.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href', imageObj.src.toString()); }; /** * Draw the HTML element for the diagram\ * * @returns {void} Draw the native element for the diagram. * @param {DiagramHtmlElement} element - Provide the element . * @param {HTMLElement} canvas - Provide the canvas element . * @param {Transforms} transform - Provide the transform value . * @param {boolean} value - Provide the pointer event value . * @param {number} indexValue - Provide the index value . * @private */ SvgRenderer.prototype.drawHTMLContent = function (element, canvas, transform, value, indexValue) { var htmlElement; var parentHtmlElement; if (canvas) { //869698- drag performance is slow when dealing with 1000 plus HTML shapes and Overview feature htmlElement = canvas.querySelector('#' + element.id + '_html_element'); } if (!htmlElement) { parentHtmlElement = canvas.querySelector("#" + element.id + "_html_element") || canvas.querySelector("#" + element.nodeId + "_html_element"); if (!parentHtmlElement) { var attr_1 = { 'id': element.nodeId + '_html_element', 'class': 'foreign-object' }; parentHtmlElement = createHtmlElement('div', attr_1); } var attr = { 'id': element.id + '_html_element', 'class': 'foreign-object' }; htmlElement = createHtmlElement('div', attr); var diagram = document.getElementById(element.diagramId).ej2_instances[0]; var isOverviewLayer = false; if (canvas.parentNode && canvas.parentNode.parentNode && canvas.parentNode.parentNode.parentNode && canvas.parentNode.parentNode.parentNode.classList.contains('e-overview')) { isOverviewLayer = true; } if (isOverviewLayer) { //893685: HTML node with node Template not shown in Overview in React. if (diagram.isReact) { diagram.renderReactTemplates(function () { htmlElement.appendChild(element.template.cloneNode(true)); }); } else { htmlElement.appendChild(element.template.cloneNode(true)); } } else { //Bug 852259: User handle template not working properly after saving and loading the diagram. // After serialization the template will be in string format, so we need to convert it to element. if (typeof element.template === 'string') { var temp = document.createElement('div'); temp.innerHTML = element.template; element.template = temp; var handle = diagram.selectedItems.userHandles.filter(function (x) { return x.name === (element.id.split('_shape')[0]) && x.template !== ''; }); handle[0].template = element.template; } // eslint-disable-next-line @typescript-eslint/no-unused-expressions // 883335-Exception Throws When Loading Data Without Defining Node Template at Application Level if (element.isTemplate && element.template) { if (diagram instanceof Diagram) { htmlElement.appendChild(element.template); } else { htmlElement.appendChild(element.template.cloneNode(true)); } } else if (element.template) { htmlElement.appendChild(element.template.cloneNode(true)); } } if (indexValue !== undefined && canvas.childNodes.length > indexValue) { canvas.insertBefore(htmlElement, canvas.childNodes[parseInt(indexValue.toString(), 10)]); } parentHtmlElement.appendChild(htmlElement); canvas.appendChild(parentHtmlElement); } var point = cornersPointsBeforeRotation(element).topLeft; htmlElement.style.height = element.actualSize.height + 'px'; htmlElement.style.width = element.actualSize.width + 'px'; htmlElement.style.left = point.x + 'px'; htmlElement.style.top = point.y + 'px'; htmlElement.style.position = 'absolute'; htmlElement.style.transform = "rotate(" + (element.rotateAngle + element.parentTransform) + "deg)"; htmlElement.style.pointerEvents = value ? 'all' : 'none'; htmlElement.style.visibility = element.visible ? 'visible' : 'hidden'; htmlElement.style.opacity = element.style.opacity.toString(); }; /** * Draw the native element for the diagram\ * * @returns {void} Draw the native element for the diagram. * @param {DiagramNativeElement} element - Provide the node element . * @param {HTMLCanvasElement} canvas - Provide the SVG element . * @param {number} height - Provide the height for the shape . * @param {number} width - Provide the width for the shape . * @param {SVGSVGElement} parentSvg - Provide the parent svg for the shape . * @private */ SvgRenderer.prototype.drawNativeContent = function (element, canvas, height, width, parentSvg) { var nativeElement; var clipPath; if (parentSvg) { nativeElement = parentSvg.getElementById(element.id + '_native_element'); clipPath = parentSvg.getElementById(element.id + '_clip'); } if (!nativeElement) { nativeElement = document.createElementNS('http://www.w3.org/2000/svg', 'g'); nativeElement.setAttribute('id', element.id + '_native_element'); nativeElement.appendChild(element.template.cloneNode(true)); var svgContentTag = this.createGElement('g', { id: element.id + '_inner_native_element' }); svgContentTag.appendChild(nativeElement); canvas.appendChild(svgContentTag); } if (clipPath) { nativeElement.removeChild(clipPath); } nativeElement.style.visibility = element.visible ? 'visible' : 'hidden'; nativeElement.style.opacity = element.style.opacity ? element.style.opacity.toString() : '1'; this.setNativTransform(element, nativeElement, height, width); if (element.scale === 'Slice') { this.drawClipPath(element, nativeElement, height, width, parentSvg); } setAttributeSvg(nativeElement, element.description ? { 'role': 'img', 'aria-label': element.description } : {}); }; SvgRenderer.prototype.setNativTransform = function (element, nativeElement, height, width) { //let angle: number; var contentWidth = element.contentSize.width !== 0 ? element.contentSize.width : 1; var contentHeight = element.contentSize.height !== 0 ? element.contentSize.height : 1; var x = element.templatePosition.x * width / contentWidth; var y = element.templatePosition.y * height / contentHeight; nativeElement.setAttribute('transform', 'rotate(' + element.parentTransform + ',' + element.offsetX + ',' + element.offsetY + ') translate(' + (element.offsetX - x - width * element.pivot.x) + ',' + (element.offsetY - y - height * element.pivot.y) + ') scale(' + (width / contentWidth) + ',' + (height / contentHeight) + ')'); }; /** *used to crop the given native element into a rectangle of the given size .\ * * @returns {SVGElement} used to crop the given native element into a rectangle of the given size. * @param {DiagramNativeElement} node - Provide the node element . * @param {SVGElement} group - Provide the SVG element . * @param {number} height - Provide the height for the shape . * @param {number} width - Provide the width for the shape . * @param {SVGSVGElement} parentSvg - Provide the parent svg for the shape . * @private */ SvgRenderer.prototype.drawClipPath = function (node, group, height, width, parentSvg) { var contentWidth = node.contentSize.width; var contentHeight = node.contentSize.height; //let actualWidth: number = node.actualSize.width; //let actualHeight: number = node.actualSize.height; var clipWidth = node.width / (width / contentWidth); var clipHeight = node.height / (height / contentHeight); var x = node.templatePosition.x + (node.width >= node.height ? 0 : (contentWidth - clipWidth) / 2); var y = node.templatePosition.y + (node.height >= node.width ? 0 : (contentHeight - clipHeight) / 2); var clipPath = parentSvg.getElementById(node.id + '_clip'); clipPath = document.createElementNS('http://www.w3.org/2000/svg', 'clipPath'); clipPath.setAttribute('id', node.id + '_clip'); group.appendChild(clipPath); var rect = parentSvg.getElementById(node.id + '_clip_rect'); rect = document.createElementNS('http://www.w3.org/2000/svg', 'rect'); clipPath.appendChild(rect); var attr = { 'id': node.id + '_clip_rect', 'width': clipWidth.toString(), 'height': clipHeight.toString(), 'x': x.toString(), 'y': y.toString() }; setAttributeSvg(rect, attr); if (checkBrowserInfo()) { group.setAttribute('clip-path', 'url(' + location.protocol + '//' + location.host + location.pathname + '#' + node.id + '_clip)'); } else { group.setAttribute('clip-path', 'url(#' + node.id + '_clip)'); } return group; }; /** * Draw the gradient for the diagram shapes .\ * * @returns {SVGElement} Draw the gradient for the diagram shapes. * @param {StyleAttributes} options - Provide the options for the gradient element . * @param {SVGElement} svg - Provide the SVG element . * @param {string} diagramId - Provide the diagram id . * @private */ SvgRenderer.prototype.renderGradient = function (options, svg, diagramId) { var max; var min; var grd; var svgContainer = getBackgroundLayerSvg(diagramId); var defs = svgContainer.getElementById(diagramId + 'gradient_pattern'); if (!defs) { defs = createSvgElement('defs', { id: diagramId + 'gradient_pattern' }); svgContainer.insertBefore(defs, svgContainer.firstChild); } var radial; var linear; //let stop: StopModel; let offset: number; removeGradient(svg.id); if (options.gradient.type !== 'None') { for (var i = 0; i < options.gradient.stops.length; i++) { max = !max ? options.gradient.stops[parseInt(i.toString(), 10)].offset : Math.max(max, options.gradient.stops[parseInt(i.toString(), 10)].offset); min = !min ? options.gradient.stops[parseInt(i.toString(), 10)].offset : Math.min(min, options.gradient.stops[parseInt(i.toString(), 10)].offset); } if (options.gradient.type === 'Linear') { linear = options.gradient; linear.id = svg.id + '_linear'; grd = this.createLinearGradient(linear); defs.appendChild(grd); } else { radial = options.gradient; radial.id = svg.id + '_radial'; grd = this.createRadialGradient(radial); defs.appendChild(grd); } for (var i = 0; i < options.gradient.stops.length; i++) { var stop_1 = options.gradient.stops[parseInt(i.toString(), 10)]; var offset = min < 0 ? (max + stop_1.offset) / (2 * max) : stop_1.offset / max; var stopElement = document.createElementNS('http://www.w3.org/2000/svg', 'stop'); setAttributeSvg(stopElement, { 'offset': offset.toString(), 'style': 'stop-color:' + stop_1.color }); grd.appendChild(stopElement); } } return grd; }; /** * Draw the Linear gradient for the diagram .\ * * @returns {SVGElement} Draw the Linear gradient for the diagram. * @param {LinearGradientModel} linear - Provide the objects for the gradient element . * @private */ SvgRenderer.prototype.createLinearGradient = function (linear) { var lineargradient = document.createElementNS('http://www.w3.org/2000/svg', 'linearGradient'); var attr = { 'id': linear.id, 'x1': linear.x1 + '%', 'y1': linear.y1 + '%', 'x2': linear.x2 + '%', 'y2': linear.y2 + '%' }; setAttributeSvg(lineargradient, attr); return lineargradient; }; /** * Draw the radial gradient for the diagram .\ * * @returns {SVGElement} Draw the radial gradient for the diagram. * @param {RadialGradientModel} radial - Provide the objects for the gradient element . * @private */ SvgRenderer.prototype.createRadialGradient = function (radial) { var radialgradient = document.createElementNS('http://www.w3.org/2000/svg', 'radialGradient'); var attr = { 'id': radial.id, 'cx': radial.cx + '%', 'cy': radial.cy + '%', 'r': radial.r + '%', 'fx': radial.fx + '%', 'fy': radial.fy + '%' }; setAttributeSvg(radialgradient, attr); return radialgradient; }; /** * Set the SVG style for the SVG elements in the diagram.\ * * @returns {void} * @param {SVGElement} svg - Provide the canvas element . * @param {StyleAttributes} style - Provide the canvas element . * @param {string} diagramId - Provide the canvas element . * @private */ SvgRenderer.prototype.setSvgStyle = function (svg, style, diagramId) { if (style.canApplyStyle || style.canApplyStyle === undefined) { if (style.fill === 'none') { style.fill = 'transparent'; } if (style.stroke === 'none') { style.stroke = 'transparent'; } var dashArray = []; var fill = void 0; if (style.dashArray) { var canvasRenderer = new CanvasRenderer(); dashArray = canvasRenderer.parseDashArray(style.dashArray); } if (style.gradient && style.gradient.type !== 'None' && diagramId) { var grd = this.renderGradient(style, svg, diagramId); if (checkBrowserInfo()) { fill = 'url(' + location.protocol + '//' + location.host + location.pathname + '#' + grd.id + ')'; } else { fill = 'url(#' + grd.id + ')'; } } else { fill = style.fill; } if (style.stroke) { svg.setAttribute('stroke', style.stroke); } if (style.strokeWidth !== undefined && style.strokeWidth !== null) { svg.setAttribute('stroke-width', style.strokeWidth.toString()); } if (dashArray) { svg.setAttribute('stroke-dasharray', dashArray.toString() || 'none'); } if (fill) { svg.setAttribute('fill', fill); } } }; //end region // text utility /** * Draw the SVG label.\ * * @returns {PointModel} Draw the SVG label . * @param {TextAttributes} text - Provide the canvas element . * @param {Object} wrapBound - Provide the canvas element . * @param {SubTextElement []} childNodes - Provide the canvas element . * @private */ SvgRenderer.prototype.svgLabelAlign = function (text, wrapBound, childNodes) { var bounds = new Size(wrapBound.width, childNodes.length * (text.fontSize * 1.2)); var pos = { x: 0, y: 0 }; var x = 0; var y = 1.2; var offsetX = text.width * 0.5; var offsety = text.height * 0.5; var pointX = offsetX; var pointY = offsety; if (text.textAlign === 'left' || text.textAlign === 'justify') { pointX = 0; } else if (text.textAlign === 'center') { if (wrapBound.width > text.width && (text.textOverflow === 'Ellipsis' || text.textOverflow === 'Clip')) { if (text.textWrapping === 'NoWrap') { pointX = 0; } else { pointX = text.width * 0.5; } } else { pointX = text.width * 0.5; } } else if (text.textAlign === 'right') { pointX = (text.width * 1); } pos.x = x + pointX + (wrapBound ? wrapBound.x : 0); pos.y = y + pointY - bounds.height / 2; return pos; }; return SvgRenderer; }()); export { SvgRenderer };