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.

587 lines (586 loc) 20.7 kB
import { compile as baseTemplateComplier } from '@syncfusion/ej2-base'; import { Rect } from '../primitives/rect'; import { Size } from '../primitives/size'; import { identityMatrix, transformPointByMatrix, rotateMatrix } from '../primitives/matrix'; import { getValue } from '@syncfusion/ej2-base'; /** * Implements the basic functionalities */ /** * Used to generate the random id \ * * @returns { boolean } Used to generate the random id .\ * * @private */ export function randomId() { var chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZabcdefghiklmnopqrstuvwxyz'; var id = ''; var num; for (var i = 0; i < 5; i++) { if (typeof window !== 'undefined' && 'crypto' in window && 'getRandomValues' in crypto) { var count = new Uint16Array(1); // tslint:disable-next-line:no-any var intCrypto = window.msCrypto || window.crypto; num = intCrypto.getRandomValues(count)[0] % (chars.length - 1); } else { num = Math.floor(Math.random() * chars.length); } if (i === 0 && num < 10) { i--; continue; } id += chars.substring(num, num + 1); } return id; } /** * Used to get the index value \ * * @returns { boolean } Used to get the index value .\ * @param {Diagram} comp - provide the Diagram value. * @param {string} id - provide the id value. * * @private */ export function getIndex(comp, id) { if (comp.nodes && comp.nodes.length > 0) { for (var i = 0; i < comp.nodes.length; i++) { if (comp.nodes[parseInt(i.toString(), 10)].id === id) { return i; } } } if (comp.connectors && comp.connectors.length > 0) { for (var i = 0; i < comp.connectors.length; i++) { if (comp.connectors[parseInt(i.toString(), 10)].id === id) { return i; } } } return null; } /** * templateCompiler method\ * * @returns { Function } templateCompiler method .\ * @param {string} template - provide the template value. * * @private */ export function templateCompiler(template) { if (template) { // eslint-disable-next-line @typescript-eslint/no-unused-vars var e = void 0; try { if (typeof template !== 'function' && document.querySelectorAll(template).length) { return baseTemplateComplier(document.querySelector(template).innerHTML.trim()); } else { return baseTemplateComplier(template); } } catch (e) { return baseTemplateComplier(template); } } return undefined; } /** * cornersPointsBeforeRotation method\ * * @returns { Rect } templateCompiler method .\ * @param {DiagramElement} ele - provide the template value. * * @private */ export function cornersPointsBeforeRotation(ele) { var bounds = new Rect(); var top = ele.offsetY - ele.actualSize.height * ele.pivot.y; var bottom = ele.offsetY + ele.actualSize.height * (1 - ele.pivot.y); var left = ele.offsetX - ele.actualSize.width * ele.pivot.x; var right = ele.offsetX + ele.actualSize.width * (1 - ele.pivot.x); var topLeft = { x: left, y: top }; //const topCenter: PointModel = { x: (left + right) / 2, y: top }; var topRight = { x: right, y: top }; //const middleLeft: PointModel = { x: left, y: (top + bottom) / 2 }; //const middleRight: PointModel = { x: right, y: (top + bottom) / 2 }; var bottomLeft = { x: left, y: bottom }; //const bottomCenter: PointModel = { x: (left + right) / 2, y: bottom }; var bottomRight = { x: right, y: bottom }; bounds = Rect.toBounds([topLeft, topRight, bottomLeft, bottomRight]); return bounds; } /** * getBounds method\ * * @returns { Rect } getBounds method .\ * @param {DiagramElement} element - provide the template value. * * @private */ export function getBounds(element) { var bounds = new Rect(); //let corners: Rect; var _a = cornersPointsBeforeRotation(element), middleLeft = _a.middleLeft, topCenter = _a.topCenter, bottomCenter = _a.bottomCenter, middleRight = _a.middleRight, topLeft = _a.topLeft, topRight = _a.topRight, bottomLeft = _a.bottomLeft, bottomRight = _a.bottomRight; element.corners = { topLeft: topLeft, topCenter: topCenter, topRight: topRight, middleLeft: middleLeft, middleRight: middleRight, bottomLeft: bottomLeft, bottomCenter: bottomCenter, bottomRight: bottomRight }; if (element.rotateAngle !== 0 || element.parentTransform !== 0) { var matrix = identityMatrix(); rotateMatrix(matrix, element.rotateAngle + element.parentTransform, element.offsetX, element.offsetY); element.corners.topLeft = topLeft = transformPointByMatrix(matrix, topLeft); element.corners.topCenter = topCenter = transformPointByMatrix(matrix, topCenter); element.corners.topRight = topRight = transformPointByMatrix(matrix, topRight); element.corners.middleLeft = middleLeft = transformPointByMatrix(matrix, middleLeft); element.corners.middleRight = middleRight = transformPointByMatrix(matrix, middleRight); element.corners.bottomLeft = bottomLeft = transformPointByMatrix(matrix, bottomLeft); element.corners.bottomCenter = bottomCenter = transformPointByMatrix(matrix, bottomCenter); element.corners.bottomRight = bottomRight = transformPointByMatrix(matrix, bottomRight); //Set corners based on rotate angle } bounds = Rect.toBounds([topLeft, topRight, bottomLeft, bottomRight]); element.corners.left = bounds.left; element.corners.right = bounds.right; element.corners.top = bounds.top; element.corners.bottom = bounds.bottom; element.corners.center = bounds.center; element.corners.width = bounds.width; element.corners.height = bounds.height; return bounds; } // Removed updateCloneProp method /** * cloneObject method\ * * @returns { Rect } cloneObject method .\ * @param {DiagramElement} obj - provide the obj value. * @param {DiagramElement} additionalProp - provide the additionalProp value. * @param {DiagramElement} key - provide the key value. * @param {DiagramElement} cloneBlazorProp - provide the cloneBlazorProp value. * * @private */ export function cloneObject(obj, additionalProp, key, cloneBlazorProp) { var newObject = {}; var keys = 'properties'; var prop = 'propName'; if (obj) { key = obj["" + prop]; var sourceObject = obj["" + keys] || obj; var properties = []; properties = properties.concat(Object.keys(sourceObject)); var customProperties = []; properties.push('version'); if (key) { var propAdditional = getFunction(additionalProp); if (propAdditional) { customProperties = propAdditional(key); } else { customProperties = []; } properties = properties.concat(customProperties); } var internalProp = getInternalProperties(key); properties = properties.concat(internalProp); //Removed blazor code for (var _i = 0, properties_1 = properties; _i < properties_1.length; _i++) { var property = properties_1[_i]; if (property !== 'historyManager') { if (property !== 'wrapper') { //const constructorId: string = 'constructor'; //const name: string = 'name'; // eslint-disable-next-line no-prototype-builtins var isEventEmmitter = obj["" + property] && obj.hasOwnProperty('observers') ? true : false; if (!isEventEmmitter) { if (obj["" + property] instanceof Array) { newObject["" + property] = cloneArray((internalProp.indexOf(property) === -1 && obj["" + keys]) ? obj["" + keys]["" + property] : obj["" + property], additionalProp, property, cloneBlazorProp); } else if (obj["" + property] instanceof Array === false && obj["" + property] instanceof HTMLElement) { newObject["" + property] = obj["" + property].cloneNode(true).innerHTML; } else if (obj["" + property] instanceof Array === false && obj["" + property] instanceof Object) { newObject["" + property] = cloneObject((internalProp.indexOf(property) === -1 && obj["" + keys]) ? obj["" + keys]["" + property] : obj["" + property], undefined, undefined, cloneBlazorProp); } else { newObject["" + property] = obj["" + property]; } } } else { if (obj["" + property]) { newObject["" + property] = { actualSize: { width: obj["" + property].actualSize.width, height: obj["" + property].actualSize.height }, offsetX: obj["" + property].offsetX, offsetY: obj["" + property].offsetY }; } } } } } return newObject; } /** * getInternalProperties method\ * * @returns { string[] } getInternalProperties method .\ * @param {string} propName - provide the propName value. * * @private */ export function getInternalProperties(propName) { switch (propName) { case 'nodes': case 'children': return ['inEdges', 'outEdges', 'parentId', 'processId', 'nodeId', 'umlIndex', 'isPhase', 'isLane']; case 'connectors': return ['parentId']; case 'annotation': return ['nodeId']; case 'annotations': return ['nodeId']; case 'shape': return ['hasHeader']; case 'layers': return ['objectZIndex']; } return []; } /** * cloneArray method\ * * @returns { Object[] } getInternalProperties method .\ * @param {string} sourceArray - provide the sourceArray value. * @param {string} additionalProp - provide the additionalProp value. * @param {string} key - provide the key value. * @param {string} cloneBlazorProp - provide the cloneBlazorProp value. * * @private */ export function cloneArray(sourceArray, additionalProp, key, cloneBlazorProp) { var clonedArray; if (sourceArray) { clonedArray = []; for (var i = 0; i < sourceArray.length; i++) { if (sourceArray[parseInt(i.toString(), 10)] instanceof Array) { clonedArray.push(sourceArray[parseInt(i.toString(), 10)]); } else if (sourceArray[parseInt(i.toString(), 10)] instanceof Object) { clonedArray.push(cloneObject(sourceArray[parseInt(i.toString(), 10)], additionalProp, key, cloneBlazorProp)); } else { clonedArray.push(sourceArray[parseInt(i.toString(), 10)]); } } } return clonedArray; } /** * extendObject method\ * * @returns { Object} getInternalProperties method .\ * @param {string} options - provide the options value. * @param {string} childObject - provide the childObject value. * * @private */ export function extendObject(options, childObject) { var properties = 'properties'; if (options) { if (!childObject) { childObject = { properties: {} }; } //const target: Object = childObject; for (var _i = 0, _a = Object.keys(options); _i < _a.length; _i++) { var property = _a[_i]; if (options["" + property] instanceof Array) { var extendeArray = extendArray(options["" + property], childObject["" + properties]["" + property]); if (!childObject["" + properties]["" + property] || !childObject["" + properties]["" + property].length) { childObject["" + property] = extendeArray; } } else if (options["" + property] instanceof Array === false && options["" + property] instanceof HTMLElement) { childObject["" + property] = options["" + property].cloneNode(true).innerHtml; } else if (options["" + property] instanceof Array === false && options["" + property] instanceof Object) { var extendedObject = extendObject(options["" + property], childObject["" + properties]["" + property]); if (extendedObject["" + properties] && !Object.keys(extendedObject["" + properties]).length) { delete extendedObject["" + properties]; } childObject["" + property] = extendedObject; } else { childObject["" + property] = childObject["" + properties]["" + property] !== undefined ? childObject["" + property] : options["" + property]; } } } return childObject; } /** * extendObject method\ * * @returns { Object} getInternalProperties method .\ * @param {string} sourceArray - provide the sourceArray value. * @param {string} childArray - provide the childArray value. * * @private */ export function extendArray(sourceArray, childArray) { var clonedArray = []; var reset = false; if (!childArray) { childArray = []; } if (!childArray.length) { reset = true; } for (var i = 0; i < sourceArray.length; i++) { if (sourceArray[parseInt(i.toString(), 10)] instanceof Array) { // eslint-disable-next-line @typescript-eslint/no-unused-vars var extendedArray = extendArray(sourceArray[parseInt(i.toString(), 10)], childArray[parseInt(i.toString(), 10)]); if (reset) { clonedArray.push(extendArray); } } else if (sourceArray[parseInt(i.toString(), 10)] instanceof Object) { var extendedObject = extendObject(sourceArray[parseInt(i.toString(), 10)], childArray[parseInt(i.toString(), 10)]); if (reset) { clonedArray.push(extendedObject); } } else { clonedArray.push(sourceArray[parseInt(i.toString(), 10)]); } } return clonedArray; } /** * textAlignToString method\ * * @returns { Object} textAlignToString method .\ * @param {string} value - provide the sourceArray value. * * @private */ export function textAlignToString(value) { var state = ''; switch (value) { case 'Center': state = 'center'; break; case 'Left': state = 'left'; break; case 'Right': state = 'right'; break; case 'Justify': state = 'justify'; break; } return state; } /** * wordBreakToString method\ * * @returns { string } wordBreakToString method .\ * @param {TextWrap | TextDecoration} value - provide the value value. * * @private */ export function wordBreakToString(value) { var state = ''; switch (value) { case 'Wrap': state = 'breakall'; break; case 'NoWrap': state = 'keepall'; break; case 'WrapWithOverflow': state = 'normal'; break; case 'LineThrough': state = 'line-through'; break; } return state; } // Create an offscreen canvas var canvas = document.createElement('canvas'); var context = canvas.getContext('2d'); /** * measures the width of text * * @returns { number } text width * @param {string} textContent - provide the textContent value. * @param {string} options - provide the options value. * * @private */ export function bBoxText(textContent, options) { // Set the font with specified style options context.font = (options.bold ? 'bold' : 'normal') + " " + options.fontSize + "px " + options.fontFamily; // Measure the text var metrics = context.measureText(textContent); return metrics.width; } /** * middleElement method\ * * @returns { number} middleElement method .\ * @param {number} i - provide the textContent value. * @param {number} j - provide the options value. * * @private */ export function middleElement(i, j) { var m = 0; m = (i + j) / 2; return m; } /** * overFlow method\ * * @returns { number} overFlow method .\ * @param {number} text - provide the text value. * @param {number} options - provide the options value. * * @private */ export function overFlow(text, options) { var i = 0; var j = 0; var middle = 0; var bounds = 0; var temp = ''; j = text.length; var t = 0; do { if (bounds > 0) { i = middle; } middle = Math.floor(middleElement(i, j)); temp += text.substr(i, middle); bounds = bBoxText(temp, options); } while (bounds <= options.width); temp = temp.substr(0, i); for (t = i; t < j; t++) { temp += text[parseInt(t.toString(), 10)]; bounds = bBoxText(temp, options); if (bounds >= options.width) { text = text.substr(0, temp.length - 1); break; } } if (options.textOverflow === 'Ellipsis') { text = text.substr(0, text.length - 3); text += '...'; } else { text = text.substr(0, text.length); } return text; } /** * whiteSpaceToString method\ * * @returns { number} whiteSpaceToString method .\ * @param {number} value - provide the value value. * @param {number} wrap - provide the wrap value. * * @private */ export function whiteSpaceToString(value, wrap) { if (wrap === 'NoWrap' && value === 'PreserveAll') { return 'pre'; } var state = ''; switch (value) { case 'CollapseAll': state = 'nowrap'; break; case 'CollapseSpace': state = 'pre-line'; break; case 'PreserveAll': state = 'pre-wrap'; break; } return state; } /** * rotateSize method\ * * @returns { number} rotateSize method .\ * @param {number} size - provide the size value. * @param {number} angle - provide the angle value. * * @private */ export function rotateSize(size, angle) { var matrix = identityMatrix(); rotateMatrix(matrix, angle, 0, 0); var topLeft = transformPointByMatrix(matrix, { x: 0, y: 0 }); var topRight = transformPointByMatrix(matrix, { x: size.width, y: 0 }); var bottomLeft = transformPointByMatrix(matrix, { x: 0, y: size.height }); var bottomRight = transformPointByMatrix(matrix, { x: size.width, y: size.height }); var minX = Math.min(topLeft.x, topRight.x, bottomLeft.x, bottomRight.x); var minY = Math.min(topLeft.y, topRight.y, bottomLeft.y, bottomRight.y); var maxX = Math.max(topLeft.x, topRight.x, bottomLeft.x, bottomRight.x); var maxY = Math.max(topLeft.y, topRight.y, bottomLeft.y, bottomRight.y); return new Size(maxX - minX, maxY - minY); } /** * rotatePoint method\ * * @returns { number} rotateSize method .\ * @param {number} angle - provide the angle value. * @param {number} pivotX - provide the pivotX value. * @param {number} pivotY - provide the pivotY value. * @param {PointModel} point - provide the point value. * @private */ export function rotatePoint(angle, pivotX, pivotY, point) { if (angle !== 0) { var matrix = identityMatrix(); rotateMatrix(matrix, angle, pivotX, pivotY); return transformPointByMatrix(matrix, point); } return point; } /** * getOffset method\ * * @returns { number} getOffset method .\ * @param {PointModel} topLeft - provide the angle value. * @param {DiagramElement} obj - provide the pivotX value. * @private */ export function getOffset(topLeft, obj) { var offX = topLeft.x + obj.desiredSize.width * obj.pivot.x; var offY = topLeft.y + obj.desiredSize.height * obj.pivot.y; return { x: offX, y: offY }; } /** * getFunction method\ * * @returns { Function } getFunction method .\ * @param {PointModel} value - provide the angle value. * @private */ export function getFunction(value) { if (value !== undefined) { if (typeof value === 'string') { value = getValue(value, window); } } return value; }