Reactグラフ表示ライブラリの選定

はじめに

AIチャットボット OPTiM AIRES のフロントエンドを開発している新卒1年目の相川です。

AIチャットボット OPTiM AIRES は、Q&A・PDFやOfficeファイルなどのドキュメント・URLなどのデータを登録するだけで、社内外からの問い合わせにAIが自動で回答できるサービスです。まず登録された資料を参照するRAG(Retrieval-Augmented Generation)で回答を試み、RAGで回答できない場合はAIモデル自身の知識にもとづいて回答します。(設定によってはRAGで回答できない場合に「回答できない」と返す運用も可能です。)

しかし、これまでの本サービスには「どのくらい質問に答えられているのか」を確認する仕組みがなく、さらに 回答が“RAGベースなのか” “モデル知識ベースなのか” といった内訳も分かりづらい状態でした。問い合わせ対応を効率化するうえで、回答率や回答方式の把握は運用改善に欠かせない情報です。

そこで今回、回答率の推移や、回答失敗・RAGベース回答・モデル知識ベース回答の内訳を可視化できるダッシュボード機能を新たに追加することになりました。

ダッシュボード画面にはグラフが必要ですが、今回始めてグラフ表示を実装することになったためライブラリの選定を行いました。この記事では、ライブラリを比較した観点と、最終的に採用したライブラリとその理由、そしてダッシュボード実装で得られた知見を紹介します。

要件

Figma

当初のダッシュボード画面のデザイン案

ダッシュボードで実現したいグラフ機能の要件は以下の通りです:

対応したいグラフ

今後の機能拡張も踏まえて以下のグラフに対応することになりました。

その他の要件

  • React 18対応
  • TypeScript対応

SVG vs Canvas

グラフ描画の基盤技術として、SVG(Scalable Vector Graphics)とCanvasの2つの選択肢があります。いずれもブラウザでグラフを描画する際の標準的な技術ですが、それぞれ異なるアプローチを採用しています。

多くのグラフ描画ライブラリもどちらか片方のレンダリング方式のみ対応しているケースが多いため、具体的なライブラリ選定前にどちらのレンダリング方式が適しているかを調査しました。

SVGの特徴

ベクターベースのXML形式グラフィックス

  • 数学的な記述(パス、座標、ベジェ曲線)で図形を定義
  • 各要素が独立したDOMノードとして扱われる
  • XML形式のため、テキストエディタで編集可能

主なAPIと操作方法

SVGでの操作例

SVG操作のサンプルコード

<!DOCTYPE html>
<html lang="ja">

<body>
  <div id="stage"></div>

  <script>
    // 1) SVG を作成して DOM に追加
    const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
    svg.setAttribute("width", "240");
    svg.setAttribute("height", "140");
    svg.setAttribute("viewBox", "0 0 240 140");

    const rect = document.createElementNS("http://www.w3.org/2000/svg", "rect");
    rect.setAttribute("x", "30");
    rect.setAttribute("y", "30");
    rect.setAttribute("width", "80");
    rect.setAttribute("height", "80");
    rect.setAttribute("rx", "6");
    rect.setAttribute("fill", "#2b8a3e");

    svg.appendChild(rect);
    document.getElementById("stage").appendChild(svg);

    // 2) 後から DOM 操作で形を変える
    setTimeout(() => {
      rect.setAttribute("width", "160");
      rect.setAttribute("height", "40");
      rect.setAttribute("y", "50");
      rect.setAttribute("fill", "#1c7ed6");
      rect.setAttribute("rx", "20");
    }, 1200);
  </script>
</body>

</html>

パフォーマンス特性

  • 利点: 少量〜中量の要素で高速、DOM操作による動的変更が容易
  • 欠点: 数万要素を超えるとレンダリングが重くなる(DOMツリーの肥大化)
  • 用途: インタラクティブなUI、シンプルなチャート

Canvasの特徴

ピクセルベースのレンダリング

  • JavaScript APIを通じて直接ピクセル操作
  • 描画命令を実行すると即座にビットマップに変換される
  • 状態を持たない:描画命令は蓄積されず都度実行

