šŸŽ„Writing MermaidJS programmaticallyšŸŒŸ

Dec 20 2023

Back to 2023 Advent Calendar

Introduction

MermaidJS is a powerful, open-source JavaScript library that makes it easy to create flowcharts, sequence diagrams, Gantt charts, and other types of visual representations directly within your web application or documentation.

MermaidJS uses a straightforward syntax, which is easy to read and write by humans. However, it is not as simple as GraphViz, and not easy to write programmatically.

Creating Nodes with Different Shapes

Shapes of the nodes are defined by the shape of surrounding brackets around node name.

  1. node with round edges: id(label)
  2. database node: id[(label)]
  3. circle node: id((label)) etc

Connecting Nodes with Edges

Shape of the edge is defined by the combination of dashes and arrows.

  1. Arrow: -->
  2. Dashed arrow: -.->
  3. Thick arrow: ==>

for example:

graph LR
  A[Node A] --> B[Node B]

Generating Flowcharts Programmatically in JavaScript

As you can see the challenge with MermaidJS markdown is node and arrow shapes are not simply defined as attributes (like in GraphViz), they are special markdown.

So we need to implement some code to convert node and edge types into markdown.

Generate node shape markdown

function getNodeShapeSyntax(node) {
  switch (node.shape) {
    case 'rect':
      return `[${node.label}]`;
    case 'circ':
      return `(${node.label})`;
    case 'roundrect':
      return `[{${node.label}}]`;
    case 'diamond':
      return `{{${node.label}}}`;
    default:
      return `[${node.label}]`;
  }
}

Generate arrow shape

function getArrowTypeSyntax(edge) {
  switch (edge.type) {
    case 'arrow':
      return '-->';
    case 'dashed':
      return '-.->';
    case 'thick':
      return '==>';
    default:
      return '-->';
  }
}

Full code to generate mermaidJS markdown in javascript

function generateMermaidSyntax() {
  const nodes = [
    { id: 'A', shape: 'roundrect', label: 'Node A' },
    { id: 'B', shape: 'diamond', label: 'Node B' },
    { id: 'C', shape: 'circ', label: 'Node C' },
    { id: 'D', shape: 'rect', label: 'Node D' },
  ];

  const edges = [
    { from: 'A', to: 'B', type: 'arrow' },
    { from: 'B', to: 'C', type: 'dashed' },
    { from: 'C', to: 'D', type: 'thick' },
  ];

  let mermaidSyntax = 'graph LR\n';

  nodes.forEach(node => {
    const nodeSyntax = getNodeShapeSyntax(node);
    mermaidSyntax += `${node.id}${nodeSyntax}\n`;
  });

  edges.forEach(edge => {
    const arrowSyntax = getArrowTypeSyntax(edge);
    mermaidSyntax += `${edge.from}${arrowSyntax}${edge.to}\n`;
  });

  return mermaidSyntax;
}