Using Flexbox Layout to Arrange Diagram Components in React

This tutorial demonstrates how to use the flexbox layout to arrange the various diagram controls that come with the diagram library for React. The controls we will arrange are DiagramView , NodeListView , Ruler , Overview, Zoomer and Ruler. This is a screenshot of the final application:

We build our project using the React framework and MindFusion diagram library for React available from https://www.npmjs.com/package/diagram-library-react.

I. Initial Project Setup

We open a terminal and navigate to the folder where we want to create our application. We use create-react-app to initialize an empty React application:

npx create-react-app flex-diagram

As you we have named our application flex-diagram. Once the initial React setup is complete, we install the diagram:

npm install diagram-library-react

Once we are done with that we can start coding our application. We add a new JavaScript file, which we name DiagramApp.js. In it we first import the default React namespace and declare a member import of the Component class. Then we declare default import of MindFuson’s diagram library under the name ‘mf’. Finally, we declare member imports of the control classes we intend to use: DiagramView, Overview, NodeListView, ZoomControl and Ruler:

import React, { Component } from 'react';
import mf from 'diagram-library';
import { DiagramView, Overview, NodeListView, ZoomControl, Ruler } from 'diagram-library-react';

Then we can create our class DagramApp, which extends component. We will need a constructor, so we declare one. In it we create an instance of the Diagram class, which represents the diagram. Note that this is not the DiagramView for React class, which renders the diagram. This is the interactive, diagram, which is actually rendered by DiagramView.

