Markdownテキストでシーケンス図とフローチャートを描く

つい先日、とあるシステムの処理の流れと一部処理のフローチャートを付けた見積り資料を書くことになり、ちょうど良い機会だったので、MarkdownでUML図表が描ける「StackEdit」を使って、オールMarkdownで資料を作成してみた。

いやぁ、打ち込んだテキストがリアルタイムに図表化されていく様は、とても新鮮で、そしてすごく面白かった。資料が出来上がった後の達成感というか、完成した図表を見た時の感動が結構はんぱない。技術系の資料作成でこんな良い体験ができたのは初めてかもしれんな…(笑)

──と、結構感動的な体験ができるMarkdownでのUML図表作成なんだが、せっかくなのでそれの書き方を含めてもう少し突っ込んだTIPSとしてまとめておこうかと思った次第。

## Markdown+UML とは？

とりあえず、「Markdown+UML」というのは私の造語だ。まぁ、正確に言うなら「UML diagrams add on Markdown」とか、「Markdown extension of UML diagrams」になるのかな。特にUML関連のMarkdown拡張には呼称がないし、長いので略して「Markdown+UML」という訳だ。便宜的にこの記事ではこの呼称を使わせてもらう。

では「Markdown+UML」の中身なんだが、端的に云えば、Markdown的な簡単なテキスト記法でシーケンス図やフローチャートといったUML図形（ダイアグラム）を描画してしまう仕組みのことだ。作成される図表ごとに独立したライブラリが提供されているので、いわゆる一般的なMarkdown仕様の範疇に入るものではなく、ライブラリ作成者の独自拡張仕様と云える。
実際、Markdownエディッタ「StackEdit」でもそれらの拡張ライブラリはサードパーティ・アドオン的に提供しているだけで、詳しい仕様の説明などはライブラリ配布元に依存している[^1]。
[^1]: そういう類のアドオンにはUML以外に数式生成用ライブラリ「[MathJax](http://www.mathjax.org/)」がある。

この記事では「StackEdit」に取り込まれている、

1. シーケンス図作成用Markdownライブラリ「**js-sequence-diagrams**」
2. フローチャート作成用Markdownライブラリ「**flowchart.js**」

──の二つのUML図形ライブラリを取り上げていく。

どちらのライブラリもWEB上にベクターグラフィックをSVGやVMLで描画できるJavaScriptライブラリ「**[Raphaël（ラファエル）](http://raphaeljs.com/)**」を利用した拡張ライブラリで、特定のMarkdownテキストをUML図形に変換してSVG画像としてのsvgタグをレンダリングする仕様になっている。そのため、「Raphaël」をインポートしたWEBページであれば、両方とも個人でも利用できるようになる。
興味がある人は、下記URLから導入方法が参照できるのでどうぞ。

> *js-sequence-diagrams*:
> http://bramp.github.io/js-sequence-diagrams/
>
> *flowchart.js*:
> http://adrai.github.io/flowchart.js/

では、早速それぞれのライブラリでのUML図形作成方法を見ていこう。

## 「js-sequence-diagrams」でシーケンス図を作る

まず、シーケンス図を作る場合、Markdownでのコードブロック記法に`sequence`という識別子を付ける。つまりは <code>```sequence ～ &#096;&#096;&#096;</code> というコードブロックに書かれたMarkdownテキストがシーケンス図に変換されるわけだ。
基本的な書き方として、左側から右側へのシーケンス軸順にドロップダウン型で記述していくことになる。各コンポーネントの記法は以下の通りだ。

- `Title: タイトル名`でタイトルブロックを表示できる。
- 各シーケンス軸間に矢印がある場合はそれぞれの軸名を`->`で結び、矢印の終端となる軸名の後に`: `を付ける（`:`の後に半角空白が必要）。
- 軸間矢印にテキストを乗せたい場合は、終端軸名末尾の`: `の後にテキストを記載する。
- 矢印は、`->`が実線で`-->`が破線となる。`->>`や`-->>`は矢印終端の形が変わる。
- 矢印がないシーケンス軸のみを書きたい場合は`participant 軸名`のように書く。
- 吹き出し的な注意文ブロックは`note left of 軸名: 注意文`や`note right of 軸名: 注意文`とすることで、シーケンス軸の左右に注意文が表示できる。軸上にかぶる様に注意文を表示する場合は`note over 軸名: 注意文`となる。
- 軸名や矢印テキスト、注意文などを改行したい場合は`\n`を使う。

文字の説明だとイマイチ直感的にわからないので、下記のサンプルを見てもらいたい。
また、Markdownから変換されたUML図形のSVG画像はQiitaにSVG形式ファイルがアップロードできないので、私のブログサイトにアップした画像を参照している。

##### **シーケンス図の例1**

<pre>
```sequence
WEBサーバ->DBサーバ: データ挿入
Note right of DBサーバ: DataBaseには\nユーザデータが\n格納される
DBサーバ-->WEBサーバ: データ参照
WEBサーバ->>DBサーバ: データ更新
&#096;&#096;&#096;
</pre>

![シーケンス図の例1](http://ka2.org/assets/files/sequence_example1.svg)

##### **シーケンス図の例2**

<pre>
```sequence
Title: アプリケーションサービス・シーケンス
ユーザー->クライアントアプリ: アプリ起動
クライアントアプリ-->OAUTH認証先: ログイン
OAUTH認証先->>WEBアプリケーション: 認証OK
WEBアプリケーション->WEBアプリケーション: データベース\nとのやり取り等\n各種処理
WEBアプリケーション-->>ユーザー: ログイン認証完了・セッション開始
​&#096;&#096;&#096;
</pre>

![シーケンス図の例2](http://ka2.org/assets/files/sequence_example2.svg)

##### **シーケンス図の例3**

<pre>
```sequence
Note right of 時間軸: 未来形
Note left of 時間軸: 過去形
Note over 時間軸: 現在進行形
&#096;&#096;&#096;
</pre>

![シーケンス図の例3](http://ka2.org/assets/files/sequence_example3.svg)

> 「js-sequence-diagrams」は「[web sequence diagrams](https://www.websequencediagrams.com/)」というWEBサービスにインスパイアされて作成しているとサイトに書いてあったので、上記で紹介しているもの以外にも使える機能がないか試してみたところ、現状の「js-sequence-diagrams」ではこの記事で紹介した機能しか使えなかった。
> web sequence diagrams のシーケンス図作成では結構色んな表現ができるので、今後もっと機能を取り込んでくれることを期待していようっと。

## 「flowchart.js」でフローチャートを作る

まず、フローチャートを作る場合、Markdownでのコードブロック記法に`flow`という識別子を付ける。つまりは <code>```flow ～ &#096;&#096;&#096;</code> というコードブロックに書かれたMarkdownテキストがフローチャートに変換されるわけだ。
基本的な書き方として、各工程（処理）の部品を定義して、その後に矢印で各部品を連結していくという書式になる。工程連結は条件分岐となる判断（コンディション）までを一つの連結式として、判断後の分岐工程から連結式を再開させるような記法だ。
現状で使える部品は「端子（フローの始点と終点を表す丸角型コンポーネント）」と「処理（具体的な処理を表現する長方形コンポーネント）」と「入出力（データの入出力を表す平行四辺形コンポーネント）」、「判断（条件分岐を表すひし形コンポーネント）」、「定義済み処理（サブルーチンなどの処理を表す左右辺が二重線になった長方形コンポーネント）」の5種類のみ。
各コンポーネントの記法は次の通り。

- 始点端子は`部品名エイリアス=>start: 表示名`、終点端子は`部品名エイリアス=>end: 表示名`と定義する。
- 処理部品は`部品名エイリアス=>operation: 部品内テキスト`と定義する。
- 判断部品は`部品名エイリアス=>condition: 部品内テキスト`と定義する。
- 定義済み処理部品は`部品名エイリアス=>subroutine: 部品内テキスト`と定義する。
- 入出力部品は`部品名エイリアス=>inputoutput: 部品内テキスト`と定義する。
- 各部品内テキストを改行したい場合はそのまま改行して複数行で定義する（シーケンス図と違って行単位での定義ではなく、`\n`は使えないので注意）。
- 端子の表示名や各部品の部品内テキストにリンクを指定する場合は、テキストの末尾に`:>http://～`のようにURLを追加する。URLの後に`[blank]`のようにtarget属性も付与できます。
- 各端子や各部品のブロックに対して任意のclass属性（HTMLソースに対しての指定）を付けたい場合は、テキストの末尾に'|クラス名'を付ける。もしそのテキストにリンクも指定したい場合は、`テキスト|クラス名:>URL`のように定義する。クラス名を付与しても特に見た目は変わりませんが、別途CSS等でスタイリングすることで部品に色を付けたりできます。
- 部品の連結は`->`で部品名エイリアスを繋いでいく。部品名エイリアスの後に`(right)`か`(left)`を付けると連結する矢印の伸び先方向を指定できます。
- 判断部品のみ部品名エイリアスの後に`(yes)`か`(no)`を付けることができ、それらが条件分岐の真偽判定後の連結ルートの起点となります。真偽判定後のルートの伸び先を指定する場合は、`(yes, right)`のように方向をあわせて指定します。

文字の説明だとイマイチ直感的にわからないので、下記のサンプルを見てもらいたい。
また、Markdownから変換されたUML図形のSVG画像はQiitaにSVG形式ファイルがアップロードできないので、私のブログサイトにアップした画像を参照している（そのためなのか、フローチャート中の連結線の終端の鏃部分の記号が欠落してしまっている…）。

##### **フローチャートの例1**

<pre>
```flow
st=>start: 処理開始
e=>end: 処理終了
io1=>inputoutput: データ入力
cond=>condition: 入力値が空
でない？
io2=>inputoutput: エラー出力
（※1）:>#footnote
sub1=>subroutine: 入力値の検証
（※2）:>http://www.google.com[blank]
op1=>operation: セッション開始

st->io1->cond
cond(yes)->sub1->op1->e
cond(no)->io2(right)->io1
​&#096;&#096;&#096;
</pre>

![フローチャートの例1](http://ka2.org/assets/files/flow_example1.svg)

> 脚注やページ内リンクに対応しているMarkdownなら、`※1 エラーの説明など... {#footnote}` のような注釈を準備しておくことで、`:>#footnote`のようなリンク指定でページ内リンクが可能。
> ※ 上記例でリンクが動作しないのは、この記事では本来のSVGタグではなく、SVG形式ファイルをIMGタグで呼び出しているため、SVGタグ内のJavaScriptが無効化されているためだ。

##### **フローチャートの例2**

<pre>
```flow
st=>start:  |flow-terminal
e=>end:  |flow-terminal
op1=>operation: 入力値の
サニタイズ|flow-ope1
op2=>operation: データベース
の値を更新|flow-ope2
sub1=>subroutine: エラー処理|flow-err
cond=>condition: 不正な入力値
がないか？|flow-cond1
c2=>condition: 入力値のnが
1であるか？|flow-cond2
io=>inputoutput: ログファイルに
入力値を追記|flow-io

st->op1(right)->cond
cond(yes, right)->c2
cond(no)->sub1(left)->op1
c2(yes)->io->e
c2(no)->op2->e
​&#096;&#096;&#096;
</pre>

![フローチャートの例2](http://ka2.org/assets/files/flow_example2.svg)


> 端子名や部品内テキストを空にしたい場合は半角空白を指定しておく。

## Markdown+UMLで生成されたUML図形の取り扱い

「js-sequence-diagrams」や「flowchart.js」でレンダリングされたSVG形式のUML図形とその図形を含むHTMLの取り扱いには結構癖がある。特にPDF化が今のところ至難で、図形部分が正常に変換されないという問題があるのだ。
「StackEdit」でさえもUML図形が複雑になってくると、PDFに出力した時にUML図形部分が壊れることが多くて、まだ実用に耐えれるレベルにはない。
Markdownで整形して、HTMLとしてレンダリングされたWEBページをブラウザの拡張機能やAdobe Acrobatを使ってPDF化しようとしても、SVGタグ部分が画像としてコンバートされずに、埋め込まれたXHTMLとして解釈されてしまうので、SVGタグを画像化する必要がある。
──ということで、SVG形式のUML図形の画像化を試してみた。

HTMLのSVGタグとしてレンダリングされたUML図形のSVGタグ部分のみを抜き出して、SVG形式ファイルを作成し、それをIllustratorに食わせてみた。しかし、シーケンス図は破線のパスが消えてしまい、フローチャートでは線全体が消えてしまうという有様だった。Illustratorで線形パスのアピアランスを修正すれば使えそうな画像になりそうな気もするが、そんな面倒な作業をしてられないので、あきらめた（笑）

今のところはブラウザに表示されたSVG画像をスクリーンショット取ってjpegとかpngとかに切り出してから、静的な画像を別途HTMLに埋め込んでからPDF化をせざるを得ないのかなぁ…。

最後に、Markdown+UMLで生成されたUML図形のSVG形式ファイル化の手順を書いておこう。
Markdown+UMLがお手軽に使えるのが「StackEdit」ぐらいしか知らないので、UML図形の生成は「StackEdit」利用を前提としている。

1. まず、「StackEdit」でUML図形を作成したら、左サイドメニュー内の「Export to disk」から「As HTML」を選んでHTMLをローカルにダウンロードする。
2. ダウンロードしたHTMLを開くと、UML図形のシーケンス図は`<div class="sequence-diagram">～</div>`に、フローチャートは`<div class="flow-chart">～</div>`にそれぞれラッピングされているので、SVG形式ファイル化したいUML図形の`<div>`内の`<svg>`タグをすべてコピーする。
3. テキスト文書ファイルを新しく作成して、その中にコピーした`<svg>`タグをペーストしたら、その`<svg>`タグの前に下記のXMLヘッダを追加する。

```:XMLヘッダ
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
```

あとは、そのテキストファイルを文字コード「UTF-8」で拡張子「.svg」にて保存すればSVG形式画像ファイルの完成だ。Qiitaのこの記事が参照しているUML図形もすべてそうやって作った次第。


うまいことPDF化できるようになると、Markdownで作ったシステム設計書を配布しやすくなるんだがなぁ…。