Dynamic data update in Vue Chart component

18 Nov 201824 minutes to read

The Vue Charts component provides methods to dynamically modify data without requiring a full chart refresh. This enables real-time data visualization, interactive features, and responsive user experiences. Common scenarios include adding sensor readings, removing outdated data points, replacing entire datasets, and enabling click-based data manipulation.

Adding a new data point

Use the addPoint method to dynamically append a new data point to a series. This is useful for real-time data streams, user interactions, or incremental data loading. The method accepts the following parameters:

  • Data point (required): The new data object to append to the series (must match the datasource structure)
  • Animation duration (optional): Duration in milliseconds for the entry animation
<template>
  <div id="app">
    <ejs-chart ref="chart" id="container" :primaryXAxis='primaryXAxis' :primaryYAxis='primaryYAxis' :title='title' :legendSettings='legendSettings' :chartArea='chartArea'>
        <e-series-collection>
          <e-series :dataSource='seriesData' type='Spline' xName='x' yName='y' name='Users' width=2 :marker='marker'></e-series>
        </e-series-collection>
    </ejs-chart>
    <ejs-button id='add' @click.native='onClick'>Add Point</ejs-button>
  </div>
</template>
<script setup>
import { provide, ref } from "vue";
import { ChartComponent as EjsChart, SeriesCollectionDirective as ESeriesCollection, SeriesDirective as ESeries, SplineSeries, Category, DataLabel, Legend } from "@syncfusion/ej2-vue-charts";
import { ButtonComponent as EjsButton } from "@syncfusion/ej2-vue-buttons";

const chart = ref(null);
const seriesData = [
  { x: "Germany", y: 72 },
  { x: "Russia", y: 103.1 },
  { x: "Brazil", y: 139.1 },
  { x: "India", y: 462.1 },
  { x: "China", y: 721.4 },
  { x: "USA", y: 286.9 },
  { x: "Great Britain", y: 115.1 },
  { x: "Nigeria", y: 97.2 }
];
const primaryXAxis = {
  valueType: 'Category', 
  enableTrim: false, 
  majorTickLines: { width: 0 }, 
  majorGridLines: { width: 0 }
};
const primaryYAxis = {
  minimum: 0, 
  maximum: 800, 
  labelFormat: '{value}M', 
  edgeLabelPlacement: 'Shift'
};
const marker = {
  visible: true, 
  dataLabel: { 
    visible: true, 
    position: 'Top', 
    font: { 
      fontWeight: '600' 
    } 
  }
};
const title = 'Internet Users - 2016';
const legendSettings = {
  visible: false
};
const chartArea = {
  border: {
    width: 1
  }
};

provide('chart', [SplineSeries, Category, DataLabel, Legend]);

const onClick = function() {     
  this.$refs.chart.ej2Instances.series[0].addPoint({ x: 'Japan', y: 118.2 });
};

</script>
<style>
  #container {
    height: 350px;
  }
</style>
<template>
    <div id="app">
        <ejs-chart ref="chart" id="container" :primaryXAxis='primaryXAxis' :primaryYAxis='primaryYAxis' :title='title' :legendSettings='legendSettings' :chartArea='chartArea'>
          <e-series-collection>
            <e-series :dataSource='seriesData' type='Spline' xName='x' yName='y' name='Users' width=2 :marker='marker'></e-series>
          </e-series-collection>
        </ejs-chart>
        <ejs-button id='add' @click.native='onClick'>Add Point</ejs-button>
    </div>
</template>
<script>
import Vue from "vue";
import { ChartPlugin, SplineSeries, Category, DataLabel, Legend } from "@syncfusion/ej2-vue-charts";
import { ButtonPlugin } from "@syncfusion/ej2-vue-buttons";

Vue.use(ChartPlugin);
Vue.use(ButtonPlugin);

