Vue2とEChartsを連携させたインタラクティブなグラフ描画手法

環境構築と依存関係の導入

Vue2プロジェクトにEChartsを導入し、動的なデータ可視化を実現するための基盤を構築します。必要なパッケージをインストールし、コンポーネント内で利用できるようにします。

npm install echarts element-ui axios

コンポーネントのスクリプトセクションでEChartsを読み込みます。

import * as echarts from 'echarts';
import axios from 'axios';

検索条件フォームの実装

Element UIを用いて、デバイス選択、メトリクス選択、および期間指定のためのインラインフォームを構築します。期間の指定には、開始日と終了日を個別に設定するのではなく、日付範囲ピッカーを活用してコードを簡潔にします。

<template>
  <div class="visualization-container">
    <el-form :inline="true" :model="searchCriteria" ref="filterForm" :rules="validationRules">
      <el-form-item label="デバイス" prop="equipmentId">
        <el-select v-model="searchCriteria.equipmentId" @change="fetchMetrics" placeholder="デバイスを選択">
          <el-option v-for="dev in equipmentList" :key="dev.id" :label="dev.name" :value="dev.id" />
        </el-select>
      </el-form-item>
      <el-form-item label="メトリクス" prop="metricId">
        <el-select v-model="searchCriteria.metricId" placeholder="メトリクスを選択">
          <el-option v-for="m in metricList" :key="m.id" :label="m.name" :value="m.id" />
        </el-select>
      </el-form-item>
      <el-form-item label="期間" prop="dateRange">
        <el-date-picker
          v-model="searchCriteria.dateRange"
          type="daterange"
          range-separator="〜"
          start-placeholder="開始日"
          end-placeholder="終了日"
        />
      </el-form-item>
      <el-form-item>
        <el-button type="primary" @click="executeSearch">検索</el-button>
        <el-button @click="resetCriteria">リセット</el-button>
      </el-form-item>
    </el-form>
    <div ref="chartWrapper" style="width: 100%; height: 450px;"></div>
  </div>
</template>

データ取得とグラフ描画のロジック

フォームの検証を行い、条件を満たした場合にAPIへデータをリクエストします。取得したデータをEChartsが要求する形式に変換し、グラフを描画します。非同期処理にはasync/awaitを活用し、可読性を高めています。

export default {
  data() {
    return {
      searchCriteria: {
        equipmentId: null,
        metricId: null,
        dateRange: []
      },
      equipmentList: [],
      metricList: [],
      validationRules: {
        equipmentId: [{ required: true, message: 'デバイスを選択してください', trigger: 'change' }],
        metricId: [{ required: true, message: 'メトリクスを選択してください', trigger: 'change' }],
        dateRange: [{ required: true, message: '期間を選択してください', trigger: 'change' }]
      },
      chartInstance: null,
      lineChartConfig: {
        xAxis: { type: 'category', data: [] },
        yAxis: { type: 'value' },
        series: [{ data: [], type: 'line' }]
      }
    };
  },
  mounted() {
    this.fetchDevices();
  },
  methods: {
    async executeSearch() {
      this.$refs.filterForm.validate(async (isValid) => {
        if (!isValid) return;
        
        const [startDate, endDate] = this.searchCriteria.dateRange;
        try {
          const response = await axios.get('/api/v1/trend', {
            params: {
              equipmentId: this.searchCriteria.equipmentId,
              metricId: this.searchCriteria.metricId,
              startTime: startDate.getTime(),
              endTime: endDate.getTime()
            }
          });
          
          if (response.data.success) {
            this.processChartData(response.data.records);
          } else {
            this.$message.error(response.data.message);
          }
        } catch (error) {
          this.$message.error('データの取得に失敗しました');
        }
      });
    },
    processChartData(records) {
      const timeAxis = [];
      const valueAxis = [];
      
      records.forEach((record) => {
        timeAxis.push(record.timestamp);
        valueAxis.push(record.value);
      });
      
      this.lineChartConfig.xAxis.data = timeAxis;
      this.lineChartConfig.series[0].data = valueAxis;
      
      this.renderChart();
    },
    renderChart() {
      if (!this.chartInstance) {
        this.chartInstance = echarts.init(this.$refs.chartWrapper);
      }
      this.chartInstance.setOption(this.lineChartConfig, true);
    },
    resetCriteria() {
      this.$refs.filterForm.resetFields();
    }
  }
};

マスタデータの取得

画面表示時にデバイスの一覧を取得し、デバイス選択変更時には紐づくメトリクス一覧を取得するロジックです。

    async fetchDevices() {
      const response = await axios.get('/api/v1/devices');
      if (response.data.success) {
        this.equipmentList = response.data.result;
      }
    },
    async fetchMetrics(equipmentId) {
      const response = await axios.get(`/api/v1/metrics?equipmentId=${equipmentId}`);
      if (response.data.success) {
        this.metricList = response.data.result;
        this.searchCriteria.metricId = null;
      }
    }

タグ: Vue2 ECharts ElementUI Axios DataVisualization

7月11日 21:44 投稿