12k
All articles

Mermaidでダイアグラムのレイアウトを制御する方法

Mermaid 12の図のレイアウトをELKまたはdagreで制御。全体・図ごとの設定やELKの調整方法、更新前の表示に戻す手順を解説します。

OpenReplay Team
OpenReplay Team
Mermaidでダイアグラムのレイアウトを制御する方法

Mermaid 12では、layout 設定キーでレイアウトエンジンを指定します。ほとんどのグラフ系ダイアグラムではELKがデフォルトです。以前のエンジンに戻すには、フロントマターまたは mermaid.initialize() で layout: dagre を設定します。

アップグレード後にドキュメントサイトを再ビルドしたところ、誰も手を加えていないフローチャートの形や色が変わっていた、ということがあるかもしれません。古い回答で紹介されている flowchart: { defaultRenderer: ... } のような、ダイアグラム種別ごとの設定セクションでは解決できません。

本記事では、何が変わったのか、レイアウトをどこで設定するのか、どの設定が優先されるのか、ELKをどうチューニングするのか、そして元に戻したはずなのに何も変わらないように見えるのはなぜかを解説します。フローチャートの基本については、ワークフローのためのフローチャート作成を参照してください。

重要なポイント

  • Mermaid 12.0.0以降、レイアウトを指定していないフローチャート、状態図、クラス図、ER図、要求図、ユースケース図、agentflowダイアグラムは、dagreではなくELKで配置されます。
  • layout: dagre で戻るのは配置だけで、見た目は元に戻りません。12より前の描画を完全に再現するには、layout: dagre、theme: default、look: classic の3つが必要です。
  • ダイアグラムごとのフロントマターやディレクティブは mermaid.initialize() より優先されます。そのため、独自にレイアウトを指定しているダイアグラムには、サイト全体のdagre設定が効きません。
  • Mermaid 12で、flowchart、class、stateの各設定セクションから defaultRenderer が削除されました。代わりにトップレベルの layout キーを使用してください。
  • tinyビルドにはELKが含まれていません。@mermaid-js/layout-elk を追加しない限り、dagreにフォールバックします。

Mermaid 12で何が変わったのか

Mermaid 12からは、レイアウトを指定していないダイアグラムがdagreではなくELKで配置されます。つまり、ダイアグラムを一切変更していなくても、アップグレード後に形が変わることがあります。Layouts設定ページには、新たにELKがデフォルトになった7種類のダイアグラムが記載されています。フローチャート、状態図、クラス図、ER図、要求図、ユースケース図、agentflowです。ELKはメインパッケージに同梱され、自動的に登録されます。なお、マインドマップは引き続きcose-bilkentがデフォルトです。tidy-treeは別パッケージの @mermaid-js/layout-tidy-tree から提供されます。

mermaid@12.0.0のリリースノートには、もう1つの変更点も記載されています。テーマ設定ページのダイアグラムごとのデフォルトに挙げられた、より広範なダイアグラム種別で、デフォルトのテーマがredux-colorに、デフォルトのルック(look)がneoに変わりました。したがって、v12のダイアグラムの見た目が変わる原因は2つあります。レイアウトエンジンの変更と、テーマおよびルックの変更です。

レイアウトはどこで設定するのか:フロントマター、initialize()、種別ごとの設定

Mermaidのレイアウトは、1つのダイアグラム単位でも、サイト内の全ダイアグラムに対しても設定できます。テーマとルックは、特定のダイアグラム種別だけに適用することも可能です。設定が競合した場合は、最も限定的な設定が優先されます。

スコープ設定場所構文優先される対象
1つのダイアグラムフロントマターまたはディレクティブconfig: layout: dagre以下のすべて
すべてのダイアグラムmermaid.initialize() のトップレベル{ layout: 'dagre' }種別のデフォルトとグローバルデフォルト
1つのダイアグラム種別組み込みの種別デフォルト(Mermaidが設定)グローバルデフォルト
すべてグローバルデフォルト(Mermaidが設定)なし

12.0.0のリリースノートでは、解決順序は次のとおりとされています。まずフロントマターまたはディレクティブ、次に initialize()、次にダイアグラム種別のデフォルト、最後にグローバルデフォルトです。

1つのダイアグラムを完全に元に戻すには、次のように記述します。

---
config:
  layout: dagre
  theme: default
  look: classic
---
flowchart LR
  Request --> Auth{Valid token?}
  Auth -->|yes| Handler
  Auth -->|no| Reject