export default {
  data() {
    return {
        seriesData: [
          { x: "Germany", y: 72 },
          { x: "Russia", y: 103.1 },
          { x: "Brazil", y: 139.1 },
          { x: "India", y: 462.1 },
          { x: "China", y: 721.4 },
          { x: "USA", y: 286.9 },
          { x: "Great Britain", y: 115.1 },
          { x: "Nigeria", y: 97.2 }
        ],
        primaryXAxis: {
          valueType: 'Category', 
          enableTrim: false, 
          majorTickLines: { width: 0 }, 
          majorGridLines: { width: 0 }
        },
        primaryYAxis:
        {
          minimum: 0, 
          maximum: 800, 
          labelFormat: '{value}M', 
          edgeLabelPlacement: 'Shift'
        },
        marker: {
          visible: true, 
          dataLabel: { 
            visible: true, 
            position: 'Top', 
            font: { 
              fontWeight: '600' 
            } 
          }
        },
        title: 'Internet Users - 2016',
        legendSettings: {
          visible: false
        },
        chartArea: {
          border: {
            width: 1
          }
        }
    };
  },
  provide: {
    chart: [SplineSeries, Category, DataLabel, Legend]
  },
  methods: {
      onClick: function() {     
        this.$refs.chart.ej2Instances.series[0].addPoint({ x: 'Japan', y: 118.2 });
      }
  }
};
</script>
<style>
  #container {
    height: 350px;
  }
</style>

Removing an existing data point

Use the removePoint method to dynamically delete a data point from a series by its index. This is useful for filtering data, removing outliers, or responding to user actions. The method accepts the following parameters:

  • Point index (required): The zero-based index of the data point to remove
  • Animation duration (optional): Duration in milliseconds for the exit animation
<template>
  <div id="app">
    <ejs-chart ref="chart" id="container" :primaryXAxis='primaryXAxis' :primaryYAxis='primaryYAxis' :title='title' :legendSettings='legendSettings' :chartArea='chartArea'>
        <e-series-collection>
          <e-series :dataSource='seriesData' type='Spline' xName='x' yName='y' name='Users' width=2 :marker='marker'></e-series>
        </e-series-collection>
    </ejs-chart>
    <ejs-button id='add' @click.native='onClick'>Add Point</ejs-button>
  </div>
</template>
<script setup>
import { provide, ref } from "vue";
import { ChartComponent as EjsChart, SeriesCollectionDirective as ESeriesCollection, SeriesDirective as ESeries, SplineSeries, Category, DataLabel, Legend } from "@syncfusion/ej2-vue-charts";
import { ButtonComponent as EjsButton } from "@syncfusion/ej2-vue-buttons";

const chart = ref(null);
const seriesData = [
  { x: "Germany", y: 72 },
  { x: "Russia", y: 103.1 },
  { x: "Brazil", y: 139.1 },
  { x: "India", y: 462.1 },
  { x: "China", y: 721.4 },
  { x: "USA", y: 286.9 },
  { x: "Great Britain", y: 115.1 },
  { x: "Nigeria", y: 97.2 }
];
const primaryXAxis = {
  valueType: 'Category', 
  enableTrim: false, 
  majorTickLines: { width: 0 }, 
  majorGridLines: { width: 0 }
};
const primaryYAxis = {
  minimum: 0, 
  maximum: 800, 
  labelFormat: '{value}M', 
  edgeLabelPlacement: 'Shift'
};
const marker = {
  visible: true, 
  dataLabel: { 
    visible: true, 
    position: 'Top', 
    font: { 
      fontWeight: '600' 
    } 
  }
};
const title = 'Internet Users - 2016';
const legendSettings = {
  visible: false
};
const chartArea = {
  border: {
    width: 1
  }
};

provide('chart', [SplineSeries, Category, DataLabel, Legend]);

const onClick = function() {     
  this.$refs.chart.ej2Instances.series[0].removePoint(0);
};

</script>
<style>
  #container {
    height: 350px;
  }
