TechVue.jsJapanese

vue3-charts with TypeScript – Area Chart 編

Vue.js
This entry is part 1 of 7 in the series Vue3 / vue3-charts with TypeScript

本記事では Vue.js v3とTypeScriptを使用して、面グラフ (Area Chart) を作成する方法を紹介します。vue3-charts ライブラリを活用し、TypeScript を有効にした Vue3 プロジェクト において、簡単に グラフ を追加する方法を ステップバイステップ で説明します。実装にあたり必要となる エラーハンドリング から スタイリング、 インタラクティブ な要素の追加まで、実践的な アプローチ を通じて Vue3 での グラフ作成を実現していこうと思います。

本記事では 面グラフ (Area Chart) に関する コンポーネント 部分についてのみ説明するため、前提となる プロジェクト の概要については、以下の記事を参考にしてください。

面グラフ コンポーネント 作成

[ads]

面グラフ (Area Chart) を components/AreaChart.vue に実装してきます。Area Chart に関しては 公式からベースとなるコードが提供されていますので、これを ベース に TypeScript で動作するようにしていきます。

<scirpt>, <template> の順番だけ、Vue3 with TypeScript のお作法に従って修正した コンポーネント は以下の通りです。

<script lang="ts">
import { defineComponent, ref } from 'vue'
import { Chart, Grid, Line } from 'vue3-charts'
import { plByMonth } from '@/data'

export default defineComponent({
  name: 'LineChart',
  components: { Chart, Grid, Line },
  setup() {
    const data = ref(plByMonth)
    const direction = ref('horizontal')
    const margin = ref({
      left: 0,
      top: 20,
      right: 20,
      bottom: 0
    })

    const axis = ref({
      primary: {
        type: 'band'
      },
      secondary: {
        domain: ['dataMin', 'dataMax + 100'],
        type: 'linear',
        ticks: 8
      }
    })

    return { data, direction, margin, axis }
  }
})
</script>
<template>
  <Chart
    :size="{ width: 500, height: 420 }"
    :data="data"
    :margin="margin"
    :direction="direction"
    :axis="axis">

    <template #layers>
      <Grid strokeDasharray="2,2" />
      <Area :dataKeys="['name', 'pl']" type="monotone" :areaStyle="{ fill: 'url(#grad)' }" />
      <Line
        :dataKeys="['name', 'pl']"
        type="monotone"
        :lineStyle="{
          stroke: '#9f7aea'
        }"
      />
      <Marker v-if="marker" :value="1000" label="Mean." color="green" strokeWidth="2" strokeDasharray="6 6" />
      <defs>
        <linearGradient id="grad" gradientTransform="rotate(90)">
          <stop offset="0%" stop-color="#be90ff" stop-opacity="1" />
          <stop offset="100%" stop-color="white" stop-opacity="0.4" />
        </linearGradient>
      </defs>
    </template>

    <template #widgets>
      <Tooltip
        borderColor="#48CAE4"
        :config="{
          pl: { color: '#9f7aea' },
          avg: { hide: true },
          inc: { hide: true }
        }"
      />
    </template>

  </Chart>
</template>

ただし、この状態でいくつか エラー が出ています。次の セクション では、まずこれらに対処していきます。

AreaChart.vue エラー 対処

[ads]

Chart コンポーネントプロパティ (direction) 修正

以下の箇所で、 TS2322 エラー が発生しています。

AreaChart.vue
    <Chart :size="{ width: 500, height: 420 }" :data="data" :margin="margin" :direction="direction" :axis="axis">

エラー 内容は以下の通り

Type 'string' is not assignable to type 'Direction | undefined'.ts(2322)

LineChart.vue, BarChart.vue でも同様の エラー でしたので、AreaChart.vue でも同様の対処を実施していきます。

AreaChart.vue

Ref の インポート を追加します

import { defineComponent, ref, Ref } from 'vue'

Direction 型 を vue3-charts ライブラリからインポートします

import { Direction } from 'vue3-charts/src/types'

