背景: 書籍の静的な図をWebで動かす
書籍から株主総会スケジュールのデータをJSON化したものがあり、これをWebでインタラクティブに可視化するプロジェクトに取り組んだ。書籍の図は紙面に固定されているが、Webならホバーでハイライトしたり、クリックで詳細を出したりできる。そこを活かしたかった。
実装した3つの表示形式
1. 縦型テーブルタイムライン(agm-timeline.vue)
3列テーブル構成で作った。
| 日程 | 法定期間・期限(SVG矢印) | 手続 |
最初はシンプルな縦タイムラインとして実装したが、書籍の画像を見直して3列テーブル形式に作り替えた。
SVG矢印の描画
中央列にSVGで矢印を描画している。丸ドット(●) → 垂直線 → L字曲がり → 三角矢印(▶) というスタイルで、法定期間の開始と終了を視覚的につなぐ。
レーン割り当てアルゴリズム
複数の矢印が同時に表示されると重なってしまう。これを避けるため、自動レーン分けのアルゴリズムを組んだ。各矢印の開始行と終了行を見て、重複しないレーンに配置する。
ホバーインタラクション
イベント行にホバーすると、関連する矢印がオレンジでハイライトされ、無関係な矢印はフェードアウトする。最初はホバー時のみ矢印を表示する設計だったが、全矢印を常時表示に変更した。ホバーは強調表示の役割だけに絞った方が、全体の構造を把握しやすい。
2. 日次ガントチャート(agm-gantt.vue)
Excel的なセルベースの日次タイムライン。1マス=1日で時間経過が直感的にわかる。
トグルボタンでイベントがない期間を折りたたみ/展開できるようにした。株主総会スケジュールは数ヶ月にまたがるため、空白期間をそのまま表示すると横に長くなりすぎる。
3. 横型タイムライン(agm-timeline-horizontal.vue)
縦型を横にしたバリエーション。階段状(ピラミッド型)レイアウトで各行を右にインデントし、手続きの流れを視覚的に表現している。
JSON → TypeScript変換
当初はデータを .json ファイルで管理していたが、途中で .ts に切り替えた。
理由はViteのHMR(ホットリロード)。JSONの静的importだと、ファイル変更時にHMRが即時反映されないケースがあった。.ts ファイルにすればViteのHMRモジュールグラフに含まれるため、変更が即座にブラウザに反映される。
// timeline.json → timeline.ts
export const timelineData = {
events: [
{ id: "settlement", date: "2026-03-31", label: "決算日" },
{ id: "earnings", date: "2026-04-27", label: "決算発表(決算短信)" },
// ...
],
dependencies: [
{ from: "settlement", to: "earnings", label: "27日" },
// ...
]
} as const;
as const をつけることで型推論が効き、タイポの検出にも役立つ。
同様に ai_studio_code.json → references.ts にも変換した。
左右分割レイアウトと参照パネル
タイムラインを左側2/3、参照パネルを右側1/3に固定配置する構成にした。
- イベント行をクリックすると右パネルに解説コンテンツが表示される
- 参照データ(references.ts)には本文、関連法令タグ、必要書類などの詳細情報を持たせた
- クリック前後でテーブル幅が変わらないよう、常に2/3幅を確保する設計にした
パネルが開いたときにテーブルがリフローすると読みづらいため、この設計は地味だが大事なポイント。
スキーマ定義の3分割
当初は1つのTypeScriptファイルに全データを統合していた。しかしファイルが大きくなりすぎたため、3つに分割した。
- タイムライン表示用スキーマ: イベント、依存関係、日付情報
- 参照解説用スキーマ: 本文テキスト、法令タグ、必要書類リスト
- 統合型: 両方を参照する上位スキーマ
分割の判断基準は「表示に必要なデータ」と「詳細表示に必要なデータ」の境界。タイムライン描画には日付とラベルがあれば十分で、法令の条文や必要書類リストは参照パネルでしか使わない。
実務の話: 決算短信と会計監査の関係
実装中に気づいた実務的な話もまとめておく。
決算短信は監査前に出る
4/27に決算発表(決算短信)を出すケースがあるが、これは上場規程404条に基づく適時開示であり、監査報告書は添付されていない。会計監査人の監査完了は後日になる(法令上は受領後4週間等の期限あり)。
実務上の数字合わせ
決算短信の数字と最終的な監査済み数字が乖離しないよう、実務上は事前に会計監査人と数字をすり合わせている。「短信で出した数字が監査で否認される」という事態は、通常の上場企業では避けるべきリスクとして管理されている。
GW前発表はかなり早い
GW前の4月末に決算発表するのはかなり早い方。GW明けの5/16頃まで延ばしても問題ない企業が多い。「法定期限から逆算して日程が決まる」という説明を見かけるが、これは不正確で、実際は実務上の慣行や投資家への姿勢で決まる部分が大きい。
技術的なポイントまとめ
Nuxt 3のVueページとして実装
app/pages/ 配下にVueファイルを配置。Nuxt Contentの記事ではなく、独立したVueページとして実装した。インタラクティブな可視化にはVueコンポーネントのリアクティビティが必要なため。
データファイルの配置場所
最初は content/ ディレクトリにデータファイルを置いていたが、app/data/ に移動した。content/ 配下はNuxt Contentのビルド対象になるため、データファイルを置くとビルド時の処理に含まれてしまう。app/data/ に移動することで、通常のViteモジュールとして扱われ、HMRも効くようになった。
Chrome DevTools MCPでのイテレーション
ブラウザでの見た目確認にChrome DevTools MCPを使った。SVG矢印の位置調整やホバーエフェクトの確認は、コードだけでは判断しにくい。実際のレンダリング結果を見ながらパラメータを調整するサイクルが有効だった。
サーバー再起動が必要なケース
content/ 配下のファイルを変更した場合、Nuxt Contentのファイルウォッチャーが検知してくれるが、スキーマ定義の変更やファイルの追加・削除ではサーバー再起動が必要になることがあった。HMRが効かないときは pnpm dev の再起動で解決した。