[nuxt.js] RESAS-APIから人口データを取得する(その2)

前回の記事では、RESAS-APIから人口構成のデータをJSON形式で取得するところまで行きました。今回はそのデータを加工して、「highchart.js」を利用した折れ線グラフを作成してみます。

データの整形

取得したJSONデータを、highchartのグラフに変換しやすい形式に整形してみます。

components/Population.vue
this.population = res.data.result.data.map((item) => {
        return {
          name: item.label,
          data: item.data.map((d) => {
            return {
              x: d.year,
              y: d.value,
            }
          }),
        }
      })

これで、ブラウザに出力されるデータ(population)が下記のようになりました。

[
    {
        "name": "総人口",
        "data": [
            {
                "x": 1960,
                "y": 3906487
            },
            {
                "x": 1965,
                "y": 4309944
            },
            ------ 中略  ------
        ]
    },
    {
        "name": "年少人口",
        "data": [
            {
                "x": 1960,
                "y": 1089072
            },
            {
                "x": 1965,
                "y": 1037393
            },
           ------ 中略  ------
        ]
    },
    {
        "name": "生産年齢人口",
        "data": [
            {
                "x": 1960,
                "y": 2594822
            },
            {
                "x": 1965,
                "y": 3006974
            },
            ------ 中略  ------
        ]
    },
    {
        "name": "老年人口",
        "data": [
            {
                "x": 1960,
                "y": 222593
            },
            {
                "x": 1965,
                "y": 265577
            },
            ------ 中略  ------
        ]
    }
]

highcharts-vueのインストール

vue.jsでhighchartsを利用するためのライブラリ「highcharts-vue」をインストールします。

$npm install --save highcharts
$npm install --save highcharts-vue

公式ドキュメントに従って、plugins配下に「highcharts-vue.js」を新規作成し、下記の通り記述します。

plugins/highcharts-vue.js
import Vue from 'vue'
import HighchartsVue from 'highcharts-vue'

Vue.use(HighchartsVue)

最後に、「nuxt.config.js」でプラグインを有効化します。「mode: 'client’」とするのを忘れないように。

Nuxtがサーバー側でレタリングする際に、クライアント(ブラウザ)は存在しませんので「document」や「window」はサーバー側ではエラーをおこすようです。

nuxt.config.js
  plugins: [
    {
      src: '@/plugins/highcharts-vue',
      mode: 'client',
    },
  ],

Chartコンポーネントの作成

では、highchartを利用してグラフを描画するコンポーネントを作成します。

今回は時系列の折れ線グラフを作成したいので、components直下に「TimeLineChart.vue」というファイルを作成しました。

components/TimeLineChart.vue
<template>
  <highcharts :options="chartOptions" />
</template>

<script>
export default {
  props: {
    displayData: {
      type: Array,
      required: true
    }
  },
  data() {
    return {}
  },
  computed: {
    chartOptions() {
      return {
        chart: {
          height: 350,
          zoomType: 'xy',
          backgroundColor: 'transparent'
        },
        title: {
          text: null
        },
        xAxis: {},
        yAxis: {
          title: {
            text: ''
          },
          labels: {
            formatter() {
              return this.value.toLocaleString()
            }
          }
        },
        responsive: {
          rules: [
            {
              condition: {
                maxheight: 280
              }
            }
          ]
        },
        plotOptions: {
          series: {
            animation: false,
            pointWidth: 10,
            label: {
              connectorAllowed: false
            }
          }
        },
        legend: {
          enabled: false
        },
        tooltip: {
          crosshairs: true,
          shared: true
        },
        credits: {
          enabled: false
        },
        series: this.displayData
      }
    }
  }
}
</script>

propsで「displayData」を取得して、そのデータをグラフに出力します。chartOptionsの設定は、Highcharts公式ドキュメントにたくさんのデモがありますので、そちらを参考に色々試してみると面白いです。

最後に、Population.vueからTimeLineChartを読み込みます。

components/Population.vue
<template>
  <client-only>
    <time-line-chart :display-data="displayData" />
  </client-only>