主なAPIと操作方法

Canvasでの操作例

Canvas操作のサンプルコード

<!DOCTYPE html>
<html>

<body>
  <canvas id="myCanvas" width="200" height="200"></canvas>
  <script>
    // Canvas APIの使用例
    const canvas = document.getElementById('myCanvas');
    const ctx = canvas.getContext('2d');

    // 円を描画
    function draw(color) {
      ctx.beginPath();
      ctx.arc(50, 50, 40, 0, 2 * Math.PI);
      ctx.fillStyle = color;
      ctx.fill();
    }

    draw('blue');

    // 再描画が必要な場合は毎回命令を実行
    function animate() {
      setTimeout(() => {
        ctx.clearRect(0, 0, canvas.width, canvas.height);
        const nextColor = animate.isBlue ? 'red' : 'blue';
        animate.isBlue = !animate.isBlue;
        draw(nextColor);
        requestAnimationFrame(animate);
      }, 500);
    }

    animate.isBlue = true;
    animate();
  </script>

</body>

</html>

パフォーマンス特性

  • 利点: DOMノード増加の影響を受けにくい
  • 欠点: 変更時は全体を再描画する必要がある、アニメーション実装が複雑
  • 最適用途: 大量データの可視化(数万要素以上のデータセット)

SVG vs Canvas比較表

項目 SVG Canvas
描画方式 ベクタグラフィックス(XMLベース) ラスタグラフィックス(ピクセルベース)
解像度依存 解像度非依存。無限に拡大縮小可能 解像度依存。Canvasサイズで解像度が決定
描画単位 DOM要素(XMLノード) ピクセル座標
パフォーマンス 要素数に比例して重くなる 要素数にほぼ依存せず安定
CSS適用 ○(各要素にCSS適用可能) ×(Canvas全体にのみCSS適用)
イベント処理 ○(各要素に個別イベントリスナー設定可能) △(ピクセル座標ベースの判定が必要)
テキスト処理 ○(検索可能、選択可能) △(ピクセルベース、テキスト検索不可)
ファイルサイズ ベクター記述のため比較的軽量 ビットマップのためデータ量が多い場合メモリ消費大
アニメーション CSS/SMILアニメーション、JavaScript JavaScriptによる手動制御(requestAnimationFrame)
アクセシビリティ 高い(DOM構造のためスクリーンリーダー対応) 低い(ピクセルベースのため支援技術が扱いにくい)

ブラウザの互換性

SVGの実装状況

  • HTML5標準仕様に含まれる
  • 全てのモダンブラウザでサポート
  • CSSとの統合が強く、Web標準の拡張性が高い

Canvasの実装状況

  • HTML5で導入された比較的新しいAPI
  • IE9以降の全ブラウザでサポート

メモリ管理とレンダリング

SVGのメモリ管理

  • DOMツリーとしてメモリに保持
  • ブラウザのDOMレンダリングエンジンを使用
  • ガベージコレクションの対象になる

Canvasのメモリ管理

  • ビットマップデータをメモリに保持
  • GPUメモリを使用する場合が多い
  • 明示的なメモリ解放が必要になる場合あり

※通常、ライブラリがメモリ管理を実装しているため、開発者はメモリ管理を意識する必要はない

結論: SVGを採用

今回はSVGレンダリングのライブラリから選ぶことにしました。

大量のデータ処理や3D表示を行わない場合はSVGが適しているケースが多く、hover時の表示や拡大縮小を伴いインタラクティブなUIの実装を得意としていることから選択しました。

ダッシュボードの要件として、以下の点を考慮しました:

  1. インタラクティブ性の重視: ホバー時のツールチップ表示、クリックイベントなど、ユーザーの操作に対する即時応答性
  2. データ量の見積もり: 月次データで最大数千要素程度(詳細は後述)
  3. デザインカスタマイズ: CSSによる細かいスタイリングとアニメーション
  4. アクセシビリティ: スクリーンリーダー対応などのユーザビリティ

