Javascriptでシーケンス図を描く

『図を書け図を!』で紹介した、HTMLとSVGでシーケンス図を作成するためのライブラリです。

本格的なUMLのシーケンス図に対応しているわけではありませんが、処理の簡単な流れを記述する程度であれば、それなりに使えます。

作った本人が言うのも何ですが、意外と便利なので自分でも使い方を忘れてしまわない様に、マニュアルを公開します。

2018年に公開した最初のバージョンは、APIの一部に不整合が有り直感的では無かったので、内部処理を全面的に変更しています。インターフェイスは極力互換性をもたせていますが、一部互換性のない箇所もあります。

シーケンス図を描き方について

機能の概要

まずは、簡単な例とそのソースです。

JavaScriptの1行目は、シーケンス図作成マネージャのインスタンスの生成です。引数は、シーケンス図を表示する要素のIDです。ライフラインはこのマネージャで作成します。

2行目から4行目で、マネージャによりライフラインを作成しています。第一引数はライフラインの名前で、ライフライン要素のclassとして設定されます。第ニ引数はライフラインの表示名です。第三引数はUMLを意識したクラス名で、表示名の後ろに:で連結して表示されます。省略した場合は何も表示しません。

必要なHTML

JavaScript ソース

5行目で、2行目で作成したライフラインに、シーケンスの起点となるアクティベーションを作成します。第一引数はアクティベーションの開始位置で、ライフライン上部のタイトル部分(背景が黄色い箱)の底辺からの距離をem単位で指定します。開始位置を省略した場合は、1emとなります。

6行目で、5行目で作成したアクティベーションから、クラスBのインスタンスを作成するメッセージを送信します。第一引数は送信先のライフラインです。第二引数はオプションで、リクエストメッセージとレスポンスメッセージの説明文を指定しています。戻り値は送信先のアクティベーションです。

7行目で、6行目のメッセージの戻り値のアクティベーションから、クラスCに通常の同期メッセージを送信します。第一引数とリクエストメッセージ・レスポンスメッセージは、6行目のcreateと同じです。オプションのmessageOffsetは、呼び出し先アクティベーションの開始位置で、呼び出し元アクティベーションの上端からの距離を、デフォルトとのオフセットでem単位で指定します。開始位置を省略した場合は、0.5emとなります。上記例では、0.5em2emを加算して2.5emとしています。

メッセージの開始位置は、条件によって異なるので、オフセットという形で指定します。

8行目は、処理に関する説明文をアクティベーションに対して追加します。引数は説明文です。

9行目も説明文の追加ですが、説明文を複数行とする場合は、<br>で分割します。

10行目はおまじないです。この中でメッセージのラインを引いたりライフラインの長さを調整します。シーケンス図の記述の最後に、必ず呼び出してください。

機能の詳細

実は、先程の紹介で殆ど全ての機能を網羅しているのですが、少しだけ抜けているので解説します。

一方メッセージ

一方メッセージ

6行目のoneWayが、一方メッセージの作成です。

同期メッセージのアクティベーションの高さ

まずは、デフォルト。

メッセージの説明が長い場合、折り返して表示したい場合があります。

そのような場合は、メッセージの開始位置や、送信先のアクティベーションのサイズを調整する必要があります。

アクティベーションのサイズ調整

6行目の、messageメソッドの第四引数がリクエストメッセージの位置指定のオフセットで、第五引数が送信先アクティベーションのサイズになります。共にem単位で指定します。

上記例では、リクエストメッセージの開始位置を、デフォルトの0.5em4em加算して4.5emとし、送信先アクティベーションのサイズを、デフォルトの2emから5emに変更しています。

メモの表示位置調整

普通にメモを付与すると、以下のようになります。

何らかの理由で、位置を調整したい場合は、オフセットを指定することが出来ます。

メモの表示位置調整

7行目で、「クラスBにメモ」を、デフォルトの0.5em1em加算して、アクティベーションのtopから、1.5emの位置に表示しています。

