i-Vinci TechBlog
株式会社i-Vinciの技術ブログ

Vue.jsでChart.js触ってみた 2

みなさん、こんにちは!
M1 Mac Book Airを年始に購入し、数ヶ月後にM2 Mac Book Airが出てちょっと悔しい藤田です。

以前、「Vue.jsでChart.js触ってみた」という記事を書きました。
今回はその続編です。

成果物

  1. 横軸のラベルの内容を変更する(callbackを利用した軸ラベルの生成)

  1. グラフの再描画をコントロールする(callback内で参照する値の変更に合わせてグラフを再描画する)

    1. と同じ画面を使います
  2. 最大値のプロットを強調する(画像を貼る)

  1. グラフの種類を変更する(Bar, Line, Pie, Radarなど)

について書きます。

ソースコードについてはこちらです。
実際に動かして確かめたり、修正して試したりしてみてください。

横軸のラベルの内容を変更する(callbackを利用した軸ラベルの生成)

横軸メモリに表示するラベルの内容を制御する方法の一つを紹介します。

カスタマイズ方法をcallback関数に記述し、カスタマイズしたい軸の設定にその関数を設定してあげます。(BarLabelCustomized.vue line: 86-90)

ticks: {
    callback: (value, index, ticks) => {
        if (value % 5 === 0) {
            return `${value} day`
        }
    }
}

表示したいラベルをデータや順番で制御したり、文字列を追加したりできます。
今回の実装では、5で割り切れる順番のラベルだけ、"xx day"という書式で表示するようにしています。

グラフの再描画をコントロールする(callback内で参照する値の変更に合わせてグラフを再描画する)

グラフの再描画をコントロールする方法の一つを紹介します。

vue-chartjsは、propsの変更による再描画に弱い時があります。(参考)
グラフの設定を動的に変更しても、意図したタイミングで再描画が走らない場合があります。

上記のリンク先にある通り、

「ミックスインが新しいチャートを描画するとき、this.renderChart(this.chartData, this.options)」を呼び出します

とある通り、何らかの状態変更を行った時に、renderChartメソッドが実行されるようにすれば大丈夫です。

今回の実装では、グラフコンポーネントにpropsとして渡されたflipという状態が変更された時に、グラフコンポーネントでrenderChartメソッドが実行されるようにしました。(BarChart.vue)

ウォッチャflipを監視して

watch: {
    flip() {
        this.reRenderChart()
    }
},

renderChartメソッドを実行します。

reRenderChart() {
    this.renderChart(this.chartData, this.options)
}

親コンポーネント側では、再描画を走らせたいタイミングでflipを変更します。
今回は、y軸に表示するラベルの単位が変更された時にflipを変更することで再描画を制御しました。(BarLabelCustomized.vue line: 43-47

watch: {
    unit() {
        this.flip = !this.flip
    }
},

このウォッチャを削除したりして、挙動がどのように変わるのか試してみてください。

因みにflipというのはフリップフロップ(flip-flop, パタパタやギッコンバっこんに相当する擬音語)回路をイメージして名付けました。
パタンパタンとtrue-falseを入れ替えることでグラフの制御をする、というような感じです。
あまり良い名付けではないかもですね(笑)

最大値のプロットを強調する

グラフに表示した値のうちどれが一番大きい値なのか、などを分かりやすくする方法の一つを紹介します。
対象のデータだけ色を変えて表示する、プロットの大きさを変える、などのいろいろなやり方があると思いますが、今回は「王冠を最大値のプロットの上に表示する」という方法で実装してみました。

表示するデータから最大値のデータの位置を取得して(MaxStampLineChart.vue line: 45-53)

// 最大値の配列位置を取得。より大きな最大値が見つかった場合は、初期化して詰め直す
if (max == null || max < value) {
    max = value
    idxes = []
    idxes.push(i)
} else if (max == value) {
    idxes.push(i)
}

グラフに渡すプラグインで、最大値の位置に画像を表示する処理(MaxStampLineChart.vue line: 96-103)を書いてあげます。

if (maxIdxes.includes(idx)) {
    const _view = d._view
    const stampWidth = 30
    const stampHeight = 30
    const x = _view.x - stampWidth / 2
    const y = _view.y - stampHeight
    ctx.drawImage(crown, x, y, stampWidth, stampHeight)
}

表示する画像データについては、<img>要素, <canvas>要素, <video>要素のいずれかである必要があります。
今回は画像を表示するので、準備した画像から<img>要素を作成しましょう。(参考(MaxStampLineChart.vue line 87-88))

const crown = new Image()
crown.src = Crown

今回は、最大値となるプロットが複数存在する場合を考慮したので、以下のようになる時もあります。

グラフの種類を変更する(Bar, Line, Pie, Radarなど)

表示するグラフの種類を動的に変更する実装を紹介します。

しかし、これはあまり実装面の面白味はないですね。
プルダウンリストで選択されたグラフのタイプを使って、表示したいグラフを呼び出すだけです。(実装箇所(SelectChart.vue))

<components
    :is="chartType"
    :chartData="chartData"
    :options="chartOptions"
/>

一つのインターフェースで様々なグラフが呼び出せるのは良いですね。
強いて言えば、グラフの種類によって「見せ方」が違ってくるはずなので、datasetsoptionをいい感じに設定してあげる必要はありそうですね。

まとめ

データをかっこよくグラフで見せる手段の一つとして、Chart.jsはやはり強力です。
仕様によっては、カスタマイズをする必要があると思います。
私の記事がその参考になると嬉しいです。