Save and Load Diagrams in React Diagram Component
21 Oct 202524 minutes to read
Serialization is the process of converting the diagram’s current state into a storage format that can be saved and later restored. This feature ensures that all diagram elements, including nodes, connectors, and their configurations, persist across application sessions.
The serialization process converts the diagram into a JSON string format, which can be stored in databases, files, or other storage systems. When needed, this serialized data can be deserialized to recreate the diagram exactly as it was previously configured.
Use serialization when you need to:
- Save user-created diagrams for future editing.
- Implement undo/redo functionality.
- Create diagram templates.
- Transfer diagrams between different sessions or users.
To save and load the diagram in React, refer to the below video link.
Saving Diagrams
Basic Save Operation
The saveDiagram method serializes the entire diagram configuration into a JSON string. This method captures all diagram elements, their properties, and the current state.
The following code illustrates how to save the diagram:
let saveData: string;
//returns serialized string of the Diagram
saveData = diagramInstance.saveDiagram();The serialized JSON string can be stored in various storage systems. The following example demonstrates local storage implementation:
//Saves the string in to local storage
localStorage.setItem('fileName', saveData);
// Retrieve the saved string from local storage
saveData = localStorage.getItem('fileName');Alternative Save Formats
The diagram can also be saved as raster or vector image files. For more information about saving the diagram as images, refer to the Print and Export sections.
Loading Diagrams
Basic Load Operation
The loadDiagram method recreates the diagram from serialized JSON data. This method accepts the previously saved JSON string as a parameter.
/*
* Loads the diagram from saved JSON data.
* parameter 1 - The string representing the diagram model JSON to be loaded.
* parameter 2 - Whether it is ej1 data or not (optional)
*/
diagramInstance.loadDiagram(saveData);Note: Before loading a new diagram, the existing diagram content is automatically cleared.
Handling Load Completion
The loaded event triggers when all diagram elements finish loading through the loadDiagram method. Use this event to perform post-load customizations or validations.
return (
loaded={(args) => {
//You can use this event to customize diagram elements during the loading process
}}/>
)The loaded event provides the following arguments:
name
Type: String
Description: Returns the event name.
diagram
Type: Diagram
Description: Returns the diagram model properties.
Users can perform customizations or modifications to the diagram elements once the loading process is complete.
Prevent Default Values
The preventDefaults property of serializationSettings reduces the size of serialized data by excluding default properties. This optimization improves performance when handling large diagrams or frequent save operations.
When enabled, only explicitly set properties are included in the JSON output, significantly reducing file size and improving load times.
return (
<div>
<DiagramComponent
serializationSettings =
></DiagramComponent>
</div>
)File-Based Save and Load Operations
21 Oct 202524 minutes to read
Using Uploader Component
JSON files can be uploaded and processed using the uploader component. Configure the uploader with appropriate server endpoints to handle file operations, then parse the uploaded JSON data to load diagrams.
The uploader requires:
-
saveUrlproperty for receiving and storing uploaded files. -
removeUrlproperty for handling file deletion operations. - File parsing logic to extract JSON data from uploaded files.
import * as React from "react";
import * as ReactDOM from "react-dom";
import { DiagramComponent } from '@syncfusion/ej2-react-diagrams';
import { UploaderComponent } from '@syncfusion/ej2-react-inputs';
import { ButtonComponent } from '@syncfusion/ej2-react-buttons';
export default function App() {
let diagramInstance;
// Initialize Uploader Object
let uploadObject = {
saveUrl:
'https://services.syncfusion.com/js/production/api/FileUploader/Save',
removeUrl:
'https://services.syncfusion.com/js/production/api/FileUploader/Remove',
}
// Callback function for when the upload is successful
function onUploadSuccess(args) {
var file = args.file.rawFile;
var reader = new FileReader();
reader.readAsText(file);
reader.onloadend = loadDiagram;
}
// Function to load the diagram from the uploaded file
function loadDiagram(event) {
diagramInstance.loadDiagram(event.target.result);
}
// Function to save the current diagram
function saveDiagram() {
download(diagramInstance.saveDiagram());
}
// Function to download the diagram data as a JSON file
function download(data) {
if (window.navigator.msSaveBlob) {
let blob = new Blob([data], { type: 'data:text/json;charset=utf-8,' });
window.navigator.msSaveBlob(blob, 'Diagram.json');
} else {
let dataStr = 'data:text/json;charset=utf-8,' + encodeURIComponent(data);
let a = document.createElement('a');
a.href = dataStr;
a.download = 'Diagram.json';
document.body.appendChild(a);
a.click();
a.remove();
}
}
// Initialize nodes for the diagram
let nodes = [
{
id: 'Start',
width: 140,
height: 50,
offsetX: 300,
offsetY: 50,
annotations: [{ id: 'label1', content: 'Start' }],
shape: { type: 'Flow', shape: 'Terminator' }
},
];
return (
// Initialize Diagram component
<div>
<label>Browse to load</label>
<UploaderComponent asyncSettings={uploadObject} success={onUploadSuccess} />
<ButtonComponent content="Save Diagram" onClick={saveDiagram} />
<DiagramComponent
id="container"
ref={(diagram) => (diagramInstance = diagram)}
width={'100%'}
height={'600px'}
nodes={nodes}
></DiagramComponent>
</div>
);
}
// Render the App component into the 'diagram' element in the DOM
const root = ReactDOM.createRoot(document.getElementById("diagram"));
root.render(<App />);import * as React from "react";
import * as ReactDOM from "react-dom";
import { DiagramComponent, NodeModel } from '@syncfusion/ej2-react-diagrams';
import { UploaderComponent, FileInfo } from '@syncfusion/ej2-react-inputs';
import { ButtonComponent } from '@syncfusion/ej2-react-buttons';
export default function App() {
let diagramInstance: DiagramComponent;
// Initialize Uploader Object
let uploadObject = {
saveUrl:
'https://services.syncfusion.com/js/production/api/FileUploader/Save',
removeUrl:
'https://services.syncfusion.com/js/production/api/FileUploader/Remove',
}
// Callback function for when the upload is successful
function onUploadSuccess(args: { file: FileInfo }) {
var file: any = args.file.rawFile;
var reader = new FileReader();
reader.readAsText(file);
reader.onloadend = loadDiagram;
}
// Function to load the diagram from the uploaded file
function loadDiagram(event: any) {
diagramInstance.loadDiagram(event.target.result);
}
// Function to save the current diagram
function saveDiagram() {
download(diagramInstance.saveDiagram());
}
// Function to download the diagram data as a JSON file
function download(data: string) {
if ((window.navigator as any).msSaveBlob) {
let blob = new Blob([data], { type: 'data:text/json;charset=utf-8,' });
(window.navigator as any).msSaveBlob(blob, 'Diagram.json');
} else {
let dataStr = 'data:text/json;charset=utf-8,' + encodeURIComponent(data);
let a: HTMLAnchorElement = document.createElement('a');
a.href = dataStr;
a.download = 'Diagram.json';
document.body.appendChild(a);
a.click();
a.remove();
}
}
// Initialize nodes for the diagram
let nodes: NodeModel[] = [
{
id: 'Start',
width: 140,
height: 50,
offsetX: 300,
offsetY: 50,
annotations: [{ id: 'label1', content: 'Start' }],
shape: { type: 'Flow', shape: 'Terminator' }
},
];
return (
// Initialize Diagram component
<div>
<UploaderComponent asyncSettings={uploadObject} success={onUploadSuccess} />
<ButtonComponent content="Save Diagram" onClick={saveDiagram} />
<DiagramComponent
id="container"
ref={(diagram: any) => (diagramInstance = diagram)}
width={'100%'}
height={'600px'}
nodes={nodes}
/>
</div>
);
}
// Render the App component into the 'diagram' element in the DOM
const root = ReactDOM.createRoot(document.getElementById("diagram") as HTMLElement);
root.render(<App />);Mermaid Syntax Integration
Overview
The Diagram component supports importing and exporting diagrams using Mermaid syntax. Mermaid is a markdown-inspired syntax for creating diagrams programmatically, enabling easy diagram creation and sharing across different platforms.
This functionality supports:
- Mind maps
- Flowcharts
- UML sequence diagrams
Saving Diagrams as Mermaid Syntax
The saveDiagramAsMermaid method converts compatible diagrams into Mermaid syntax format. This method works specifically with Flowchart and Mind map layouts.
//returns the serialized Mermaid string of the Diagram
let data = diagramInstance.saveDiagramAsMermaid();Load Diagram from Mermaid Syntax
The loadDiagramFromMermaid method creates diagrams from Mermaid syntax data, automatically generating the appropriate layout and styling.
data.
Load Flowchart Layout
The following example shows how to load flowchart diagram from mermaid syntax.
import * as React from "react";
import * as ReactDOM from "react-dom";
import { DiagramComponent, Inject, FlowchartLayout } from "@syncfusion/ej2-react-diagrams";
export default function App() {
let diagramInstance;
// Mermaid syntax for the flowchart data
let mermaidFlowchartData = `flowchart TD
A[Start] --> B(Process)
B -.- C{Decision}
C --Yes--> D[Plan 1]
C ==>|No| E[Plan 2]
style A fill:#90EE90,stroke:#333,stroke-width:2px;
style B fill:#4682B4,stroke:#333,stroke-width:2px;
style C fill:#FFD700,stroke:#333,stroke-width:2px;
style D fill:#FF6347,stroke:#333,stroke-width:2px;
style E fill:#FF6347,stroke:#333,stroke-width:2px;`;
// Function to set default properties for nodes
function getNodeDefaults(node) {
node.width = 120;
node.height = 50;
if (node.shape.shape === 'Decision') {
node.height = 80;
}
node.annotations[0].style.bold = true;
return node;
};
// Function to set default properties for connectors
function getConnectorDefaults(connector) {
connector.type = 'Orthogonal';
return connector;
};
// Function to load the Mermaid flowchart data into the diagram
function loadMermaidFlowchart() {
diagramInstance.loadDiagramFromMermaid(mermaidFlowchartData);
};
return (
// Initialize Diagram component
<div>
<button onClick={loadMermaidFlowchart} id="loadMermaidFlowchart">Load Mermaid Flowchart</button>
<DiagramComponent
id="container"
ref={(diagram) => (diagramInstance = diagram)}
width={"100%"}
height={"600px"}
layout={{ type: 'Flowchart' }}
getNodeDefaults={getNodeDefaults}
getConnectorDefaults={getConnectorDefaults}
>
<Inject services={[FlowchartLayout]} />
</DiagramComponent>
</div>
);
}
// Render the App component into the 'diagram' element in the DOM
const root = ReactDOM.createRoot(document.getElementById("diagram"));
root.render(<App />);import * as React from "react";
import * as ReactDOM from "react-dom";
import { DiagramComponent, Inject, FlowchartLayout, ConnectorModel, NodeModel } from "@syncfusion/ej2-react-diagrams";
export default function App() {
let diagramInstance: DiagramComponent;
// Mermaid syntax for the flowchart data
let mermaidFlowchartData: string = `flowchart TD
A[Start] --> B(Process)
B -.- C{Decision}
C --Yes--> D[Plan 1]
C ==>|No| E[Plan 2]
style A fill:#90EE90,stroke:#333,stroke-width:2px;
style B fill:#4682B4,stroke:#333,stroke-width:2px;
style C fill:#FFD700,stroke:#333,stroke-width:2px;
style D fill:#FF6347,stroke:#333,stroke-width:2px;
style E fill:#FF6347,stroke:#333,stroke-width:2px;`;
// Function to set default properties for nodes
function getNodeDefaults(node: NodeModel | any): NodeModel {
node.width = 120;
node.height = 50;
if (node.shape.shape === 'Decision') {
node.height = 80;
}
node.annotations[0].style.bold = true;
return node;
};
// Function to set default properties for connectors
function getConnectorDefaults(connector: ConnectorModel): ConnectorModel {
connector.type = 'Orthogonal';
return connector;
};
// Function to load the Mermaid flowchart data into the diagram
function loadMermaidFlowchart(): void {
diagramInstance.loadDiagramFromMermaid(mermaidFlowchartData);
};
return (
// Initialize Diagram component
<div>
<button onClick={loadMermaidFlowchart} id="loadMermaidFlowchart">Load Mermaid Flowchart</button>
<DiagramComponent
id="container"
ref={(diagram: any) => (diagramInstance = diagram)}
width={"100%"}
height={"600px"}
layout={{ type: 'Flowchart' }}
getNodeDefaults={getNodeDefaults}
getConnectorDefaults={getConnectorDefaults}
>
<Inject services={[FlowchartLayout]} />
</DiagramComponent>
</div>
);
}
// Render the App component into the 'diagram' element in the DOM
const root = ReactDOM.createRoot(document.getElementById("diagram") as HTMLElement);
root.render(<App />);Loading Mind Map Layout
The following example demonstrates loading a mind map diagram from Mermaid syntax:
import * as React from "react";
import * as ReactDOM from "react-dom";
import { DiagramComponent, Inject, MindMap } from "@syncfusion/ej2-react-diagrams";
export default function App() {
let diagramInstance;
// Mermaid syntax for the mindmap data
let mermaidMindmapData = `mindmap
root((mindmap))
Origins
Popularisation
Research
On effectiveness<br/>and features
On Automatic creation
Tools
Pen and paper
Mermaid`;
// Function to set default properties for nodes
function getNodeDefaults(node) {
node.width = 140;
node.height = 50;
node.annotations[0].style.bold = true;
return node;
};
// Function to set default properties for connectors
function getConnectorDefaults(connector) {
connector.type = 'Orthogonal';
return connector;
};
// Function to load the Mermaid mindmap data into the diagram
function loadMermaidMindmap() {
diagramInstance.loadDiagramFromMermaid(mermaidMindmapData);
};
return (
// Initialize Diagram component
<div>
<button onClick={loadMermaidMindmap} id="loadMermaidMindmap">Load Mermaid Mindmap</button>
<DiagramComponent
id="container"
ref={(diagram) => (diagramInstance = diagram)}
width={"100%"}
height={"350px"}
layout={{
type: 'MindMap',
verticalSpacing: 50,
horizontalSpacing: 50,
orientation: 'Horizontal',
}}
getNodeDefaults={getNodeDefaults}
getConnectorDefaults={getConnectorDefaults}
>
<Inject services={[MindMap]} />
</DiagramComponent>
</div>
);
}
// Render the App component into the 'diagram' element in the DOM
const root = ReactDOM.createRoot(document.getElementById("diagram"));
root.render(<App />);import * as React from "react";
import * as ReactDOM from "react-dom";
import { DiagramComponent, Inject, MindMap, NodeModel, ConnectorModel } from "@syncfusion/ej2-react-diagrams";
export default function App() {
let diagramInstance: DiagramComponent;
// Mermaid syntax for the mindmap data
let mermaidMindmapData: string = `mindmap
root((mindmap))
Origins
Popularisation
Research
On effectiveness<br/>and features
On Automatic creation
Tools
Pen and paper
Mermaid`;
// Function to set default properties for nodes
function getNodeDefaults(node: NodeModel | any): NodeModel {
node.width = 140;
node.height = 50;
node.annotations[0].style.bold = true;
return node;
};
// Function to set default properties for connectors
function getConnectorDefaults(connector: ConnectorModel): ConnectorModel {
connector.type = 'Orthogonal';
return connector;
};
// Function to load the Mermaid mindmap data into the diagram
function loadMermaidMindmap() {
diagramInstance.loadDiagramFromMermaid(mermaidMindmapData);
};
return (
// Initialize Diagram component
<div>
<button onClick={loadMermaidMindmap} id="loadMermaidMindmap">Load Mermaid Mindmap</button>
<DiagramComponent
id="container"
ref={(diagram: any) => (diagramInstance = diagram)}
width={"100%"}
height={"350px"}
layout={{ type: 'MindMap', orientation: 'Horizontal' }}
getNodeDefaults={getNodeDefaults}
getConnectorDefaults={getConnectorDefaults}
>
<Inject services={[MindMap]} />
</DiagramComponent>
</div>
);
}
// Render the App component into the 'diagram' element in the DOM
const root = ReactDOM.createRoot(document.getElementById("diagram") as HTMLElement);
root.render(<App />);Loading UML Sequence Diagram
The following example demonstrates loading a UML Sequence diagram from Mermaid syntax:
import * as React from "react";
import * as ReactDOM from "react-dom";
import { DiagramComponent } from "@syncfusion/ej2-react-diagrams";
export default function App() {
let diagramInstance;
const mermaidData = `
sequenceDiagram
participant User
participant Controller
participant Service
participant Database
User->>Controller: sendRequest()
activate Controller
Controller->>Service: processRequest()
activate Service
Service->>Database: queryData()
activate Database
Database-->>Service: returnData()
deactivate Database
Service-->>Controller: returnResponse()
deactivate Service
Controller-->>User: sendResponse()
deactivate Controller`;
// Function to load the Mermaid sequence diagram data into the diagram
function loadMermaidSeqDiagram() {
diagramInstance.loadDiagramFromMermaid(mermaidData);
};
return (
// Initialize Diagram component
<div>
<button onClick={loadMermaidSeqDiagram} id="loadMermaid">Load Mermaid</button>
<DiagramComponent
id="container" ref={(diagram) => (diagramInstance = diagram)}
width={"100%"} height={"600px"}>
</DiagramComponent>
</div>
);
}
// Render the App component into the 'diagram' element in the DOM
const root = ReactDOM.createRoot(document.getElementById("diagram"));
root.render(<App />);import * as React from "react";
import * as ReactDOM from "react-dom";
import { DiagramComponent } from "@syncfusion/ej2-react-diagrams";
export default function App() {
let diagramInstance: DiagramComponent;
const mermaidData: string = `
sequenceDiagram
participant User
participant Controller
participant Service
participant Database
User->>Controller: sendRequest()
activate Controller
Controller->>Service: processRequest()
activate Service
Service->>Database: queryData()
activate Database
Database-->>Service: returnData()
deactivate Database
Service-->>Controller: returnResponse()
deactivate Service
Controller-->>User: sendResponse()
deactivate Controller`;
// Function to load the Mermaid sequence diagram data into the diagram
function loadMermaidSeqDiagram() {
diagramInstance.loadDiagramFromMermaid(mermaidData);
};
return (
// Initialize Diagram component
<div>
<button onClick={loadMermaidSeqDiagram} id="loadMermaid">Load Mermaid</button>
<DiagramComponent
id="container" ref={(diagram: any) => (diagramInstance = diagram)}
width={"100%"} height={"600px"}>
</DiagramComponent>
</div>
);
}
// Render the App component into the 'diagram' element in the DOM
const root = ReactDOM.createRoot(document.getElementById("diagram") as HTMLElement);
root.render(<App />);NOTE
Mermaid syntax-based serialization and deserialization supports only Flowchart layout, Mind map layout, and UML Sequence Diagram. Ensure that your Mermaid data aligns with one of these supported layouts for successful diagram loading.