サイト全体に適用する場合、以下の1つ目の呼び出しはエンジンだけを変更するため、新しい配色はそのまま残ります。2つ目の呼び出しでは、12より前の描画全体が復元されます。

mermaid.initialize({ layout: 'dagre' });

mermaid.initialize({ layout: 'dagre', theme: 'default', look: 'classic' });

Mermaid 12では、theme、look、layout を各ダイアグラム種別の設定セクション内に記述して、その種別だけに適用することもできます。同じ場所で設定した場合、種別に限定した値がグローバルな値より優先されます。たとえば、すべてのダイアグラムをdagreに切り替えつつ、クラス図だけ以前の見た目に戻したいとします。この場合は、クラス図のページに示されているように、layout をトップレベルに置き、theme と look を class セクションに記述します。

mermaid.initialize({
  layout: 'dagre',
  class: { theme: 'default', look: 'classic' },
});

フロントマターは常に mermaid.initialize() より優先されます。たとえば、サイト全体で layout: 'dagre' を設定していても、あるダイアグラムがフロントマターで layout: elk を宣言していれば、そのダイアグラムはELKで描画されます。

MermaidのELKレイアウトが有効なのはどんなときか、どうチューニングするか

大規模なダイアグラムや要素が密集したダイアグラムにはELKを使いましょう。小さなダイアグラムで見た目に問題がなければ、dagreのままで構いません。Mermaidのドキュメントでは、ELKは大規模で複雑なグラフ向けとして紹介されています。一方、dagreも従来からある階層型レイアウトとして引き続き利用できます。アップグレード前にダイアグラムがきれいに描画されていたなら、dagreに戻すのは妥当な選択です。

構文リファレンスのレイアウトセクションには、ELKのチューニング用キーがいくつか記載されています。主なものは次のとおりです。mergeEdges は並行するエッジを統合します。nodePlacementStrategy には SIMPLE、NETWORK_SIMPLEX、LINEAR_SEGMENTS、BRANDES_KOEPF のいずれかを指定でき、default プリセットでは BRANDES_KOEPF がデフォルトです。nodePlacementAlignment はBrandes-Koepfのアライメント(BALANCED や NONE など)を設定します。省略した場合、アライメントはプリセットに従います。

---
config:
  layout: elk
  elk:
    mergeEdges: true
    nodePlacementStrategy: NETWORK_SIMPLEX
---
flowchart TD
  Build --> Test --> Deploy
  Build --> Lint --> Deploy

v12より前からELKを使っていたダイアグラムも、描画結果が変わる可能性があります。バランス型のBrandes-Koepf配置が新たにデフォルトになったためです。ELKプリセットのスキーマには、preset の値として legacy、default、modelOrder、depthFirst の4つが記載されています。depthFirst は以前のデフォルトで、legacy はプリセット導入前のELKの描画を再現するものと説明されています。

ELKの出力は12.xの中でも変更されています。

  • Mermaid 12.1.0では orientFeedbackEdges が追加され、デフォルトで有効になっています。サブグラフの出力先ノードからそのサブグラフへ戻るエッジは、サブグラフを迂回せず、下流方向にルーティングされるようになりました。
  • Mermaid 12.2.0では、エッジの端点を直線化するとラベルが別のエッジに重なる場合に、ELKが直線化を行わないようになりました。
config:
  layout: elk
  elk:
    preset: legacy
    orientFeedbackEdges: false

使用できるELKのバリエーションとサブグラフ単位のアルゴリズム

MermaidのLayoutsページには、layout: elk のほかに、layout の値として使えるELKのバリエーションが6つ記載されています。elk.stress、elk.force、elk.mrtree、elk.sporeOverlap、elk.box、elk.rectpacking です。

---
config:
  layout: elk.mrtree
---
flowchart TD
  Root --> API
  Root --> Web
  API --> Workers

12.0.0のリリースノートによると、elk.box と elk.rectpacking はノードの配置のみを行い、エッジのルーティングは行いません。そのため、エッジはノードの中心同士を結ぶ直線として描画されます。

個々のサブグラフでは、@{ algorithm: ... } を使って独自のアルゴリズムを選択できます。同じリリースノートには、指定可能な値として上記の6つのバリエーションに加え、elk.layered と elk.radial が挙げられています。また、このオーバーライドについては2つの注意点が記載されています。サポートされていない値は警告を出したうえで無視されること、そしてエッジがサブグラフの境界をまたぐ場合は継承されたアルゴリズムが代わりに使われることです。

