SoFunction
Updated on 2025-04-13

Example of code to create interactive charts using Vue and ECharts

introduction

Data visualization is an important component in modern web applications. It not only helps users better understand complex data, but also improves user experience.

Technical background

is a progressive JavaScript framework for building user interfaces. It is easy to get started while providing powerful features to build complex single-page applications. Vue's responsive system makes data binding simple and efficient.

ECharts

ECharts is an open source visualization library based on JavaScript, developed by Baidu Front-end Technology Department. It offers a wide range of chart types and highly customizable configuration options for a variety of data visualization needs.

Project construction

First, you need to create a new Vue project. If the Vue CLI has not been installed, you can install it through the following command:

npm install -g @vue/cli

Then, create a new Vue project:

vue create my-chart-app
cd my-chart-app

Next, install ECharts:

npm install echarts

Code description

  1. Chart container

    • userefGets the DOM element of the chart container.
    • existonMountedInitialize the ECharts instance in the life cycle hook and call itupdateChartMethod update the chart configuration.
  2. Chart type selection

    • usev-modelBind the chart type and call it when the change is selectedupdateChartMethod update the chart.
  3. Data Editing

    • Two modal dialogs are provided, one for editing a single data point and the other for editing all data points.
    • Use Computational PropertiesselectedXAxisValueandselectedSeriesValueTo synchronize the X-axis value and series data values ​​of the selected data point.
    • supplyaddDataPointanddeleteDataPointMethod to add and delete data points and call them after operationupdateChartMethod update the chart.
  4. Chart configuration

    • Set different chart configurations according to different chart types (line chart, histogram, pie chart, scatter chart).
    • uselabelAttributes are resident to display numerical labels and used in pie chartslabelLineProperties set the style of the connection line.

Code implementation

<script setup lang="ts">
import { defineComponent, onMounted, ref, computed } from 'vue'
import * as echarts from 'echarts'

// Define chart container referencesconst chartRef = ref<HTMLDivElement | null>(null)
let chartInstance:  | null = null

// Define chart dataconst xAxisData = ref(["Initial Phase", "Development Phase", "Complete Phase"])
const seriesData = ref([10, 50, 80])

const chartType = ref('line')

// Initialize the chartconst initChart = () => {
    if (!) return
    chartInstance = ()

    updateChart()
}

