【React + Typescript】Rechartsのグラフをカスタマイズする
Recharts は React で美しいグラフを簡単に描画できる非常に便利なライブラリです。デフォルトの設定のままでも十分に機能的なグラフを描画できるのですが、公式を読み込んでみると、予想外に様々なカスタマイズが可能であると分かりました。本稿では、まず Recharts で基本的な線グラフを描画し、それをカスタマイズして特殊な機能を実装する方法をご説明します。
基本的な線グラフの描画
まずは基本的な折れ線グラフを描画します。表示するデータは次のような英単語の学習記録です。
- 1 日に解いた問題の総数
- 正解した問題の数
- 正解率 (%)
Recharts のインストール
次のコマンドで Recharts をインストールします。
npm install recharts
表示するデータの作成
グラフで表示するデータを作成します。こちらで全コードを確認できます。
import { StudyData } from '../types';
const studyDataList: StudyData[] = [
{
date: '10/01',
問題数: 120,
正解数: 105,
正解率: 88,
},
{
date: '10/02',
問題数: 130,
正解数: 110,
正解率: 85,
},
......
{
date: '10/19',
問題数: 100,
正解数: 90,
正解率: 90,
},
];
export default studyDataList;
export type StudyData = {
date: string;
問題数: number;
正解数: number;
正解率: number;
};
コンポーネントの作成
チャートを描画するコンポーネントを作成します。
import React from 'react';
import {
CartesianGrid,
Legend,
Line,
LineChart,
Tooltip,
XAxis,
YAxis,
} from 'recharts';
import studyDataList from './studyData';
const StudyChart = () => (
<div className="container">
<LineChart
width={700}
height={300}
data={studyDataList}
margin={{
top: 5,
right: 5,
left: 5,
bottom: 5,
}}
>
<CartesianGrid strokeDasharray="3 3" />
<XAxis dataKey="date" />
<YAxis dataKey="問題数" />
<Line type="monotone" dataKey="問題数" stroke="#8884d8" />
<Line type="monotone" dataKey="正解数" stroke="#3ba2f6" />
<Line type="monotone" dataKey="正解率" stroke="#ff0092" />
<Legend />
<Tooltip />
</LineChart>
</div>
);
export default StudyChart;
import React from 'react';
import './App.css';
import StudyChart from './components/StudyChart';
const App = () => (
<div className="App">
<StudyChart />
</div>
);
export default App;
折れ線グラフを描画できました。
グラフの見た目をカスタマイズする
各プロパティを確認しながらグラフをカスタマイズしていきます。
LineChart の基本的なプロパティ
<LineChart
width={700}
height={300}
data={studyDataList}
margin={{
top: 5,
right: 5,
left: 5,
bottom: 5,
}}
>
......
</LineChart>
LineChart を BarChart にすれば棒グラフを、PieChart にすれば円グラフを描画できます。その他にも様々なグラフを描画できますので、公式でご確認ください。ここで使用したプロパティは次のとおりです:
- width: グラフの幅を指定できます。
- height: グラフの高さを指定できます。
- data: 入力元のデータを指定します。
- margin: グラフの周囲の余白を指定できます。
単位はいずれも px です。
CartesianGrid
CartesianGrid コンポーネントを使用するとグラフの背景に描画されたグリッドをカスタマイズできます。様々なプロパティがありますが、使用頻度が高いのは strokeDasharray でしょう。
<CartesianGrid strokeDasharray="3 3" />
- strokeDasharray: グリッドの破線のスタイルを指定できます。
例えば、破線の間隔を短くしたい場合は、
+ <CartesianGrid strokeDasharray="5 1" />
- <CartesianGrid strokeDasharray="3 3" />
このように変更すると、グリッドの破線が下図のように変わります。
XAxis/YAxis
X 軸と Y 軸については XAxis/YAxis の各コンポーネントで設定します。
<XAxis dataKey="date" />
<YAxis dataKey="問題数" />
それぞれ dataKey に設定した値が表示されます。サンプルコードでは X 軸に日付、Y 軸に問題数を表示するように設定しました。
ここで少し気になるのが、デフォルトの設定だと日付が 1 日おきにしか表示されない点です。すべての日付を表示したい場合は、次のように修正します。
+ <XAxis dataKey="date" interval={0} />
- <XAxis dataKey="date" />
すべての日付が重なった状態で表示されました。このままだと見辛いので、X 軸の文字のスタイルや配置を変更します。
+ <XAxis
+ dataKey="date"
+ interval={0}
+ angle={-30}
+ dx={-10}
+ dy={5}
+ tick={{
+ fontSize: 10,
+ fill: '#000',
+ }}
+ />
- <XAxis dataKey="date" interval={0} />
- tick: フォントサイズ、フォントウエイト、文字の色等を指定できます。
- angle: 指定した角度だけ文字を傾けます。
- dx: 文字の横位置を指定します。「-10」を指定すると目盛りから 10px 左に配置されます。
- dy: 文字の縦位置を指定します。「5」を指定すると目盛りから 5px 下に配置されます。
X 軸はすっきりしましたが、グリッドが縦長になってしまったのが気になるため、YAxis を次のように修正します。
+ <YAxis dataKey="問題数" tickCount={8} />
- <YAxis dataKey="問題数" />
- tickCount: 目盛りの数を指定した値に変更します。
グリッドが正方形になりました。
Line
Line コンポーネントで各ラインの設定をします。
<Line type="monotone" dataKey="問題数" stroke="#8884d8" />
<Line type="monotone" dataKey="正解数" stroke="#3ba2f6" />
<Line type="monotone" dataKey="正解率" stroke="#ff0092" />
- type: ラインの種類を指定できます。デフォルトは linear (直線) です。
- dataKey: ここで指定した値が表示されます。
- stroke: ラインの色を指定できます。
- strokeWidth: ラインの太さを指定できます。
正解率を目立たせたいので strokeWidth で太さを指定します。
+ <Line type="monotone" dataKey="正解率" stroke="#ff0092" strokeWidth={2} />
- <Line type="monotone" dataKey="正解率" stroke="#ff0092" />
正解率のラインが太くなりました。
Legend
Legend コンポーネントでグラフの凡例を設定できます。
- align: 凡例の横位置を指定できます。
- verticalAlign: 凡例の縦位置を指定できます。
- iconSize: 凡例のアイコンのサイズを指定できます。
- iconType: 凡例のアイコンの種類を指定できます。
凡例の位置をグラフの上部に変更して、アイコンのサイズと種類を変えてみます。
+ <Legend verticalAlign="top" height={30} iconSize={20} iconType="plainline" />
- <Legend />
Tooltip
Tooltip コンポーネントで、マウスホバーで表示されるツールチップの設定ができます。
- contentStyle: ツールチップのコンテンツのスタイルを指定できます。
- labelStyle: ツールチップのラベルのスタイルを指定できます。
contentStyle と labelStyle を使ってツールチップのスタイルを指定してみましょう。ラベルとボーダーの色を群青色にして、背景を透過グラデーションにしてみます。さらに、見やすいようにフォントを太字にします。
const pStyle = {
color: 'blue',
};
const divStyle = {
background: 'linear-gradient(to right, #fff, #fff8)',
fontWeight: 'bold',
border: 'solid 2px blue',
};
+ <Tooltip contentStyle={divStyle} labelStyle={pStyle} />
- <Tooltip />
次にカーソルをカスタマイズします。ラインを 2px にして、色を群青色に変更します。最後にセパレータの「:」をスペースに変更します。
- separator: 名称と値の間のセパレータを指定できます。デフォルトは「:」です。
- cursor: Boolean、Object、React Element のいずれかの値をとります。false の場合、ツールチップが表示されてもカーソルは表示されません。Object をセットするとカーソルの設定ができます。React Element をセットするとカスタムカーソルを描画できます。
+ <Tooltip
+ contentStyle={divStyle}
+ labelStyle={pStyle}
+ separator=" "
+ cursor={{ stroke: 'blue', strokeWidth: 2 }}
+ />
- <Tooltip contentStyle={divStyle} labelStyle={pStyle} />
ところで、ツールチップに表示されている値に単位を付けたい場合はどうしたらよいでしょうか。
その場合は、Line コンポーネントの unit プロパティで指定します。
- unit: 折れ線グラフに表示されている値に単位を指定できます。
+ <Line type="monotone" dataKey="問題数" stroke="#8054d8" unit="問" />
+ <Line type="monotone" dataKey="正解数" stroke="#3ba2f6" unit="問" />
+ <Line
+ type="monotone"
+ dataKey="正解率"
+ stroke="#ff0092"
+ strokeWidth={2}
+ unit="%"
+ />
- <Line type="monotone" dataKey="問題数" stroke="#8884d8" />
- <Line type="monotone" dataKey="正解数" stroke="#3ba2f6" />
- <Line type="monotone" dataKey="正解率" stroke="#ff0092" strokeWidth={2} />
ツールチップに単位が表示されました。
クリック時の処理を追加する
グラフをクリックしたときに何か処理をさせたいこともあるのではないでしょうか。X 軸の日付をクリックしたときに正解率に応じてメッセージを表示する処理を追加してみましょう。
クリック時の処理その 1
XAxis に onClick 属性を追加します。ついでに、カーソルの形状が変わるように設定しておきましょう。
<XAxis
dataKey="date"
interval={0}
angle={-30}
dx={-10}
dy={5}
tick={{
fontSize: 10,
fill: '#000',
+ cursor: 'pointer',
}}
+ onClick={handleClickXAxis}
/>
event の型を never にしておくと「event['value']」で日付のデータを取得できます。
注: 日付の取得については、もっと良い方法があるかもしれません。ご存じの方は是非コメントにてご教示ください。
const StudyChart = () => {
+ const getAccuracy = (date: string): number => {
+ // 日付から正解率を取得する
+ for (let i = 0; i < studyDataList.length; i += 1) {
+ if (studyDataList[i].date === date) {
+ return studyDataList[i].正解率;
+ }
+ }
+ return 0;
+ };
+
+ const getMessage = (accuracy: number): string => {
+ // 正解率に応じたメッセージを取得する
+ let message = '';
+ if (accuracy > 90) {
+ message = '🎉大変よくできました🎊';
+ } else if (accuracy <= 90 && accuracy > 70) {
+ message = '🌸がんばりました🌼';
+ } else {
+ message = '🥺がんばりましょう🥺';
+ }
+
+ return message;
+ };
+
+ const handleClickXAxis = (event: never): void => {
+ alert(getMessage(getAccuracy(event['value'])));
+ };
return (
......
);
};
export default StudyChart;
X 軸の日付をクリックしてみてください。メッセージが表示されれば成功です。
クリック時の処理その 2
最後に、X 軸の日付ではなく、グラフ内で正解率のドットをクリックするとメッセージが表示されるようにしてみましょう。
Line コンポーネントに activeDot プロパティを追記します。
<Line
type="monotone"
dataKey="正解率"
stroke="#ff0092"
strokeWidth={2}
unit="%"
+ activeDot={{
+ onClick: (_e, payload) => handleClickDot(payload),
+ cursor: 'pointer',
+ }}
/>
このとき payload の中から date (日付のデータ) を取り出す必要がありますが、TypeScript の場合は一筋縄ではいきません。
まずは types/intex.ts に RechartsDotPayload 型を追記します。
export type StudyData = {
date: string;
問題数: number;
正解数: number;
正解率: number;
};
+ export type RechartsDotPayload = {
+ cursor: string;
+ cx: number;
+ cy: number;
+ dataKey: string;
+ fill: string;
+ index: number;
+ r: number;
+ stroke: string;
+ strokeWidth: number;
+ value: number;
+ payload: StudyData;
+ };
次に handleClickDot 関数を記述しますが、このとき payload を unknown 型にして、型アサーションで RechartsDotPayload 型に近づけ、さらに dotPayload.payload を StudyData 型に近づけます。
参考サイト: サバイバル TypeScript
import { RechartsDotPayload, StudyData } from '../types';
......
const StudyChart = () => {
......
const handleClickDot = (payload: unknown): void => {
const dotPayload = payload as Record<keyof RechartsDotPayload, unknown>;
const studyData = dotPayload.payload as Record<keyof StudyData, unknown>;
if (typeof studyData.date === 'string') {
alert(getMessage(getAccuracy(studyData.date)));
}
};
正解率のドットをクリックしてみてください。メッセージが表示されれば成功です。
全コードはこちらで確認できます。
最後に
ここまで読んでくださってありがとうございました。Recharts の柔軟性がご理解いただけましたでしょうか。
ただし、本稿でご紹介したカスタマイズ方法はほんの一部に過ぎません。さらに凝ったグラフを描画したい場合は、公式を読み込んでみることをお勧めいたします。
Discussion