Featured image of post Trying out mermaid.js

Trying out mermaid.js

What is mermaid.js?

mermaid.js is a JavaScript library that allows you to graphically display complex charts and diagrams, such as flowcharts, diagrams, and Gantt charts, using its own text-based syntax (Mermaid syntax). It is also adopted by various services like GitHub, Qiita, and Notion. This time, we will make mermaid.js usable in hugo.

Making mermaid.js usable in hugo

The procedure is as follows:

  1. Add the following to layouts/partials/extend_footer.html.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
{{ if or .Params.mermaid .Site.Params.mermaid }}
<script src="https://cdn.jsdelivr.net/npm/mermaid@10.3.0/dist/mermaid.min.js"></script>
{{- $loadmermaid := resources.Get "js/load-mermaid.js" }}
<script src="{{ $loadmermaid.RelPermalink }}"></script>
<script>
    window.initMermaid();
    if (isDarkTheme()) {
        setPrefTheme('dark');
    } else {
        setPrefTheme('light');
    }
</script>
{{ end }}
  • mermaid.min.js is loaded only when mermaid: true is set via the if statement. This library is about 3MB and unexpectedly large.
  1. Create assets/js/load-mermaid.js. This process is used for initialization and to redraw when the theme is dynamically switched.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
(function(window){
'use strict'

  const elementCode = '.mermaid'
  const loadMermaid = function(theme) {
    window.mermaid.initialize({theme})
    window.mermaid.init({theme}, document.querySelectorAll(elementCode))
  }
  const saveOriginalData = function(){
    return new Promise((resolve, reject) => {
      try {
        var els = document.querySelectorAll(elementCode),
            count = els.length;
        els.forEach(element => {
          element.setAttribute('data-original-code', element.innerHTML)
          count--
          if(count == 0){
            resolve()
          }
        });
      } catch (error) {
       reject(error) 
      }
    })
  }
  const resetProcessed = function(){
    return new Promise((resolve, reject) => {
      try {
        var els = document.querySelectorAll(elementCode),
            count = els.length;
        els.forEach(element => {
          if(element.getAttribute('data-original-code') != null){
            element.removeAttribute('data-processed')
            element.innerHTML = element.getAttribute('data-original-code')
          }
          count--
          if(count == 0){
            resolve()
          }
        });
      } catch (error) {
       reject(error) 
      }
    })
  } 

  const init = ()=>{
    saveOriginalData()
    .catch( console.error )
    document.body.addEventListener('dark-theme-set', ()=>{
      resetProcessed()
      .then(loadMermaid('dark'))
      .catch(console.error)
    })
    document.body.addEventListener('light-theme-set', ()=>{
      resetProcessed()
      .then(loadMermaid('default'))
      .catch(console.error)
    })
  }
  window.initMermaid = init
})(window);

The base code was referenced from below:

  1. Modify the theme switching process in header.html
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
function switchTheme(theme) {
  switch (theme) {
    case 'light':
{{ if or .Params.mermaid .Site.Params.mermaid }}
      document.body.dispatchEvent(new CustomEvent('light-theme-set'));
{{ end }}
      document.body.classList.remove('dark');
      break;
    case 'dark':
{{ if or .Params.mermaid .Site.Params.mermaid }}
      document.body.dispatchEvent(new CustomEvent('dark-theme-set'));
{{ end }}
      document.body.classList.add('dark');
      break;
    // auto
    default:
      if (window.matchMedia('(prefers-color-scheme: dark)').matches) {
{{ if or .Params.mermaid .Site.Params.mermaid }}
        document.body.dispatchEvent(new CustomEvent('dark-theme-set'));
{{ end }}
        document.body.classList.add('dark');
      }
  }
}
  1. Create layouts/shortcodes/mermaid.html
1
2
3
<div class="mermaid" align="{{ if .Get "align" }}{{ .Get "align" }}{{ else }}center{{ end }}">
  {{ safeHTML .Inner }}
</div>

The preparation to use mermaid.js is now complete.

Trying out mermaid.js

  1. Add the following to the article’s front matter
1
mermaid: true
  1. Add the following to the article body

Flowchart

1
2
3
4
5
6
{{<mermaid align="center">}}
graph TD
    A[Start] -->|Condition 1| B(Condition 2)
    B --> C{Condition 3}
    C -->|Condition 4| D[End]
{{</mermaid>}}

Output Result

graph TD A[Start] -->|Condition 1| B(Condition 2) B --> C{Condition 3} C -->|Condition 4| D[End]

Gantt Chart

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
{{<mermaid align="center">}}
gantt
    section Project
    Requirement Definition :done,      a, 2024-05-25, 5d
    Basic Design :done,      b, after a,    5d
    Detailed Design :done,      c, after b,    5d
    Manufacturing    :active,    d, after c,    10d
    Unit Testing :crit,      e, after d,    5d
    Integration Testing :           f, after e,    5d
    System Testing :           g, after f,    5d
    Release :milestone, h, after g,    1d
{{</mermaid>}}

Output Result

gantt section Project Requirement Definition :done, a, 2024-05-25, 5d Basic Design :done, b, after a, 5d Detailed Design :done, c, after b, 5d Manufacturing :active, d, after c, 10d Unit Testing :crit, e, after d, 5d Integration Testing : f, after e, 5d System Testing : g, after f, 5d Release :milestone, h, after g, 1d

Sequence Diagram

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
{{<mermaid align="center">}}
sequenceDiagram
    participant user
    participant view
    participant controller
    participant model
    participant database
    user->>view: ID/PW Input
    view->>controller: Authentication Request
    controller->>model: Authentication Request
    model->>database: Authentication Request
    database-->>model: Return Authentication Result
    model-->>controller: Return Authentication Result
    controller-->>view: Return Authentication Result
    view-->>user: Display Authentication Result
{{</mermaid>}}

Output Result

sequenceDiagram participant user participant view participant controller participant model participant database user->>view: ID/PW Input view->>controller: ajax query controller->>model: Authentication Request model->>database: Issue SQL database-->>model: Return SQL Result model-->>controller: Return Authentication Request Result controller-->>view: Return ajax query result view-->>user: Display Authentication Result

That is all.

References

comments powered by Disqus