class DiagramApp extends Component {
  constructor(props) {
    super(props);

    // create the diagram
    var diagram = new mf.Diagramming.Diagram();
    ...........................

Then we create an array of ShapeNode instances, which will be used by the NodeListView control. Again, the NodeListView is a UI component that renders the nodes, but it does not create them. They are provided to it as a parameter.

var nodes = [];
    var shapes = ["Actor", "RoundRect", "Triangle", "Decision"];
    for (var i = 0; i < shapes.length; ++i) {
      var node = new mf.Diagramming.ShapeNode(diagram);
      node.setText(shapes[i]);
      node.setShape(shapes[i]);

      nodes.push(node);
 }

We create an array just with the id-s of the ShapeNode -s, which we will use as labels for them as well. You can check the id-s of the available predefined ShapeNode -s at https://www.mindfusion.eu/onlinehelp/jsdiagram/index.htm?CC_refTable_of_Predefined_Shapes_4.htm.

Finally, we need to store the diagram, together with the nodes and the shape id-s in the React state. We will need them when we create the HTML for our application. In React, the way to access class variables is to store them in the state.

    this.state = {
      diagram: diagram,
      nodes: nodes,
      captions: shapes
    };

II. Arranging the UI with CSS and the Flexbox Layout

Our flexbox layout has this structure:

We have colored the different areas of the page in different colors to show you the sections in the flexbox layout. The main container takes 100% of the space e.g. the whole page. We fix its height to be at least 500px. The layout of the flexbox is row without wrap, which means that the elements will not be rearranged in severa rows by resize. That is exactly what we need. Here is the code of the container style:

.container{
  display: flex;
  flex: 1 1 100%;
  min-height: 500px;
  flex-flow: row nowrap;
  background-color: azure;
  }

The first item in the container is the vertical column where we want to place the Overview and NodeListView controls under each other. This column needs to stay fixed size. We do not want it resized when the user resizes the page. It is the diagram in the middle that must be resized when the available space changes. We call the column “left-sidebar” and set its ‘flex-flow’ to column. We use again no wrap to stop the layout placing the two controls next to each other, if the available space gets too short. We also fix the width of this element to 200 pixels, which suits our controls fine.

.left-sidebar{
  flex: 0 0 200px;
  display: flex;
  flex-flow: column nowrap;
  background-color: beige;
  }

There is difference in how we want the Overview an NodeListView controls to take space. The overview requires fixed amount of space. We want the extra space to be given to the NodeListView. That is why we add one more style to be applied to it:

.item {
  align-self: stretch;
  background-color:lightpink;
  flex: 1 1 300px;  
  }

We give 1 as a value to flex-grow and flex-shrink, indicating that we expect this element to get resized rather than the other items in the right column.

We are ready to deal with the diagram now, which is in the middle. Here it is important to indicate that this element will stretch to take all the available place. Moreover, when the space gets smaller, it is this item that must shrink:

.center-area {
     align-self: stretch;
     background-color:chartreuse;
     flex: 10 10 500px;
     max-height: 800px;
     overflow: hidden;
}

We set big values to the flex-grow and ‘flex-shrink’ attributes and set the flex-basis to 500 px. We must restrict the height of the diagram to 800px, because it could get really long. Important attribute it ‘align-self’, which is applied to items arranged by flexbox containers, not to the container itself. Here we use this attribute to tell the diagram to stretch itself, when space is available. The overflow attribute is hidden to avoid rendering of needless scrollbars in large diagrams.

Finally, the right sidebar will host the Zoom control. It is similar to the left sidebar, but it does not have a ‘special’ item such as the NodeListView. The Zoom control is a UI control with fixed size and does not need special handling. We just need to make sure no extra space is diverted to it, if the window gets too big:

.right-sidebar{
  flex: 0 0 50px;
  background-color: lavender;  
  }

And that was the last style for the last element that we need to define. Now we are ready to apply those styles to the real React components and arrange them.

III. The ‘render’ Method

The first thing we declare in the ‘render’ method of our new DiagramApp React component are some properties:

 var props = {
      "id": "diagram1",
      "linkHeadShapeSize": 2,
      "routeLinks": true,
      "roundedLinks": true,
      "backBrush": "#e0e9e9"
    };

These are properties for the Diagram instance and we will provide them through the JavaScrpt spread operator. Then in the return statement we first declare the container div element. Its style is “container”. In it we declare the left sidebar, which will hold the overview and the NodeListView. We declare them as well:

return (      

        <div className="container">
         
            <div className="left-sidebar">
           
              <Overview diagram={this.state.diagram}></Overview>  
  		<NodeListView className="item" 
                nodes={this.state.nodes}
                captions={this.state.captions}
              ></NodeListView>        
             
             
            </div>            

        </div>      

    );

The Overview is bound to the diagram, which we keep in the state object. The NodeListView requires list with the nodes and captions, if we want to have captions over nodes. We want and we have stored the nodes and the captions in state as well.

After that is turn for the diagram. It will take the central area and its class is ‘center-area’. In addition to Diagram, we will use the Ruler control as well. We place it first and nest the diagram inside it. We use the spread operator to assign to the diagram the properties, which we have initialize at the beginning of the method.

<div className="center-area">              
            <Ruler style={{ width: "100%", height:"800px" }}>
                <DiagramView diagram={this.state.diagram} 
                  {...props}
                  />
            </Ruler>
            </div>

Finally, we declare the right sidebar, which contains the Zoom control. The Zoom control also needs to be bound to a diagram instance and we use state to get reference to our diagram:

         
          <div className="right-sidebar">
          <ZoomControl diagram={this.state.diagram}></ZoomControl>        
        </div>

With that our component is ready. We need only to place it in index.js instead of the default App Component:

import DiagramApp from './DiagramApp';

ReactDOM.render(
 
    ,
  document.getElementById('root')
);

We can run the sample with

npm start

Then you can see your application on port 3000 on localhost.

You can download the full code structured as npm project from this link:

Download Full Source Code

For technical question, please use the JS Diagram forum: https://mindfusion.eu/Forum/YaBB.pl?board=jsdiag_disc

About Diagramming for JavaScript: This native JavaScript library provides developers with the ability to create and customize any type of diagram, decision tree, flowchart, class hierarchy, graph, genealogy tree, BPMN diagrams and much more. The control offers rich event set, numerous customization options, animations, graph operations, styling and themes. You have more than 100 predefined nodes, table nodes and more than 15 automatic layout algorithms. Learn more about Diagramming for JavaScript at https://mindfusion.eu/javascript-diagram.html.