---
title: "依存ゼロで作るダッシュボードのグラフ"
description: "ダッシュボードのトレンドライン、スパークライン、カテゴリ別の棒グラフは、すべてインラインの SVG で書きました。チャートライブラリはなし、全部合わせて数百行、ダークモードもおまけでついてきます。自分で書くグラフが向いている場面と、絶対にやめておくべき場面をまとめます。"
url: "https://bookatu.com/ja-jp/blog/dashboard-charts-with-zero-dependencies"
language: "ja"
section: "ブログ"
category: "エンジニアリング"
author: "Bookatu エンジニアリングチーム"
published: "2026-07-11"
updated: "2026-07-11"
tags: ["svg グラフ", "ライブラリなし グラフ", "ダークモード グラフ", "フロントエンド パフォーマンス", "データ可視化"]
---

# 依存ゼロで作るダッシュボードのグラフ

ダッシュボードのトレンドライン、スパークライン、カテゴリ別の棒グラフは、すべてインラインの SVG で書きました。チャートライブラリはなし、全部合わせて数百行、ダークモードもおまけでついてきます。自分で書くグラフが向いている場面と、絶対にやめておくべき場面をまとめます。

> **要点**
>
> - ダッシュボードのグラフは、たいてい数種類の図形の組み合わせです。線、面、いくつかの棒。SVG 要素にすれば数十個で、ライブラリが必要な規模ではありません。
> - 線と塗りの色を CSS 変数で指定すれば、グラフはテーマに自動で追従します。ダークモードも含めてです。
> - すべての状態を自分で決められます。データが空のとき、1点しかないとき、動きを減らす設定のとき、スクリーンリーダーで読むとき。
> - 操作できるグラフ、スケール、自分では下手にしか作り直せない種類のグラフが必要になったら、そこでライブラリを使います。

在庫ダッシュボードを追加したとき、まず思いついたのはチャートライブラリを入れることでした。よく使われているものはどれも優秀です。ただ、どれもサイズが大きく、テーマの扱いに独自の流儀があり、千通りの状況に対応するように作られています。私たちに必要だったのは四つだけでした。二系列のトレンドライン、行ごとのスパークライン、在庫量の棒、カテゴリ別の内訳です。代わりにインライン SVG で書いたところ、全部合わせても多くのライブラリの型定義ファイルより小さく収まりました。

![明るいテーマの在庫ダッシュボード。トレンドグラフ、カテゴリ別の内訳、順位付きのリストが並ぶ](https://bookatu.com/blog/shots/inventory-control-center-light.png)

*手書きの4つのグラフです。トレンドライン、区切りのあるカテゴリバー、値の大きさ順に並ぶ棒、行ごとのスパークライン。*

## グラフとは1本のパスである

道具立てを取り払ってしまえば、折れ線グラフは1つの文字列です。手元の数値から組み立てた SVG のパスにすぎません。各点の順番を x に、値を y に対応させて、つなぐだけです。書き留めておく価値がある細かい点は余白くらいです。最大値を上端より数ピクセル下に対応させておかないと、頂点の線が viewBox に半分切り取られてしまいます。

```js
const W = 300, H = 80, PAD = 3; // top pad so the peak stroke is not clipped
const max = Math.max(1, ...values);
const x = (i) => (i / (values.length - 1)) * W;
const y = (v) => PAD + (H - PAD) * (1 - v / max);

const d = values
  .map((v, i) => `${i === 0 ? 'M' : 'L'}${x(i).toFixed(1)} ${y(v).toFixed(1)}`)
  .join(' ');

// <path d={d} fill="none" stroke="var(--color-primary)" strokeWidth="2" />
```

## ダークモードはタダでついてくる

地味に効いているのはテーマ対応です。私たちのデザイントークンは CSS 変数で、SVG の stroke や fill も他のプロパティと同じようにそれを受け取れます。stroke="var(--color-primary)" と書いておけば、テーマが切り替わった瞬間にグラフも色を変えます。グラフ側のテーマ設定も、パレットの二重管理も、グラフと他の画面との色のずれもありません。後からダークのパレットを調整したときも、グラフには一切手を触れずについてきました。

![同じ在庫ダッシュボードをダークテーマで表示したところ](https://bookatu.com/blog/shots/inventory-control-center-dark.png)

*同じコンポーネントのダークモードです。グラフには一切手を入れていません。CSS 変数が仕事をしました。*

## 端の状態は自分のもの

ライブラリは機能には気前がよく、自分たちにしか関係のない端の状態にはそっけないものです。データが1点しかないとき、スパークラインはどう振る舞うべきでしょうか。開業したばかりで値がすべてゼロのとき、トレンドグラフは何と言うべきでしょうか。自分で書いたコンポーネントなら、こうした判断をはっきりと、しかも安く決められます。一文を添えた正直な空の状態、クラッシュではなく平らな線、どのグラフの隣にもスクリーンリーダー向けの文章での要約、そして描画アニメーションを切る prefers-reduced-motion のメディアクエリを一つ。

- どのグラフにも aria-label と、平易な言葉での要約をつけます。SVG は飾りで、データを伝えるのは文章のほうです。
- 線を描いていく演出は stroke-dashoffset で作り、prefers-reduced-motion で切れるようにします。
- 計算とマークアップは同じ場所に置きます。上から下まで1画面で読めるグラフのコンポーネントは、夜11時でも直せるコンポーネントです。
- 空の状態から先に設計します。新しいアカウントは、他のどの状態よりもそれを目にします。

## ライブラリを使うべきとき

要件が本気で牙をむき始めた瞬間から、自分で書くのは賢い選択ではなくなります。ズームや範囲選択、対数スケール、きちんと補間された積み上げ面グラフ、目盛りを賢く配置する軸、数万点を描くための canvas レンダリング。どれもすでに解かれた問題で、それを手作業で解き直すのは、2日の機能が2か月の趣味に変わる道です。私たちの基準は単純です。グラフが見せるためのものなら SVG を書く。グラフが利用者の操作する道具なら、依存を受け入れて、維持してくれている人に感謝する。

> 小さなグラフ4つに最適なチャートライブラリは、結局のところ for ループでした。