// Update chart configurationconst updateChart = () => {
    if (!chartInstance) return

    let option;

    switch () {
        case 'line':
        case 'bar':
            option = {
                tooltip: {
                    trigger: 'axis',
                    formatter: '{b}: {c}'
                },
                legend: {
                    orient: 'vertical',
                    left: 'left',
                    textStyle: { color: '#666' }
                },
                xAxis: {
                    show: true,
                    type: 'category',
                    data: ,
                    axisLine: { lineStyle: { color: '#999' } },
                    axisLabel: { color: '#666' }
                },
                yAxis: {
                    show: true,
                    type: 'value',
                    axisLine: { lineStyle: { color: '#999' } },
                    splitLine: { lineStyle: { color: ['#eaeaea'], width: 1, type: 'dashed' } },
                    axisLabel: { color: '#666' }
                },
                series: [
                    {
                        data: ,
                        type: ,
                        itemStyle: { color: '#5470c6' },
                        label: { //Resident display value tag                            show: true,
                            position: 'top', // Tag location                            color: '#666'
                        },
                        ...( === 'line' ? { areaStyle: { color: 'rgba(84, 112, 198, 0.3)' } } : {})
                    }
                ],
                grid: { left: '5%', right: '5%', bottom: '10%' }
            };
            break;
        case 'pie':
            option = {
                tooltip: {
                    trigger: 'item',
                    formatter: '{a} <br/>{b}: {c} ({d}%)'
                },
                legend: {
                    orient: 'vertical',
                    left: 'left',
                    textStyle: { color: '#666' }
                },
                xAxis: {
                    show: false // Exclusively disable the X-axis                },
                yAxis: {
                    show: false // explicitly disable the Y axis                },
                series: [
                    {
                        name: 'data',
                        type: 'pie',
                        radius: ['40%', '70%'],
                        avoidLabelOverlap: false,
                        label: {
                            show: true, //Resident display value tag                            position: 'outside', // Tag location                            formatter: '{b}: {c} ({d}%)', // Customize the label format                            color: '#666'
                        },
                        emphasis: {
                            label: { show: true, fontSize: '20', fontWeight: 'bold' }
                        },
                        data: ((name, index) => ({
                            name,
                            value: [index],
                            itemStyle: { color: ['#5470c6', '#91cc75', '#fac858'][index % 3] }
                        }))
                    }
                ]
            };
            break;
        case 'scatter':
            option = {
                tooltip: {
                    trigger: 'item',
                    formatter: '{b}: {c}'
                },
                legend: {
                    orient: 'vertical',
                    left: 'left',
                    textStyle: { color: '#666' }
                },
                xAxis: {
                    show: true,
                    type: 'category',
                    data: ,
                    axisLine: { lineStyle: { color: '#999' } },
                    axisLabel: { color: '#666' }
                },
                yAxis: {
                    show: true,
                    type: 'value',
                    axisLine: { lineStyle: { color: '#999' } },
                    splitLine: { lineStyle: { color: ['#eaeaea'], width: 1, type: 'dashed' } },
                    axisLabel: { color: '#666' }
                },
                series: [
                    {
                        symbolSize: 20,
                        data: ((name, index) => [index, [index]]),
                        type: 'scatter',
                        label: { //Resident display value tag                            show: true,
                            position: 'top', // Tag location                            color: '#666'
                        },
                        itemStyle: { color: '#5470c6' }
                    }
                ]
            };
            break;
        default:
            option = {};
    }

    (option)
    ('option',option)
}

// Listen to the graph click eventonMounted(() => {
    initChart()

    chartInstance?.on('click', (params) => {
         = true;
         =  ?? -1;
    });
})

// Handle X-axis data changesconst handleXAxisChange = (index: number, value: string) => {
    [index] = value
    updateChart()
}

// Process series of data changesconst handleSeriesChange = (index: number, value: string) => {
    [index] = parseFloat(value)
    updateChart()
}

// Modal dialog box statusconst showModalSingle = ref(false);
const showModalAll = ref(false);
const selectedDataIndex = ref(-1);

// Calculate properties: Get the selected X-axis valueconst selectedXAxisValue = computed({
    get: () => [],
    set: (newValue) => handleXAxisChange(, newValue)
});

// Calculation attribute: Get the selected series data valueconst selectedSeriesValue = computed({
    get: () => [].toString(),
    set: (newValue) => handleSeriesChange(, newValue)
});

// Add data pointsconst addDataPoint = () => {
    (`New data points ${ + 1}`);
    (0);
    updateChart(); // Update the chart to reflect the added data points};

// Delete data pointsconst deleteDataPoint = (index: number) => {
    (index, 1);
    (index, 1);
    updateChart();
};
</script>

