- 記事一覧 >
- ブログ記事
【React】RechartsのBrushを使ってレンジスライダーを追加
はじめに
React の Recharts を使って、グラフのレンジスライダーを作成しました。
今回、これの実装方法について、書きたいと思います。
この記事に Recharts そのものの解説は有りません。
別記事
React TypeScript ESLint Prettier VSCode のプロジェクト作成
で、開発環境を作って、
Material UI(MUI) Recharts WebSocket FastAPIでリアルタイムグラフ描画
で、ダッシュボード内に Recharts がありますので、そのソースコードがスタート位置です。
具体的には、
の
Chart.tsx
がスタート位置です。
追加実装部分
いきりなり結論から書きますと、以下の部分を追加して、実現しました。
<Brush
dataKey="time"
stroke="#448aff"
height={30}
startIndex={4}
endIndex={6}
>
<AreaChart data={data}>
<CartesianGrid strokeDasharray="3 3" />
<Area
type="monotone"
dataKey="amount"
stroke="none"
fillOpacity={1}
fill="#bdbdbd"
/>
</AreaChart>
</Brush>
Brush など、import に追加が必要でしたが、省略しています。
重要だったのは、以下の2点です。
1.<Brush />
によって、スライダーが出現する。
2.<Brush />
の子要素にチャートを指定すると、スライダーの背景のチャートになる。
特に 2 の方は、最初、気付かず、スライダーに重ねてチャートを配置して、大きさを合わせて...って、無駄な苦労をしていました。知ってしまえばなんてことなかったです。
以降、これを基本とし、続きは各パラメータの話になります。トラベラー(ドラッグできるハンドル部分)の形状を変更できたりします。
$ npm start
で、http://localhost:3000
にアクセスした結果の全体像です。
前述の通り、Material UI のダッシュボードを使っています。
Brush オプション
公式サイト(https://recharts.org/en-US/api/Brush
) の内容を紐解きました。
dataKey
キーになる項目を指定します。今回の場合、
以下のようにキー : 値 を生成していて、time
でスライドさせたいので、dataKey="time"
です。
function createData(time: string, amount?: number) {
return { time, amount };
}
const data = [
createData('00:00', 0),
createData('03:00', 300),
createData('06:00', 600),
createData('09:00', 800),
createData('12:00', 1500),
createData('15:00', 2000),
createData('18:00', 2400),
createData('21:00', 2400),
createData('24:00', undefined),
];
x
レンジスライダーの配置位置 x 座標です。x={100}
の場合、以下のようになります。(親チャートの左端 が 0 です。正の値で右に移動します。指定しない場合、0 です。)
y
レンジスライダーの配置位置 y 座標です。
y={0}
の場合、以下のようになります。(親チャートの上端が 0 です。正の値で下に移動します。指定しない場合、親チャートのすぐ下に配置されます。)
width
レンジスライダーの幅です。
width={200}
の場合、以下のようになります。
height
レンジスライダーの高さです。
height={10}
の場合、以下のようになります。
data
<Brush />
コンポーネントが独自に持つデータ(Array)のようですが、用途が良く分かりませんでした。
チャートに無関係のデータを渡しても表示には影響しません。
travellerWidth
まず、トラベラー(traveller)とは、ドラッグできるハンドルのことです。
travellerWidth でトラベラーの幅を変更できます。travellerWidth={30}
の場合、以下のようになります。
traveller
公式サイトに載っていませんが、型定義を見ていたら、書いてあって、気になったので、試してみました。
React 要素を渡すか、要素を生成する関数を渡して、トラベラーの形状を変更できます。
トラベラーの形状のデフォルトは、以下のようです。
static renderDefaultTraveller(props: any) {
const { x, y, width, height, stroke } = props;
const lineY = Math.floor(y + height / 2) - 1;
return (
<>
<rect x={x} y={y} width={width} height={height} fill={stroke} stroke="none" />
<line x1={x + 1} y1={lineY} x2={x + width - 1} y2={lineY} fill="none" stroke="#fff" />
<line x1={x + 1} y1={lineY + 2} x2={x + width - 1} y2={lineY + 2} fill="none" stroke="#fff" />
</>
);
}
これを、以下のように変更して渡してみます。
function renderCustomTraveller(props: any) {
const { x, y, width, height, stroke } = props;
return (
<rect x={x} y={y} width={width} height={height} fill={stroke} stroke="none" />
);
}
・・・
<Brush
dataKey="time"
stroke="#448aff"
traveller={renderCustomTraveller}
height={30}
startIndex={4}
endIndex={6}
>
結果、こうなります。(少しわかりにくいですが、白い部分が無くなりました。)
直接要素指定の方は、以下のようになります。
<Brush
dataKey="time"
stroke="#448aff"
traveller={
<svg>
<rect
width="3"
height="15"
fill="rgb(0,0,255)"
stroke="rgb(0,0,0)"
/>
</svg>
}
height={30}
startIndex={4}
endIndex={6}
>
結果、こうなります。
今回の場合、<svg>
に以下の props
が渡されて、React.cloneElement
で適用されて、トラベラーの形状が決まって、<rect .../>
によって、その中を描画しているという感じです。
【 svg の props 】
fill: '#fff'
height: 30
stroke: '#448aff'
width: 5
x : 444.5
y: 139
gap
2 にしたら、2 倍の移動距離、2 倍の範囲になるという意味でしょうか、gap={2}
を指定すると、こうなります。
startIndex
endIndex
最初の選択範囲を指定できます。startIndex={4}
endIndex={6}
で、4 目盛目(12:00)~ 6 目盛目(18:00)の範囲を選択した状態が初期状態です。(上記、gap
オプションは指定無しです。)
tickFormatter
目盛りの表示をカスタマイズできます。tickFormatter={(text, index) => `${text}-${index}`}
とした場合、こうなります。
onChange
目盛りの範囲が変わるたびに呼び出されます。
function handleBrushChange(newIndex: any) {
console.log(newIndex);
}
・・・
<Brush
dataKey="time"
stroke="#448aff"
height={30}
startIndex={4}
endIndex={6}
onChange={handleBrushChange}
>
のように、現在位置を取得できて、newIndex
は、 {startIndex: 4, endIndex: 6}
のような値です。
Brush 子要素について
<Brush />
の子要素にチャートを持ってくるとレンジスライダーの背景のチャートになります。
以下のような <AreaChart />
の子要素なのですが、これは、単体でもチャートとして機能するようなごく普通の書き方になります。
一応、説明を加えておきます。
<AreaChart data={data}>
<CartesianGrid strokeDasharray="3 3" />
<Area
type="monotone"
dataKey="amount"
stroke="none"
fillOpacity={1}
fill="#bdbdbd"
/>
</AreaChart>
まず、<AreaChart data={data}>
についてですが、data={data}
の部分は、実際には、親要素のチャートのデータに引きずられて、描画には、反映されないようでした。
つまり、<AreaChart data={[]}>
としても同じ結果になります。
<CartesianGrid strokeDasharray="3 3" />
点線の点の長さ<space>間隔
になります。
type="monotone"
なめらかなカーブを描いた形になります。
dataKey="amount"
親要素チャートの dataKey に合わせます。指定しなかったり、適当に指定はできません。
stroke="none"
縁取りする線の色を指定できます。 "none"
は線無しです。
stroke="red"
とすると、以下のようになります。
fillOpacity={1}
塗りつぶしの透過度になります。
fill="#bdbdbd"
塗りつぶす色です。
<AreaChart />
のデフォルト値は、以下のようになっています。(透過度 0.6 の青っぽい色)
static defaultProps = {
stroke: '#3182bd',
fill: '#3182bd',
fillOpacity: 0.6,
xAxisId: 0,
yAxisId: 0,
legendType: 'line',
connectNulls: false,
// points of area
points: [] as AreaPointItem[],
dot: false,
activeDot: true,
hide: false,
isAnimationActive: !Global.isSsr,
animationBegin: 0,
animationDuration: 1500,
animationEasing: 'ease',
};
小さくて少しわかりにくいですが、<defs><linearGradient...>...</linearGradient></defs>
で以下のようにグラデーション調にもできます。
<AreaChart data={[]}>
<defs>
<linearGradient id="colorUv" x1="0" y1="0" x2="0" y2="1">
<stop offset="5%" stopColor="#8884d8" stopOpacity={0.8} />
<stop offset="95%" stopColor="#8884d8" stopOpacity={0} />
</linearGradient>
</defs>
<CartesianGrid strokeDasharray="3 3" />
<Area
type="monotone"
dataKey="amount"
stroke="#8884d8"
fillOpacity={1}
fill="url(#colorUv)"
/>
</AreaChart>
以上!!
その他、宣伝、誹謗中傷等、当方が不適切と判断した書き込みは、理由の如何を問わず、投稿者に断りなく削除します。
書き込み内容について、一切の責任を負いません。
このコメント機能は、予告無く廃止する可能性があります。ご了承ください。
コメントの削除をご依頼の場合はTwitterのDM等でご連絡ください。