はじめに
前回の記事では Google Apps Script (GAS) と D2.js で実現するダイアグラムビューアを作成しました。
今回はその発展として、ウェブブラウザ上で D2コード を書いた瞬間に SVG が更新される 簡易 D2 エディタ を実装します。
エディタはすべて ウェブブラウザ と GAS だけで完結するため、その他のサーバーは不要です。
ゴール
左にコード、右に即時レンダリング結果が表示されるシンプルな構成です。
技術スタックの役割
技術 | レイヤー | 主な役割 |
---|---|---|
D2.js | クライアント(描画エンジン) | D2 言語の記述をリアルタイムで SVG ダイアグラムに変換 |
CodeMirror 6 | クライアント(UI・エディタ) | D2 スクリプトを記述・編集・リアルタイムプレビューのトリガー |
GAS | サーバー(HTML 配信) | Web UI を提供し、必要に応じて Google ドキュメントなどから D2 コードを取得 |
プロジェクト作成手順
-
GAS プロジェクトを新規作成
- Apps Script エディタで「新しいプロジェクト」を選択
-
Code.gs
を追加Code.gsfunction doGet() { return HtmlService.createHtmlOutputFromFile('index'); }
-
index.html
を追加(次章参照) -
[デプロイ] → [ウェブアプリ]
- 「新しいデプロイ」「アクセスを全員」に設定し URL を取得
- これでブラウザからアクセス可能
作成した index.html ファイル
index.html
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8" />
<title>D2.js エディタ</title>
<style>
/* 全体のフォントと余白設定 */
body {
font-family: sans-serif;
padding: 1em;
}
/* エディタと描画結果を左右に並べる */
.container {
display: flex;
gap: 1em;
align-items: flex-start;
}
/* 左側:CodeMirror エディタ */
#editor {
width: 50%;
border: 1px solid #ccc;
}
/* 右側:SVG描画エリア */
#diagram {
width: 50%;
overflow: hidden;
}
/* SVGにボーダーを付けて見やすく、サイズをウィンドウに対して自動調整 */
#diagram svg {
box-sizing: border-box;
width: 100%;
height: 80vh;
display: block;
border: 1px solid #ccc;
}
</style>
<!-- CodeMirror の状態管理モジュールをインポート -->
<script type="importmap">
{
"imports": {
"@codemirror/state": "https://esm.sh/@codemirror/state@6.4.1"
}
}
</script>
</head>
<body>
<h2>D2.js 簡易エディタ</h2>
<div class="container">
<div id="editor"></div>
<div id="diagram"></div>
</div>
<script type="module">
// CodeMirror 用のモジュールを読み込み
import { EditorView, basicSetup } from "https://esm.sh/@codemirror/basic-setup@0.20.0?external=@codemirror/state";
import { EditorState } from "https://esm.sh/@codemirror/state@6.4.1";
// D2.js 本体を読み込み(WASMベースの図表エンジン)
import { D2 } from "https://esm.sh/@terrastruct/d2@0.1.23";
const diagramDiv = document.getElementById("diagram");
// 初期図表コード:x → y → z の簡単なフロー
const initialCode = `x -> y
y -> z
x: 開始
y: 処理
z: 終了`;
// エディタ内容が変更されたら再描画
const updateListener = EditorView.updateListener.of((update) => {
if (update.docChanged) {
renderDiagram(update.state.doc.toString());
}
});
// CodeMirror エディタを初期化
const editor = new EditorView({
state: EditorState.create({
doc: initialCode,
extensions: [basicSetup, updateListener],
}),
parent: document.getElementById("editor"),
});
const d2 = new D2(); // D2.js インスタンス生成
// SVG描画を行う関数
async function renderDiagram(code) {
try {
const result = await d2.compile(code); // D2コードをコンパイル
const svg = await d2.render(result.diagram, result.renderOptions); // SVG出力
diagramDiv.innerHTML = svg; // HTMLに表示
} catch (err) {
diagramDiv.innerHTML = `<pre style="color:red;">${err.message}</pre>`; // エラー表示
}
}
// 初回描画
renderDiagram(initialCode);
</script>
</body>
</html>
ポイント
-
importmap
を使うことでモジュール同士の依存解決が簡潔 - エディタ更新を
updateListener
でフックしrenderDiagram()
を呼ぶだけ - 失敗時はエラーメッセージを SVG 領域に赤字表示
サンプル D2 コードと結果
以下のコードをエディタに貼ると即座にフロー図が再描画されます。
サンプル
Start: 開始
Input: 入力確認
Decision: 正常?
ProcessA: データ登録
ProcessB: エラー処理
End: 終了
Start -> Input -> Decision
Decision -> ProcessA: はい
Decision -> ProcessB: いいえ
ProcessA -> End
ProcessB -> End
まとめ
これで、GAS とブラウザだけで完結する リアルタイム D2 ダイアグラムエディタ が完成しました
次のステップとして編集したダイアグラムをロード・セーブする機能を追加します