</style>
<template>
    <div id="app">
        <ejs-chart ref="chart" id="container" :primaryXAxis='primaryXAxis' :primaryYAxis='primaryYAxis' :title='title' :legendSettings='legendSettings' :chartArea='chartArea'>
          <e-series-collection>
            <e-series :dataSource='seriesData' type='Spline' xName='x' yName='y' name='Users' width=2 :marker='marker'></e-series>
          </e-series-collection>
        </ejs-chart>
        <ejs-button id='remove' @click.native='onClick'>Remove Point</ejs-button>
    </div>
</template>
<script>
import Vue from "vue";
import { ChartPlugin, SplineSeries, Category, DataLabel, Legend } from "@syncfusion/ej2-vue-charts";
import { ButtonPlugin } from "@syncfusion/ej2-vue-buttons";

Vue.use(ChartPlugin);
Vue.use(ButtonPlugin);

export default {
  data() {
    return {
        seriesData: [
          { x: "Germany", y: 72 },
          { x: "Russia", y: 103.1 },
          { x: "Brazil", y: 139.1 },
          { x: "India", y: 462.1 },
          { x: "China", y: 721.4 },
          { x: "USA", y: 286.9 },
          { x: "Great Britain", y: 115.1 },
          { x: "Nigeria", y: 97.2 }
        ],
        primaryXAxis: {
          valueType: 'Category', 
          enableTrim: false, 
          majorTickLines: { width: 0 }, 
          majorGridLines: { width: 0 }
        },
        primaryYAxis:
        {
          minimum: 0, 
          maximum: 800, 
          labelFormat: '{value}M', 
          edgeLabelPlacement: 'Shift'
        },
        marker: {
          visible: true, 
          dataLabel: { 
            visible: true, 
            position: 'Top', 
            font: { 
              fontWeight: '600' 
            } 
          }
        },
        title: 'Internet Users - 2016',
        legendSettings: {
          visible: false
        },
        chartArea: {
          border: {
            width: 1
          }
        }
    };
  },
  provide: {
    chart: [SplineSeries, Category, DataLabel, Legend]
  },
  methods: {
      onClick: function() {     
        this.$refs.chart.ej2Instances.series[0].removePoint(0);
      }
  }
};
</script>
<style>
  #container {
    height: 350px;
  }
</style>

Replacing entire data points

Use the setData method to replace all data points in a series with a new dataset. This is useful for category switching, time range changes, or complete data refreshes. The method accepts the following parameters:

  • New data source (required): The complete new dataset array to display
  • Animation duration (optional): Duration in milliseconds for the transition animation
<template>
  <div id="app">
    <ejs-chart ref="chart" id="container" :primaryXAxis='primaryXAxis' :primaryYAxis='primaryYAxis' :title='title' :chartArea='chartArea' :axisRangeCalculated='axisRangeCalculated'>
        <e-series-collection>
            <e-series :dataSource='seriesData' type='Column' xName='x' yName='y' columnWidth=0.5 :cornerRadius='cornerRadius'></e-series>
        </e-series-collection>
    </ejs-chart>
    <ejs-button id='update' @click.native='onClick'>Update Data</ejs-button>
  </div>
</template>
<script setup>
import { provide, ref } from "vue";
import { ChartComponent as EjsChart, SeriesCollectionDirective as ESeriesCollection, SeriesDirective as ESeries, ColumnSeries, Category } from "@syncfusion/ej2-vue-charts";
import { ButtonComponent as EjsButton } from "@syncfusion/ej2-vue-buttons";

const chart = ref(null);
const seriesData = [
  { x: 'Jewellery', y: 75 },
  { x: 'Shoes', y: 45 },
  { x: 'Footwear', y: 73 },
  { x: 'Pet Services', y: 53 },
  { x: 'Business Clothing', y: 85 },
  { x: 'Office Supplies', y: 68 },
  { x: 'Food', y: 45 }
];
const primaryXAxis = {
  valueType: 'Category', 
  majorGridLines: { width: 0 }, 
  labelStyle: { size: '12px' }, 
  labelIntersectAction: 'Rotate90'
};
const primaryYAxis = {
  title: 'Sales (in percentage)', 
  labelFormat: '{value}%', 
  lineStyle: { width: 0 }, 
  majorTickLines: { width: 0 }, 
  interval: 5, 
  minimum: 0, 
  maximum: 100
};
const cornerRadius = { 
  topLeft: 15, 
  topRight: 15 
};
const title = 'Sales by product';
const chartArea = {
  border: {
    width: 0
  }
};