8行目で、「クラスAにメモ」を、デフォルトの0.5em3em加算して、直前のレスポンスメッセージから、3.5emの位置に表示しています。

複雑な一方メッセージ

イベント制御などで、複雑な一方メッセージによるシーケンス図を描く時に、標準のままでは不都合な場合があります。

まずは、下記シーケンスを見てください。

デフォルトの一方指示で、複雑な一方メッセージ

デフォルトでは、一方メッセージも同期メッセージと同じように、呼び出し先のアクティベーションのサイズに合わせて、呼び出し元のアクティベーションのサイズを変更します。

このため、本来は分離させたいクラスBのアクティベーションが、くっついた状態になってしまいます。

そこで、呼び出し元のアクティベーションを変更しない指示で、一方メッセージを表示します。

再描画しない指示で、複雑な一方メッセージ

8行目と9行目が、呼び出し元のアクティベーションを変更しない一方メッセージです。

8行目では、送信先アクティベーションのサイズを、第四引数で3emに変更しています。第三引数には、デフォルトのままである0を指定します。

9行目では、デフォルトより2.5em下から、一方メッセージを出力しています。

並列動作

一つのオブジェクトに対し、同時に複数のスレッド(プロセス)がアクセスすることがあります。

これをシーケンス図にすると、一つのライフラインに対し、同時に複数のアクティベーションが生成されることを意味します。

同じ位置にアクティベーションが表示されるとわかりにくいので、アクティベーションの幅分ずらして表示させます。

ずらす方向は、右向き(-->)のメッセージでは通常の左側、左向き(<--)のメッセージでは通常の右側となります。

並列動作を表現するシーケンス

現時点の最下位置の取得

一つのライフラインを起点として、全てのシーケンスが完結するのであれば特に問題ありませんが、複数のライフラインからメッセージが送信されるようなシーケンスでは、2つめ(とそれ以降)のライフラインに作成するアクティベーションの位置を調整したい場合があります。

アクティベーションの作成は、絶対位置で開始位置を指定するので、相対指定はできません。

デフォルトでは、その時点で表示中のアクティベーションのうち、最も下にある下辺の1.5em下から新しいアクティベーションを開始します。

次の例では、アクティベーションの開始を、最も下にある下辺の0.5em上からとしています。

現時点の最下位置からメッセージを投げる

3行目sdManager.bottomが、その時点で表示中のアクティベーションのうち、最も下にある下辺の位置となります。

sdManager.bottom - 0.5で、最も下にある下辺の0.5em上ということになります。

但し、sdManager.bottomの内容は絶対に更新しないでください。更新した場合、それ以降のシーケンスが正しく表示されません。

シーケンス図をカスタマイズする

シーケンス図の表示内容は、基本的に全てCSSで指定されているので、これを上書きすることで変更することが出来ます。

クラスAのライフラインには'lifeA'を、クラスBのライフラインには'lifeB'を、クラスCのライフラインには'lifeC'を、それぞれの名前としています。

シーケンス図を表示する起点となっている要素のIDは、seq07です。

カスタマイズ用のCSS

シーケンス図のカスタマイズで、他の図に影響を与えたくない場合は、CSSのセレクタを起点となる要素のIDから始めるようにします。この例では、#seq07です。

1行目は、このシーケンス図にある全てのライフラインのタイトル部分を選択します。背景色を水色に変更しています。

4行目は、このシーケンス図にある全てのアクティベーションを選択します。背景色を灰色に変更しています。

7行目は、このシーケンス図にあるlifeBというクラス名のライフラインの、全てのメモを選択します。前景色を赤色に変更しています。

10行目は、このシーケンス図にあるlifeCというクラス名のライフラインの、左マージンを6emとしています。メッセージ名が長いなど、ライフラインとライフラインの間隔を開けたい場合などは、このように指定します。デフォルトは2emです。

13行目と16行目は、メッセージのタイトルを選択しています。メッセージのタイトルやメモには、それぞれユニークなIDが自動的に付与されるので、それを利用することで個別にスタイルを変更できます。

命名規則は、以下のとおりです。

