1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Vue3とvue-chartjsでレーダーチャートの実装を試してみる

Last updated at Posted at 2022-10-18

Vue3でレーダーチャートを実装する必要が出てきたため、手元で動かしてみるために必要そうな情報をまとめます。
使用するライブラリとしては、差し当たりGitHubのスター数が多かったvue-chartjsを対象としています。

検証環境の準備

create-vueコマンドで初期化します。

検証用かつJavaScriptでの実装を想定しているため、プラグインの追加は最小限で良いものとします。

❯ npm init vue@latest

Vue.js - The Progressive JavaScript Framework

✔ Project name: … vue3-radar-chart
✔ Add TypeScript? … No
✔ Add JSX Support? … No
✔ Add Vue Router for Single Page Application development? … No
✔ Add Pinia for state management? … No
✔ Add Vitest for Unit Testing? … No
✔ Add Cypress for both Unit and End-to-End testing? … No
✔ Add ESLint for code quality? … Yes
✔ Add Prettier for code formatting? … Yes

vue-chartjsのリファレンスのinstallationより必要なパッケージをインストールします。

npm i vue-chartjs chart.js

この時点で追加されたパッケージのバージョンは以下の通り。

package.json
{
  "name": "vue3-radar-chart",
  "version": "0.0.0",
  "scripts": {
    "dev": "vite",
    "build": "vite build",
    "preview": "vite preview --port 4173",
    "lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs --fix --ignore-path .gitignore"
  },
  "dependencies": {
    "chart.js": "^3.9.1",
    "vue": "^3.2.38",
    "vue-chartjs": "^4.1.2"
  },
  "devDependencies": {
    "@rushstack/eslint-patch": "^1.1.4",
    "@vitejs/plugin-vue": "^3.0.3",
    "@vue/eslint-config-prettier": "^7.0.0",
    "eslint": "^8.22.0",
    "eslint-plugin-vue": "^9.3.0",
    "prettier": "^2.7.1",
    "vite": "^3.0.9"
  }
}

レーダーチャートの実装

vue-chartjsのリファレンスの《Examples》にある実装例を参考にします。

特に必要性はないですが、単一ファイルコンポーネントへの書き換えを行ってみます。JSファイルとして管理したほうが良いのでしょうか。

サンプルはTypeScriptで実装されていますが、今回はJavaScriptでの実装を想定しているため型情報を落とします。

App.vue
<script setup>
import RadarChart from './components/RadarChart.vue'
</script>

<template>
  <RadarChart 
    v-bind:chartId="'my-radar-chart'"
    v-bind:cssClasses="'my-radar-chart-container'" />
</template>

<style>
/* assets/main.cssは全行コメントアウト */
.my-radar-chart-container {
  margin: 0 auto;
  max-width: 500px;
}
</style>
components/RadarChart.vue
<script>
import { defineComponent, h } from 'vue'

import { Radar } from 'vue-chartjs'
import {
  Chart as ChartJS,
  Title,
  Tooltip,
  Legend,
  PointElement,
  RadialLinearScale,
  LineElement
} from 'chart.js'

ChartJS.register(
  Title,
  Tooltip,
  Legend,
  PointElement,
  RadialLinearScale,
  LineElement
)