defineComponentsetup() で、 direction を Direction 型として設定します。

    setup() {
        const data = ref(plByMonth)
        const direction: Ref<Direction> = ref('horizontal')

Chart コンポーネントプロパティ (axis) 修正

direction と同様に、 Chart コンポーネント 設定部分で axis プロパティ にも エラー が発生しています。

AreaChart.vue
    <Chart :size="{ width: 500, height: 420 }" :data="data" :margin="margin" :direction="direction" :axis="axis">

エラー 内容は以下のとおりです。

Type '{ primary: { type: string; }; secondary: { domain: string[]; type: string; ticks: number; }; }' is not assignable to type 'ChartAxis'.ts(2322)

axis プロパティ の エラー も LineChart.vue と同じ内容ですので、同様に対処していきます。

AreaChart.vue

ChartAxis 型 を vue3-charts ライブラリからインポートします

import { Direction, ChartAxis } from 'vue3-charts/src/types'

defineComponentsetup() で、 axis を ChartAxis 型として設定します。

        const axis: Ref<ChartAxis> = ref({

ChartAxis 型に必要な primary/domain プロパティ を追加します。

        const axis: Ref<ChartAxis> = ref({
            primary: {
                domain: ['dataMin', 'dataMax'],
                type: 'band'
            },
            secondary: {
                domain: ['dataMin', 'dataMax + 100'],
                type: 'linear',
                ticks: 8
            }
        })

Area コンポーネント 追加

ベースのコード をよく見ると、 Area コンポーネント が インポート されていませんので、 Area コンポーネント を利用可能にしていきます。

AreaChart.vue

Area コンポーネント を vue3-charts からインポートします

import { Chart, Grid, Line, Area } from 'vue3-charts'

defineComponent で、Area コンポーネント を 登録します。 また合わせて、 defineComponentnameLineChart から AreaChart に変更しておきます。

export default defineComponent({
    name: 'AreaChart',
    components: { Chart, Grid, Line, Area },

Marker コンポーネント 修正

Area Chart (面グラフ) 自体ではありませんが、 ベースとなるコード には Marker サブコンポーネント が定義されています。 ただし、以下の エラー が発生しているため、対応していきます。

AreaChart.vue

エラー が発生しているのは以下の箇所です。

            <Marker v-if="marker" :value="1000" label="Mean." color="green" strokeWidth="2" strokeDasharray="6 6" />

エラー の内容は以下のようなものです。

Property 'marker' does not exist on type '{ $: ComponentInternalInstance; $data: {}; $props: Partial<{}> & Omit<{} & VNodeProps & AllowedComponentProps & ComponentCustomProps & Readonly<...>, never>; ... 10 more ...; $watch<T extends string | ((...args: any) => any)>(source: T, cb: T extends (...args: any) => infer R ? (args_0: R, args_1: R) => any : (...ar...'.ts(2339)

ベースとなるコード をよく見ると、 <template> で 定義している Marker コンポーネント が インポート されていませんので、 Area コンポーネント 同様の対処をしていきます。

AreaChart.vue

Marker コンポーネント を vue3-charts からインポートします

import { Chart, Grid, Marker, Line, Area } from 'vue3-charts'

defineComponentMarker コンポーネント を 登録します。

export default defineComponent({
    name: 'AreaChart',
    components: { Chart, Grid, Marker, Line, Area },

Marker コンポーネント の プロパティ で v-if="marker" を用いていますが、 marker という変数は使われていないので、削除します。 また、strokeWidth 箇所で以下の エラー が発生しています。

Type 'string' is not assignable to type 'number'.ts(2322)

strokeWidth は 値を数値として渡す必要があるため、 v-bind を用いて :strokeWidth="10" と記載することで数値を渡せるようになり、 エラー を解消することができます。

<Marker :value="1000" label="Mean." color="green" :strokeWidth="2" strokeDasharray="6 6" />

Tooltip 対応

ベースとなるコード の <template> には Tooltip コンポーネントの記載がありますが、 インポート されていないため表示されていません。 以下の修正を加えて、 Tooltip が表示されるようにしていきます。

AreaChart.vue

Tooltip コンポーネント を vue3-charts からインポートします

import { Chart, Grid, Tooltip, Marker, Line, Area } from 'vue3-charts'

あわせて、 defineComponentcomponentsTooltip を登録します。

export default defineComponent({
    name: 'AreaChart',
    components: { Chart, Grid, Tooltip, Marker, Line, Area },

ここまでの修正を終えた状態で プロジェクト を実行すると、以下のような グラフ が表示されるようになります。

データポイント に カーソル をあわせることで Tooltip が表示されます。

eslint エラー 定義済み名称 への 対処 (Marker, Line, Area)

ここでは 発生している eslint エラー に対処していきます。今回利用した コンポート名 Marker, Line, Area は プログラム 今回のような 小さなプロジェクト では問題になることはありませんが、HTML 標準 として規定されている名称の コンポーネント は使うべきではないため、as を用いて 別名で利用することにします。

AreaChart.vue

以下の箇所で eslint エラー が発生しています。

export default defineComponent({
    name: 'AreaChart',
    components: { Chart, Grid, Marker, Line, Area },

エラー の内容は以下のとおりです。

Name "Marker" is reserved.eslintvue/no-reserved-component-names

同じ エラー が Line, Area にも出ています。 予約済みの名称と重複してしまっているため別名を用いることが推奨されています。それぞれ ChartMarker, LineChartComponent, AreaChartComponent という別名で インポートしていきます。

import { 
    Chart, Grid, 
    Marker as ChartMarker,
    Line as LineChartComponent,
    Area as AreaChartComponent
} from 'vue3-charts'

あわせて、 defineComponent も更新します。

export default defineComponent({
    name: 'AreaChart',
    components: { 
        Chart, Grid, Tooltip, 
        ChartMarker, LineChartComponent, AreaChartComponent 
    },

テンプレート にも更新した コンポーネント名称を反映していきます。

<template>
    <Chart :size="{ width: 500, height: 420 }" :data="data" :margin="margin" :direction="direction" :axis="axis">

        <template #layers>
            <Grid strokeDasharray="2,2" />
            <AreaChartComponent :dataKeys="['name', 'pl']" type="monotone" :areaStyle="{ fill: 'url(#grad)' }" />
            <LineChartComponent :dataKeys="['name', 'pl']" type="monotone" :lineStyle="{
                stroke: '#9f7aea'
            }" />
            <ChartMarker :value="1000" label="Mean." color="green" :strokeWidth="2" strokeDasharray="6 6" />
            <defs>
                <linearGradient id="grad" gradientTransform="rotate(90)">
                    <stop offset="0%" stop-color="#be90ff" stop-opacity="1" />
                    <stop offset="100%" stop-color="white" stop-opacity="0.4" />
                </linearGradient>
            </defs>
        </template>

        <template #widgets>
            <Tooltip borderColor="#48CAE4" :config="{
                pl: { color: '#9f7aea' },
                avg: { hide: true },
                inc: { hide: true }
            }" />
        </template>

    </Chart>
</template>

面グラフ の カスタマイズ

[ads]

ここまでで、 ベースとなるコード を使って 面グラフ が描画されるようになりました。 この セクション では、 面グラフ を少し カスタマイズ してみます。

純粋な 面グラフ だけ表示

ベースとなるコード は Area, Line が併用されている形ですが、 Area だけの シンプル な構成の見た目を確認してみます。 ここでは LineChartComponentChartMarker を削除して 純粋に 面グラフ だけを表示した状態から カスタマイズしていきます。

AreaChart.vue
            <AreaChartComponent :dataKeys="['name', 'pl']" type="monotone" :areaStyle="{ fill: 'url(#grad)' }" />
            <!-- <LineChartComponent :dataKeys="['name', 'pl']" type="monotone" :lineStyle="{
                stroke: '#9f7aea'
            }" /> -->
            <!-- <ChartMarker :value="1000" label="Mean." color="green" :strokeWidth="2" strokeDasharray="6 6" /> -->

データポイント に カーソル を合わせると ツールチップ が表示された 純粋な 面グラフ が表示されていることがわかります。

以降の セクション では Area コンポーネント の プロパティ に注目して、いくつかの カスタマイズ を実際に施していきます。

areaStyle プロパティ(面の塗りつぶし)

AreaChartComponentareaStyle を設定することで 面グラフ の 色合い などを変更することができます。

AreaChart.vue

ベースとなるコード では "{ fill: 'url(#grad)' }" という値が指定されています。

<AreaChartComponent :dataKeys="['name', 'pl']" type="monotone" :areaStyle="{ fill: 'url(#grad)' }" />

この場合、 以下の箇所で詳細な設定を指定することになります。

            <defs>
                <linearGradient id="grad" gradientTransform="rotate(90)">
                    <stop offset="0%" stop-color="#FF6347" stop-opacity="1" />
                    <stop offset="100%" stop-color="white" stop-opacity="0.4" />
                </linearGradient>
            </defs>

単色塗りつぶし

まずは最も シンプル な形でみていきます。

AreaChart.vue

面グラフ を赤で塗りつぶしてみます。

<AreaChartComponent :dataKeys="['name', 'pl']" type="monotone" :areaStyle="{ fill: 'red' }" />

グラデーション

ベースとなるコード は最初から少し応用編といってもよい グラデーション塗りつぶし が実装されています。 これを少し カスタマイズ してみます。

AreaChart.vue

仕組みとしては、 #grad という形で linearGardient を定義する形です。

<AreaChartComponent :dataKeys="['name', 'pl']" type="monotone" :areaStyle="{ fill: 'url(#grad)' }" />
            <defs>
                <linearGradient id="grad" gradientTransform="rotate(90)">
                    <stop offset="0%" stop-color="#be90ff" stop-opacity="1" />
                    <stop offset="100%" stop-color="white" stop-opacity="0.4" />
                </linearGradient>
            </defs>
offset
stop-color
stop-opacity

以降では、 linearGradient の値を変化させて カスタマイズ させていきます。

単色 グラデーション

AreaChart.vue

同一色でグラデーションさせてみます。透明度 (stop-opacity) を変化させることで実現します。

            <defs>                
                <linearGradient id="grad" gradientTransform="rotate(90)">
                    <stop offset="0%" stop-color="red" stop-opacity="1" />
                    <stop offset="100%" stop-color="red" stop-opacity="0.2" />
                </linearGradient>
            </defs>

月毎にグラデーションされるのではなく、全体のなかで大きな値が最も濃くなる点が特徴です。

2色 グラデーション

AreaChart.vue

緑黄色、赤でグラデーションさせてみます。 stop offset ごとの stop-color を変えることで実現します。

            <defs>                
                <linearGradient id="grad" gradientTransform="rotate(90)">
                    <stop offset="0%" stop-color="green" stop-opacity="1" />
                    <stop offset="100%" stop-color="red" stop-opacity="0.4" />
                </linearGradient>
            </defs>

今回のように、突出したデータがあるとグラデーションの効果が出にくいかもしれません。

3色 グラデーション

AreaChart.vue

緑と赤とでグラデーションさせてみます。中間色として stop offset="50%" のデータを追加することで実現します。なお、わかりやすいように、 透明度は全て 1 にしています。

            <defs>                
                <linearGradient id="grad" gradientTransform="rotate(90)">
                    <stop offset="0%" stop-color="green" stop-opacity="1" />
                    <stop offset="50%" stop-color="yellow" stop-opacity="1" />
                    <stop offset="100%" stop-color="red" stop-opacity="1" />
                </linearGradient>
            </defs>

今回のように、突出したデータがある場合は、2色より3色の方がメリハリが効きそうですね。

style プロパティ(面の形)

ここでは style プロパティ を用いて 面グラフ の形を カスタマイズ していきます。 単色塗り の 面グラフ を基にしていきます。 なお、style を指定しない場合は デフォルトとして normal が採用されます。 指定できる スタイル は 以下の 4種類 です。

normal

AreaChart.vue

以下のように type="normal" とすることで、monotone に比べ、緩やかなカーブを描く 面グラフとなります。 傾向を強調した形 と言ってもいいかもしれません。

<AreaChartComponent :dataKeys="['name', 'pl']" type="normal" :areaStyle="{ fill: 'red' }" />

monotone

AreaChart.vue

以下のように type="monotone" とすることで、カーブを描いた 面グラフ となります。 公式

<AreaChartComponent :dataKeys="['name', 'pl']" type="monotone" :areaStyle="{ fill: 'red' }" />

step

AreaChart.vue

以下のように type="step" とすることで、階段状の 面グラフ となります。

<AreaChartComponent :dataKeys="['name', 'pl']" type="step" :areaStyle="{ fill: 'red' }" />

natural

AreaChart.vue

以下のように type="natural" とすることで、monotone に比べ、緩やかなカーブを描く 面グラフとなります。 傾向を強調した形 と言ってもいいかもしれません。

<AreaChartComponent :dataKeys="['name', 'pl']" type="natural" :areaStyle="{ fill: 'red' }" />

まとめ

[ads]

Vue3 と TypeScript での 面グラフ 作成における解説はここまでです。vue3-charts を用いた 面グラフ の実装から、エラー対処、カスタマイズ、といったさまざまな技術を探求してきました。これらの知識を活用し、あなたのプロジェクトに魅力的なビジュアルを加えてみてください。

TS2322 に対処する

必要な コンポーネント Area, Tooltip, Marker を追加する

style, areaStyle プロパティ を駆使して カスタマイズする

Series Navigation
Ads