Nuxt.jsで開発しているWebサービスで、
棒グラフとか線グラフを使いたいなと思い、いろいろ調べた備忘録。
vue-chartjsを使うと、いい感じのグラフが簡単にできた(´ω`)
こんな感じで使ってます!!
登録されている本の総額と総冊数の推移を棒グラフと線グラフで表示!!
色も文字も変えられて、いい感じに(´ω`)
vue-chartjsの使い方
全体の流れはこんな感じ。
- インストール
- コンポーネントを作る
- コンポーネントを配置する
1. インストール
まずはインストール
$ npm install vue-chartjs chart.js --save
2. コンポーネントを作る
<!-- Template Tag can not be merged... -->
<script lang="ts">
import { Component, Vue, Prop, Watch, mixins } from "nuxt-property-decorator";
import Chart from "chart.js";
import VueChart from "vue-chartjs";
const Line = VueChart.Line;
const reactiveProp = VueChart.mixins.reactiveProp;
@Component
export default class ChartLine extends mixins(Line, reactiveProp) {
@Prop({ default: {} }) chartData: Chart.ChartData;
@Prop({ default: {} }) options: Chart.ChartOptions;
mounted() {
this.renderChart(this.chartData, this.options);
}
}
</script>
注意点としては、以下の3つ
-
vue-chartjs
が生成するので、<template>
タグをつけない -
mixins
が重複するので、import Chart from "chart.js";
- データのProp名はreactivePropで決まってるので
chartData
にする
参考: src/mixins/index.js | Github
この例は折れ線グラフのため、Line
をextendsしてるけど、
ほかのチャートは、それぞれコンポーネントを用意すればOK
棒グラフの場合はこんな感じ。
<!-- Template Tag can not be merged... -->
<script lang="ts">
import { Component, Vue, Prop, Watch, mixins } from "nuxt-property-decorator";
import Chart from "chart.js";
import VueChart from "vue-chartjs";
// 棒グラフの場合は、Barを使う
const Bar = VueChart.Bar;
const reactiveProp = VueChart.mixins.reactiveProp;
@Component
// mixinsもBarに変更
export default class ChartLine extends mixins(Bar, reactiveProp) {
@Prop({ default: {} }) chartData: Chart.ChartData;
@Prop({ default: {} }) options: Chart.ChartOptions;
mounted() {
this.renderChart(this.chartData, this.options);
}
}
</script>
3. コンポーネントを配置する
2.で作成したコンポーネントChartLineとChartBarを配置する。
チャートのデータ(chartData)やオプション、スタイルをpropで設定。
<template>
<div class="chart-container">
<ChartLine :chartData="chartData" :options="chartOption" :styles="chartStyles" />
</div>
</template>
<script lang="ts">
import { Component, Vue, Prop } from "nuxt-property-decorator";
import { ChartData, ChartOptions } from "chart.js";
import ChartLine from "~/components/ChartLine.vue";
import ChartBar from "~/components/ChartBar.vue";
@Component({ components: { ChartLine, ChartBar } })
export default class ChartPage extends Vue {
// チャートのデータ
private chartData: ChartData = {
// 横軸のラベル
labels: ["A", "B", "C", "D", "E"],
// データのリスト
datasets: [
{
label: "Data One", // データのラベル
data: [1, 5, 3, 4, 3] // データの値。labelsと同じサイズ
},
{
label: "Data Two",
data: [10, 50, 30, 40, 30]
}
]
};
// チャートのオプション
private chartOption: ChartOptions = {
// アスペクト比を固定しないように変更
maintainAspectRatio: false
};
// チャートのスタイル: <canvas>のstyle属性として設定
private chartStyles = {
height: "100%",
width: "100%"
};
}
</script>
<style lang="scss">
.chart-container {
/**
* vue-chartjsで生成する<canvas>がabsoluteのため、
* relateveを設定
*/
position: relative;
/**
* chartStylesを設定しているので、
* height/wightが有効になる
*/
height: 40vh;
width: 80vw;
margin: 0 auto;
}
</style>
こんな感じでチャートデータを渡すと、こんな感じに(´ω`)
注意: ハマったポイント
グラフ描画だけであれば、データを渡すだけなので簡単(´ω`)
ただ、サイズを変えるのは一苦労...
注意するのは3つ。
-
chartOption
でmaintainAspectRatio: false
を指定 -
chartStyles
でチャートのheight/widthを100%に設定 - 親要素(
.chart-container
)にposition: relative;
vue-chartjsにはchartStyles
以外にもpropがあるので、
ほかは公式ドキュメントを参照
いろいろ設定を変えてみる
色や形を変えるなどチャート自体の設定は、
chart.jsの公式ドキュメントを見ていく感じっぽい。
困ったら、公式ドキュメントをみれば、だいたい行けた感じ(´ω`)
ここからは、実際に使ってみた設定例を紹介。
長いので、目次を見て好きなのを見るのがオススメ。
dataset関連
参考: Charts · Chart.js documentation
ここに載ってる、それぞれのグラフを見るといい感じ♪
線の色を変える: borderColor
private chartData: ChartData = {
labels: ["A", "B", "C", "D", "E"],
datasets: [
{
label: "Data One",
data: [1, 5, 3, 4, 3],
borderColor: "green" // 線の色
},
{
label: "Data Two",
data: [10, 50, 30, 40, 30],
borderColor: "red"
}
]
};
線の色を変えても、棒グラフの色は変わらない。。
塗りつぶしの色を変える: backgroundColor
private chartData: ChartData = {
labels: ["A", "B", "C", "D", "E"],
datasets: [
{
label: "Data One",
data: [1, 5, 3, 4, 3],
borderColor: "green", // 線の色
backgroundColor: "rgba(0, 255, 0, 0.4)" // 塗りつぶしの色
},
{
label: "Data Two",
data: [10, 50, 30, 40, 30],
borderColor: "red",
backgroundColor: "rgba(255, 0, 0, 0.4)"
}
]
};
いい感じになったけど、折れ線グラフの場合は、点の背景色も変わるので、透過しないほうが良いかも。
色関連の値には、rgbaも使える。
塗りつぶしをしない: fill
private chartData: ChartData = {
labels: ["A", "B", "C", "D", "E"],
datasets: [
{
label: "Data One",
data: [1, 5, 3, 4, 3],
borderColor: "green",
backgroundColor: "rgba(0, 255, 0, 0.4)",
fill: false // 折れ線グラフの塗りつぶしを無効化
},
{
label: "Data Two",
data: [10, 50, 30, 40, 30],
borderColor: "red",
backgroundColor: "rgba(255, 0, 0, 0.4)",
fill: false
}
]
};
線を真っ直ぐにする: tension
private chartData: ChartData = {
labels: ["A", "B", "C", "D", "E"],
datasets: [
{
label: "Data One",
data: [1, 5, 3, 4, 3],
borderColor: "green",
backgroundColor: "rgba(0, 255, 0, 0.4)",
fill: false,
tension: 0 // 線を真っ直ぐにする
},
{
label: "Data Two",
data: [10, 50, 30, 40, 30],
borderColor: "red",
backgroundColor: "rgba(255, 0, 0, 0.4)",
fill: false,
tension: 0
}
]
};
折れ線ぽっくなった(´ω`)
折れ線グラフの点の大きさを変える: radius
/ hoverRadius
private chartData: ChartData = {
labels: ["A", "B", "C", "D", "E"],
datasets: [
{
label: "Data One",
data: [1, 5, 3, 4, 3],
borderColor: "green",
backgroundColor: "rgba(0, 255, 0, 0.4)",
fill: false,
tension: 0,
radius: 8, // 点の大きさ
hoverRadius: 20 // 点の大きさ(マウスホバー時)
},
{
label: "Data Two",
data: [10, 50, 30, 40, 30],
borderColor: "red",
backgroundColor: "rgba(255, 0, 0, 0.4)",
fill: false,
tension: 0,
radius: 8,
hoverRadius: 20
}
]
};
グラフを組み合わせる(複合グラフ): type
private chartData: ChartData = {
labels: ["A", "B", "C", "D", "E"],
datasets: [
{
label: "Data One",
data: [1, 5, 3, 4, 3],
borderColor: "green",
backgroundColor: "rgba(0, 255, 0, 0.4)",
fill: false,
tension: 0,
radius: 8,
hoverRadius: 20,
},
{
label: "Data Two",
data: [10, 50, 30, 40, 30],
borderColor: "red",
backgroundColor: "rgba(255, 0, 0, 0.4)",
fill: false,
tension: 0,
radius: 8,
hoverRadius: 20,
type: "line" // 折れ線グラフで表示
}
]
};
Barのときにチャートのtype
を指定すると変更できる。
参考: Mixed · Chart.js documentation
参考: chart.js で複数軸の複合グラフを描く - Qiita
options関連
参考: Configuration · Chart.js documentation
このあたりを見ていくといい感じ。
それぞれの例がわかりくくいけど、このあたりにoption
のどこに書けばいいか書いてある。
また、Y軸関連は、こっち。
参考: Axes · Chart.js documentation
凡例の位置を変える: legend
private chartOption: ChartOptions = {
maintainAspectRatio: false,
legend: { position: "bottom" }, // 凡例の位置を変える
}
参考: Legend · Chart.js documentation
折れ線グラフの点の大きさなどを全体で設定: elements
private chartData: ChartData = {
labels: ["A", "B", "C", "D", "E"],
datasets: [
{
label: "Data One",
data: [1, 5, 3, 4, 3],
borderColor: "green",
backgroundColor: "rgba(0, 255, 0, 0.4)"
},
{
label: "Data Two",
data: [10, 50, 30, 40, 30],
borderColor: "red",
backgroundColor: "rgba(255, 0, 0, 0.4)",
type: "line"
}
]
};
// チャートのオプション
private chartOption: ChartOptions = {
maintainAspectRatio: false,
legend: { position: "bottom" },
elements: {
point: {
radius: 8, // 点の大きさ
hoverRadius: 20 // 点の大きさ(マウスホバー時)
},
line: {
tension: 0, // 線を真っ直ぐにする
fill: false // 折れ線グラフの塗りつぶしを無効化
}
}
};
参考: Elements · Chart.js documentation
Y軸を2つにする: scales.yAxes
private chartData: ChartData = {
labels: ["A", "B", "C", "D", "E"],
datasets: [
{
label: "Data One",
data: [1, 5, 3, 4, 3],
borderColor: "green",
backgroundColor: "rgba(0, 255, 0, 0.4)"
},
{
label: "Data Two",
data: [10, 50, 30, 40, 30],
borderColor: "red",
backgroundColor: "rgba(255, 0, 0, 0.4)",
type: "line",
yAxisID: "y-axis-2" // Y軸のIDを指定
}
]
};
// チャートのオプション
private chartOption: ChartOptions = {
maintainAspectRatio: false,
legend: { position: "bottom" },
elements: {
point: { radius: 8, hoverRadius: 20 },
line: { tension: 0, fill: false }
},
scales: {
yAxes: [
{
// 左の軸。設定はデフォルトのまま
},
{
id: "y-axis-2",
position: "right" // 右に表示する
}
]
}
};
参考: Axes · Chart.js documentation
Y軸のラベルを変える: scales.yAxes.ticks
private chartOption: ChartOptions = {
maintainAspectRatio: false,
legend: { position: "bottom" },
elements: {
point: { radius: 8, hoverRadius: 20 },
line: { tension: 0, fill: false }
},
scales: {
yAxes: [
{
ticks: {
// 左の軸は、先頭に'¥'をつける
callback: (label, index, labels) => "¥" + label.toLocaleString()
}
},
{
id: "y-axis-2",
position: "right",
ticks: {
// 右の軸は、末尾に'冊'をつける
callback: (label, index, labels) => label.toLocaleString() + "冊"
}
}
]
}
};
ただ、このままだとホバーしたときのツールチップの値は変わらない。。
後述するtooltips.callbacks.label
を使って変更が必要。
参考: Axes · Chart.js documentation
参考: コピペでOK!Chart.js の数字を3桁カンマで表示する方法 – console dot log
横軸を非表示にする: scales.yAxes.display
private chartOption: ChartOptions = {
maintainAspectRatio: false,
legend: { position: "bottom" },
elements: {
point: { radius: 8, hoverRadius: 20 },
line: { tension: 0, fill: false }
},
scales: {
yAxes: [
{
ticks: {
callback: (label, index, labels) => "¥" + label.toLocaleString()
}
},
{
id: "y-axis-2",
position: "right",
display: false, // 右の軸を非表示にする
ticks: {
callback: (label, index, labels) => label.toLocaleString() + "冊"
}
}
]
},
}
参考: Axes · Chart.js documentation
ホバー時のツールチップで両方表示にする: tooltips.mode
private chartOption: ChartOptions = {
maintainAspectRatio: false,
legend: { position: "bottom" },
elements: {
point: { radius: 8, hoverRadius: 20 },
line: { tension: 0, fill: false }
},
scales: {
yAxes: [
{ ticks: { callback: (label, index, labels) => "¥" + label.toLocaleString() } },
{
id: "y-axis-2",
position: "right",
ticks: { callback: (label, index, labels) => label.toLocaleString() + "冊" }
}
]
},
tooltips: { // ツールチップの設定
mode: "index" // 全データを表示する
}
};
参考: Tooltip · Chart.js documentation
ツールチップの表示を変える: tooltips.callbacks.label
private chartOption: ChartOptions = {
maintainAspectRatio: false,
legend: { position: "bottom" },
elements: {
point: { radius: 8, hoverRadius: 20 },
line: { tension: 0, fill: false }
},
scales: {
yAxes: [
{ ticks: { callback: (label, index, labels) => "¥" + label.toLocaleString() } },
{
id: "y-axis-2",
position: "right",
ticks: { callback: (label, index, labels) => label.toLocaleString() + "冊" }
}
]
},
tooltips: { // ツールチップの設定
mode: "index",
callbacks: {
label: function(tooltipItem, data) { // ラベルの表示変更
// データが'Data One'か'Data Two'かのインデックスを取得
const index = tooltipItem.datasetIndex;
if (index === 0) {
// 凡例にあるラベルを取得
var label = data.datasets[index].label || "";
if (label) label += ": ";
// 該当データを取得して、先頭に'¥'をつける
label += "¥" + tooltipItem.yLabel.toLocaleString();
return label;
} else {
var label = data.datasets[index].label || "";
if (label) label += ": ";
label += tooltipItem.yLabel.toLocaleString() + "冊";
return label;
}
}
}
}
};
参考: Tooltip · Chart.js documentation
参考: コピペでOK!Chart.js の数字を3桁カンマで表示する方法 – console dot log
その他の便利関数
画面サイズを判定する
window.matchMedia().matches
でメディアクエリがJavaScriptで使えるらしい。。
以下のような関数を作っておけば、
private isDesktop() {
return window.matchMedia("screen and (min-width:768px)").matches;
}
画面サイズなどによって、
- 横軸ラベルの表示/非表示を切り替えたり、
- 適用するスタイルを変えたり、
- 点の大きさを変えたり
できる。
参考: Chart.js でレスポンシブ指定をするとサイズが自由に変更できなくなる - 約束の地
カラーコードのHEXをRGBAに変換する
こんな感じで、HEXカラーコードとopacityからRGBAに変換できる。
private convertHex(hex: string, opacity: number) {
const arr = hex.replace("#", "");
const r = parseInt(arr.substring(0, 2), 16);
const g = parseInt(arr.substring(2, 4), 16);
const b = parseInt(arr.substring(4, 6), 16);
return "rgba(" + r + "," + g + "," + b + "," + opacity + ")";
}
RGBで入力するのは大変なので、これがあると便利(´ω`)
こんな感じで使えます(´ω`)
{
label: "Data Two",
data: [10, 50, 30, 40, 30],
borderColor: "red",
backgroundColor: this.convertHex("#FF0000", 0.4),
}
参考: Hex 2 rgba converter - JSFiddle
おわりに
vue-chartjsをつかえば、
TypeScriptなNuxt.jsでも簡単にいろんなグラフが表示できる(´ω`)
こんなのつくってます!!
積読用の読書管理アプリ 『積読ハウマッチ』をリリースしました!
積読ハウマッチは、Nuxt.js+Firebaseで開発してます!
もしよかったら、遊んでみてくださいヽ(=´▽`=)ノ
こんな感じで、積読本・読了本の総数でどこまでいけるか表示したりしています♪
なんかつけてる(*´ω`*)
— 積読ハウマッチ📚きらぷか (@kira_puka) September 20, 2019
月までは遠いので、まずは近いところから(*´ω`*) pic.twitter.com/JMHoFbv5cg
要望・感想・アドバイスなどあれば、
公式アカウント(@MemoryLoverz)や開発者(@kira_puka)まで