drawio-diagram
要件定義や設計の図をdraw.io (mxGraph)のXMLとして手書きで生成するときに使う。Factory Consoleがインライン描画できる自己完結したXMLを作る規約を定める。
SKILL.md.claude/skills/drawio-diagram/SKILL.md
GitHubdraw.io (mxGraph) XMLの書き方(drawio-diagram)
この図の使われ方
生成したXMLファイルは、Consoleが同梱のdiagrams.netのビューアーで、隔離したiframeの中にインライン描画する。URLには載せない。 ビューアーは外部へ通信しないので、AWSなどの外部の図形ライブラリは使えず、図形が描かれない。toolbar、ズーム、レイヤも使えない。 XML自体が、すべての情報を含む自己完結した文書である必要がある。 外部ファイルの参照や、相対パスの画像は使わない。
図にリンクを入れない。link属性と、ラベルのHTMLの属性付きの<a>、<area>、<map>、<meta>、<object>、<embed>、<form>、<img>、<image>などは使わない。
HTMLのタグの中のonclick=のようなイベントハンドラ属性も使わない。
ラベルに、HTMLのコメント(<!--)と、<!か<?で始まる構文は使えない。
x </ yのように、</の後ろが英字でない書き方も使えない。
ラベルに次の要素は使えない。属性の有無を問わず拒否する。
<textarea>、<title>、<xmp>、<noscript>、<noembed>、<noframes>、<plaintext>、<iframe>、<style>、<script><svg>、<math><set>、<animate>、<animateMotion>、<animateTransform>
Map<title>のように、型の表記がこれらの要素名と同じになるときは、型の名前を変えるか、文章で書く。
タグの外の文章にあるone = 1やonline=trueは拒否しない。
usemap=、formaction=、srcdoc=も使わない。
placeholders属性と、<mxfile>のvars属性は使わない。
placeholdersは、どの要素にあっても、値を問わずFactoryが拒否する。
ラベルの%名前%が祖先のセルの属性、ページの名前、varsの値に置き換わり、置き換えた後のラベルを検査で確かめきれないためである。
Promise<Object>のように、属性を持たない要素名だけの表記は使ってよい。
<A extends B = C>のように、型引数の名前がaやmapなどの要素名と同じで、後ろに名前=が続く表記は、属性付きの要素とみなして拒否することがある。そのときは、型引数の名前を変えるか、文章で書く。
図のXMLは信頼できない入力として描くので、リンクや圧縮で検査をすり抜ける図は、Factoryが生成の時点と読み戻しの時点で拒否するためである。
最小スケルトン
<mxfile host="app.diagrams.net">
<diagram name="DIAGRAM_NAME" id="UNIQUE_ID">
<mxGraphModel dx="800" dy="600" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="850" pageHeight="1100" math="0" shadow="0">
<root>
<mxCell id="0" />
<mxCell id="1" parent="0" />
<!-- vertex と edge をここに追加 -->
</root>
</mxGraphModel>
</diagram>
</mxfile>
mxCell id="0"とid="1"(parent="0")はdraw.ioの内部ルートで、必ず両方置く。以降のセルは、すべてparent="1"から辿れるようにする。diagramのid(UNIQUE_ID)は、ファイル内で一意であればよい。自分で決めた一意な文字列でよい。diagramのname(DIAGRAM_NAME)は、ファイル名(<name>.drawio)と本文の参照()と同じ値にする。nameは[a-z0-9-]{1,64}の形式にする。
vertex(ノード)の書き方
<mxCell id="node1" value="要求を受け取る" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;" vertex="1" parent="1">
<mxGeometry x="40" y="40" width="160" height="60" as="geometry" />
</mxCell>
valueが表示テキストである。styleは;区切りのキー=値の並びで、rounded、whiteSpace=wrap、html=1が基本のセットである。geometryのx/yは左上の座標、width/heightはノードのサイズである。as="geometry"は固定である。
edge(矢印)の書き方
<mxCell id="edge1" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;" edge="1" parent="1" source="node1" target="node2">
<mxGeometry relative="1" as="geometry" />
</mxCell>
source/targetは、接続元と接続先のvertexのidである。ラベルを付けたい場合は、valueに文言を入れる。- 状態遷移図で条件ラベルを付ける場合も、同じく
valueを使う(例:value="approve")。 parentは必ず"1"にし、ルートセルを親にする。mxGeometryにはas="geometry"を必ず付ける。relative="1"はedgeに特有の指定である。
レイアウト規則
- グリッドの単位は120pxを基準にする。これがノード間の水平・垂直の間隔の目安である。
- 原則として、上から下への一方向のレイアウトにする。フローチャートなら左から右でもよい。矢印が交差する配置は避ける。
- 1つの図に詰め込むノードは15個までを目安にする。それを超える複雑さになりそうなら、図を分割して「1図1概念」にする(例: 全体構成図と、承認フローだけの図を分ける)。
図の種類ごとの目安は次のとおり。
| 種類 | 書き方 |
|---|---|
| コンテキスト図 | システムと外部アクター(GitHub、Discord、人)の関係を描く。ノードは少なくし、矢印にはやりとりの内容をラベルで書く。 |
| フロー図(擬似シーケンス) | 処理ステップを上から下に並べ、矢印で順序を表す。分岐は、菱形か条件ラベル付きの矢印で表す。 |
| 状態遷移図 | 状態をノード、遷移をラベル付きのedgeで表す。終端状態は、色や二重線のstyleで視覚的に区別する。 |
| データモデル図 | テーブルやエンティティをノードにし、関連をedgeで結ぶ。カラムの一覧は、value内に改行(<br>)区切りで列挙してよい。 |
非圧縮XMLであること
<mxfile>にcompressed="true"を付けない。属性ごと省略してもよい。- deflateとbase64で圧縮したペイロードではなく、人が読めるプレーンなXMLをそのまま出力する。
<diagram>の中に、空白以外のテキストやCDATAを入れない。要素と属性だけで書く。- このスキルの責務は、妥当な非圧縮のXMLを作るところまでである。XMLの検証はFactory側(
f/factory/lib/drawio.ts)が行い、表示はConsoleが行う。
エスケープ規則
value属性やテキストの中では、次の文字をXMLエンティティに置き換える。
| 文字 | 置き換え |
|---|---|
& |
& |
< |
< |
> |
> |
"(属性値内) |
" |
valueの中で改行したい場合は、<br>(エスケープ済みの<br>)を使う。
完全な例(4ノード・3エッジ)
Issue受付から承認までの簡易フロー図を示す。
<mxfile host="app.diagrams.net">
<diagram name="issue-intake-flow" id="d1">
<mxGraphModel dx="800" dy="600" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="850" pageHeight="1100" math="0" shadow="0">
<root>
<mxCell id="0" />
<mxCell id="1" parent="0" />
<mxCell id="n1" value="Issue に factory ラベル" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;" vertex="1" parent="1">
<mxGeometry x="40" y="40" width="160" height="60" as="geometry" />
</mxCell>
<mxCell id="n2" value="claim して要件生成" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;" vertex="1" parent="1">
<mxGeometry x="40" y="160" width="160" height="60" as="geometry" />
</mxCell>
<mxCell id="n3" value="承認待ち(要対応)" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#ffe6cc;strokeColor=#d79b00;" vertex="1" parent="1">
<mxGeometry x="40" y="280" width="160" height="60" as="geometry" />
</mxCell>
<mxCell id="n4" value="承認済み" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;" vertex="1" parent="1">
<mxGeometry x="40" y="400" width="160" height="60" as="geometry" />
</mxCell>
<mxCell id="e1" edge="1" parent="1" source="n1" target="n2">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="e2" edge="1" parent="1" source="n2" target="n3">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="e3" value="approve" edge="1" parent="1" source="n3" target="n4">
<mxGeometry relative="1" as="geometry" />
</mxCell>
</root>
</mxGraphModel>
</diagram>
</mxfile>
セルフチェック
<mxfile>がルート要素で、compressed属性が無いかfalseである。placeholders属性と、<mxfile>のvars属性が無い。- すべての
vertex/edgeのparentが"1"を辿れる。孤立したセルが無い。 - すべての
source/targetが、実在するvertexのidを指している。 &<>"がエスケープされている。ファイルの内容やユーザー入力に由来するラベルのテキストは特に注意する。- すべての
mxCellのidが一意で、ルートセルの0/1を再利用していない。 - 図名、ファイル名(
<name>.drawio)、本文の参照()が一致している。nameは[a-z0-9-]{1,64}の形式である。 - 非圧縮の生のXMLが256KB以内である。超える場合は、「1図1概念」の原則に従って図を分割する。