nextjs + react-chartjs-2 でウォーターフォールチャートを描く

やりたいこと

環境

  • "next": "13.4.9",
  • "chart.js": "^4.3.0",
  • "react-chartjs-2": "^5.2.0",

今回触れないこと

  • react / nextjs の話
  • tailwindcss の話
  • chart.js の話
  • TypeScriptの話(勉強中なので許して…)

実装

WaterfallChartのコンポーネントを作成

方針

  • 普通にBarChartを描くコードを作り、dataをいじるだけ

準備

$ npx create-next-app # nextjsアプリケーションの雛形を作成
$ cd <dir> # プロジェクトのディレクトリに移動

$ npm install --save chart.js react-chartjs-2 # 必要なパッケージのインストール

$ npm run dev # 起動

WaterfallChart コンポーネントの作成

まずは普通の棒グラフ

  • src/app/WaterfallChart.tsxを作成
"use client";
import { Bar } from "react-chartjs-2";
import {
  Chart as ChartJS,
  BarElement,
  CategoryScale,
  LinearScale,
  Title,
  Tooltip,
  Legend,
} from "chart.js";

ChartJS.register(
  CategoryScale,
  LinearScale,
  BarElement,
  Title,
  Tooltip,
  Legend
);

const options = {
  plugins: {
    title: {
      display: false,
    },
  },
  responsive: true,
  interaction: {
    mode: "index" as const,
    intersect: false,
  },
  scales: {
    x: {
      stacked: true,
    },
    y: {
      stacked: true,
    },
  },
};

const data = {
  labels: ["期初", "1Q末", "2Q末", "3Q末", "期末"],
  datasets: [
    {
      label: "在庫数",
      data: [100, 300, 200, 50, 200], // 数値は適当です。「在庫数がそんな遷移するわけねーだろ」などの指摘はしない
    },
  ],
};

export const WaterfallChart = () => {
  return <Bar options={options} data={data} />;
};
  • src/app/page.tsxを変更
    • 自動生成されたもののmain要素内を削除
      • tailwindcss関連は今回は変更していない
    • 作成したWaterfallChartを埋め込む
import { WaterfallChart } from "./WaterfallChart";

export default function Home() {
  return (
    <main className="flex min-h-screen flex-col items-center justify-between p-24">
      <WaterfallChart />
    </main>
  );
}
  • 結果表示

棒グラフの表示確認

WaterfallChart形式にする

  • data.datasets[0].data を number[] から (number|number[])[]に変更する
--- a/src/app/WaterfallChart.tsx
+++ b/src/app/WaterfallChart.tsx
@@ -41,11 +41,18 @@ const options = {
 };
 
 const data = {
-  labels: ["期初", "1Q末", "2Q末", "3Q末", "期末"],
+  labels: ["期初", "1Q", "2Q", "3Q", "4Q", "期末"],
   datasets: [
     {
       label: "在庫数",
-      data: [100, 300, 200, 50, 200],
+      data: [
+        100, // number型の要素は通常の棒グラフとして描画
+        [100, 300], // number[]型の要素は0番目の要素~1番目の要素の区間のみをグラフに描画
+        [300, 200],
+        [200, 50],
+        [50, 200],
+        200,
+      ],
     },
   ],
 };
  • 結果表示

ウォーターフォールチャートの表示

増減による色の変更

  • 増加した期間は青、減少した期間は赤でグラフを表示する
diff --git a/src/app/WaterfallChart.tsx b/src/app/WaterfallChart.tsx
index df2f7e1..38f517e 100644
--- a/src/app/WaterfallChart.tsx
+++ b/src/app/WaterfallChart.tsx
@@ -53,10 +53,26 @@ const data = {
         [50, 200],
         200,
       ],
+      backgroundColor: backgroundColor(),
     },
   ],
 };
 
+function backgroundColor() { // datasets.dataの各要素の状態によって色を分岐
+  return (ctx: any) => {
+    if (!ctx.parsed._custom) { // number型要素の場合は黄色で表示
+      return "rgba(255, 255, 102, 0.5)";
+    }
+
+    const start = ctx.parsed._custom.start;
+    const end = ctx.parsed._custom.end;
+
+    return end >= start
+      ? "rgba(102, 178, 255, 0.5)" // 増加
+      : "rgba(255, 102, 178, 0.5)"; // 減少
+  };
+}
+
 export const WaterfallChart = () => {
   return <Bar options={options} data={data} />;
 };
  • 結果表示

色付きウォーターフォールチャート

参考

react-chartjs-2.js.org

www.youtube.com