
ReactとD3で実現するSVGグラフ表示
製造ビジネステクノロジー部では、プロジェクト開始前の段階から、データの可視化要件としてグラフ表示機能が求められることが少なくありません。
グラフライブラリの選定においては、「これさえ選べば間違いない」という万能の選択肢は存在しないのが現状です。
- 必要なグラフの種類
- データポイントが多くなる場合のパフォーマンス要件
- カスタマイズ性
- チーム内の技術スタックとの親和性
プロジェクトの具体的な要件を踏まえた上で、これらの要素を総合的に評価して、最適なグラフライブラリを選定する必要があります。
D3について
D3は一般的なグラフライブラリと異なり、定義済みのチャートを提供せず、いくつかの基本機能を組み合わせてグラフを構築します。
プロジェクトの要件に応じて、SVGベースの宣言的アプローチとCanvasベースのアプローチを選択できる高い柔軟性を提供する一方、基本的なグラフでも相応のコード量が必要になるため学習曲線は急峻と言えます。
単純なグラフ表示だけが目的であれば、高レベルなライブラリの使用も検討すべきです。
例えばこれらのグラフライブラリはD3をベースに作成されています。
SVGでの折れ線グラフの作成
Next.jsとD3を使って、実際に折れ線グラフを作成してみます。
作成するのは次の画像のグラフです。
シンプルなグラフで、ホバーしてもユーザーへのインタラクションはありません。データポイントも特別多くなるわけではないため、CanvasではなくSVGで作成します。またサンプルコードではClient Componentになっていますが、この例の場合であればServer Componentでも問題ありません。
SVGでグラフを作成する場合、描画するグラフをすべてReact上でSVGの要素で表現する必要があります。
例えばX/Y軸であればシンプルに <line />
を使って座標を指定するだけです。
{/* X軸 */}
<line
x1={plotPosition.origin.x}
y1={plotPosition.origin.y}
x2={plotPosition.x.x}
y2={plotPosition.x.y}
stroke="currentColor"
/>
{/* Y軸 */}
<line
x1={plotPosition.origin.x}
y1={plotPosition.origin.y}
x2={plotPosition.y.x}
y2={plotPosition.y.y}
stroke="currentColor"
/>
軸ができてもデータポイントの座標が取得できなければグラフにはなりません。
Linear scalesを使うことで、データの値をSVG上の座標に変換する関数を作成することができます。
const yScale = useMemo(() => {
const min = d3.min(yData) ?? 0;
const max = d3.max(yData) ?? 0;
return d3
.scaleLinear()
.domain([min, max])
.range([plotPosition.origin.y, plotPosition.y.y]);
}, [plotPosition.origin.y, plotPosition.y.y, yData]);
例えばこのyScale
になると、yData
の最小から最大の値をplotPosition.origin.y
からplotPosition.y.y
までの座標に変換する関数になります。
軸の区切りについても、ticks
を使うと簡単に実現可能です。
const yTicks = useMemo(() => {
const ticks = yScale.ticks();
const scale = d3
.scaleLinear()
.domain([ticks.at(0) ?? 0, ticks.at(-1) ?? 0])
.range([plotPosition.origin.y, plotPosition.y.y]);
return ticks.map((tick) => ({
value: tick,
y: scale(tick),
}));
}, [plotPosition.origin.y, plotPosition.y.y, yScale]);
ticks
を使い等間隔の区間を作成した後、再度scaleLinear
を使って座標に変換しています。
D3の機能を使うことで、SVG上に柔軟にグラフを描画することができます。特にscaleLinear関数は、データ値からSVG座標への変換を簡単に行えるため、グラフ作成の基本となります。
このように簡単にグラフ表示をするだけであればそこまで難しくは感じないかもしれません。ですが、ここにアニメーションやhover時のツールチップなどの要件が増えていくとどうでしょうか。これらのインタラクティブな要素を追加することで、実装の複雑さは増していきます。
まとめ
D3.jsを使ったSVGのグラフ作成は、以下のステップで行われます。
- データの準備
- scale関数の作成(データ値からSVG座標への変換)
- データポイントや線の描画
- 軸や目盛りの描画
SVGを使用すると宣言的にグラフを記述でき、インタラクティブな要素も実装しやすいですが、大量のデータを扱う場合はパフォーマンスが課題になります。一方、Canvasを使用すると多数のデータポイントを効率的に描画できますが、実装が複雑になります。
プロジェクトの要件に応じて、適切なアプローチを選択することが重要です。また、単純なグラフ表示だけが目的であれば、高レベルライブラリを使用することで開発効率を大幅に向上させることができます。