@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.
611 lines (610 loc) • 29.1 kB
JavaScript
import { NodeConstraints, AnnotationConstraints } from '../enum/enum';
import { Node } from '../objects/node';
import { randomId } from './../utility/base-util';
/**
* These utility methods help to process the data and to convert it to desired dimensions
*/
/**
* getULMClassifierShapes method \
*
* @returns {DiagramElement} getULMClassifierShapes method .\
* @param { DiagramElement} content - provide the content value.
* @param {NodeModel} node - provide the node value.
* @param {Diagram} diagram - provide the diagram value.
* @private
*/
export function getULMClassifierShapes(content, node, diagram) {
var classifier;
var textWrap = 'NoWrap';
if (node.shape.classifier === 'Class') {
classifier = node.shape.classShape;
}
else if (node.shape.classifier === 'Enumeration') {
classifier = node.shape.enumerationShape;
}
else if (node.shape.classifier === 'Interface') {
classifier = node.shape.interfaceShape;
}
//let attributeText: string = '';
node.container = { type: 'Stack', orientation: 'Vertical' };
node.constraints = (NodeConstraints.Default | NodeConstraints.HideThumbs) &
~(NodeConstraints.Rotate | NodeConstraints.Resize);
node.style = {
fill: node.style.fill, strokeColor: node.style.strokeColor,
strokeWidth: 1.5
};
node.children = [];
if (node.maxWidth) {
textWrap = 'Wrap';
}
var newObj = new Node(diagram, 'nodes', {
id: node.id + '_umlClass_header',
offsetX: node.offsetX, offsetY: node.offsetY,
annotations: [
{
id: 'name', content: classifier.name,
offset: { x: 0.5, y: 0.65 }, margin: { left: 10, right: 10 },
style: {
bold: true, fontSize: 14, color: classifier.style.color, fill: classifier.style.fill,
textWrapping: textWrap
}
}, {
content: '<<' + node.shape.classifier + '>>', margin: { left: 10, right: 10 },
id: 'class', style: {
fontSize: classifier.style.fontSize,
color: classifier.style.color, fill: classifier.style.fill,
textWrapping: textWrap
}, offset: { x: 0.5, y: 0.3 }, constraints: AnnotationConstraints.ReadOnly
}
],
constraints: (NodeConstraints.Default | NodeConstraints.HideThumbs) & ~(NodeConstraints.Rotate | NodeConstraints.Drag | NodeConstraints.Resize),
verticalAlignment: 'Stretch',
horizontalAlignment: 'Stretch',
style: { fill: node.style.fill, strokeColor: (node.style.strokeColor === 'black') ? '#ffffff00' : node.style.strokeColor }
}, true);
diagram.initObject(newObj);
diagram.nodes.push(newObj);
diagram.UpdateBlazorDiagramModel(newObj, 'Node');
node.children.push(newObj.id);
getClassNodes(node, diagram, classifier, textWrap);
getClassMembers(node, diagram, classifier, textWrap);
/* eslint-disable */
node.offsetX = node.offsetX;
node.offsetY = node.offsetY;
node.style.fill = node.style.fill;
node.borderColor = node.borderColor;
diagram.initObject(node);
/* eslint-enable */
return content;
}
/**
* getClassNodes method \
*
* @returns {void} getClassNodes method .\
* @param { Node} node - provide the node value.
* @param {Diagram} diagram - provide the diagram value.
* @param {UmlClassModel} classifier - provide the classifier value.
* @param {TextWrap} textWrap - provide the textWrap value.
* @private
*/
export function getClassNodes(node, diagram, classifier, textWrap) {
if (node.shape.classifier === 'Enumeration') {
var member = classifier.members;
if (member && member.length) {
addSeparator(node, diagram);
var memberText = '';
for (var i = 0; i < member.length; i++) {
var members = member[parseInt(i.toString(), 10)];
if (members.name !== '') {
memberText += members.name;
}
if (i !== member.length) {
var style = getStyle(node, members);
var temp = new Node(diagram, 'nodes', {
id: randomId() + '_umlMember',
annotations: [
{
id: 'name', content: memberText, offset: { x: 0, y: 0.5 },
style: {
bold: true, fontSize: style.fontSize, color: style.color, fill: style.fill,
textWrapping: textWrap, italic: style.italic, fontFamily: style.fontFamily,
whiteSpace: style.whiteSpace, textAlign: style.textAlign,
textDecoration: style.textDecoration, textOverflow: style.textOverflow
},
margin: { left: 14, right: 5 }, horizontalAlignment: 'Left'
}
], verticalAlignment: 'Stretch', horizontalAlignment: 'Stretch',
style: {
fill: node.style.fill, strokeColor: (node.style.strokeColor === 'black') ?
'#ffffff00' : node.style.strokeColor, textWrapping: textWrap
},
constraints: (NodeConstraints.Default | NodeConstraints.HideThumbs) & ~(NodeConstraints.Rotate | NodeConstraints.Drag | NodeConstraints.Resize),
minHeight: 25
}, true);
diagram.initObject(temp);
diagram.nodes.push(temp);
diagram.UpdateBlazorDiagramModel(temp, 'Node');
node.children.push(temp.id);
memberText = '';
if (members.isSeparator && (i !== member.length - 1)) {
addSeparator(node, diagram, members.separatorStyle);
}
//isSeperator boolean set as false whether it is set as true for last element
if (members.isSeparator && (i === member.length - 1)) {
members.isSeparator = false;
}
}
}
}
}
else {
var attributes = classifier.attributes;
if (attributes.length) {
var attributeText = '';
addSeparator(node, diagram);
for (var i = 0; i < attributes.length; i++) {
var text = void 0;
var attribute = attributes[parseInt(i.toString(), 10)];
if (attribute.scope && (attribute).scope === 'Public') {
text = ' +';
}
else if (attribute.scope && attribute.scope === 'Private') {
text = '-';
}
else if (attribute.scope && attribute.scope === 'Protected') {
text = '#';
}
else {
text = '~';
}
if (attribute.name !== '') {
if (text) {
attributeText += text + ' ' + attribute.name + ' ' + ': ' + attribute.type;
}
}
if (i !== attributes.length) {
var style = getStyle(node, attribute);
var temp = new Node(diagram, 'nodes', {
id: randomId() + '_umlProperty', style: { fill: node.style.fill,
strokeColor: (node.style.strokeColor === 'black') ? '#ffffff00' : node.style.strokeColor },
annotations: [
{
id: 'name', content: attributeText, offset: { x: 0, y: 0.5 },
style: {
bold: true, fontSize: style.fontSize, color: style.color, fill: style.fill,
textWrapping: textWrap, italic: style.italic, fontFamily: style.fontFamily,
whiteSpace: style.whiteSpace, textAlign: style.textAlign,
textDecoration: style.textDecoration, textOverflow: style.textOverflow
},
margin: { left: 14, right: 5 }, horizontalAlignment: 'Left'
}
], verticalAlignment: 'Stretch', horizontalAlignment: 'Stretch',
constraints: (NodeConstraints.Default | NodeConstraints.HideThumbs) & ~(NodeConstraints.Rotate | NodeConstraints.Drag | NodeConstraints.Resize),
minHeight: 25
}, true);
diagram.initObject(temp);
diagram.nodes.push(temp);
diagram.UpdateBlazorDiagramModel(temp, 'Node');
node.children.push(temp.id);
attributeText = '';
if (attribute.isSeparator && (i !== attributes.length - 1)) {
addSeparator(node, diagram, attribute.separatorStyle);
}
//isSeperator boolean set as false whether it is set as true for last element
if (attribute.isSeparator && (i === attributes.length - 1)) {
attribute.isSeparator = false;
}
}
}
}
}
}
/**
* getClassNodesChild method - This method is utilized to dynamically add members to a UML node at runtime. \
*
* @returns {void} getClassNodesChild method .\
* @param { Node} node - provide the node value.
* @param {Diagram} diagram - provide the diagram value.
* @param {UmlClassModel} classifier - provide the classifier value.
* @param {TextWrap} textWrap - provide the textWrap value.
* @private
*/
export function getClassNodesChild(node, diagram, classifier, textWrap) {
if (node.shape.classifier === 'Enumeration') {
var member = classifier.members;
var memberText = '';
// if there is no members in existing array, then the separator need to be added for new member
if (member.length === 1) {
var newIndex = member.length;
addSeparatorChild(node, diagram, newIndex);
}
var count = 0;
// Need to indentify the index value for newly added member
for (var i = 0; i < member.length - 1; i++) {
if (member[parseInt(i.toString(), 10)].isSeparator === true) {
count++;
}
}
var index = member.length + count + 1;
//Iterate through an array of members and create each member as a child node to the UML node
for (var i = 0; i < member.length; i++) {
var members = member[member.length - 1];
if (members.name !== '') {
memberText += members.name;
}
if (i !== member.length) {
var style = getStyle(node, members);
var temp = new Node(diagram, 'nodes', {
id: randomId() + '_umlMember',
annotations: [
{
id: 'name', content: memberText, offset: { x: 0, y: 0.5 },
style: {
bold: true, fontSize: style.fontSize, color: style.color, fill: style.fill,
textWrapping: textWrap, italic: style.italic, fontFamily: style.fontFamily,
whiteSpace: style.whiteSpace, textAlign: style.textAlign,
textDecoration: style.textDecoration, textOverflow: style.textOverflow
},
margin: { left: 14, right: 5 }, horizontalAlignment: 'Left'
}
], verticalAlignment: 'Stretch', horizontalAlignment: 'Stretch',
style: {
fill: node.style.fill, strokeColor: (node.style.strokeColor === 'black') ?
'#ffffff00' : node.style.strokeColor, textWrapping: textWrap
},
constraints: (NodeConstraints.Default | NodeConstraints.HideThumbs) & ~(NodeConstraints.Rotate | NodeConstraints.Drag | NodeConstraints.Resize),
minHeight: 25
}, true);
temp.parentId = node.id;
temp.umlIndex = index;
diagram.add(temp);
memberText = '';
}
break;
}
}
}
/**
* getClassAttributesChild method - This method is utilized to dynamically add attributes to a UML node at runtime.\
*
* @returns {void} getClassAttributesChild method .\
* @param { Node} node - provide the node value.
* @param {Diagram} diagram - provide the diagram value.
* @param {UmlClassModel} classifier - provide the classifier value.
* @param {TextWrap} textWrap - provide the textWrap value.
* @private
*/
export function getClassAttributesChild(node, diagram, classifier, textWrap) {
if (classifier.attributes && classifier.attributes.length) {
var attributes = classifier.attributes;
var attributeText = '';
var text = void 0;
// if there is no attributes in existing array, then the separator need to be added for new attribute
if (attributes.length === 1) {
var newIndex = attributes.length;
addSeparatorChild(node, diagram, newIndex);
}
var count = 0;
// Need to indentify the index value for newly added attribute
for (var i = 0; i < attributes.length - 1; i++) {
if (attributes[parseInt(i.toString(), 10)].isSeparator === true) {
count++;
}
}
var index = attributes.length + count + 1;
//Iterate through an array of attributes and create each attribute as a child node to the UML node
for (var i = 0; i < attributes.length; i++) {
var attribute = attributes[attributes.length - 1];
if (attribute.scope && (attribute).scope === 'Public') {
text = ' +';
}
else if (attribute.scope && attribute.scope === 'Private') {
text = '-';
}
else if (attribute.scope && attribute.scope === 'Protected') {
text = '#';
}
else {
text = '~';
}
if (attribute.name !== '') {
if (text) {
attributeText += text + ' ' + attribute.name + ' ' + ': ' + attribute.type;
}
}
if (i !== attributes.length) {
var style = getStyle(node, attribute);
var temp = new Node(diagram, 'nodes', {
id: randomId() + '_umlProperty', style: {
fill: node.style.fill,
strokeColor: (node.style.strokeColor === 'black') ? '#ffffff00' : node.style.strokeColor
},
annotations: [
{
id: 'name', content: attributeText, offset: { x: 0, y: 0.5 },
style: {
bold: true, fontSize: style.fontSize, color: style.color, fill: style.fill,
textWrapping: textWrap, italic: style.italic, fontFamily: style.fontFamily,
whiteSpace: style.whiteSpace, textAlign: style.textAlign,
textDecoration: style.textDecoration, textOverflow: style.textOverflow
},
margin: { left: 14, right: 5 }, horizontalAlignment: 'Left'
}
], verticalAlignment: 'Stretch', horizontalAlignment: 'Stretch',
constraints: (NodeConstraints.Default | NodeConstraints.HideThumbs) & ~(NodeConstraints.Rotate | NodeConstraints.Drag | NodeConstraints.Resize),
minHeight: 25
}, true);
temp.parentId = node.id;
temp.umlIndex = index;
diagram.add(temp);
attributeText = '';
}
break;
}
}
}
/**
* getClassMembers method \
*
* @returns {void} getClassMembers method .\
* @param { Node} node - provide the node value.
* @param {Diagram} diagram - provide the diagram value.
* @param {UmlClassModel} classifier - provide the classifier value.
* @param {TextWrap} textWrap - provide the textWrap value.
* @private
*/
export function getClassMembers(node, diagram, classifier, textWrap) {
if (classifier.methods && classifier.methods.length) {
var methods = classifier.methods;
addSeparator(node, diagram);
var argumentText = '';
var methodText = '';
var text = void 0;
for (var i = 0; i < methods.length; i++) {
var method = methods[parseInt(i.toString(), 10)];
if (method.scope && method.scope === 'Public') {
text = ' +';
}
else if (method.scope && method.scope === 'Private') {
text = '-';
}
else if (method.scope && method.scope === 'Protected') {
text = '#';
}
else {
text = '~';
}
if (method.parameters) {
for (var j = 0; j < method.parameters.length; j++) {
if (method.parameters[parseInt(j.toString(), 10)].type) {
argumentText += method.parameters[parseInt(j.toString(), 10)].name + ':' + method.parameters[parseInt(j.toString(), 10)].type;
}
else {
argumentText += method.parameters[parseInt(j.toString(), 10)].name;
}
if (j !== method.parameters.length - 1) {
argumentText += ',';
}
}
}
if (method.name !== '') {
if (text) {
methodText += text + ' ' + method.name + '(' + argumentText + ')' + ' ' + ':' + ' ' + method.type;
}
//893885: Parameter Name in UMLClass with multiple Methods are updated wrongly
//clear the value stored in parameter variable after each method initiaization
argumentText = '';
}
if (i !== methods.length) {
var style = getStyle(node, method);
var temp = new Node(diagram, 'nodes', {
id: randomId() + '_umlMethods', verticalAlignment: 'Stretch', horizontalAlignment: 'Stretch',
annotations: [
{
id: 'name', content: methodText, offset: { x: 0, y: 0.5 },
style: {
bold: true, fontSize: style.fontSize, color: style.color, fill: style.fill,
textWrapping: textWrap, italic: style.italic, fontFamily: style.fontFamily,
whiteSpace: style.whiteSpace, textAlign: style.textAlign,
textDecoration: style.textDecoration, textOverflow: style.textOverflow
},
margin: { left: 14, right: 5 }, horizontalAlignment: 'Left'
}
],
style: {
fill: node.style.fill, strokeColor: (node.style.strokeColor === 'black') ?
'#ffffff00' : node.style.strokeColor
}, minHeight: 25,
constraints: (NodeConstraints.Default | NodeConstraints.HideThumbs) & ~(NodeConstraints.Rotate | NodeConstraints.Drag | NodeConstraints.Resize)
}, true);
diagram.initObject(temp);
diagram.nodes.push(temp);
diagram.UpdateBlazorDiagramModel(temp, 'Node');
node.children.push(temp.id);
methodText = '';
if (method.isSeparator && (i !== methods.length - 1)) {
addSeparator(node, diagram, method.separatorStyle);
}
//isSeperator boolean set as false whether it is set as true for last element
if (method.isSeparator && (i === methods.length - 1)) {
method.isSeparator = false;
}
}
}
}
}
/**
* getClassMembersChild method - This method is utilized to dynamically add methods to a UML node at runtime. \
*
* @returns {void} getClassMembersChild method .\
* @param { Node} node - provide the node value.
* @param {Diagram} diagram - provide the diagram value.
* @param {UmlClassModel} classifier - provide the classifier value.
* @param {TextWrap} textWrap - provide the textWrap value.
* @private
*/
export function getClassMembersChild(node, diagram, classifier, textWrap) {
if (classifier.methods && classifier.methods.length) {
var methods = classifier.methods;
var argumentText = '';
var methodText = '';
var text = void 0;
var initialIndex = 1;
var index = void 0;
var attributeCount = 0;
var methodCount = 0;
var shapeModel = node.shape;
var isClass = shapeModel.classifier === 'Class';
var isInterface = shapeModel.classifier === 'Interface';
var umlShape = isClass ? shapeModel.classShape : shapeModel.interfaceShape;
// Need to indentify the index value for newly added method
if (methods.length === 1) {
if (umlShape.attributes.length > 0) {
attributeCount = umlShape.attributes.filter(function (attr) { return attr.isSeparator; }).length;
initialIndex = 1 + 1 + umlShape.attributes.length + attributeCount;
index = initialIndex + 1;
addSeparatorChild(node, diagram, initialIndex);
}
else {
index = initialIndex + 1;
}
}
// To determine the index value for adding methods, it is essential to take into account the existing attributes
else {
attributeCount = umlShape.attributes.filter(function (attr) { return attr.isSeparator; }).length;
methodCount = umlShape.methods.filter(function (method) { return method.isSeparator; }).length;
initialIndex = 1 + 1 + umlShape.attributes.length + attributeCount + umlShape.methods.length + methodCount;
index = initialIndex + 1;
}
//Iterate through an array of methods and create each method as a child node to the UML node
for (var i = 0; i < methods.length; i++) {
var method = methods[methods.length - 1];
if (method.scope && method.scope === 'Public') {
text = ' +';
}
else if (method.scope && method.scope === 'Private') {
text = '-';
}
else if (method.scope && method.scope === 'Protected') {
text = '#';
}
else {
text = '~';
}
if (method.parameters) {
for (var j = 0; j < method.parameters.length; j++) {
if (method.parameters[parseInt(j.toString(), 10)].type) {
argumentText += method.parameters[parseInt(j.toString(), 10)].name + ':' + method.parameters[parseInt(j.toString(), 10)].type;
}
else {
argumentText += method.parameters[parseInt(j.toString(), 10)].name;
}
if (j !== method.parameters.length - 1) {
argumentText += ',';
}
}
}
if (method.name !== '') {
if (text) {
methodText += text + ' ' + method.name + '(' + argumentText + ')' + ' ' + ':' + ' ' + method.type;
}
}
if (i !== methods.length) {
var style = getStyle(node, method);
var temp = new Node(diagram, 'nodes', {
id: randomId() + '_umlMethods', verticalAlignment: 'Stretch', horizontalAlignment: 'Stretch',
annotations: [
{
id: 'name', content: methodText, offset: { x: 0, y: 0.5 },
style: {
bold: true, fontSize: style.fontSize, color: style.color, fill: style.fill,
textWrapping: textWrap, italic: style.italic, fontFamily: style.fontFamily,
whiteSpace: style.whiteSpace, textAlign: style.textAlign,
textDecoration: style.textDecoration, textOverflow: style.textOverflow
},
margin: { left: 14, right: 5 }, horizontalAlignment: 'Left'
}
],
style: {
fill: node.style.fill, strokeColor: (node.style.strokeColor === 'black') ?
'#ffffff00' : node.style.strokeColor
}, minHeight: 25,
constraints: (NodeConstraints.Default | NodeConstraints.HideThumbs) & ~(NodeConstraints.Rotate | NodeConstraints.Drag | NodeConstraints.Resize)
}, true);
temp.parentId = node.id;
temp.umlIndex = index;
diagram.add(temp);
methodText = '';
}
break;
}
}
}
/**
* addSeparator method \
*
* @returns {void} addSeparator method .\
* @param { Node} stack - provide the stack value.
* @param {Diagram} diagram - provide the diagram value.
* @param {SeperatorStyle} SeperatorStyle - provide the Seperator color.
* @private
*/
export function addSeparator(stack, diagram, SeperatorStyle) {
var lineObject = new Node(diagram, 'nodes', {
id: randomId() + '_path', height: 1, constraints: NodeConstraints.Default & ~(NodeConstraints.Select),
verticalAlignment: 'Stretch', horizontalAlignment: 'Stretch',
style: {
strokeColor: (stack.style.strokeColor === 'black') ? '#ffffff00' : stack.style.strokeColor,
fill: SeperatorStyle ? SeperatorStyle.fill : 'white'
}
}, true);
diagram.initObject(lineObject);
diagram.nodes.push(lineObject);
stack.children.push(lineObject.id);
}
/**
* addSeparatorChild method -This method is designed to add a separator for the newly added child type to the UML node. \
*
* @returns {void} addSeparator method .\
* @param { Node} stack - provide the stack value.
* @param {Diagram} diagram - provide the diagram value.
* @param {number} newIndex - provide the index value.
* @private
*/
export function addSeparatorChild(stack, diagram, newIndex) {
var lineObject = new Node(diagram, 'nodes', {
id: randomId() + '_path', height: 1, constraints: NodeConstraints.Default & ~(NodeConstraints.Select),
verticalAlignment: 'Stretch', horizontalAlignment: 'Stretch',
style: { strokeColor: (stack.style.strokeColor === 'black') ? '#ffffff00' : stack.style.strokeColor, fill: 'white' }
}, true);
lineObject.parentId = stack.id;
lineObject.umlIndex = newIndex;
diagram.add(lineObject);
}
/**
* getStyle method \
*
* @returns {TextStyleModel} addSeparator method .\
* @param { Node} stack - provide the stack value.
* @param {UmlClassModel} node - provide the node value.
* @private
*/
export function getStyle(stack, node) {
var newStyle = {};
var style = node.style;
newStyle.fill = (style.fill !== 'transparent') ? style.fill : stack.style.fill;
newStyle.color = style.color;
newStyle.fontFamily = (style.fontFamily !== 'Arial') ? style.fontFamily : stack.style.fontFamily;
newStyle.italic = style.italic;
newStyle.bold = style.bold;
newStyle.whiteSpace = style.whiteSpace;
newStyle.textAlign = style.textAlign;
newStyle.textWrapping = style.textWrapping;
newStyle.textDecoration = style.textDecoration;
newStyle.textOverflow = style.textOverflow;
// newStyle.margin = style.mar
newStyle.fontSize = (style.fontSize !== 12) ? style.fontSize : stack.style.fontSize;
newStyle.strokeColor = (style.strokeColor !== 'black') ? style.strokeColor : stack.style.strokeColor;
newStyle.strokeWidth = (style.strokeWidth !== 1) ? style.strokeWidth : stack.style.strokeWidth;
return newStyle;
}