こんにちは、mabuiです。
Reactで作っている仮想通貨の情報を表示するサンプルにルーティングを導入して、
通貨ごとの個別ページに何を表示しようか考えたところ、
チャートを表示することにしました。
今回はその時に使用したPlotly.jsでのチャート実装方法を紹介します。
動作イメージ
30日分の日足を描画した、シンプルなチャートです。
各足の情報が見れるのと、好きな範囲で期間を狭めたりもできます。
Plotly.jsとは
Plotly.js
おしゃれなグラフを表示できるJavaScriptのライブラリです。
グラフ描画のライブラリは複数ありますが、
インタラクティブ性が高いチャートグラフを表示したかったのと、
以前Python版のPlotly.pyを使用していたのでこちらを使用することにしました。
actionクラスにチャート描画のロジック作成
actions/detail.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 |
import Plotly from "plotly.js-dist"; function groupBy(list, keyGetter) { const map = new Map(); list.forEach((item) => { const key = keyGetter(item); const collection = map.get(key); if (!collection) { map.set(key, [item]); } else { collection.push(item); } }); return map; } function getData(x, open, close, high, low) { const trace1 = { x: x, close: close, decreasing: { line: { color: '#7F7F7F' } }, high: high, increasing: { line: { color: '#17BECF' } }, line: { color: 'rgba(31,119,180,1)' }, low: low, open: open, type: 'candlestick', xaxis: 'x', yaxis: 'y' }; return [trace1]; } function getLayout(id, x, low, high) { const layout = { title: id, dragmode: 'zoom', margin: { r: 10, t: 25, b: 40, l: 60 }, showlegend: false, xaxis: { autorange: true, domain: [0, 1], range: [x[0], x[x.length - 1]], rangeslider: { range: [x[0], x[x.length - 1]] }, title: 'Date', type: 'date' }, yaxis: { autorange: true, domain: [0, 1], range: [Math.min(...low), Math.max(...high)], type: 'linear' } }; return layout; } const Actions = { plot(id) { return function (dispatch) { // 換算する通貨 const vsCurrency = 'jpy'; // チャート取得日数 const days = 30; // coingeckoのapiから対象銘柄(id)のチャート情報取得 const endpoint = "https://api.coingecko.com/api/v3/coins/" + id + "/market_chart?vs_currency=" + vsCurrency + "&days=" + days; const list = []; const x = []; const open = []; const close = []; const high = []; const low = []; fetch(endpoint).then((response) => { const json = response.json(); json.then((value) => { const prices = value.prices; // const marketCaps = value.market_caps; // const totalVolumes = value.total_volumes; for (const key in prices) { const price = prices[key]; const datetime = new Date(price[0]); const ymd = datetime.getFullYear() + '-' + datetime.getMonth() + '-' + datetime.getDate() list.push({'date': ymd, 'price': price[1]}); } }); }).then(() => { setTimeout(() => { // 日付でグルーピングして、日足情報に変換 const grouped = groupBy(list, price => price.date); for (const entity of grouped) { const list = []; for (const price of entity[1]) { list.push(price.price); } // 日付とohlcをそれぞれ取得 x.push(entity[0]); open.push(list[0]); close.push(list[list.length - 1]); high.push(Math.max(...list)); low.push(Math.min(...list)); } const data = getData(x, open, close, high, low); const layout = getLayout(id, x, low, high); // HTMLのdiv要素のグラフ生成 Plotly.newPlot(document.getElementById('plot'), data, layout); }, 100); }); } } } export default Actions |
描画ロジック用にactionクラスを作成しました。
Candlestick Charts in plotly.js
基本的にこちらのPlotlyドキュメントを参考にして、
ドキュメント上で固定値に設定されている値動きのデータに対して、
coingeckoのapiから時系列の値動きデータを引っ張ってきて当て込んでいます。
apiのidには、coinmarketcapからひっぱてきたwebsite_slug(通貨名)
が情報一致していたので使用する荒技を行なっていますが、
サンプルなので良しとします。
coinmarketcapだと値動きデータは有料になってしまいます。
Plotlyのapiリファレンスを参考に、レイアウトの変更ができます。
サンプルではlayoutのプロパティにtitleを追加して、
グラフ上部に通貨名を表示しています。
actionでは最後にPlotly.newPlotメソッドを呼び出しています。
このメソッドはhtml要素を第一引数に指定して、その要素内に
新しく生成したグラフ情報を渡します。
コンポーネントの作成
components/detail.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
import React from 'react'; import { Link } from "react-router-dom"; // コンポーネント作成 class Detail extends React.Component { render() { return ( <div> <p><Link to="/">back</Link></p> <div> <h2>選択したコイン情報</h2> <div id="plot"></div> </div> {this.props.plot(this.props.match.params.id)} </div> ) } } export default Detail |
Plotly.newPlotメソッドで指定したid="plot”のdiv要素を用意して
チャートグラフをレンダリングしています。
要素を直接指定しているので、state, propsにグラフの情報を持たせる必要はなく、
actionのplotメソッドを呼び出して実行するのみでグラフが表示されます。
今回作成したコードのGitHubはこちらです。