インタラクティブなUIの実装においてSVGが優位で、数万要素を超えるような大規模データ描画の必要性も低いためSVGのデメリットも問題にならないと判断しました。

もし数万オーダーの要素や3D描画などの描画要件を実現する必要がある場合にはCanvasを検討するとよいと思います。

Vanilla JS vs Reactライブラリ

グラフ描画ライブラリにはChart.jsなどの純粋なJavaScriptライブラリと、RechartsなどのReact用ライブラリの2つのアプローチが存在します。Vanilla JS向けのライブラリを含めると選択の幅がかなり広がるので改めてメリット・デメリットを調べてみました。

Vanilla JSライブラリの特徴(Chart.jsなど)

命令型プログラミングによる直接DOM操作

// Chart.jsの使用例
const ctx = document.getElementById('myChart').getContext('2d');
const chart = new Chart(ctx, {
    type: 'bar',
    data: {
        labels: ['Red', 'Blue', 'Yellow'],
        datasets: [{
            label: 'Votes',
            data: [12, 19, 3]
        }]
    }
});

// データ更新時は手動で更新
chart.data.datasets[0].data = [15, 20, 5];
chart.update();

アーキテクチャ特性

  • 直接DOM操作: CanvasやSVG要素を直接操作
  • 状態管理: ライブラリ自身がチャートの状態を内部管理
  • データ更新: 明示的なupdate()呼び出しが必要
  • メモリ管理: チャートインスタンスの破棄を明示的に行う必要がある

Reactライブラリの特徴(Rechartsなど)

宣言的プログラミングによるコンポーネントベース開発

// Rechartsの使用例
import { BarChart, Bar, XAxis, YAxis, CartesianGrid, Tooltip } from 'recharts';

const data = [
  { name: 'Red', value: 12 },
  { name: 'Blue', value: 19 },
  { name: 'Yellow', value: 3 }
];

function MyChart({ chartData }) {
  return (
    <BarChart data={chartData}>
      <CartesianGrid strokeDasharray="3 3" />
      <XAxis dataKey="name" />
      <YAxis />
      <Tooltip />
      <Bar dataKey="value" fill="#8884d8" />
    </BarChart>
  );
}

// データ更新時はprops経由で自動反映
<MyChart chartData={newData} />

Vanilla JS vs Reactライブラリ比較表

項目 Chart.jsなどのVanilla JSライブラリ RechartsなどのReactライブラリ
プログラミングモデル 命令型(手続き型) コンポーネントベース
データ更新 手動update()呼び出し props/state変更で自動反映
メモリ管理 明示的な破棄が必要 Reactコンポーネントのマウント/アンマウントに追従
学習コスト ライブラリ固有のAPI学習 Reactの知識+ライブラリ固有のAPI学習

結論: ReactプロジェクトならReactライブラリが無難

今回のダッシュボード開発においては、以下の観点からReact用ライブラリを採用しました:

  1. 開発生産性: Reactの宣言的プログラミングモデルとの親和性が高く、コードの可読性と保守性が高い
    • JSXによる宣言的な記述で、複雑なグラフ構成も直感的に実装できる
  2. 状態管理: Reactエコシステムとのシームレスな統合が可能
    • Reactのライフサイクルと統合することで、データ変更時の自動再描画が可能
    • hooks、contextなどと自然に統合できる
  3. コンポーネント化の恩恵: 再利用可能なチャートコンポーネントを作成しやすい

開発効率が大きく変わるのでReactプロジェクトにおいて特別な理由が無ければReact用ライブラリを選ぶ方が良いと思います。

パフォーマンス

ダッシュボード機能で想定されるデータからパフォーマンス面で妥当かどうか見積もりました。

描画する要素の洗い出し

ダッシュボードで表示する主なデータ項目:

利用状況データ(7つの指標)

  • 問い合わせ件数
  • 登録データからの回答数
  • AIからの回答数
  • 回答率
  • ドキュメントデータ量
  • Q&Aデータ量
  • クローリングデータ量

