- Why Switch to Syncfusion® JavaScript Diagram from mxGraph
- Migrating mxGraph XML data to Syncfusion® JavaScript Diagram
- Migrating from mxGraph to Syncfusion® JavaScript Diagram control
- Creating Basic Nodes
- Connecting Diagram Elements
- Annotation Creation and Formatting
- Using Ports
- Applying Layouts
- Saving and Loading Diagrams
- Event Handling
- Diagram Canvas Configuration and Customization
- Symbol Palette
- Diagram Interactions
- Keyboard Interactions
- Enhanced Interactions in Syncfusion JavaScript Diagram over mxGraph
Contact Support
Migrating from mxGraph to Syncfusion® JavaScript Diagram control
11 Jun 202524 minutes to read
mxGraph was once one of the most popular client-side diagramming libraries for JavaScript. However, with its official end-of-life status since 2020, the need for modern alternatives has grown. Syncfusion® JavaScript Diagram presents a powerful and feature-rich option with robust features, better performance, and extensive documentation. This guide will walk you through setting up the Syncfusion® JavaScript Diagram, and migrating typical diagramming scenarios from mxGraph
to this platform. You’ll also learn how to convert existing mxGraph
diagrams into an EJ2-compatible format and continue building with a supported solution.
Why Switch to Syncfusion® JavaScript Diagram from mxGraph
- Enhanced Performance: Syncfusion® JavaScript Diagram offers superior performance for handling complex and large diagrams effectively.
-
Active Maintenance: Syncfusion® JavaScript Diagram is regularly updated and supported, unlike
mxGraph
, which is no longer maintained. - Modern Integration: Seamlessly integrates with frameworks like Angular, React, and Vue.
- Rich Customization: Provides advanced customization options with a wide range of shapes and connectors.
- Robust Support: Backed by strong community support and extensive documentation.
Migrating mxGraph XML data to Syncfusion® JavaScript Diagram
Let’s say you have diagram data stored as mxGraph
XML format. To migrate this data to Syncfusion® JavaScript Diagram, you need to convert the XML by following several key steps to achieve visual consistency with the original designs:
-
Load and Parse XML: Fetch the
mxGraph
XML data and useDOMParser
to convert it into a document format for further processing. -
Extract Diagram Elements: Identify and extract nodes and connectors. Additionally, gather annotations, shapes, and styles to ensure all visual aspects are captured.
-
Convert to Syncfusion® JavaScript Diagram Format: Transform the extracted nodes, connectors, annotations, and styles into the format required by Syncfusion® JavaScript Diagram.
-
Render the Diagram: Use the Syncfusion® JavaScript Diagram API to create and render the diagram with the converted elements, displaying it correctly in your application.
const { Diagram } = ej.diagrams;
const mxGraphXMLData = `
<mxGraphModel dx="933" dy="555" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="1040" pageHeight="300" math="0" shadow="0">
<root>
<mxCell id="0" />
<mxCell id="1" parent="0" />
<mxCell id="lXHuHNEkXH5VenCzG6mj-22" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" parent="1" source="lXHuHNEkXH5VenCzG6mj-5" target="lXHuHNEkXH5VenCzG6mj-6" edge="1">
<mxGeometry relative="1" as="geometry">
<mxPoint x="170" y="160" as="targetPoint" />
</mxGeometry>
</mxCell>
<mxCell id="lXHuHNEkXH5VenCzG6mj-23" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" parent="1" source="lXHuHNEkXH5VenCzG6mj-6" target="lXHuHNEkXH5VenCzG6mj-7" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="lXHuHNEkXH5VenCzG6mj-24" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" parent="1" source="lXHuHNEkXH5VenCzG6mj-7" target="lXHuHNEkXH5VenCzG6mj-8" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="lXHuHNEkXH5VenCzG6mj-16" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=0;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;strokeWidth=2;fillColor=#d5e8d4;strokeColor=#82b366;" parent="1" source="lXHuHNEkXH5VenCzG6mj-8" target="lXHuHNEkXH5VenCzG6mj-9" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="lXHuHNEkXH5VenCzG6mj-17" value="YES" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="lXHuHNEkXH5VenCzG6mj-16" vertex="1" connectable="0">
<mxGeometry relative="1" as="geometry">
<mxPoint as="offset" />
</mxGeometry>
</mxCell>
<mxCell id="lXHuHNEkXH5VenCzG6mj-18" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;fillColor=#f8cecc;strokeColor=#b85450;strokeWidth=2;" parent="1" source="lXHuHNEkXH5VenCzG6mj-8" target="lXHuHNEkXH5VenCzG6mj-11" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="lXHuHNEkXH5VenCzG6mj-19" value="NO" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="lXHuHNEkXH5VenCzG6mj-18" vertex="1" connectable="0">
<mxGeometry relative="1" as="geometry">
<mxPoint as="offset" />
</mxGeometry>
</mxCell>
<mxCell id="lXHuHNEkXH5VenCzG6mj-25" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;" parent="1" source="lXHuHNEkXH5VenCzG6mj-9" target="lXHuHNEkXH5VenCzG6mj-10" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="lXHuHNEkXH5VenCzG6mj-26" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;" parent="1" source="lXHuHNEkXH5VenCzG6mj-11" target="lXHuHNEkXH5VenCzG6mj-12" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="lXHuHNEkXH5VenCzG6mj-5" value="Order Received" style="ellipse;html=1;aspect=fixed;labelPosition=center;verticalLabelPosition=bottom;align=center;verticalAlign=top;fontStyle=1;strokeWidth=2;shadow=0;" parent="1" vertex="1">
<mxGeometry x="60" y="130" width="40" height="40" as="geometry" />
</mxCell>
<mxCell id="lXHuHNEkXH5VenCzG6mj-6" value="Retrieve Data" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;fontStyle=0;strokeWidth=2;" parent="1" vertex="1">
<mxGeometry x="180" y="120" width="120" height="60" as="geometry" />
</mxCell>
<mxCell id="lXHuHNEkXH5VenCzG6mj-7" value="Approve Data" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;fontStyle=0;strokeWidth=2;" parent="1" vertex="1">
<mxGeometry x="380" y="120" width="120" height="60" as="geometry" />
</mxCell>
<mxCell id="lXHuHNEkXH5VenCzG6mj-8" value="Approved?" style="rhombus;whiteSpace=wrap;html=1;fontStyle=0;labelPosition=center;verticalLabelPosition=middle;align=center;verticalAlign=middle;strokeWidth=2;" parent="1" vertex="1">
<mxGeometry x="580" y="120" width="80" height="60" as="geometry" />
</mxCell>
<mxCell id="lXHuHNEkXH5VenCzG6mj-9" value="Order Items" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;fontStyle=0;strokeWidth=2;" parent="1" vertex="1">
<mxGeometry x="740" y="60" width="120" height="60" as="geometry" />
</mxCell>
<mxCell id="lXHuHNEkXH5VenCzG6mj-10" value="Order Processed" style="ellipse;html=1;aspect=fixed;labelPosition=center;verticalLabelPosition=bottom;align=center;verticalAlign=top;strokeWidth=4;fontStyle=1" parent="1" vertex="1">
<mxGeometry x="940" y="70" width="40" height="40" as="geometry" />
</mxCell>
<mxCell id="lXHuHNEkXH5VenCzG6mj-11" value="Send Rejection Mail" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f8cecc;strokeColor=#b85450;fontStyle=0;strokeWidth=2;" parent="1" vertex="1">
<mxGeometry x="740" y="180" width="120" height="60" as="geometry" />
</mxCell>
<mxCell id="lXHuHNEkXH5VenCzG6mj-12" value="Order Not Processed" style="ellipse;html=1;aspect=fixed;labelPosition=center;verticalLabelPosition=bottom;align=center;verticalAlign=top;strokeWidth=4;fontStyle=1" parent="1" vertex="1">
<mxGeometry x="940" y="190" width="40" height="40" as="geometry" />
</mxCell>
</root>
</mxGraphModel>
`;
// This function loads XML data, parses it into EJ2 Diagram elements, and renders the diagram.
try {
const xmlDocument = new window.DOMParser().parseFromString(
mxGraphXMLData,
'application/xml'
);
const { nodes, connectors } = parseMxGraph(xmlDocument);
const diagram = new Diagram({
width: '100%',
height: '600px',
nodes,
connectors,
snapSettings: { constraints: ej.diagrams.SnapConstraints.All },
});
diagram.appendTo('#element');
diagram.dataBind();
diagram.refresh();
} catch (error) {
console.error(error);
}
// Parses mxGraph XML to extract nodes and connectors to be converted into EJ2 Diagram format
function parseMxGraph(xmlDoc) {
const mxCells = Array.from(xmlDoc.querySelectorAll('mxCell'));
const nodes = [];
let connectors = [];
const nodeMap = {};
const childMap = {};
const containerNodes = [];
const groupDefs = [];
// Iterate over mxCells to categorize them into nodes and connectors
mxCells.forEach((cell) => {
const style = cell.getAttribute('style') || '';
const styles = parseStyleString(style);
const isVertex = cell.getAttribute('vertex') === '1';
const isEdge = cell.getAttribute('edge') === '1';
let isLabel = cell.getAttribute('connectable') === '0';
const isGroup = style.includes('group');
const id = cell.getAttribute('id');
const parent = cell.getAttribute('parent');
// Group shapes are treated as vertices, not labels
if (isGroup) isLabel = false;
// Convert mxGraph vertex cells (excluding labels) to EJ2 nodes
if (isVertex && !isLabel) {
const isContainer =
'containerType' in styles || style.includes('swimlane');
const node = createNode(cell, styles);
nodeMap[id] = node;
if (parent) {
childMap[parent] = childMap[parent] || [];
childMap[parent].push(id);
}
if (isContainer) {
containerNodes.push({ id, node });
} else if (isGroup) {
groupDefs.push({ id, node });
} else {
nodes.push(node);
}
} else if (isEdge) {
// Convert mxGraph edge cells to EJ2 connectors
connectors.push(createConnector(cell, styles, mxCells));
}
});
// Associate children nodes with their parent containers or groups
attachChildrenToParents(childMap, nodeMap);
// Finalize the list of nodes and connectors for the EJ2 diagram
finalizeNodesAndConnectors(
nodes,
connectors,
containerNodes,
groupDefs,
childMap
);
return { nodes, connectors };
}
// Parses a style string into an object for easier manipulation while creating EJ2 elements
function parseStyleString(str) {
const out = {};
str.split(';').forEach((token) => {
if (!token) return;
const [k, v] = token.split('=');
if (v === undefined) out.shape = k;
else out[k] = v;
});
return out;
}
// Creates EJ2 diagram nodes from mxGraph cells based on style and geometric data
function createNode(cell, s) {
const geo = cell.querySelector('mxGeometry');
const x = +geo.getAttribute('x') || 0;
const y = +geo.getAttribute('y') || 0;
const w = +geo.getAttribute('width') || 100;
const h = +geo.getAttribute('height') || 100;
const shape = resolveShape(s);
const node = configureNodeBase(cell, w, h, x, y, shape, s);
const annotationStyle = parseFontStyle(s.fontStyle);
const rawContent = decodeAnnotationContent(cell, s);
const annotation = configureAnnotation(s, shape, rawContent, annotationStyle);
node.annotations.push(annotation);
if (shape.shape === 'Decision') {
addDecisionPorts(node);
}
return node;
}
// Configures node base properties from geometric and style data
function configureNodeBase(cell, width, height, offsetX, offsetY, shape, s) {
return {
id: cell.getAttribute('id'),
width,
height,
offsetX: offsetX + width / 2,
offsetY: offsetY + height / 2,
shape,
style: {
fill: s.fillColor || '#ffffff',
strokeColor: s.strokeColor || '#000000',
strokeWidth: +(s.strokeWidth || 1),
},
annotations: [],
};
}
// Decodes HTML entity encoded content from mxGraph XML
function decodeAnnotationContent(cell, s) {
const isHtml = s.html === '1';
const rawContent = isHtml
? decodeHtmlEntities(cell.getAttribute('value') || '')
: cell.getAttribute('value') || '';
return rawContent;
}
// Resolves the appropriate shape for EJ2 from mxGraph styling
function resolveShape(s) {
const shapeLookup = {
ellipse: { type: 'Basic', shape: 'Ellipse' },
rhombus: { type: 'Flow', shape: 'Decision' },
rectangle: { type: 'Basic', shape: 'Rectangle' },
};
const shape = shapeLookup[s.shape] || shapeLookup.rectangle;
if (shape.shape === 'Rectangle' && s.rounded === '1') {
shape.cornerRadius = 8;
}
return shape;
}
// Configures annotation based on position and style information from mxGraph
function configureAnnotation(s, shape, rawContent, annotationStyle) {
const annotation = {
content: rawContent,
style: annotationStyle,
};
if (shape.shape === 'Ellipse') {
annotation.offset = { x: 0.5, y: 1 };
annotation.margin = { top: 5 };
annotation.verticalAlignment = 'Top';
annotation.fontWeight = '500';
annotation.width = 'auto';
} else {
annotation.verticalAlignment =
s.verticalLabelPosition === 'bottom' ? 'Bottom' : 'Center';
}
return annotation;
}
// Adding ports to decision nodes to support connector bindings
function addDecisionPorts(node) {
node.ports = [
{ id: 'portTop', offset: { x: 0.5, y: 0 } },
{ id: 'portBottom', offset: { x: 0.5, y: 1 } },
];
}
// Creates EJ2 diagram connectors from mxGraph edges
function createConnector(cell, s, mxCells) {
const connector = {
id: cell.getAttribute('id'),
type: 'Orthogonal',
sourceID: cell.getAttribute('source'),
targetID: cell.getAttribute('target'),
style: {
strokeColor: s.strokeColor || '#000000',
strokeWidth: +(s.strokeWidth || 1),
},
};
// Attach connector labels for YES/NO conditions
attachLabelToConnector(connector, cell, mxCells);
return connector;
}
// Associates labels from edge children to their connectors
function attachLabelToConnector(connector, cell, mxCells) {
const labelCell = mxCells.find(
(c) =>
c.getAttribute('parent') === connector.id &&
c.getAttribute('connectable') === '0' &&
c.hasAttribute('value')
);
if (labelCell) {
const labelStyle = parseFontStyle(
parseStyleString(labelCell.getAttribute('style')).fontStyle
);
const label = labelCell.getAttribute('value').toLowerCase();
connector.annotations = [
{
content: labelCell.getAttribute('value'),
style: labelStyle,
},
];
if (label === 'yes') {
connector.sourcePortID = 'portTop';
} else if (label === 'no') {
connector.sourcePortID = 'portBottom';
}
}
}
// Map children to parents within the diagram, aiding in proper hierarchy structuring
function attachChildrenToParents(childMap, nodeMap) {
Object.entries(childMap).forEach(([parentId, childIds]) => {
if (nodeMap[parentId]) {
nodeMap[parentId].children = childIds;
}
});
}
// Finalize and filter out containers from regular nodes and connectors for accurate rendering
function finalizeNodesAndConnectors(
nodes,
connectors,
containerNodes,
groupDefs,
childMap
) {
containerNodes.forEach(({ node }) => {
nodes.push(node);
});
groupDefs.forEach(({ id }) => {
const children = childMap[id] || [];
if (children.length) {
nodes.push({ id, children });
}
});
const containerIds = new Set(containerNodes.map((c) => c.id));
connectors = connectors.filter(
(c) => !containerIds.has(c.sourceID) && !containerIds.has(c.targetID)
);
}
// Interprets font style from mxGraph format for EJ2 rendering
function parseFontStyle(fontStyleValue) {
const style = {};
const styleCode = parseInt(fontStyleValue || '0', 10);
if ((styleCode & 1) === 1) style.bold = true;
if ((styleCode & 2) === 2) style.italic = true;
if ((styleCode & 4) === 4) style.textDecoration = 'Underline';
style.textAlign = 'Left';
return style;
}
// Decodes HTML entities in JavaScript
function decodeHtmlEntities(text) {
const div = document.createElement('div');
div.innerHTML = text;
return div.innerText || div.textContent;
}
<!DOCTYPE html><html lang="en"><head>
<title>EJ2 Diagram</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="Typescript UI Controls">
<meta name="author" content="Syncfusion">
<link href="index.css" rel="stylesheet">
<link href="https://cdn.syncfusion.com/ej2/30.1.37/ej2-base/styles/material.css" rel="stylesheet">
<link href="https://cdn.syncfusion.com/ej2/30.1.37/ej2-buttons/styles/material.css" rel="stylesheet">
<link href="https://cdn.syncfusion.com/ej2/30.1.37/ej2-popups/styles/material.css" rel="stylesheet">
<link href="https://cdn.syncfusion.com/ej2/30.1.37/ej2-splitbuttons/styles/material.css" rel="stylesheet">
<link href="https://cdn.syncfusion.com/ej2/30.1.37/ej2-diagrams/styles/material.css" rel="stylesheet">
<link href="https://cdn.syncfusion.com/ej2/30.1.37/ej2-navigations/styles/fabric.css" rel="stylesheet">
<script src="https://cdn.syncfusion.com/ej2/30.1.37/dist/ej2.min.js" type="text/javascript"></script>
<script src="https://cdn.syncfusion.com/ej2/syncfusion-helper.js" type ="text/javascript"></script>
</head>
<body>
<div id="container">
<div id="element"></div>
</div>
<script>
var ele = document.getElementById('container');
if(ele) {
ele.style.visibility = "visible";
}
</script>
<script src="index.js" type="text/javascript"></script>
</body></html>
Next, let’s closely examine how the mxGraph
diagram elements are rendered and how you can achieve the same output using Syncfusion® JavaScript Diagram.
Migrating from mxGraph to Syncfusion® JavaScript Diagram control
The following examples demonstrating how to redefine common diagramming elements from mxGraph
using Syncfusion® JavaScript Diagram.
Creating Basic Nodes
In mxGraph
, basic nodes are created using vertices.
const graph = new mxGraph(container);
const parent = graph.getDefaultParent();
graph.getModel().beginUpdate();
try {
const v1 = graph.insertVertex(parent, null, 'Hello', 20, 20, 80, 30);
} finally {
graph.getModel().endUpdate();
}
In Syncfusion® JavaScript Diagram, you create nodes by specifying their properties such as position and size.
const diagram = new ej.diagrams.Diagram({
width: '100%',
height: '600px',
nodes: [{
id: 'node1',
offsetX: 60,
offsetY: 35,
width: 80,
height: 30,
annotations: [{ content: 'Hello' }]
}]
});
diagram.appendTo('#diagram');
Connecting Diagram Elements
In mxGraph
, connections between elements are formed by inserting edges between vertices.
const v1 = graph.insertVertex(parent, null, 'Node1', 20, 20, 80, 30);
const v2 = graph.insertVertex(parent, null, 'Node2', 200, 150, 80, 30);
const e1 = graph.insertEdge(parent, null, '', v1, v2);
In Syncfusion® JavaScript Diagram, you create connectors by specifying the source and target node IDs.
const nodes = [
{ id: 'node1', offsetX: 60, offsetY: 35, width: 80, height: 30, annotations: [{ content: 'Node1' }] },
{ id: 'node2', offsetX: 200, offsetY: 150, width: 80, height: 30, annotations: [{ content: 'Node2' }] }
];
const connectors = [
{ id: 'connector1', sourceID: 'node1', targetID: 'node2' }
];
Annotation Creation and Formatting
In mxGraph
, styling labels requires editing a style object and applying it to the node. Custom label positioning needs extra configuration and is less straightforward.
const vertex = graph.insertVertex(parent, null, 'Decision', 100, 100, 80, 40);
const style = graph.getStylesheet().getDefaultVertexStyle();
style[mxConstants.STYLE_FONTCOLOR] = '#FF0000';
style[mxConstants.STYLE_FONTSTYLE] = mxConstants.FONT_BOLD;
style[mxConstants.STYLE_FONTSIZE] = 14;
style[mxConstants.STYLE_ALIGN] = mxConstants.ALIGN_CENTER;
style[mxConstants.STYLE_VERTICAL_ALIGN] = mxConstants.ALIGN_MIDDLE;
graph.getModel().setStyle(vertex, mxStyleRegistry.getName(style));
In Syncfusion® JavaScript Diagram, annotations are defined within the annotations array of a node, allowing for straightforward customization:
const node = {
id: 'decisionNode',
offsetX: 300,
offsetY: 200,
width: 100,
height: 60,
shape: { type: 'Flow', shape: 'Decision' },
annotations: [{
content: 'Decision',
style: {
color: '#FF0000',
bold: true,
fontSize: 14
},
offset: { x: 0.5, y: 1.2 },
verticalAlignment: 'Top',
horizontalAlignment: 'Center',
margin: { top: 10 }
}]
};
Using Ports
In mxGraph
, ports are additional vertices within a parent vertex.
const vertex = graph.insertVertex(parent, null, 'Node 1', 100, 100, 80, 30);
const port = graph.insertVertex(vertex, null, '', 1, 0.5, 10, 10,
'shape=ellipse;perimter=ellipsePerimeter;portConstraint=east;');
port.geometry.offset = new mxPoint(-5, -5);
port.geometry.relative = true;
In Syncfusion® JavaScript Diagram, ports are similarly enabled by defining them within a node, specifying offsets and shapes.
var diagram = new ej.diagrams.Diagram({
width: '100%',
height: '600px',
nodes: [{
id: 'node1',
offsetX: 90,
offsetY: 60,
width: 100,
height: 40,
annotations: [{ content: 'Node 1' }],
ports: [{
id: 'port1',
offset: { x: 1, y: 0.5 },
visibility: ej.diagrams.PortVisibility.Visible,
shape: 'Circle',
width: 10,
height: 10
}]
}]
});
diagram.appendTo('#diagram');
Applying Layouts
In mxGraph
, layouts like hierarchical are applied by using specific layout classes.
var v1 = graph.insertVertex(parent, null, 'Start', 0, 0, 100, 40);
var v2 = graph.insertVertex(parent, null, 'Middle', 0, 0, 100, 40);
var v3 = graph.insertVertex(parent, null, 'End', 0, 0, 100, 40);
graph.insertEdge(parent, null, '', v1, v2);
graph.insertEdge(parent, null, '', v2, v3);
var layout = new mxHierarchicalLayout(graph, mxConstants.DIRECTION_NORTH);
layout.execute(parent);
In Syncfusion® JavaScript Diagram, layouts are defined in the diagram using layout
property.
ej.diagrams.Diagram.Inject(ej.diagrams.HierarchicalTree);
var diagram = new ej.diagrams.Diagram({
width: '100%',
height: '600px',
layout: {
type: 'HierarchicalTree',
horizontalSpacing: 25,
verticalSpacing: 35
},
nodes: [
{
id: 'node1',
annotations: [{ content: 'Parent' }]
},
{
id: 'node2',
annotations: [{ content: 'Child 1' }]
},
{
id: 'node3',
annotations: [{ content: 'Child 2' }]
}
],
connectors: [
{ id: 'connector1', sourceID: 'node1', targetID: 'node2' },
{ id: 'connector2', sourceID: 'node1', targetID: 'node3' }
]
});
diagram.appendTo('#diagram');
Saving and Loading Diagrams
In mxGraph
, the graph model is serialized and deserialized using XML.
// Save the graph model to XML string
function saveGraph(graph) {
const encoder = new mxCodec();
const node = encoder.encode(graph.getModel());
const xml = mxUtils.getXml(node);
return xml;
}
// Load the graph model from XML string
function loadGraph(graph, xml) {
const doc = mxUtils.parseXml(xml);
const codec = new mxCodec(doc);
codec.decode(doc.documentElement, graph.getModel());
graph.refresh();
}
In Syncfusion® JavaScript Diagram, diagram states are saved and loaded using JSON strings for persistence.
const savedDiagram = diagram.saveDiagram(); // returns JSON string
diagram.loadDiagram(savedDiagram); // restores diagram
Event Handling
In mxGraph
, you handle events by adding listeners to the graph.
graph.addListener(mxEvent.CLICK, function(sender, evt) {
const cell = evt.getProperty('cell');
if (cell != null) {
console.log('Cell clicked:', cell.value);
}
});
In Syncfusion® JavaScript Diagram, event handling is configured with function callbacks in the diagram.
var diagram = new ej.diagrams.Diagram({
width: '100%',
height: '600px',
click: function(args) {
if (args.element && args.element.annotations) {
console.log('Node clicked:', args.element.annotations[0].content);
}
}
});
diagram.appendTo('#diagram');
Diagram Canvas Configuration and Customization
Configuring the mxGraph
diagram canvas often involves manual calculations and numerous API calls. In comparison, Syncfusion® JavaScript Diagram provides a more straightforward approach with built-in properties and methods.
Grid Lines
In mxGraph
, enabling and customizing grid lines involves setting various properties.
graph.setGridEnabled(true);
graph.setGridSize(10);
graph.view.gridColor = '#e0e0e0';
In Syncfusion® JavaScript Diagram, grid lines are configured using the snapSettings property, allowing for a straightforward setup while also supporting additional customization options that are self-explanatory:
var diagram = new ej.diagrams.Diagram({
width: '100%', height: '600px',
snapSettings: {
constraints: ej.diagrams.SnapConstraints.ShowLines,
horizontalGridlines: { lineColor: '#e0e0e0', lineDashArray: '2,2' },
verticalGridlines: { lineColor: '#e0e0e0', lineDashArray: '2,2' }
}
});
diagram.appendTo('#element');
Ruler
To use rulers in mxGraph
, you’ll need to undertake custom development since it lacks native support for this feature. In contrast, Syncfusion® Diagram provides built-in ruler support that can be easily activated with a straightforward property setting:
var diagram = new ej.diagrams.Diagram({
width: '100%', height: '600px',
rulerSettings: { showRulers: true }
});
diagram.appendTo('#element');
Page Settings
In mxGraph
, setting up page dimensions and appearance involves setting properties on the graph object like pageVisible
, pageBreaksVisible
, and setPageSize
.
graph.pageVisible = true;
graph.pageBreaksVisible = true;
graph.setPageSize(new mxRectangle(0, 0, 800, 600));
graph.container.style.backgroundColor = '#f5f5f5';
In Syncfusion® JavaScript Diagram (ej2), the pageSettings property provides a straightforward way to configure page settings, including support for multiple pages and showing page breaks.
var diagram = new ej.diagrams.Diagram({
width: '100%', height: '600px',
pageSettings: {
width: 800, height: 600,
background: { color: '#f5f5f5' },
showPageBreaks: true,
multiplePage: true // Enables multiple page feature
}
});
diagram.appendTo('#element');
Scroll Settings
In mxGraph
, scroll behavior is primarily handled through the container’s CSS and enabling panning. There are no built-in APIs for configuring advanced scroll behavior like auto-scroll or scroll boundaries.
// Basic scroll setup via container styling and panning
graph.setPanning(true);
graph.panningHandler.useLeftButtonForPanning = true;
graph.container.style.overflow = 'auto';
In Syncfusion® JavaScript Diagram, the scrollSettings property provides detailed control over scroll behavior, including auto-scroll, scroll limits, and scroll frequency.
var diagram = new ej.diagrams.Diagram({
width: '100%', height: '600px',
scrollSettings: {
scrollLimit: 'Infinity',
canAutoScroll: true,
autoScrollBorder: { left: 20, top: 20, right: 20, bottom: 20 },
autoScrollFrequency: 100
}
});
diagram.appendTo('#element');
Symbol Palette
Unlike Syncfusion® JavaScript Diagram, mxGraph
does not offer a built-in SymbolPalette UI component. You must manually build a palette using HTML elements, style them, and use mxUtils.makeDraggable() for drag-and-drop integration. Below is an example of easily creating a palette with Syncfusion® JavaScript Diagram.
const palette = new ej.diagrams.SymbolPalette({
palettes: [{
id: 'flowShapes',
expanded: true,
symbols: [
{ id: 'Terminator', shape: { type: 'Flow', shape: 'Terminator' } },
{ id: 'Process', shape: { type: 'Flow', shape: 'Process' } }
],
title: 'Flow Shapes'
}]
});
palette.appendTo('#palette');
Diagram Interactions
Syncfusion® JavaScript Diagram provides easy support for key interactions like zooming, panning, selection, dragging, resizing, rotating, and keyboard navigation with little setup. Its user-friendly API and clear properties simplify implementation. In contrast, mxGraph
usually needs more manual setup and extra coding to achieve similar outcomes.
Zooming
In mxGraph
, implementing zoom functionality involves invoking specific methods and managing the zoom scale manually.
// Zoom in
graph.zoomIn();
// Zoom out
graph.zoomOut();
// Zoom to specific scale
graph.zoomTo(1.5); // 150% zoom
With Syncfusion® JavaScript Diagram, you can easily control zooming using built-in methods or through the user interface.
// Zoom in
diagram.zoomTo({ type: 'ZoomIn', zoomFactor: 0.2 });
// Zoom out
diagram.zoomTo({ type: 'ZoomOut', zoomFactor: 0.2 });
// Zoom to specific scale
diagram.zoomTo({ type: 'Zoom', zoomFactor: 1.5 }); // 150% zoom
Panning
In mxGraph
, panning is enabled by setting the panning handler and configuring the mouse button for panning:
// Enable panning
graph.setPanning(true);
graph.panningHandler.useLeftButtonForPanning = true;
In Syncfusion® JavaScript Diagram, to enable panning, you need to set the tool property to include ZoomPan:
// Enable panning
diagram.tool = ej.diagrams.DiagramTools.ZoomPan;
Undo / Redo
In mxGraph
, enabling undo and redo requires setting up an mxUndoManager and wiring it to the model events.
const undoManager = new mxUndoManager();
graph.getModel().addListener(mxEvent.UNDO, undoManager);
undoManager.undo();
undoManager.redo();
Syncfusion® JavaScript Diagram provides built-in undo and redo commands, requiring no additional setup:
diagram.undo();
diagram.redo();
In addition to the interactions showcased above, Syncfusion® JavaScript Diagram supports many more intuitive and powerful interactions—such as snapping, constraints, drag-and-drop from palettes, tooltips, and context menus. All of these can be enabled or customized with minimal configuration, making it easy to deliver a seamless and interactive diagramming experience.
NOTE
To know more about the Interactions in Syncfusion® JavaScript Diagram, refer to the documentation.
Keyboard Interactions
Keyboard shortcuts enhance user productivity by allowing quick access to common actions. While both mxGraph
and Syncfusion® JavaScript Diagram support keyboard interactions, Syncfusion® offers a more extensive set of built-in commands and easier customization.
The following table compares common keyboard shortcuts and their implementations in mxGraph
and Syncfusion® JavaScript Diagram:
Action | mxGraph Implementation | Syncfusion® JavaScript Diagram Implementation |
---|---|---|
Select All | Requires custom key handler setup using mxKeyHandler or mxDefaultKeyHandler
|
Built-in support: Ctrl + A selects all nodes/connectors |
Copy | Custom implementation needed using mxClipboard.copy and key handler |
Built-in support: Ctrl + C copies selected elements |
Paste | Custom implementation needed using mxClipboard.paste and key handler |
Built-in support: Ctrl + V pastes copied elements |
Cut | Custom implementation needed using mxClipboard.cut and key handler |
Built-in support: Ctrl + X cuts selected elements |
Undo | Requires setting up mxUndoManager and binding Ctrl + Z manually |
Built-in support: Ctrl + Z undoes the last action |
Redo | Requires setting up mxUndoManager and binding Ctrl + Y manually |
Built-in support: Ctrl + Y redoes the last undone action |
Delete | Custom implementation needed to bind Delete key to remove selected elements |
Built-in support: Delete key removes selected elements |
Label Editing | Requires custom event handling for label editing initiation and termination | Built-in support: F2 to start editing, Esc to cancel |
Zoom In/Out | Custom implementation needed to bind Ctrl + MouseWheel for zooming |
Built-in support: Ctrl + MouseWheel zooms in/out |
Nudge Elements | Custom implementation needed to move elements with arrow keys | Built-in support: Arrow keys move elements by 1px; Shift + Arrow moves by 5px |
Group/Ungroup | Custom implementation needed to group/ungroup elements with key bindings | Built-in support: Ctrl + G to group, Ctrl + Shift + U to ungroup |
Rotate Elements | Custom implementation needed to rotate elements with key bindings | Built-in support: Ctrl + R rotates clockwise, Ctrl + L rotates counter-clockwise |
Flip Elements | Custom implementation needed to flip elements with key bindings | Built-in support: Ctrl + H flips horizontally, Ctrl + J flips vertically |
Align Text | Custom implementation needed to align text with key bindings | Built-in support: Use Ctrl + Shift + L/C/R/J for horizontal and Ctrl + Shift + E/M/V for vertical text alignment. |
Enhanced Interactions in Syncfusion JavaScript Diagram over mxGraph
Syncfusion® JavaScript Diagram offers a comprehensive set of built-in commands for common diagramming tasks. Unlike mxGraph
, which often needs lengthy manual code, these commands can be used with minimal coding, enhancing productivity and maintainability.
Fit to Page
In mxGraph
, fitting a diagram to the page involves calculating bounds, determining scale, and manually adjusting the viewport.
const bounds = graph.getGraphBounds();
const scale = Math.min(container.clientWidth / bounds.width, container.clientHeight / bounds.height);
graph.view.setScale(scale);
graph.view.setTranslate(-bounds.x, -bounds.y);
In Syncfusion® JavaScript Diagram, this can be achieved with a single method call:
diagram.fitToPage();
Bring to Center
Centering an element in mxGraph
involves manual calculations based on the element’s bounds and viewport dimensions.
const bounds = graph.getCellBounds(cell);
const dx = container.clientWidth / 2 - (bounds.x + bounds.width / 2);
const dy = container.clientHeight / 2 - (bounds.y + bounds.height / 2);
graph.view.setTranslate(dx, dy);
In Syncfusion® JavaScript Diagram, this is simplified with a direct API method:
diagram.bringToCenter('node1');
Bring into View
In mxGraph
, bringing an element into view can be done using the scrollCellToVisible
method, which scrolls the diagram to reveal the specified cell.
graph.scrollCellToVisible(cell);
In Syncfusion® JavaScript Diagram, bringing a node into view is very similar to doing so in mxGraph
.
diagram.bringIntoView('node1');
In addition to the commands shown above, Syncfusion® JavaScript Diagram provides a full set of built-in commands for easy diagram editing and interaction. These commands cover common tasks for arranging, transforming, navigating, and managing diagram elements, accessible via straightforward API calls or user-friendly keyboard shortcuts.
NOTE
To learn more about the built-in commands in Syncfusion® JavaScript Diagram, refer to our documentation.