</template>

<script>
import TimeLineChart from '@/components/TimeLineChart.vue'
export default {
  components: {
    TimeLineChart
  },
  data() {
    return {
      population: [],
      resasUrl: 'population/composition/perYear?',
      prefCode: '28',
      cityCode: '-'
    }
  },
  computed: {
    displayData() {
      return this.population.filter(item => item.name === '総人口')
    }
  },
  created() {
    this.fetchSomething()
  },
  methods: {
    async fetchSomething() {
      const res = await this.$api(
        `${this.resasUrl}prefCode=${this.prefCode}&cityCode=${this.cityCode}`
      )
      this.population = res.data.result.data.map(item => {
        return {
          name: item.label,
          data: item.data.map(d => {
            return {
              x: d.year,
              y: d.value
            }
          })
        }
      })
    }
  }
}
</script>

人口構成のデータは「総人口」「年少人口」「生産年齢人口」「老年人口」の4区分に分かれていますので、filterメソッドを利用して、総人口のデータのみを抽出しています。

 computed: {
    displayData() {
      return this.population.filter(item => item.name === '総人口')
    }
  },

propsでTimeLineChartにdisplayDataを渡してあげるとグラフが表示されます。「総人口」の部分を変更すれば、その他のデータもグラフ表示することができます。

また、今後の拡張性を考えて、RESAS-APIのURLパラメータをdataに設定することとしました。

  data() {
    return {
      population: [],
      resasUrl: 'population/composition/perYear?',
      prefCode: '28',
      cityCode: '-'
    }
  },

この1行で、dataの値からURLを生成することができます。

`${this.resasUrl}prefCode=${this.prefCode}&cityCode=${this.cityCode}`

デザインを整える

以上でグラフは表示させるようになりましたが、今後の拡張性を考えて、少しデザインを整えていきます。

Sassのインストール

まずはCSS 拡張言語「Sass」をインストールします。

$npm install --save node-sass sass-loader @nuxtjs/style-resources

下記のリンクを参考にさせていただきました。

Vuetifyのインストール

次に、マテリアルコンポーネントを提供するVue UIライブラリである「Vuetify」をインストールします。

$npm install --save @nuxtjs/vuetify -D

nuxt.config.jsファイルを更新して、ビルドにVuetifyモジュールを含めます。

nuxt.config.js
buildModules: [
    '@nuxtjs/vuetify',
  ],

コンポーネントの修正

最後に、vuetifyのコンポーネントを利用して、Population.vueのデザインを整えます。

Population.vue
<template>
  <v-card>
    <client-only>
      <v-list-item-title class="title">
            兵庫県の人口推移
          </v-list-item-title>
      <div class="graph">
        <time-line-chart :display-data="displayData" />
      </div>
    </client-only>
  </v-card>
</template>

<script>
import TimeLineChart from '@/components/TimeLineChart.vue'
export default {
  components: {
    TimeLineChart
  },
  data() {
    return {
      population: [],
      resasUrl: 'population/composition/perYear?',
      prefCode: '28',
      cityCode: '-'
    }
  },
  computed: {
    displayData() {
      return this.population.filter(item => item.name === '総人口')
    }
  },
  created() {
    this.fetchSomething()
  },
  methods: {
    async fetchSomething() {
      const res = await this.$api(
        `${this.resasUrl}prefCode=${this.prefCode}&cityCode=${this.cityCode}`
      )
      this.population = res.data.result.data.map(item => {
        return {
          name: item.label,
          data: item.data.map(d => {
            return {
              x: d.year,
              y: d.value
            }
          })
        }
      })
    }
  }
}
</script>

<style lang="sass" scoped>
.title
  margin: 5px
  padding: 5px
  font-size: 1.5em
.v-card
  margin: 20px
  padding: 10px
  height: 100%
.graph
  margin: 10px
  padding: 10px
  height: 100%
</style>

ソースコード

ここまでのコードをGitHubに公開しています。

こちらもご覧ください

本ブログの管理人がNuxt.jsで開発したサイトです。