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>