Ateam Lifestyle x cyma Advent Calendar 2018の12日目は、株式会社エイチームライフスタイルのエンジニア@kazenomachiが担当します。
本稿では、Reactのチャート描画ライブラリRechartsで様々なチャートを出力する方法を紹介していきます。
やりたいこと
- Reactで、簡単なグラフ(折れ線グラフや棒グラフ)を描画したい
- できるだけ簡単に分かりやすいコードで書きたい
Rechartsとは?
Reactで簡単にSVGチャートを描画できるライブラリです。
他にもチャートを描画することができるライブラリは多くありますが、今回は以下の点を理由にRechartsを選びました。
- Reactコンポーネントを使ってReactらしくコードを書ける(読みやすい)
- ある程度カスタマイズも可能で、レスポンシブ対応も簡単そう
基本編
まずは早速、基本のグラフを書いてみます。
公式ドキュメントに従って実装すれば簡単にグラフを作ることができます。
折れ線グラフ
See the Pen 折れ線グラフ by Nao Kubota (@kazenomachi) on CodePen.
今回グラフで表示したデータは以下の通りです。
X軸に日付、Y軸に気温を表示しています。
const data = [
{ date: moment('2018-12-01').unix() * 1000, 最高気温: 10, 最低気温: 1 },
{ date: moment('2018-12-02').unix() * 1000, 最高気温: 12, 最低気温: 4 },
{ date: moment('2018-12-03').unix() * 1000, 最高気温: 18, 最低気温: 8 },
{ date: moment('2018-12-04').unix() * 1000, 最高気温: 10, 最低気温: 0 },
{ date: moment('2018-12-05').unix() * 1000, 最高気温: 9, 最低気温: 1 },
{ date: moment('2018-12-06').unix() * 1000, 最高気温: 13, 最低気温: 2 },
{ date: moment('2018-12-07').unix() * 1000, 最高気温: 16, 最低気温: 5 },
]
グラフは以下の通りです。
折れ線グラフでは LineChart
を使います。
ResponsiveContainer
で囲めば、レスポンシブになります。便利!
<ResponsiveContainer width="95%">
<LineChart
data={this.props.data} // 表示するデータ
margin={{top: 5, right: 50, left: 50, bottom: 25}}>
<XAxis // X軸
dataKey="date" // X軸の基準となるデータ項目名
tickFormatter={(props) => moment(props).format('YYYY/MM/DD')} // X軸を YYYY/MM/DD 形式で表示します
/>
<YAxis // Y軸
domain={['dataMin', 'dataMax']}
ticks={[-10,-5,0,5,10,15,20,25,30]} // Y軸に表示する温度
unit="℃" // Y軸の単位
/>
<CartesianGrid // ガイド線の表示
stroke="#ccc"
strokeDasharray="3 3"
/>
<Tooltip // ツールチップの表示
labelFormatter={(props) => moment(props).format('YYYY/MM/DD(ddd)')} // ラベルの表示フォーマット(日付)
/>
<Line // 最高気温のデータを表示
name="最高気温"
dataKey="最高気温" // this.props.data のキー
stroke="salmon" // 線の色
unit="℃" //単位
/>
<Line // 最低気温のデータを表示
name="最低気温"
dataKey="最低気温" // this.props.data のキー
stroke="skyblue" // 線の色
unit="℃" //単位
/>
</LineChart>
</ResponsiveContainer>
棒グラフ
渡すデータは同じですが、LineChart
を BarChart
にすれば棒グラフになります。
See the Pen 棒グラフ by Nao Kubota (@kazenomachi) on CodePen.
棒グラフ(データを配列で渡す)
BarChart
ではデータを配列で渡すこともできます。表示が以下のように変わります。
See the Pen 棒グラフ2 by Nao Kubota (@kazenomachi) on CodePen.
応用編
React
のstate
を使って操作できるグラフを作ってみます。
凡例をクリックし、表示項目を指定できるようにします。
See the Pen stateでグラフの表示を切り替える by Nao Kubota (@kazenomachi) on CodePen.
state
は以下の通り初期化します。
constructor(props) {
super()
this.state = {
data: props.data, // グラフデータ
chartColors: { // グラフ表示色
総売上: '#ffd700',
商品A: '#3cb371',
商品B: '#87ceeb',
来客数: '#9370db'
},
leftYAxisUnit: '円', // Y軸左側に表示する単位
rightYAxisUnit: '人', // Y軸右側に表示する単位
leftYAxis: ['総売上', '商品A', '商品B'], // Y軸左側に合わせる項目
rightYAxis: ['来客数'], // Y軸右側に合わせる項目
disabled: ['来客数'] // 非表示項目
}
}
項目名がクリックされた時に行う処理を実装します。
setState
でstate
のdisabled
項目を変更します。
toggleChart = toggleKey => {
if (_.includes(this.state.disabled, toggleKey)) {
// 表示されている項目を非表示にします
this.setState({
// disabledから指定されたキーを削除
disabled: this.state.disabled.filter(value => value !== toggleKey)
})
} else {
// 非表示の項目を表示します
this.setState({
// disabledに指定されたキーを追加
disabled: this.state.disabled.concat(toggleKey)
})
}
}
グラフの上に表示する凡例をカスタマイズします。
onClick
でtoggleChart
を呼び出すようにします。
customizedLegend = () => {
return(
<div className="customized-legend">
{
_.toPairs(this.state.chartColors).map(pair => { // 項目名と表示色のペア
const disable = _.includes(this.state.disabled, pair[0])
const style = {
marginRight: 10,
color: disable ? "#ccc" : "#000", // 非表示項目のフォントの色を変えます
cursor: 'pointer'
}
return (
<span
className="legend-item"
onClick={() => this.toggleChart(pair[0])} // onClickでtoggleChartを実行します
style={style}
>
{ // 凡例の ● を表示 }
<Surface width={20} height={20} viewBox="0 0 20 20">
<Symbols cx={13} cy={13} type="circle" size={100} fill={pair[1]} />
{
// 非表示項目の場合 ● を ○ にするため、円の中に白丸を描きます
disable && (
<Symbols
cx={13}
cy={13}
type="circle"
size={50}
fill="#fff"
/>
)
}
</Surface>
{ // 項目名を表示 }
<span>{pair[0]}</span>
</span>
)
})
}
</div>
)
}
グラフ部分は以下の通りとなります。
Legend
のcontent
でcustomizedLegend
を表示するようにしています。
state
が変わると、this.state
を使用している部分が再描画されるので、グラフを動かしながら読んでみるとおもしろいと思います。
今回はdisabled
項目しか変更していませんが、例えばchartColors
を変えるとグラフの色が変わったりします。
<ResponsiveContainer width="95%">
<ComposedChart
data={this.state.data}
margin={{top: 0, right: 50, left: 50, bottom: 25}}>
<XAxis
dataKey="date"
tickFormatter={(props) => moment(props).format('YYYY/MM/DD')}
/>
<YAxis
orientation="left"
yAxisId="leftYAxis"
domain={['dataMin', 'dataMax']}
ticks={[600000,700000,800000,900000,1000000,1100000,1200000,1300000]}
unit="円"
/>
<YAxis
orientation="right"
yAxisId="rightYAxis"
domain={['dataMin', 'dataMax']}
ticks={[700,800,900,1000,1100,1200,1300,1400]}
unit="人"
/>
<CartesianGrid
stroke="#ccc"
strokeDasharray="3 3"
/>
<Tooltip
labelFormatter={(props) => moment(props).format('YYYY/MM/DD(ddd)')}
/>
<Legend
verticalAlign="top"
height={50}
align="left"
content={this.customizedLegend()}
/>
{
_.toPairs(this.state.chartColors)
.filter(pair => !_.includes(this.state.disabled, pair[0]))
.map(pair => (
<Bar
key={pair[0]}
name={pair[0]}
dataKey={pair[0]}
stackId={_.includes(['商品A', '商品B'], pair[0]) ? 'sales' : ''}
yAxisId={_.includes(this.state.leftYAxis, pair[0]) ? 'leftYAxis' : 'rightYAxis'}
unit={_.includes(this.state.leftYAxis, pair[0]) ? this.state.leftYAxisUnit : this.state.rightYAxisUnit}
fill={pair[1]}
/>
))
}
</ComposedChart>
</ResponsiveContainer>
まとめ
データを用意してコンポーネントに渡し、いくつかオプションを指定するだけで簡単にグラフを表示することができました。
stateを使って再描画するような処理も、Reactらしく簡単に書けて良かったです。
今回紹介したグラフ以外にも、公式サイトのExamplesやAPIドキュメントにあるように、様々なグラフを簡単に実装できます。
ドキュメントに無いような特殊なグラフを実装するのには向いていませんが、手早く簡単に一般的なグラフを実装したい時には役に立つと思います!
Ateam Lifestyle x cyma Advent Calendar 2018、明日は @kiitan さんに書いてもらう予定です。ぜひお楽しみに!
エイチームグループでは、一緒に働けるチャレンジ精神旺盛な仲間を募集しています。興味を持たれた方はぜひエイチームグループ採用サイトを御覧ください。
https://www.a-tm.co.jp/recruit/