export default defineComponent({
  name: 'RadarChart',
  components: {
    Radar
  },
  props: {
    chartId: {
      default: 'radar-chart'
    },
    width: {
      default: 400
    },
    height: {
      default: 400
    },
    cssClasses: {
      type: String
    },
    styles: {
      default: () => {}
    },
    plugins: {
      default: () => []
    }
  },
  setup(props) {
    const chartData = {
      labels: [
        'Eating',
        'Drinking',
        'Sleeping',
        'Designing',
        'Coding',
        'Cycling',
        'Running'
      ],
      datasets: [
        {
          label: 'My First dataset',
          backgroundColor: 'rgba(179,181,198,0.2)',
          borderCapStyle: 'square',
          borderColor: 'rgba(179,181,198,1)',
          pointBackgroundColor: 'rgba(179,181,198,1)',
          pointBorderColor: '#fff',
          pointHoverBackgroundColor: '#fff',
          pointHoverBorderColor: 'rgba(179,181,198,1)',
          data: [65, 59, 90, 81, 56, 55, 40]
        },
        {
          label: 'My Second dataset',
          backgroundColor: 'rgba(255,99,132,0.2)',
          borderColor: 'rgba(255,99,132,1)',
          pointBackgroundColor: 'rgba(255,99,132,1)',
          pointBorderColor: '#fff',
          pointHoverBackgroundColor: '#fff',
          pointHoverBorderColor: 'rgba(255,99,132,1)',
          data: [28, 48, 40, 19, 96, 27, 100]
        }
      ]
    }

    const chartOptions = {
      responsive: true,
      maintainAspectRatio: false
    }

    return () =>
      h(Radar, {
        chartData,
        chartOptions,
        chartId: props.chartId,
        width: props.width,
        height: props.height,
        cssClasses: props.cssClasses,
        styles: props.styles,
        plugins: props.plugins
      })
  }
})
</script>

基本的にはvue-chartjsからインポートしたRadarコンポーネントを第1引数に、propschartDatachartOptions をオブジェクトリテラルでまとめたものを第2引数として Vueの h() 関数 に渡し、さらにそれをRender関数に渡して描画させるという構造のようです。

return () =>
  h(Radar, {
    chartData,
    chartOptions,
    chartId: props.chartId,
    width: props.width,
    height: props.height,
    cssClasses: props.cssClasses,
    styles: props.styles,
    plugins: props.plugins
  })

詳細の確認は省略しますが、h()関数の第2引数にはvue-chartjsのRadarコンポーネントに定義されたプロパティを渡すという理解で良さそうです。

また、余談としてRadarChart.vueも<script setup>の記法で書きたかったのですが、以下の通りRender関数との相性が悪いようでした。

このケースでは render 関数はサポートされていません。代わりに、通常の <script> と setup オプションを使用してください。

以下に各プロパティ設定値の定義についての参照先を記載します。

chartId / width / height / cssClasses / styles

グラフが実際に描画される際には<div>タグ、<canvas>タグの入れ子になるようです。開発者ツールで確認することができます。

そしてこれらの設定値は以下のvue-chartjsの実装から、それぞれのタグに対する属性指定であると見えます。

vue-chartjs/src/BaseCharts.ts L263-271

return () =>
  h('div', { style: props.styles, class: props.cssClasses }, [
    h('canvas', {
      id: props.chartId,
      width: props.width,
      height: props.height,
      ref: canvasEl
    })
  ])

chartData

データ構造はChart.jsリファレンスのRadar Chartの《Dataset Properties》の記載に準拠するようです。

Namespace: dataに対応。

以下のリファレンスを確認します。

chartOptions

データ構造はChart.jsリファレンスの《Configuration》配下の記載に準拠するようです。

Namespace: optionsに対応。

差し当たり、responsivemaintainAspectRatioについては以下のリファレンスを確認します。

Appendix

このままの実装だとChart.jsのRadar Chartのサンプルの見た目と異なり、線で囲われたエリアの背景色が付かない点が気になります。

関連情報を調べたところ、Chart.jsからFillerモジュールをインポートすれば背景色が付くことがわかりました。

リファレンスとしてはこちらに記載があるようです。

import {
  Chart as ChartJS,
  Title,
  Tooltip,
  Legend,
  PointElement,
  RadialLinearScale,
  LineElement,
  Filler // 追加
} from 'chart.js'

ChartJS.register(
  Title,
  Tooltip,
  Legend,
  PointElement,
  RadialLinearScale,
  LineElement,
  Filler // 追加
)

vue3-radar-chart.png

インポートして登録するだけでで有効になるようですが、fillプロパティで明示化したほうが良いかもしれません。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?