(a)_(b)_active(c)_(d)_(e)

  (a) 起点となる要素のID。new SDManager('xxxx')で渡している、'xxxx'
  (b) ライフラインの名前
  (c) ライフライン上の、アクティベーションの番号。01から始まる連番
  (d) アクティベーション上のメッセージの番号。1から始まる連番
  (e) リクエストメッセージ:reqMsg
      レスポンスメッセージ:resMsg
      メモ:memo

16行目で、(d)が3となっているのは、メモもメッセージと同様に管理されているためです。1つめのメッセージが1、メモが2、2つ目のメッセージが3となります。

注意点

フォントサイズ

シーケンス図が影響を受ける範囲のフォントサイズを変更する場合、起点となる要素かその先祖に指定してください。起点となる要素の子孫に指定すると、表示が崩れます。

センタリング

絶対配置で要素を配置している関係上、正確にセンタリングを行うことは出来ません。

また、CSSのdisplay: flex;margin: auto;等でセンタリング指示を行うと、表示が崩れます。

しかし、図をセンタに表示したいという要望は多いと思われるので、いくつかの解決策を紹介します。

パディングを指定する

起点となる要素の左側のパディングを、図がセンタリングされているように見える程度に設定します。

パディングでセンタリングさせるCSS
パディングでシーケンス図をセンタリング

上記のシーケンス図のように、左右対称ではないケースでは、数字だけで正確にセンタリングするよりも、人の目でセンタリングされているように見える位置に調整したほうが、心地よく見えることもあります。

但し、幅が固定ではないコンテンツでは、意味がありません。

レンダリング後にdisplay: flex;を設定する

CSSのセンタリング指示で表示が崩れるのは、SVGのレンダリング前にセンタリングの指示がHTML要素にのみ反映されるせいだと思われるので、レンダリング後にJavaScriptで設定します。

レンダリング後にdisplay: flex;を設定するScript
レンダリング後にdisplay: flex;でセンタリング

この方法では、センタリングされるのはあくまでもライフラインのみなので、長いメモがライフラインの外にはみ出している様なケースでは、不自然な表示となりますが、左右の幅が可変のコンテンツでも、追随してくれるという利点があります。

但し、コンテンツの横幅がシーケンス図よりも小さくなる場合(スマホで表示したような場合)、正しく表示されません。

レンダリング後にwidthとmarginを設定する

widthmarginを、レンダリング後にJavaScriptで設定します。

レンダリング後にwidthとmarginを設定するScript
レンダリング後にwidthとmarginでセンタリング

正確にシーケンス図の横幅を取得する方法がないので、あくまでも見た目重視で設定します(トライ・アンド・エラー※ってやつです。)。左右の幅が可変のコンテンツでも、追随してくれます。


※正確にはトライアル・アンド・エラーだそうです。

ダウンロードとセットアップ

ライブラリのダウンロード

下記より、アーカイブをダウンロードして、適当なディレクトリに解凍してください。

  [日付]   [サイズ] byte

[SHA256]

アーカイブを解凍すると、以下のようなディレクトリ構成となります。

dir/
+-jslib/
  +-01.00.00.01/
    +-jsdraw2.css
    +-jsdraw2.js
    +-jsdrawSD2.css
    +-jsdrawSD2.js
    +-jsdrawFC.css
    +-jsdrawFC.js
    +-jswebutilities.js
+-sequence_template.html
+-flow_template.html

sequence_template.htmlがHTMLのテンプレートで、内容は次章で簡単に解説します。

HTMLのテンプレート

必要なライブラリをロードし、最低限のコードを記述したテンプレートHTMLです。

テンプレートHTML

必要なスクリプトとスタイルシートは、上記の5ファイルです。

ライブラリのパスなどは、配置した環境に合わせて読み替えてください。

13行目から19行目までが、シーケンスを記述するスクリプトになります。

12行目loadイベントに登録していますが、DOMContentLoadedイベントでも問題ありません。

14行目でマネージャのコンストラクタに渡しているidは、24行目div要素のidです。