<template>
  <!-- Chart container -->
  <div ref="chartRef" :style="{ width: '100%', height: '400px', backgroundColor: '#fff', borderRadius: '8px', boxShadow: '0 2px 4px rgba(0, 0, 0, 0.1)' }"></div>

  <!-- Chart type selection -->
  <select v-model="chartType" @change="updateChart" style="margin-top: 20px; padding: 8px; border: 1px solid #ccc; border-radius: 4px;">
    <option value="line">Line chart</option>
    <option value="bar">Bar chart</option>
    <option value="pie">Pie chart</option>
    <option value="scatter">Scatter plot</option>
  </select>

  <!-- Edit all data button -->
  <button @click="showModalAll = true" style="margin-top: 20px; margin-left: 10px; padding: 8px 16px; background-color: #5470c6; color: #fff; border: none; border-radius: 4px; cursor: pointer;">
    Edit all data
  </button>

  <!-- Single Data Point Modal Dialog -->
  <div v-if="showModalSingle" style="position: fixed; top: 0; left: 0; right: 0; bottom: 0; background-color: rgba(0, 0, 0, 0.5); display: flex; justify-content: center; align-items: center;">
    <div style="background-color: white; padding: 20px; border-radius: 8px; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);">
      <h3>Edit data points {{ selectedDataIndex + 1 }}</h3>
      <div>
        <label>XAxis data:</label>
        <input 
          :value="selectedXAxisValue" 
          @input="selectedXAxisValue = ($ as HTMLInputElement).value" 
          style="width: 100%; padding: 8px; margin-top: 5px; border: 1px solid #ccc; border-radius: 4px;"
        />
      </div>
      <div>
        <label>Series data:</label>
        <input 
          :value="selectedSeriesValue" 
          @input="selectedSeriesValue = ($ as HTMLInputElement).value" 
          style="width: 100%; padding: 8px; margin-top: 5px; border: 1px solid #ccc; border-radius: 4px;"
        />
      </div>
      <button @click="showModalSingle = false" style="margin-top: 10px; padding: 8px 16px; background-color: #5470c6; color: #fff; border: none; border-radius: 4px; cursor: pointer;">
        closure
      </button>
    </div>
  </div>

  <!-- All data modal dialogs -->
  <div v-if="showModalAll" style="position: fixed; top: 0; left: 0; right: 0; bottom: 0; background-color: rgba(0, 0, 0, 0.5); display: flex; justify-content: center; align-items: center;">
    <div style="background-color: white; padding: 20px; border-radius: 8px; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); width: 80%; max-width: 600px;">
      <h3>Edit all data</h3>
      <table style="width: 100%; border-collapse: collapse;">
        <thead>
          <tr>
            &lt;th style="padding: 8px; text-align: left; background-color: #f2f2f2; color: #333;">Serial number</th>            &lt;th style="padding: 8px; text-align: left; background-color: #f2f2f2; color: #333;">X-axis data</th>            &lt;th style="padding: 8px; text-align: left; background-color: #f2f2f2; color: #333;">Series of data</th>            &lt;th style="padding: 8px; text-align: left; background-color: #f2f2f2; color: #333;">Operation</th>          &lt;/tr&gt;
        &lt;/thead&gt;
        &lt;tbody&gt;
          &lt;tr v-for="(item, index) in xAxisData" :key="index"&gt;
            &lt;td style="border-bottom: 1px solid #ddd; padding: 8px;"&gt;{{ index + 1 }}&lt;/td&gt;
            &lt;td style="border-bottom: 1px solid #ddd; padding: 8px;"&gt;
              &lt;input 
                :value="xAxisData[index]" 
                @input="handleXAxisChange(index, ($ as HTMLInputElement).value)" 
                style="width: 100%; padding: 8px; border: 1px solid #ccc; border-radius: 4px;"
              /&gt;
            &lt;/td&gt;
            &lt;td style="border-bottom: 1px solid #ddd; padding: 8px;"&gt;
              &lt;input 
                :value="seriesData[index]" 
                @input="handleSeriesChange(index, ($ as HTMLInputElement).value)" 
                style="width: 100%; padding: 8px; border: 1px solid #ccc; border-radius: 4px;"
              /&gt;
            &lt;/td&gt;
            &lt;td style="border-bottom: 1px solid #ddd; padding: 8px;"&gt;
              &lt;button @click="deleteDataPoint(index)" style="padding: 8px 16px; background-color: #ff4d4f; color: #fff; border: none; border-radius: 4px; cursor: pointer;"&gt;
                delete
              &lt;/button&gt;
            &lt;/td&gt;
          &lt;/tr&gt;
        &lt;/tbody&gt;
      &lt;/table&gt;
      &lt;button @click="addDataPoint" style="margin-top: 10px; padding: 8px 16px; background-color: #5470c6; color: #fff; border: none; border-radius: 4px; cursor: pointer;"&gt;
        Add data points
      &lt;/button&gt;
      &lt;button @click="showModalAll = false" style="margin-top: 10px; padding: 8px 16px; background-color: #5470c6; color: #fff; border: none; border-radius: 4px; cursor: pointer;"&gt;
        closure
      &lt;/button&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/template&gt;

This is the end of this article about code examples for creating interactive charts using Vue and ECharts. For more related Vue ECharts interactive chart content, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!