検索キーワードデータ

  • キーワードごとの出現回数(10〜100件程度を想定)

描画要素数の見積もり

表示期間 データ粒度 描画要素数の計算 概算要素数 オーダー
月表示 日次(約30日) 30日 × 7指標(棒+折れ線) 約210要素 O(10²)
年表示 月次(12ヶ月) 12ヶ月 × 7指標 約84要素 O(10²)
長期表示 月次(5年分) 60ヶ月 × 7指標 約420要素 O(10²)
長期表示 日次(3年) 365日 × 3年 × 7指標 約7,665要素 O(10³)
  • 最大でも数千要素程度の描画で収まる見込み
  • SVGのパフォーマンス特性上、十分に実用的な範囲
  • Canvasを採用するほどの大量データ処理は不要

ライブラリ選定

複数のReactグラフライブラリを調査し、最終的に2つの候補に絞り込みました。

調査対象ライブラリ

主要なReactグラフライブラリとして以下の5つを比較検討しました:

  • MUI X Charts: MUIチームが開発するMaterial-UI統合ライブラリ。MUIを利用しているためその延長線として利用を検討。レンダリングエンジンを独自実装している。
  • Recharts: Reactコミュニティで最も人気のあるグラフライブラリ。React向けチャートライブラリとしてデファクトで、React18対応、TypeScript対応、軸やツールチップなどグラフの各種部品を別々のコンポーネントとして利用できる。
  • Victory: Nearformが開発する柔軟性の高いモジュラーなライブラリ。React Nativeにも対応しており、ResponsiveContainerによるレスポンシブ対応が可能。RadarやTreeMapなどの特殊なチャートタイプもサポート。
  • Nivo: D3.jsベースの豊富なカスタマイズオプションを持つライブラリ。モジュール化された設計で必要な機能を組み合わせて使用可能。SSRにも対応しており、エンタープライズ向けの豊富なチャートタイプを提供。
  • Ant Design Charts: 蚂蚁集团(Alibaba)が開発するAnt Design統合のグラフライブラリ。Ant Designのデザインシステムと統合されており、中国国内で高い普及率を誇る。

ライブラリ比較表

※2026/2/10 調査

観点 @mui/x-charts recharts victory nivo @ant-design/charts
開発主体 MUI Team 有志 Nearform 有志 蚂蚁集团(アリババ系列)
React 18 ⭕️ ⭕️ ⭕️ ? ⭕️
Bar ⭕️ ⭕️ ⭕️ ⭕️ ⭕️
Line ⭕️ ⭕️ ⭕️ ⭕️ ⭕️
Area ⭕️ ⭕️ ⭕️ ⭕️ ⭕️
Combo ⭕️ ⭕️ ⭕️ Issue ⭕️ Issue ⭕️
Pie ⭕️ ⭕️ ⭕️ ⭕️ ⭕️
2軸 ⭕️ ⭕️ ⭕️ ⭕️ ⭕️
Tooltip ⭕️ ⭕️ ⭕️ ⭕️ ⭕️
Zoom ⭕️(有料) ⭕️ 折れ線グラフのみ? ⭕️ ⭕️ (Slider)
アニメーション ⭕️ CSS ⭕️ ⭕️ ⭕️ ⭕️
Canvas ⭕️ (experiment) ⭕️ (一部非対応) ⭕️
SSR ⭕️ ⭕️ ⭕️ ⭕️
計算エンジン D3.js D3.js D3.js D3.js 独自
ライセンス MIT(Communityプラン) MIT MIT MIT MIT
GitHub star 5.6k(mui-xリポジトリ全体) 26.6k 11.2k 14k 2.2k
最終リリース 2026-2-2 2026-1-22 2025-01-15 2025-05-23 2025-12-23

直近2年間(2024/2/4~2026/2/1)のnpmダウンロード数推移

