chartkick × Highchartsでドーナツグラフを作る
実装したいこと
- ドーナツグラフの真ん中に合計額
- ラベルはグラフ上に表示
- ラベルが細かくて重なってしまう場合は非表示
- 凡例を非表示
chartkick
を使用したら、簡単に実装できました。
ただ、chartkick × Highcharts
についての日本語記事がほぼない&各オプションの指定が公式から探しにくく、苦労しました。
chartkick
では、chart-js
Google Charts
Highcharts
を使用することができます。
最初、chart-js
を使用していたのですが、細かい設定はできない&ラベル表示がデフォルトでないため扱いが難しかったので、途中でHighcharts
に変更しました。見た目もHighcharts
のほうが綺麗な気がします。
環境
rails (6.0.3.4)
"chartkick": "^3.2.1",
"highcharts": "^8.2.2",
chartkickのインストール
GitHub - ankane/chartkick: Create beautiful JavaScript charts with one line of Ruby
gem "chartkick"
Rails6
なので、
yarn add chartkick highcharts
require("chartkick").use(require("highcharts"))
View
line_chart(表示したいデータ)
pie_chart(表示したいデータ)
のように、表示させたいviewファイルに記述するだけでグラフを生成できます。
今回は円グラフを作りたいので、pie_chart
を選択します。
(テンプレートエンジンはslim
を使用)
#公式の例 = pie_chart Goal.group(:name).count
グローバルオプションの追加
今回は1種類のグラフしか使用しないので、全体に適用するグローバルオプションを指定していきます。
Chartkick
で使用できるオプションと、Highcharts
から使うオプションで記述方法が異なります。
Highcharts
のオプションは、library
以下に記述していきます。
Chartkick.options = { donut: true, # ドーナツグラフ width: '400px', colors: [ "#769fcd", "#b9d7ea", "#d6e6f2", "#f7fbfc", ], message: {empty: "データがありません"}, thousands: ",", suffix: "円", legend: false, # 凡例非表示 library: { # ここからHighchartsのオプション title: { # タイトル表示(ここでは、グラフの真ん中に配置して,viewでデータを渡しています。*後述) align: 'center', verticalAlign: 'middle', }, chart: { backgroundColor: 'none', plotBorderWidth: 0, plotShadow: false }, plotOptions: { pie: { dataLabels: { enabled: true, distance: -40, # ラベルの位置調節 allowOverlap: false, # ラベルが重なったとき、非表示にする style: { #ラベルフォントの設定 color: '#555', textAlign: 'center', textOutline: 0, #デフォルトではラベルが白枠で囲まれていてダサいので消す } }, size: '110%', innerSize: '60%', # ドーナツグラフの中の円の大きさ borderWidth: 0, } }, } }
Highchartsの公式でDemoが見られるので、これをcodepenで操作しながらオプションを試しました。 annotations.labelOptions.shadow | Highcharts JS API Reference
View
これは力技で無理やり実装したので、多分もっといい方法がありそう
コントローラーで定義したインスタンス変数@expenses
@sum_of_expenditure
を取得して表示しています。(内容は省略)
= pie_chart @expenses,library: {title: {text: "支出<br> #{@sum_of_expenditure)"}}
グラフ内に表示したいタイトルはグローバルオプションではなく、ローカルオプションで渡します。