【Angular】Mermaidで図を描画する

 今回はブラウザで Mermaid 形式でテキストを記入して、図を描画する方法を解説していきます。特につながりはないのですが、前回のソースを使いまわしています。

 完成しているコードは下記にあります。

Angular-sample/markdown at main · tsuneken5/Angular-sample
Contribute to tsuneken5/Angular-sample development by creating an account on GitHub.

環境

  • node: 18.20.0
  • Angular CLI:17.0.0
  • Mermaid:11.3.0

パッケージのインストール

$ npm install mermaid

 ライブラリは Mermaid を使用します。

GitHub - mermaid-js/mermaid: Generation of diagrams like flowcharts or sequence diagrams from text in a similar manner as markdown
Generation of diagrams like flowcharts or sequence diagrams from text in a similar manner as markdown - mermaid-js/merma...
/* To learn more about this file see: https://angular.io/config/tsconfig. */
{
  "compileOnSave": false,
  "compilerOptions": {
    "outDir": "./dist/out-tsc",
    "forceConsistentCasingInFileNames": true,
    "strict": true,
    "noImplicitOverride": true,
    "noPropertyAccessFromIndexSignature": true,
    "noImplicitReturns": true,
    "noFallthroughCasesInSwitch": true,
    "esModuleInterop": true,
    "sourceMap": true,
    "declaration": false,
    "downlevelIteration": true,
    "experimentalDecorators": true,
    "moduleResolution": "node",
    "importHelpers": true,
    "target": "ES2022",
    "module": "ES2022",
    "useDefineForClassFields": false,
    "skipLibCheck": true,
    "lib": [
      "ES2022",
      "dom"
    ]
  },
  "angularCompilerOptions": {
    "enableI18nLegacyMessageIdFormat": false,
    "strictInjectionParameters": true,
    "strictInputAccessModifiers": true,
    "strictTemplates": true
  }
}

 このまま Mermaid を使用すると TypeScript の型チェックでエラーが出るので、 tsconfig.json で "skipLibCheck": true を設定して *.d.ts ファイルに対する型チェックをスキップするようにします。

コンポーネントの生成

$ ng generate component mermaid
import { Component } from '@angular/core';
import { DomSanitizer, SafeHtml } from '@angular/platform-browser';

import { InputComponent } from '../../share/input/input.component';
import { OutputComponent } from '../../share/output/output.component';

import mermaid from 'mermaid';

@Component({
  selector: 'app-mermaid',
  standalone: true,
  imports: [InputComponent, OutputComponent],
  templateUrl: './mermaid.component.html',
  styleUrl: './mermaid.component.css'
})
export class MermaidComponent {
  public safeHTML!: SafeHtml;

  constructor(
    private sanitizer: DomSanitizer
  ) {
    mermaid.initialize({ startOnLoad: false });
  }

  public async onParse(message: any) {
    const content = '<div class="mermaid">' + message + '</div>';
    this.safeHTML = this.sanitizer.bypassSecurityTrustHtml(content);

    setTimeout(async () => {
      await mermaid.run({
        querySelector: '.mermaid',
      });
    }, 0);
  }
}

 基本的には HTMLで <div class="mermaid"> {{ content }}</div> を準備しておいて、TypeScriptから content に Mermaid 形式でテキストを代入してやればいいのですが、 MathJax のときと同じく出力の方法を変えたくなかったので別の方法を採っています。

22行目

 startOnLoad: true の場合は、HTMLが読み込み終わった時点で自動で変換処理が実行されます。 今回は startOnLoad: false とすることで、任意のタイミングで変換処理を実行するようにします。

26行目

 startOnLoad: true の場合はMermaid形式のテキストを <div class="mermaid"></div> の要素を記載すれば class="mermaid" の要素を対象に自動で変換してくれます。

29~30行目

 DOMの更新を待ってから、 mermaid.run() で手動で変換処理を実行します。引数に対象となるDOMを指定できます。

確認

graph LR
      A["$$x^2$$"] -->|"$$\sqrt{x+3}$$"| B("$$\frac{1}{2}$$")
      A -->|"$$\overbrace{a+b+c}^{\text{note}}$$"| C("$$\pi r^2$$")
      B --> D("$$x = \begin{cases} a &\text{if } b \\ c &\text{if } d \end{cases}$$")
      C --> E("$$x(t)=c_1\begin{bmatrix}-\cos{t}+\sin{t}\\ 2\cos{t} \end{bmatrix}e^{2t}$$")

注意点

 <div class=”mermaid”></div> の要素に余計なものを書くとシンタックスエラーになります。例えば下記のような入力をするとエラーになります。

# Mermaid
graph LR
      A["$$x^2$$"] -->|"$$\sqrt{x+3}$$"| B("$$\frac{1}{2}$$")
      A -->|"$$\overbrace{a+b+c}^{\text{note}}$$"| C("$$\pi r^2$$")
      B --> D("$$x = \begin{cases} a &\text{if } b \\ c &\text{if } d \end{cases}$$")
      C --> E("$$x(t)=c_1\begin{bmatrix}-\cos{t}+\sin{t}\\ 2\cos{t} \end{bmatrix}e^{2t}$$")

コメント

タイトルとURLをコピーしました