Getting started with React
In this tutorial we will add a Diagram Editor and a Diagram Viewer to a basic React application.
We will not cover the installation and other basics. For that, please refer to the general getting started tutorial.
Introduction
In this tutorial we will add both the editor and the viewer to the same React component. Our initial diagram (so you don't get an empty starting point) is stored in the initialDiagram
variable, for simplicity. Normally it would come from some kind of storage through the component's props.
Note that this is not a React tutorial and it may not follow the best React practices. The goal here is to show how to include MJS Diagram in a React app with minimal conceptual overhead. For a complete real-life demo implementation checkout the Diagrams app and it's source code.
We are using TypeScript in the code below, but you should be able to easily use the code in plain JavaScript by stripping out the types.
In case you want to jump straight into code, hop over to the complete sample for this tutorial on Codesandbox.
State and refs
MJS Diagram components take up the whole area of their parent container, so we need to setup the placeholders for both the editor and the viewer.
return (
<div className="App">
<div className="diagram-editor" ref={editorContainerRef}></div>
<div className="diagram-viewer" ref={viewerContainerRef}></div>
</div>
);
We define the dimensions of these divs in our CSS and, as you can see, we set refs on these divs so we can refer them in our code. So we define both of these refs in our code:
const viewerContainerRef = useRef<HTMLDivElement>(null);
const editorContainerRef = useRef<HTMLDivElement>(null);
As our MJS Diagram components are not React componets, we need to setup refs to refer them as well.
const viewerRef = useRef<DiagramViewer | null>(null);
const editorRef = useRef<DiagramEditor | null>(null);
The DiagramViewer
class comes from the @markerjs/mjs-diagram/viewer
module and DiagramEditor
can be found in @markerjs/mjs-diagram/editor
.
We will hold our diagram config (also known as diagram state) in our React componet's state. We are passing our "saved" initialDiagram
config as the initial state.
const [diagram, setDiagram] = useState<DiagramState>(initialDiagram);
The DiagramState
type comes from the @markerjs/mjs-diagram/core
module.
We are now ready to setup our editor.
Diagram editor
As our components are "external" to React we are using the useEffect
hook to setup and update MJS Diagram components.
As we need to setup the editor just once, we will check if our editorRef
is null before proceeding. Then we create a new instance of DiagramEditor
and add it as child to a respective div using the editorContainerRef
.
We are creating a flowchart editor in this tutorial, so we need to set the editor's stencilEditorSet = flowchartStencilEditorSet
. The flowchartStencilEditorSet
comes from a flowchart stencilset in @markerjs/mjs-diagram/stencilsets/flowchart/flowchart
When the user clicks on the "save" button in the toolbar saveclick
event is fired. We add an event handler for the saveclick
event to update our component's state with a new diagram configuration provided in the event's detail.state
property.
Finally, we need to restore our saved state in the editor using its restoreState
method.
Here's the complete code for our editor-related hook:
useEffect(() => {
if (editorRef.current === null) {
const editor = new DiagramEditor();
editorContainerRef.current?.appendChild(editor);
editorRef.current = editor;
editor.addEventListener("saveclick", (ev) => {
setDiagram(ev.detail.state);
});
editorRef.current.stencilEditorSet = flowchartStencilEditorSet;
}
editorRef.current.restoreState(diagram);
}, []);
Diagram viewer
Adding the viewer is almost identical to the editor. Instead of the DiagramEditor
we instantiate a DiagramViewer
, we don't need to handle any events, and we set a stencilSet = flowchartStencilSet
(instead of stencilEditorSet
).
Finally, we call the viewer's show()
method to pass our diagram's config. And we shouldn't forget to pass our diagram
state variable as a dependency for the hook, so that it's rerendered when the diagram is edited and saved.
Here's the complete useEffect
hook for the diagram viewer:
useEffect(() => {
if (viewerRef.current === null) {
const viewer = new DiagramViewer();
viewerContainerRef.current?.appendChild(viewer);
viewerRef.current = viewer;
viewerRef.current.stencilSet = flowchartStencilSet;
}
viewerRef.current.show(diagram);
}, [diagram]);
The complete demo
That is all it takes and below is this demo in action. Try editing the diagram and click save to see the changes reflected in the lower (viewer) part.
Check this demo out and fork it on Codesandbox.
See also
Diagrams app is a complete real-life React (Next.js) MJS Diagram implementation. The source code is available on GitHub.