provide('chart', [ColumnSeries, Category]);

const getRandomInt = function(min, max) {
  return Math.floor(Math.random() * (max - min + 1)) + min;
};

const axisRangeCalculated = function(args) {
  if (args.axis.name === 'primaryYAxis') {
      args.maximum = args.maximum > 100 ? 100 : args.maximum;
      if (args.maximum > 80) {
          args.interval = 20;
      }
      else if (args.maximum > 40) {
          args.interval = 10;
      }
  }
};
      
const onClick = function() {     
  var newData = this.$refs.chart.ej2Instances.series[0].dataSource.map((item) => {
      var value = getRandomInt(10, 90);
      return { x: item.x, y: value };
  });
  if (this.$refs.chart.ej2Instances.series[0]) {
      this.$refs.chart.ej2Instances.series[0].setData(newData, 500);
  }
};

</script>
<style>
  #container {
    height: 350px;
  }
</style>
<template>
    <div id="app">
        <ejs-chart ref="chart" id="container" :primaryXAxis='primaryXAxis' :primaryYAxis='primaryYAxis' :title='title' :chartArea='chartArea' :axisRangeCalculated='axisRangeCalculated'>
          <e-series-collection>
            <e-series :dataSource='seriesData' type='Column' xName='x' yName='y' columnWidth=0.5 :cornerRadius='cornerRadius'></e-series>
          </e-series-collection>
        </ejs-chart>
        <ejs-button id='update' @click.native='onClick'>Update Data</ejs-button>
    </div>
</template>
<script>
import Vue from "vue";
import { ChartPlugin, ColumnSeries, Category } from "@syncfusion/ej2-vue-charts";
import { ButtonPlugin } from "@syncfusion/ej2-vue-buttons";

Vue.use(ChartPlugin);
Vue.use(ButtonPlugin);

function getRandomInt(min, max) {
    return Math.floor(Math.random() * (max - min + 1)) + min;
}

export default {
  data() {
    return {
        seriesData: [
          { x: 'Jewellery', y: 75 },
          { x: 'Shoes', y: 45 },
          { x: 'Footwear', y: 73 },
          { x: 'Pet Services', y: 53 },
          { x: 'Business Clothing', y: 85 },
          { x: 'Office Supplies', y: 68 },
          { x: 'Food', y: 45 }
        ],
        primaryXAxis: {
          valueType: 'Category', 
          majorGridLines: { width: 0 }, 
          labelStyle: { size: '12px' }, 
          labelIntersectAction: 'Rotate90'
        },
        primaryYAxis:
        {
          title: 'Sales (in percentage)', 
          labelFormat: '{value}%', 
          lineStyle: { width: 0 }, 
          majorTickLines: { width: 0 }, 
          interval: 5, 
          minimum: 0, 
          maximum: 100
        },
        cornerRadius: { 
          topLeft: 15, 
          topRight: 15 
        },
        title: 'Sales by product',
        chartArea: {
          border: {
            width: 0
          }
        }
    };
  },
  provide: {
    chart: [ColumnSeries, Category]
  },
  methods: {
      axisRangeCalculated: function(args) {
          if (args.axis.name === 'primaryYAxis') {
              args.maximum = args.maximum > 100 ? 100 : args.maximum;
              if (args.maximum > 80) {
                args.interval = 20;
              }
              else if (args.maximum > 40) {
                args.interval = 10;
              }
          }
      },
      onClick: function() {     
          var newData = this.$refs.chart.ej2Instances.series[0].dataSource.map((item) => {
            var value = getRandomInt(10, 90);
            return { x: item.x, y: value };
          });
          if (this.$refs.chart.ej2Instances.series[0]) {
              this.$refs.chart.ej2Instances.series[0].setData(newData, 500);
          }
      }
  }
};
</script>
<style>
  #container {
    height: 350px;
  }