レイアウトの修正が反映されないのはなぜか

元に戻そうとしてうまくいかない場合、ほとんどは次の5つのいずれかが原因です。以下の順にチェックしてください。

  1. defaultRenderer をまだ設定している。 フローチャート構文ページに記載されているとおり、v12でflowchart、class、stateの各セクションから削除されました。代わりに layout を使用してください。
  2. layout: dagre だけを設定している。 redux-colorテーマとneoルックはまだ有効なままです。3つのキーをすべて設定してください。
  3. フロントマターが initialize() の設定を上書きしている。 該当するダイアグラムのフロントマターから layout を削除してください。
  4. レイアウト名のスペルミス、または未登録のレイアウト名を指定している。 リリースノートによると、Mermaidはエラーをスローせず、警告を出してdagreにフォールバックします。コンソールを確認してください。
  5. tinyビルドを使用している。 次のセクションを参照してください。

defaultRenderer からの移行は1行の変更で済みます。

// Before (removed in v12)
mermaid.initialize({ flowchart: { defaultRenderer: 'elk' } });

// After
mermaid.initialize({ layout: 'elk' });

利用しているドキュメントプラットフォームがまだv12に移行していない場合、これらのキーは以前の動作のままの可能性があります。各プラットフォームのドキュメントを確認してください。

tinyビルドでdagreにフォールバックするのはなぜか

Mermaidのtinyビルドには、ELKが含まれていません。そのため、tinyビルドでELKを指定したダイアグラムはdagreで描画されます。このケースに対応するため、@mermaid-js/layout-elk パッケージは引き続き公開されています。登録手順については、使用方法ドキュメントのELK and the tiny buildセクションに従ってください。通常のビルドでは、既存の registerLayoutLoaders の呼び出しは引き続き動作しますが、もはや不要なので削除して構いません。

まとめ

Mermaid 12へのアップグレード後にダイアグラムが変わった場合、原因はほぼ確実に2つです。ELKレイアウトエンジンと、新しいテーマおよびルックです。まずは、何を元に戻したいのかを決めましょう。以前の形だけを戻したい場合は、layout: dagre を設定します。12より前の描画を完全に再現したい場合は、layout: dagre、theme: default、look: classic を設定します。そのうえで、設定内に defaultRenderer が残っていないか、サイト全体の設定を上書きしているフロントマターがないかを確認してください。

よくある質問

Mermaid 12でもflowchart-elkというダイアグラムキーワードは使えますか?

はい、使えます。Mermaid 12.0.0のリリースノートによると、flowchart-elkは明示的なダイアグラムキーワードとして引き続き機能します。変更されたのはdefaultRendererオプションのほうです。Mermaidはこのオプションを拒否せずに無視するため、設定に残っていてもエラーは発生しませんが、効果もありません。flowchartのdefaultRendererに'elk'を指定してELKレイアウトを適用していたダイアグラムは、代わりにlayout: elkを設定してください。

ELKが同梱されたことで、Mermaid 12の読み込みサイズは大きくなりますか?

大きく増えるのはシングルファイルビルドだけです。ESMビルドでは、ELKは別チャンクになっており、ダイアグラムで使用された場合にのみ読み込まれます。12.0.0のリリースノートによると、IIFEビルドであるmermaid.min.jsはELKをインライン化しているため、gzip圧縮後で約500 kB増加します。tinyビルドはELKを含まないためサイズは変わらず、ELKを指定したレイアウトはdagreで処理されます。

ELKのチューニングオプションを、各ダイアグラムのフロントマターではなくサイト全体で設定できますか?

はい、できます。elkはMermaidの設定スキーマにおけるトップレベルのプロパティなので、layoutと並べてmermaid.initialize()に渡せます。たとえば、layout: 'elk'と、mergeEdges: trueおよびnodePlacementStrategy: 'NETWORK_SIMPLEX'を含むelkオブジェクトを指定します。%%{init}%%ディレクティブでも、1つのダイアグラムに対して同じelkオブジェクトを指定できます。なお、個々のダイアグラムのフロントマターは、引き続きサイト全体の値より優先されます。

DevTools for the frontend

Gain Debugging Superpowers

Unleash the power of session replay to reproduce bugs, track slowdowns and uncover frustrations in your app. Get complete visibility into your frontend with OpenReplay — the most advanced open-source session replay tool for developers.

Star on GitHub12k

We use cookies to improve your experience. By using our site, you accept cookies.