出典: npm trends (https://npmtrends.com/@ant-design/charts-vs-@mui/x-charts-vs-@nivo/core-vs-@victory-vs-recharts-vs-victory)

ライブラリ毎の所感

全てのライブラリが基本的なグラフタイプ(棒・線・面・複合・円グラフ)とツールチップ、2軸表示に対応していましたが、以下の観点でRechartsとMUI X Chartsから選択することにしました

  • SVGベース: インタラクティブ性の確保(DOM操作によるイベントハンドリングが可能)
  • React 18対応: 最新バージョン対応(Concurrent Features、Automatic Batching対応)
  • コミュニティの活発さ: 継続的なメンテナンス(Recharts: 26.1k stars、MUI X Charts: MUI全体として活発)

各ライブラリの強みと弱み:

  • MUI X Charts: Material-UIとのシームレスな統合が最大の強み。MUIテーマ、コンポーネントシステムとの親和性が高く、既存のMUIプロジェクトへの導入が容易。ただし、複合グラフのカスタマイズ性では他のライブラリに一歩劣る。

  • Recharts: 最もバランスの取れたライブラリ。D3.jsの力を活かした柔軟なカスタマイズ性と、Reactコンポーネントとしての使いやすさを両立。syncIdによるグラフ間ハイライト同期やComposedChartによる複合グラフの実装が容易。

  • Victory: 高いモジュラー性と拡張性がある。ResponsiveContainerによるレスポンシブ対応や、React Native対応が特徴。個人的に他のライブラリのドキュメントの構成が違い少し分かりづらく感じました。

  • Nivo: D3.jsの豊富な機能をReactコンポーネントとして提供。高度なカスタマイズが可能だが、ライブラリサイズが大きく、学習曲線が急峻。モノレポ構成で必要な機能だけをインポートできる利点がある。

  • Ant Design Charts: 中国市場での実績が豊富。G2Plotベースの高品質なチャートを提供するが、日本語ドキュメントが少なく採用事例もあまり見つからなかった。

最終的な比較対象ライブラリ

上記の調査を経て、最終的に以下の2つのライブラリを詳細比較しました:

  • Recharts: Reactグラフライブラリのデファクトスタンダード
  • MUI X Charts: Material-UI(MUI)との統合を重視する場合の選択肢

コードの比較

それぞれのライブラリでダッシュボード画面のコンポーネントを実装して比較しました。どちらのライブラリも要求仕様を満たせることを確認しました。

サンプルコード

サンプルデータ(chartData.ts)

export type ComboChartPoint = {
  day: string
  answeredByRules: number
  answeredByAi: number
  failed: number
  answerRate: number
}

export const comboChartData: ComboChartPoint[] = [
  { day: 'Mon', answeredByRules: 72, answeredByAi: 38, failed: 5, answerRate: 89 },
  { day: 'Tue', answeredByRules: 81, answeredByAi: 42, failed: 4, answerRate: 91 },
  { day: 'Wed', answeredByRules: 69, answeredByAi: 35, failed: 7, answerRate: 86 },
  { day: 'Thu', answeredByRules: 88, answeredByAi: 45, failed: 3, answerRate: 93 },
  { day: 'Fri', answeredByRules: 84, answeredByAi: 47, failed: 4, answerRate: 92 },
  { day: 'Sat', answeredByRules: 58, answeredByAi: 30, failed: 6, answerRate: 84 },
  { day: 'Sun', answeredByRules: 62, answeredByAi: 33, failed: 5, answerRate: 87 },
]

Recharts

import {
  Bar,
  CartesianGrid,
  ComposedChart,
  Legend,
  Line,
  ResponsiveContainer,
  Tooltip,
  XAxis,
  YAxis,
} from 'recharts'
import type { ComboChartPoint } from './chartData'

type Props = {
  data: ComboChartPoint[]
}

export function RechartsComboChart({ data }: Props) {
  return (
    <ResponsiveContainer width="100%" height={340}>
      <ComposedChart data={data} margin={{ top: 12, right: 8, bottom: 4, left: 8 }}>
        <CartesianGrid strokeDasharray="3 3" />
        <XAxis dataKey="day" />
        <YAxis yAxisId="count" />
        <YAxis yAxisId="rate" orientation="right" domain={[0, 100]} tickFormatter={(value) => `${value}%`} />
        <Tooltip />
        <Legend />

        <Bar yAxisId="count" dataKey="answeredByRules" name="参照あり回答" stackId="answers" fill="#43a047" />
        <Bar yAxisId="count" dataKey="answeredByAi" name="参照なし回答" stackId="answers" fill="#f9a825" />
        <Bar yAxisId="count" dataKey="failed" name="回答失敗" stackId="answers" fill="#9e9e9e" />
        <Line yAxisId="rate" dataKey="answerRate" name="回答率" type="linear" stroke="#f4511e" dot={false} />
      </ComposedChart>
    </ResponsiveContainer>
  )
}

Rechartsの実装サンプル

MUI X Charts

import Box from '@mui/material/Box'
import { BarPlot } from '@mui/x-charts/BarChart'
import { ChartsAxisHighlight } from '@mui/x-charts/ChartsAxisHighlight'
import { ChartContainer } from '@mui/x-charts/ChartContainer'
import { ChartsTooltip } from '@mui/x-charts/ChartsTooltip'
import { LineHighlightPlot, LinePlot } from '@mui/x-charts/LineChart'
import { ChartsXAxis } from '@mui/x-charts/ChartsXAxis'
import { ChartsYAxis } from '@mui/x-charts/ChartsYAxis'
import type { AllSeriesType } from '@mui/x-charts/models'
import type { ComboChartPoint } from './chartData'

type Props = {
  data: ComboChartPoint[]
}

export function MuiComboChart({ data }: Props) {
  const series: AllSeriesType[] = [
    {
      type: 'bar',
      label: '参照あり回答',
      data: data.map((item) => item.answeredByRules),
      stack: 'answers',
      color: '#43a047',
      yAxisId: 'count',
    },
    {
      type: 'bar',
      label: '参照なし回答',
      data: data.map((item) => item.answeredByAi),
      stack: 'answers',
      color: '#f9a825',
      yAxisId: 'count',
    },
    {
      type: 'bar',
      label: '回答失敗',
      data: data.map((item) => item.failed),
      stack: 'answers',
      color: '#9e9e9e',
      yAxisId: 'count',
    },
    {
      type: 'line',
      label: '回答率',
      data: data.map((item) => item.answerRate),
      color: '#f4511e',
      yAxisId: 'rate',
      curve: 'linear',
      connectNulls: true,
      valueFormatter: (value) => `${value}%`,
    },
  ]

  return (
    <Box sx={{ width: '100%', height: 340 }}>
      <ChartContainer
        series={series}
        margin={{ top: 12, right: 8, bottom: 4, left: 8 }}
        xAxis={[
          {
            id: 'day',
            data: data.map((item) => item.day),
            scaleType: 'band',
          },
        ]}
        yAxis={[
          {
            id: 'count',
            scaleType: 'linear',
            position: 'left',
            min: 0,
            width: 50,
          },
          {
            id: 'rate',
            scaleType: 'linear',
            position: 'right',
            min: 0,
            max: 100,
            width: 55,
            valueFormatter: (value) => `${value}%`,
          },
        ]}
      >
        <ChartsAxisHighlight x="line" />
        <BarPlot />
        <LinePlot />
        <LineHighlightPlot />
        <ChartsXAxis axisId="day" />
        <ChartsYAxis axisId="count" label="件数" />
        <ChartsYAxis axisId="rate" label="回答率" />
        <ChartsTooltip trigger="axis" />
      </ChartContainer>
    </Box>
  )
}

MUI X Chartsの実装サンプル

Recharts vs MUI X Charts比較表

項目 Recharts MUI X Charts
実装コスト 🟢 高柔軟性で複雑な要件も実現しやすい 🟡 基本グラフは手軽だが高度なカスタマイズで実装コスト増
カスタマイズ性 🟢 SVG直接アクセス可能な極めて高い自由度 🟡 MUIテーマ依存でAPI範囲内のカスタマイズ
複合グラフ 🟢 ComposedChartで柔軟な組み合わせが可能 🟡 設定が限定的になる場合あり
ツールチップ 🟢 完全カスタム可能な高柔軟性 🟡 MUI統合は良いが自由度で一歩劣る
学習コスト 🟢 デファクトスタンダードで情報豊富 🟡 MUIユーザーには馴染みやすいが情報量少ない
コンポーネント構成 🟢 各要素が独立コンポーネントで柔軟 🟡 MUIエコシステム統合が前提
開発活発さ 🟢 大規模コミュニティで継続サポート 🟢 MUI全体として活発
利用実績 🟢 プロダクション環境で豊富な実績 🟡 後発だが採用拡大中

RechartsとMUI X Chartsの所感

Rechartsの強み

  • 豊富なドキュメントと実装例: デファクトスタンダードとしての長い歴史があり、Stack Overflowやブログ記事が充実。
  • 複合グラフの実装が容易: ComposedChartコンポーネントで棒グラフと線グラフの重ね合わせがシンプルに実現可能。
  • syncIdによるグラフ間ハイライト同期: 複数のグラフ間でデータポイントのハイライトを同期できる。
  • SVG直接操作による細かいデザイン調整: Reactコンポーネントとして各要素を個別に制御可能。
  • アニメーション内蔵: デフォルトで滑らかなアニメーション効果が適用される。
  • 広範な採用実績: 多くのプロダクトで採用されており、実績豊富。

MUI X Chartsの強み

  • MUIデザインシステムとのシームレスな統合: Material-UIのテーマ、色、タイポグラフィを自動的に継承。
  • MUIユーザーにとって学習コストが低い: 既存のMUI知識がそのまま活かせる。

結論: Rechartsを採用

ダッシュボードの要件として、デザインの細かいカスタマイズ性とインタラクティブ性の高さを重視した結果、Rechartsを採用することに決定しました。

選定理由

  1. カスタマイズ性の優位性: 複合グラフやツールチップのカスタマイズにおいて柔軟な実装が可能
  2. 実装・学習コストのバランス: デファクトスタンダードとしての豊富な情報源があり、長期的なメンテナンス性に優れる

MUI X Chartsは複合グラフのカスタマイズ性やハイライト同期の実装において、Rechartsよりも自分で書く必要のある機能が多く実装コストが高かったです。対応しているグラフの種類もRechartsに比べて少なく、今後の発展に期待という印象です。MUIユーザーでシンプルなグラフを表示したいという用途には良いと思いました。

他のライブラリの検討結果:

  • Victory: React Native対応やレスポンシブ機能など独自の強みをあるのは良いと思いました。ただし、今回の要件では重要では無かったことと、メンテナンスがあまり活発でない印象だったので不採用としました。
  • Nivo: D3.jsの豊富な機能を活かした高度なカスタマイズが可能だが、ライブラリサイズの大きさと学習コストの高さが気になり採用しませんでした。
  • Ant Design Charts: モダンで有力候補ではあったのですが日本語のドキュメント・採用事例の少なさを考慮し今回は見送りました。(公式ドキュメントの英語対応も不十分なので実装の際に苦労しそうだなと感じました。)

まとめ

月並みな感想ですがRechartsはデファクトなだけあって機能面・カスタマイズ性の面で優秀だと思いました。

タスクを通しての感想としては複合グラフについてはドキュメントが少なく、コードを確認しながら調査を進める必要があり苦労しました。今回紹介したライブラリ以外にもHighchartsなどの有償ライブラリを含め様々な選択肢があり面白かったです。

このような技術選定プロセスを経て、私たちは日々最適な開発環境を追求し、ユーザーに価値あるサービスを提供しています。オプティムでは、技術への探求心を持ち、共にサービスを成長させるソフトウェアエンジニアを積極的に募集しています!ご興味をお持ちいただけた方は、ぜひ採用ページもご覧ください。

www.optim.co.jp

参考

おまけ

リリースしたダッシュボード画面

実装したダッシュボード画面のスクリーンショット

本実装は先輩が行いました。実装が爆速&高品質でかっこよかったです。