</style>

Click to add or remove a data point

Enable users to add or remove data points by clicking on the chart. Listen to the chartMouseClick event to capture click coordinates and point information. When a user clicks within the chart area, extract the x and y axis values from the event arguments. If the location is empty, use addPoint to add a new data point at those coordinates. If a user clicks on an existing data point, identify its index and use removePoint to delete it. This creates an intuitive interface for data exploration and editing.

<template>
  <div id="app">
    <ejs-chart ref="chart" id="container" :primaryXAxis='primaryXAxis' :primaryYAxis='primaryYAxis' :title='title' :chartArea='chartArea' :axisRangeCalculated='axisRangeCalculated' :chartMouseClick='chartMouseClick'>
        <e-series-collection>
          <e-series :dataSource='seriesData' type='Line' xName='x' yName='y' width=3 :marker='marker'></e-series>
        </e-series-collection>
    </ejs-chart>
  </div>
</template>
<script setup>
import { provide, ref } from "vue";
import { ChartComponent as EjsChart, SeriesCollectionDirective as ESeriesCollection, SeriesDirective as ESeries, LineSeries, DataLabel, Tooltip } from "@syncfusion/ej2-vue-charts";

const chart = ref(null);
const seriesData = [
  { x: 20, y: 20 }, 
  { x: 80, y: 80 }
];
const primaryXAxis = {
  edgeLabelPlacement: 'Shift', 
  rangePadding: 'Additional', 
  majorGridLines: { width: 0 }
};
const primaryYAxis = {
  title: 'Value', 
  interval: 20, 
  lineStyle: { width: 0 }, 
  majorTickLines: { width: 0 }
};
const marker = {
  visible: true, 
  isFilled: true, 
  border: { 
    width: 2, 
    color: 'White' 
  }, 
  width: 13, 
  height: 13 
};
const title = 'User supplied data';
const chartArea = {
  border: {
    width: 0
  }
};

provide('chart', [LineSeries, DataLabel, Tooltip]);

const chartMouseClick = function(args) {
  let isRemoved = false;
  if (args.axisData) {
      for (let i = 0; i < this.$refs.chart.ej2Instances.series[0].points.length; i++) {
            let markerWidth = this.$refs.chart.ej2Instances.series[0].marker.width / 2;
            let roundedX = Math.round(args.axisData['primaryXAxis']) + markerWidth;
            let roundedY = Math.round(args.axisData['primaryYAxis']) + markerWidth;
            let pointX = Math.round(this.$refs.chart.ej2Instances.series[0].points[i].x) + markerWidth;
            let pointY = Math.round(this.$refs.chart.ej2Instances.series[0].points[i].y) + markerWidth;
            if ((roundedX === pointX || roundedX + 1 === pointX || roundedX - 1 === pointX) &&
                (roundedY === pointY || roundedY + 1 === pointY || roundedY - 1 === pointY)) {
                if (this.$refs.chart.ej2Instances.series[0].points.length > 1) {
                    const points = this.$refs.chart.ej2Instances.series[0].points;
                    const duration = i === 0 || i === points[points.length - 1].index ? 500 : 0;
                    this.$refs.chart.ej2Instances.series[0].removePoint(i, duration);
                }
                isRemoved = true;
            }
      }
      if (!isRemoved) {
          this.$refs.chart.ej2Instances.series[0].addPoint({ x: Math.round(args.axisData['primaryXAxis']), y: Math.round(args.axisData['primaryYAxis']) });
      }
  }
};
      
