はじめに
Qiita の markdown で簡単な図を描きたいと思っている人は多いのではないでしょうか。Qiita 公式からは mermaid や PlantUML などの作図言語が用意されているとはいえ,コレらはフローチャートのようなビジネスチャートを自動製図するのに特化している分,思ったような図が描けなくてモドカシイ思いをしている人もいるでしょう。
そんな人には朗報?かもしれません。Qiita でも直接 SVG(Scalable Vector Graphics)を使ってチマチマと作図できる方法を発見しました。とりあえず作図例を以下に示します。
コレどうやって描いているの?
Qiita でもサポートされている PlantUML の隠し機能?であるインライン SVG スプライトを使います。もともとはスプライト(アイコン,絵文字,古くは外字とも)と呼ばれる小さな図形を SVG を使って定義し,それらのスプライトを再利用できるようにするといったものです。具体的には下記のように FIGURE
という名のスプライトを SVG で定義した後で <$FIGURE>
という形で参照します。
```plantuml
@startuml
sprite FIGURE <svg width="500" height="500" viewbox="0 0 500 500">
(この中に SVG の図形要素を記述する)
</svg>
title <$FIGURE>
@enduml
```
ただし,残念ながら SVG の持つ豊富な機能のうち,ごくごく一部の機能しか実装していないようです。サポートしているタグは以下の5種類しかありません。厳密にいえば <svg> も加えて6種類ですが。
タグ | 機能 | 指定可能オプション |
---|---|---|
<g> | グループ化 | fill, transform |
<text> | テキスト | x, y, fill, font-size |
<path> | パス塗り潰し | d, fill, transform |
<circle> | 円描画・塗り潰し | cx, cy, r, fill, stroke, stroke-width, transform(?) |
<ellipse> | 楕円描画・塗り潰し | cx, cy, rx, ry, fill, stroke, stroke-width, transform |
また,各タグの機能もサブセットというか,不完全な実装に留まっています。ここでは「できない」機能で気づいた点を挙げます。
- <g>
グループ化した要素をまとめて回転させることができます。自分は塗り潰し色(fill オプション)をグループで定義して記述量を減らすのに用いています。なお,<use> タグが無いので定義したグループの再利用ができません。また <text> タグはグループ化の対象外のようです。 - <text>
文字の回転ができません。テキストをグループ化して,グループ全体で回転させてもテキストだけ無効になってしまいます。なお全てのオプションの指定が必須であり,一つでも省略するとエラーになります。また描画位置の起点が左下端固定であり,中揃えや右揃え等の指定ができないため,中揃えに見せるためには文字幅を計算して位置を微調整する必要があります。 - <path>
閉曲線の塗り潰しは可能ですが,境界線のみの描画はできません。 - <circle> と <ellipse>
本来は塗り潰しと境界線の描画を同時に行うことができますが,このスプライト機能ではいずれか一方しかできません。具体的には fill="none" と指定しないと境界線が描かれません。このため境界線の色と塗り潰し色が異なる場合,タグを2回(先に塗り潰し,次に境界線の描くという形で)使うことになります。あと <circle> の transform(座標変換)はバグっているように感じます。とくに rotate の動作が奇妙に思います。
個人的には文字の回転ができない点が非常に残念であり,コレができれば将棋盤が作れたのにとは思います。また <path> で必ず塗り潰されてしまい,自由曲線を描けないことも惜しいところです。
機能限定については本記事執筆(2024年4月)時点の情報に基づきます。
線の描き方
基本的に線(直線・曲線)を描くのが難しく,円や楕円の境界線は描けてもその一部だけ(円弧)は描けません。じゃあ,上の図ではどうしているのかというと,すごく細い矩形領域を塗り潰して作成し,回転させているだけです。まあ別に回転させずに平行四辺形を描いても良いのですが,線の太さが変わってしまいます。
<path d="M25 146 h150 v8 h-150" fill="black"/>
<path d="M25 146 h150 v8 h-150" fill="black" transform="rotate(-30,25,150)"/>
<path d="M25 146 l129.9 -75 v8 l-129.9 75" fill="black"/>
文字の表示位置
薄い黄色で示す正方形の領域(128×128ピクセル)の領域に対し,サイズ 128 ピクセルの英数文字を左下端を基準にして書き込んだ場合を示します。正方形の中心位置に揃えようとすると概ね右方向に 20 ピクセル,上方向に 16 ピクセル移動させる必要があります。
一方,漢字などのワイド文字の場合,横幅はちょうどよいのですが,何故か上下方向はベースラインを突き抜けています。これも上方向に 16 ピクセル移動させると正方形の中心位置に揃います。
文字の違い(英数文字,漢字)に注意すれば,フォントサイズに比例してこれらの位置補正を行えば良いようです。正確を期す人はフォントのメトリクス情報を確認したほうが良いでしょう。
拡大縮小機能
定義したスプライトを配置するときに拡大・縮小できます。
<$FIGURE*2>
のように倍率を書けます。倍率は <$FIGURE*0.5>
のように小数でも大丈夫です。
```plantuml
@startuml
sprite FIGURE <svg width="128" height="128" viewbox="0 0 128 128">
<path d="M0 64 h64 l-12 -48 l-20 -16 l-20 16" fill="yellow"/>
</svg>
title <$FIGURE*2> <$FIGURE> <$FIGURE*0.5>
@endutml
```
ただし,テキストだけ拡大・縮小できないのが残念なところです。
```plantuml
@startuml
sprite FIGURE <svg width="64" height="64" viewbox="0 0 64 64">
<path d="M0 64 h64 l-12 -48 l-20 -16 l-20 16" fill="yellow"/>
<text x="12" y="56" fill="black" font-size="40">歩</text>
</svg>
title <$FIGURE*2> <$FIGURE> <$FIGURE*0.5>
@endutml
```