Dynamic data update in Vue Chart component

26 Jun 202424 minutes to read

Adding a new data point

The addPoint method is used to dynamically add a new data point to the chart series. This method is particularly useful when you want to update the chart with a new data point without having to refresh the entire chart. This method takes two parameters:

  • The first parameter is the new data point to add to your existing data source.
  • The optional second parameter specifies the animation duration for adding the new data point.
<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

The removePoint method is used to dynamically remove a data point from the chart series. This method is particularly useful when you want to update the chart by removing an existing data point without having to refresh the entire chart. This method takes two parameters:

  • The first parameter is the index of the data point that needs to be removed from the existing data source.
  • The optional second parameter specifies the animation duration for removing the data point.
<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

To replace the existing data source in the chart with a new data source, you can simply use the setData method. This method allows you to replace the existing data points in the chart series with a new set of data points, enabling you to easily update the chart with new information. This method takes two parameters:

  • The first parameter is the new set of data points to be updated.
  • The optional second parameter specifies the animation duration for updating the new data source.
<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

You can use mouse or touch events to dynamically add or remove data points from an existing data source by clicking on the appropriate position within the chart area. To add a new data point to the existing data source, click anywhere in the chart area, retrieve the x-axis and y-axis information of the clicked location from the chartMouseClick event arguments. Then, utilize the addPoint method to add a new data point to the existing data source.

To remove a data point from the existing data source, simply click on the desired data point. To achieve this, first, verify whether the clicked data point obtained from chartMouseClick already exists in the data source. If it does, remove it by utilizing the removePoint method based on its index.

<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>