const axisRangeCalculated = function(args) {
  if (args.axis.name === 'primaryXAxis') {
      if (args.interval < 10) {
          args.maximum = args.maximum + 10;
          args.minimum = args.minimum - 10;
          args.interval = 10;
      }
  }
  if (args.axis.name === 'primaryYAxis') {
      if (args.maximum <= 60) {
          args.interval = 10;
      }
  }
};

</script>
<style>
  #container {
    height: 350px;
  }
</style>
<template>
    <div id="app">
        <ejs-chart ref="chart" id="container" :primaryXAxis='primaryXAxis' :primaryYAxis='primaryYAxis' :title='title' :chartArea='chartArea' :axisRangeCalculated='axisRangeCalculated' :chartMouseClick='chartMouseClick'>
          <e-series-collection>
            <e-series :dataSource='seriesData' type='Line' xName='x' yName='y' width=3 :marker='marker'></e-series>
          </e-series-collection>
        </ejs-chart>
    </div>
</template>
<script>
import Vue from "vue";
import { ChartPlugin, LineSeries, DataLabel, Tooltip } from "@syncfusion/ej2-vue-charts";

Vue.use(ChartPlugin);

export default {
  data() {
    return {
        seriesData: [
          { x: 20, y: 20 }, 
          { x: 80, y: 80 }
        ],
        primaryXAxis: {
          edgeLabelPlacement: 'Shift', 
          rangePadding: 'Additional', 
          majorGridLines: { width: 0 }
        },
        primaryYAxis:
        {
          title: 'Value', 
          interval: 20, 
          lineStyle: { width: 0 }, 
          majorTickLines: { width: 0 }
        },
        marker: { 
          visible: true, 
          isFilled: true, 
          border: { 
            width: 2, 
            color: 'White' 
          }, 
          width: 13, 
          height: 13 
        },
        title: 'User supplied data',
        chartArea: {
          border: {
            width: 0
          }
        }
    };
  },
  provide: {
    chart: [LineSeries, DataLabel, Tooltip]
  },
  methods: {
      chartMouseClick: function(args) {
        let isRemoved = false;
        if (args.axisData) {
            for (let i = 0; i < this.$refs.chart.ej2Instances.series[0].points.length; i++) {
                let markerWidth = this.$refs.chart.ej2Instances.series[0].marker.width / 2;
                let roundedX = Math.round(args.axisData['primaryXAxis']) + markerWidth;
                let roundedY = Math.round(args.axisData['primaryYAxis']) + markerWidth;
                let pointX = Math.round(this.$refs.chart.ej2Instances.series[0].points[i].x) + markerWidth;
                let pointY = Math.round(this.$refs.chart.ej2Instances.series[0].points[i].y) + markerWidth;
                if ((roundedX === pointX || roundedX + 1 === pointX || roundedX - 1 === pointX) &&
                    (roundedY === pointY || roundedY + 1 === pointY || roundedY - 1 === pointY)) {
                    if (this.$refs.chart.ej2Instances.series[0].points.length > 1) {
                        const points = this.$refs.chart.ej2Instances.series[0].points;
                        const duration = i === 0 || i === points[points.length - 1].index ? 500 : 0;
                        this.$refs.chart.ej2Instances.series[0].removePoint(i, duration);
                    }
                    isRemoved = true;
                }
            }
            if (!isRemoved) {
                    this.$refs.chart.ej2Instances.series[0].addPoint({ x: Math.round(args.axisData['primaryXAxis']), y: Math.round(args.axisData['primaryYAxis']) });
            }
        }
      },
      axisRangeCalculated: function(args) {
        if (args.axis.name === 'primaryXAxis') {
            if (args.interval < 10) {
                args.maximum = args.maximum + 10;
                args.minimum = args.minimum - 10;
                args.interval = 10;
            }
        }
        if (args.axis.name === 'primaryYAxis') {
            if (args.maximum <= 60) {
                args.interval = 10;
            }
        }
      }
  }
};
</script>
<style>
  #container {
    height: 350px;
  }
</style>