How can I help you?
Synchronized Charts in Vue Chart component
3 Feb 202624 minutes to read
Synchronized charts allow multiple chart instances to share common interactions so that actions performed on one chart are reflected across the others. This approach is useful for comparing related datasets and analyzing trends consistently across multiple visualizations.
Tooltip synchronization
The tooltip can be synchronized across multiple charts by using the showTooltip and hideTooltip methods. When the user hovers over a data point in one chart, the showTooltip method can be invoked for the other charts to display the corresponding tooltip information simultaneously.
In the showTooltip method, specify the following parameters programmatically to enable the tooltip for a specific chart:
-
x– The x-value of the data point or the x-coordinate. -
y– The y-value of the data point or the y-coordinate.
<template>
<div class="control-section">
<div class="row">
<div class="col" id="container1">
<ejs-chart style='display:block' align='center' id='chartcontainer1' :title='title1'
:primaryXAxis='primaryXAxis' :primaryYAxis='primaryYAxis1' :tooltip='tooltip1' :titleStyle='titleStyle'
:chartMouseLeave='chartMouseLeave1' :chartMouseMove='chartMouseMove1' :chartMouseUp='chartMouseUp1' ref="chart1">
<e-series-collection>
<e-series :dataSource='seriesData' type='Line' xName='USD' yName='EUR' width = 2
:emptyPointSetting='emptyPointSettings'> </e-series>
</e-series-collection>
</ejs-chart>
</div>
<div class="col" id="container2">
<ejs-chart style='display:block' align='center' id='chartcontainer2' :title='title2'
:primaryXAxis='primaryXAxis' :primaryYAxis='primaryYAxis2' :tooltip='tooltip2' :titleStyle='titleStyle'
:chartMouseLeave='chartMouseLeave2' :chartMouseMove='chartMouseMove2' :chartMouseUp='chartMouseUp2' ref="chart2">
<e-series-collection>
<e-series :dataSource='seriesData' type='Area' xName='USD' yName='INR' opacity=0.6
:border='border'>
</e-series>
</e-series-collection>
</ejs-chart>
</div>
</div>
</div>
</template>
<script setup>
import { provide } from "vue";
import { ChartComponent as EjsChart, SeriesCollectionDirective as ESeriesCollection, SeriesDirective as ESeries, AreaSeries, LineSeries, DateTime, Tooltip } from "@syncfusion/ej2-vue-charts";
import { synchronizedData } from './dataSource.js';
import { Browser } from '@syncfusion/ej2-base';
import {ref} from 'vue';
const chart1=ref(null);
const chart2=ref(null);
const seriesData= synchronizedData;
const primaryXAxis= {
minimum: new Date(2023, 1, 18),
maximum: new Date(2023, 7, 18),
valueType: 'DateTime',
labelFormat: 'MMM d',
lineStyle: { width: 0 },
majorGridLines: { width: 0 },
interval: Browser.isDevice ? 2 : 1,
edgeLabelPlacement: Browser.isDevice ? 'None' : 'Shift',
labelRotation: Browser.isDevice ? -45 : 0
};
const primaryYAxis1= {
labelFormat: 'n2',
majorTickLines: { width: 0 },
lineStyle: { width: 0 },
minimum: 0.86,
maximum: 0.96,
interval: 0.025
};
const primaryYAxis2= {
labelFormat: 'n1',
majorTickLines: { width: 0 },
lineStyle: { width: 0 },
minimum: 79,
maximum: 85,
interval: 1.5
};
const border= { width: 2 };
const tooltip1= {
enable: true,
shared: true,
header: '',
enableMarker: false,
format: '<b>€${point.y}</b> <br>${point.x} 2023',
fadeOutDuration: Browser.isDevice ? 2500 : 1000
};
const tooltip2= {
enable: true,
shared: true,
header: '',
enableMarker: false,
format: '<b>₹${point.y}</b> <br>${point.x} 2023',
fadeOutDuration: Browser.isDevice ? 2500 : 1000
};
const emptyPointSettings= { mode: 'Drop' };
const titleStyle= { textAlignment: 'Near' };
const title1= "US to EURO";
const title2= "US to INR";
provide('chart', [AreaSeries, LineSeries, DateTime, Tooltip]);
const chartMouseLeave1= function () {
chart2.value.ej2Instances.hideTooltip();
};
const chartMouseUp1= function () {
if (Browser.isDevice || chart1.value.ej2Instances.startMove) {
chart2.value.ej2Instances.hideTooltip();
}
};
const chartMouseMove1= function (args) {
if ((!Browser.isDevice && !chart1.value.ej2Instances.isTouch && !chart1.value.ej2Instances.isChartDrag) || chart1.value.ej2Instances.startMove) {
chart2.value.ej2Instances.startMove = chart1.value.ej2Instances.startMove;
chart2.value.ej2Instances.showTooltip(args.x, args.y);
}
};
const chartMouseMove2= function (args) {
if ((!Browser.isDevice && !chart2.value.ej2Instances.isTouch && !chart2.value.ej2Instances.isChartDrag) || chart2.value.ej2Instances.startMove) {
chart1.value.ej2Instances.startMove = chart2.value.ej2Instances.startMove;
chart1.value.ej2Instances.showTooltip(args.x, args.y);
}
};
const chartMouseLeave2= function () {
chart1.value.ej2Instances.hideTooltip();
};
const chartMouseUp2= function () {
if (Browser.isDevice || chart2.value.ej2Instances.startMove) {
chart1.value.ej2Instances.hideTooltip();
}
};
</script>
<style>
#container {
height: 350px;
}
#control-container {
padding: 1px !important;
}
.row {
display: flex;
}
.col {
width: 50%;
margin: 10px;
height: 270px;
}
</style><template>
<div class="control-section">
<div class="row">
<div class="col" id="container1">
<ejs-chart style='display:block' align='center' id='chartcontainer1' :title='title1'
:primaryXAxis='primaryXAxis' :primaryYAxis='primaryYAxis1' :tooltip='tooltip1' :titleStyle='titleStyle'
:chartMouseLeave='chartMouseLeave1' :chartMouseMove='chartMouseMove1' :chartMouseUp='chartMouseUp1'
ref="chart1">
<e-series-collection>
<e-series :dataSource='seriesData' type='Line' xName='USD' yName='EUR' width=2
:emptyPointSetting='emptyPointSettings'> </e-series>
</e-series-collection>
</ejs-chart>
</div>
<div class="col" id="container2">
<ejs-chart style='display:block' align='center' id='chartcontainer2' :title='title2'
:primaryXAxis='primaryXAxis' :primaryYAxis='primaryYAxis2' :tooltip='tooltip2' :titleStyle='titleStyle'
:chartMouseLeave='chartMouseLeave2' :chartMouseMove='chartMouseMove2' :chartMouseUp='chartMouseUp2'
ref="chart2">
<e-series-collection>
<e-series :dataSource='seriesData' type='Area' xName='USD' yName='INR' opacity=0.6 :border='border'>
</e-series>
</e-series-collection>
</ejs-chart>
</div>
</div>
</div>
</template>
<script>
import { ChartComponent, SeriesDirective, SeriesCollectionDirective, AreaSeries, LineSeries, DateTime, Tooltip } from "@syncfusion/ej2-vue-charts";
import { synchronizedData } from './dataSource.js';
import { Browser } from '@syncfusion/ej2-base';
export default {
name: "App",
components: {
"ejs-chart": ChartComponent,
"e-series-collection": SeriesCollectionDirective,
"e-series": SeriesDirective
},
data() {
return {
seriesData: synchronizedData,
primaryXAxis: {
minimum: new Date(2023, 1, 18),
maximum: new Date(2023, 7, 18),
valueType: 'DateTime',
labelFormat: 'MMM d',
lineStyle: { width: 0 },
majorGridLines: { width: 0 },
interval: Browser.isDevice ? 2 : 1,
edgeLabelPlacement: Browser.isDevice ? 'None' : 'Shift',
labelRotation: Browser.isDevice ? -45 : 0
},
primaryYAxis1: {
labelFormat: 'n2',
majorTickLines: { width: 0 },
lineStyle: { width: 0 },
minimum: 0.86,
maximum: 0.96,
interval: 0.025
},
primaryYAxis2: {
labelFormat: 'n1',
majorTickLines: { width: 0 },
lineStyle: { width: 0 },
minimum: 79,
maximum: 85,
interval: 1.5
},
border: { width: 2 },
tooltip1: {
enable: true,
shared: true,
header: '',
enableMarker: false,
format: '<b>€${point.y}</b> <br>${point.x} 2023',
fadeOutDuration: Browser.isDevice ? 2500 : 1000
},
tooltip2: {
enable: true,
shared: true,
header: '',
enableMarker: false,
format: '<b>₹${point.y}</b> <br>${point.x} 2023',
fadeOutDuration: Browser.isDevice ? 2500 : 1000
},
emptyPointSettings: { mode: 'Drop' },
titleStyle: { textAlignment: 'Near' },
title1: "US to EURO",
title2: "US to INR"
};
},
provide: {
chart: [AreaSeries, LineSeries, DateTime, Tooltip]
},
methods: {
chartMouseLeave1: function () {
this.$refs.chart2.ej2Instances.hideTooltip();
},
chartMouseUp1: function () {
if (Browser.isDevice || this.$refs.chart1.ej2Instances.startMove) {
this.$refs.chart2.ej2Instances.hideTooltip();
}
},
chartMouseMove1: function (args) {
if ((!Browser.isDevice && !this.$refs.chart1.ej2Instances.isTouch && !this.$refs.chart1.ej2Instances.isChartDrag) || this.$refs.chart1.ej2Instances.startMove) {
this.$refs.chart2.ej2Instances.startMove = this.$refs.chart1.ej2Instances.startMove;
this.$refs.chart2.ej2Instances.showTooltip(args.x, args.y);
}
},
chartMouseMove2: function (args) {
if ((!Browser.isDevice && !this.$refs.chart2.ej2Instances.isTouch && !this.$refs.chart2.ej2Instances.isChartDrag) || this.$refs.chart2.ej2Instances.startMove) {
this.$refs.chart1.ej2Instances.startMove = this.$refs.chart2.ej2Instances.startMove;
this.$refs.chart1.ej2Instances.showTooltip(args.x, args.y);
}
},
chartMouseLeave2: function () {
this.$refs.chart1.ej2Instances.hideTooltip();
},
chartMouseUp2: function () {
if (Browser.isDevice || this.$refs.chart2.ej2Instances.startMove) {
this.$refs.chart1.ej2Instances.hideTooltip();
}
}
}
};
</script>
<style>
#container {
height: 350px;
}
#control-container {
padding: 1px !important;
}
.row {
display: flex;
}
.col {
width: 50%;
margin: 10px;
height: 270px;
}
</style>Crosshair synchronization
The crosshair can be synchronized across multiple charts by using the showCrosshair and hideCrosshair methods. When the user moves the pointer over one chart, calling the showCrosshair method on the other charts aligns the crosshair position across all synchronized charts, making data comparison easier.
In the showCrosshair method, specify the following parameters to render the crosshair for a particular chart:
-
x– Specifies the x-value of the data point or the x-coordinate. -
y– Specifies the y-value of the data point or the y-coordinate.
<template>
<div class="control-section">
<div class="row">
<div class="col" id="container1">
<ejs-chart style='display:block' align='center' id='chartcontainer1' :title='title1'
:primaryXAxis='primaryXAxis' :primaryYAxis='primaryYAxis1' :crosshair='crosshair' :titleStyle='titleStyle'
:chartMouseLeave='chartMouseLeave1' :chartMouseMove='chartMouseMove1' :chartMouseUp='chartMouseUp1'
ref="chart1">
<e-series-collection>
<e-series :dataSource='seriesData' type='Spline' xName='USD' yName='EUR' width=2
:emptyPointSetting='emptyPointSettings'> </e-series>
</e-series-collection>
</ejs-chart>
</div>
<div class="col" id="container2">
<ejs-chart style='display:block' align='center' id='chartcontainer2' :title='title2'
:primaryXAxis='primaryXAxis' :primaryYAxis='primaryYAxis2' :crosshair='crosshair' :titleStyle='titleStyle'
:chartMouseLeave='chartMouseLeave2' :chartMouseMove='chartMouseMove2' :chartMouseUp='chartMouseUp2'
ref="chart2">
<e-series-collection>
<e-series :dataSource='seriesData' type='Area' xName='USD' yName='INR' opacity=0.6 :border='border'>
</e-series>
</e-series-collection>
</ejs-chart>
</div>
</div>
</div>
</template>
<script setup>
import { provide } from "vue";
import { ref } from 'vue';
import { ChartComponent as EjsChart, SeriesCollectionDirective as ESeriesCollection, SeriesDirective as ESeries, AreaSeries, SplineSeries, DateTime, Crosshair } from "@syncfusion/ej2-vue-charts";
import { synchronizedData } from './dataSource.js';
import { Browser } from '@syncfusion/ej2-base';
const chart1 = ref(null);
const chart2 = ref(null);
const seriesData = synchronizedData;
const primaryXAxis = {
minimum: new Date(2023, 1, 18),
maximum: new Date(2023, 7, 18),
valueType: 'DateTime',
labelFormat: 'MMM d',
lineStyle: { width: 0 },
majorGridLines: { width: 0 },
interval: Browser.isDevice ? 2 : 1,
edgeLabelPlacement: Browser.isDevice ? 'None' : 'Shift',
labelRotation: Browser.isDevice ? -45 : 0,
crosshairTooltip: { enable: true }
};
const primaryYAxis1 = {
labelFormat: 'n2',
majorTickLines: { width: 0 },
lineStyle: { width: 0 },
minimum: 0.86,
maximum: 0.96,
interval: 0.025
};
const primaryYAxis2 = {
labelFormat: 'n1',
majorTickLines: { width: 0 },
lineStyle: { width: 0 },
minimum: 79,
maximum: 85,
interval: 1.5
};
const border = { width: 2 };
const crosshair = { enable: true, lineType: 'Vertical', dashArray: '2,2' };
const emptyPointSettings = { mode: 'Drop' };
const titleStyle = { textAlignment: 'Near' };
const title1 = "US to EURO";
const title2 = "US to INR";
provide('chart', [AreaSeries, SplineSeries, DateTime, Crosshair]);
const chartMouseLeave1 = () => {
chart2.value.ej2Instances.hideCrosshair();
};
const chartMouseUp1 = () => {
if (Browser.isDevice || chart1.value.ej2Instances.startMove) {
chart2.value.ej2Instances.hideCrosshair();
}
};
const chartMouseMove1 = (args) => {
if ((!Browser.isDevice && !chart1.value.ej2Instances.isTouch && !chart1.value.ej2Instances.isChartDrag) || chart1.value.ej2Instances.startMove) {
chart2.value.ej2Instances.startMove = chart1.value.ej2Instances.startMove;
chart2.value.ej2Instances.showCrosshair(args.x, args.y);
}
};
const chartMouseMove2 = (args) => {
if ((!Browser.isDevice && !chart2.value.ej2Instances.isTouch && !chart2.value.ej2Instances.isChartDrag) || chart2.value.ej2Instances.startMove) {
chart1.value.ej2Instances.startMove = chart2.value.ej2Instances.startMove;
chart1.value.ej2Instances.showCrosshair(args.x, args.y);
}
};
const chartMouseLeave2 = () => {
chart1.value.ej2Instances.hideCrosshair();
};
const chartMouseUp2 = () => {
if (Browser.isDevice || chart2.value.ej2Instances.startMove) {
chart1.value.ej2Instances.hideCrosshair();
};
}
</script>
<style>
#container {
height: 350px;
}
#control-container {
padding: 1px !important;
}
.row {
display: flex;
}
.col {
width: 50%;
margin: 10px;
height: 270px;
}
</style><template>
<div class="control-section">
<div class="row">
<div class="col" id="container1">
<ejs-chart style='display:block' align='center' id='chartcontainer1' :title='title1'
:primaryXAxis='primaryXAxis' :primaryYAxis='primaryYAxis1' :crosshair='crosshair' :titleStyle='titleStyle'
:chartMouseLeave='chartMouseLeave1' :chartMouseMove='chartMouseMove1' :chartMouseUp='chartMouseUp1'
ref="chart1">
<e-series-collection>
<e-series :dataSource='seriesData' type='Spline' xName='USD' yName='EUR' width=2
:emptyPointSetting='emptyPointSettings'> </e-series>
</e-series-collection>
</ejs-chart>
</div>
<div class="col" id="container2">
<ejs-chart style='display:block' align='center' id='chartcontainer2' :title='title2'
:primaryXAxis='primaryXAxis' :primaryYAxis='primaryYAxis2' :crosshair='crosshair' :titleStyle='titleStyle'
:chartMouseLeave='chartMouseLeave2' :chartMouseMove='chartMouseMove2' :chartMouseUp='chartMouseUp2'
ref="chart2">
<e-series-collection>
<e-series :dataSource='seriesData' type='Area' xName='USD' yName='INR' opacity=0.6 :border='border'>
</e-series>
</e-series-collection>
</ejs-chart>
</div>
</div>
</div>
</template>
<script>
import { ChartComponent, SeriesDirective, SeriesCollectionDirective, AreaSeries, SplineSeries, DateTime, Crosshair } from "@syncfusion/ej2-vue-charts";
import { synchronizedData } from './dataSource.js';
import { Browser } from '@syncfusion/ej2-base';
export default {
name: "App",
components: {
"ejs-chart": ChartComponent,
"e-series-collection": SeriesCollectionDirective,
"e-series": SeriesDirective
},
data() {
return {
seriesData: synchronizedData,
primaryXAxis: {
minimum: new Date(2023, 1, 18),
maximum: new Date(2023, 7, 18),
valueType: 'DateTime',
labelFormat: 'MMM d',
lineStyle: { width: 0 },
majorGridLines: { width: 0 },
interval: Browser.isDevice ? 2 : 1,
edgeLabelPlacement: Browser.isDevice ? 'None' : 'Shift',
labelRotation: Browser.isDevice ? -45 : 0,
crosshairTooltip: { enable: true }
},
primaryYAxis1: {
labelFormat: 'n2',
majorTickLines: { width: 0 },
lineStyle: { width: 0 },
minimum: 0.86,
maximum: 0.96,
interval: 0.025
},
primaryYAxis2: {
labelFormat: 'n1',
majorTickLines: { width: 0 },
lineStyle: { width: 0 },
minimum: 79,
maximum: 85,
interval: 1.5
},
border: { width: 2 },
crosshair: { enable: true, lineType: 'Vertical', dashArray: '2,2' },
emptyPointSettings: { mode: 'Drop' },
titleStyle: { textAlignment: 'Near' },
title1: "US to EURO",
title2: "US to INR"
};
},
provide: {
chart: [AreaSeries, SplineSeries, DateTime, Crosshair]
},
methods: {
chartMouseLeave1: function () {
this.$refs.chart2.ej2Instances.hideCrosshair();
},
chartMouseUp1: function () {
if (Browser.isDevice || this.$refs.chart1.ej2Instances.startMove) {
this.$refs.chart2.ej2Instances.hideCrosshair();
}
},
chartMouseMove1: function (args) {
if ((!Browser.isDevice && !this.$refs.chart1.ej2Instances.isTouch && !this.$refs.chart1.ej2Instances.isChartDrag) || this.$refs.chart1.ej2Instances.startMove) {
this.$refs.chart2.ej2Instances.startMove = this.$refs.chart1.ej2Instances.startMove;
this.$refs.chart2.ej2Instances.showCrosshair(args.x, args.y);
}
},
chartMouseMove2: function (args) {
if ((!Browser.isDevice && !this.$refs.chart2.ej2Instances.isTouch && !this.$refs.chart2.ej2Instances.isChartDrag) || this.$refs.chart2.ej2Instances.startMove) {
this.$refs.chart1.ej2Instances.startMove = this.$refs.chart2.ej2Instances.startMove;
this.$refs.chart1.ej2Instances.showCrosshair(args.x, args.y);
}
},
chartMouseLeave2: function () {
this.$refs.chart1.ej2Instances.hideCrosshair();
},
chartMouseUp2: function () {
if (Browser.isDevice || this.$refs.chart2.ej2Instances.startMove) {
this.$refs.chart1.ej2Instances.hideCrosshair();
}
}
}
};
</script>
<style>
#container {
height: 350px;
}
#control-container {
padding: 1px !important;
}
.row {
display: flex;
}
.col {
width: 50%;
margin: 10px;
height: 270px;
}
</style>Zooming synchronization
Zoom levels can be synchronized across multiple charts by using the zoomComplete event. In the zoomComplete event, retrieve the zoomFactor and zoomPosition values from the zoomed chart.
These values can then be applied to the other charts to ensure that all synchronized charts maintain the same zoom state during user interaction.
<template>
<div class="control-section">
<div class="row">
<div class="col" id="container1">
<ejs-chart style='display:block' align='center' id='chartcontainer1' :title='title1'
:primaryXAxis='primaryXAxis' :primaryYAxis='primaryYAxis1' :zoomSettings='zoomSettings'
:titleStyle='titleStyle' :zoomComplete='zoomComplete' ref="chart1">
<e-series-collection>
<e-series :dataSource='seriesData' type='Line' xName='USD' yName='EUR' width=2
:emptyPointSetting='emptyPointSettings'> </e-series>
</e-series-collection>
</ejs-chart>
</div>
<div class="col" id="container2">
<ejs-chart style='display:block' align='center' id='chartcontainer2' :title='title2'
:primaryXAxis='primaryXAxis' :primaryYAxis='primaryYAxis2' :zoomSettings='zoomSettings'
:titleStyle='titleStyle' :zoomComplete='zoomComplete' ref="chart2">
<e-series-collection>
<e-series :dataSource='seriesData' type='SplineArea' xName='USD' yName='INR' opacity=0.6 :border='border'>
</e-series>
</e-series-collection>
</ejs-chart>
</div>
</div>
</div>
</template>
<script setup>
import { onMounted, provide } from "vue";
import { ChartComponent as EjsChart, SeriesCollectionDirective as ESeriesCollection, SeriesDirective as ESeries, LineSeries, SplineAreaSeries, DateTime, Zoom } from "@syncfusion/ej2-vue-charts";
import { synchronizedData } from './dataSource.js';
import { Browser } from '@syncfusion/ej2-base';
import {ref} from'vue';
const chart1=ref(null);
const chart2=ref(null);
let zoomFactor = 0;
let zoomPosition = 0;
const seriesData = synchronizedData;
const primaryXAxis = {
minimum: new Date(2023, 1, 18),
maximum: new Date(2023, 7, 18),
valueType: 'DateTime',
labelFormat: 'MMM d',
lineStyle: { width: 0 },
majorGridLines: { width: 0 },
interval: Browser.isDevice ? 2 : 1,
edgeLabelPlacement: Browser.isDevice ? 'None' : 'Shift',
labelRotation: Browser.isDevice ? -45 : 0
};
const primaryYAxis1 = {
labelFormat: 'n2',
majorTickLines: { width: 0 },
lineStyle: { width: 0 },
minimum: 0.86,
maximum: 0.96,
interval: 0.025
};
const primaryYAxis2 = {
labelFormat: 'n1',
majorTickLines: { width: 0 },
lineStyle: { width: 0 },
minimum: 79,
maximum: 85,
interval: 1.5
};
const border = { width: 2 };
const zoomSettings = {
enableMouseWheelZooming: true,
enablePinchZooming: true,
enableScrollbar: false,
enableDeferredZooming: false,
enableSelectionZooming: true,
enablePan: true,
mode: 'X',
toolbarItems: ['Pan', 'Reset']
};
const emptyPointSettings = { mode: 'Drop' };
const titleStyle = { textAlignment: 'Near' };
const title1 = "US to EURO";
const title2 = "US to INR";
let charts = [];
provide('chart', [LineSeries, SplineAreaSeries, DateTime, Zoom]);
const zoomComplete = function (args) {
if (args.axis.name === 'primaryXAxis') {
zoomFactor = args.currentZoomFactor;
zoomPosition = args.currentZoomPosition;
zoomCompleteFunction(args);
}
};
const zoomCompleteFunction = function (args) {
for (var i = 0; i < charts.length; i++) {
if (args.axis.series[0].chart.element.id !== charts[i].element.id) {
charts[i].primaryXAxis.zoomFactor = zoomFactor;
charts[i].primaryXAxis.zoomPosition = zoomPosition;
charts[i].zoomModule.isZoomed = args.axis.series[0].chart.zoomModule.isZoomed;
charts[i].zoomModule.isPanning = args.axis.series[0].chart.zoomModule.isPanning;
}
}
};
onMounted(()=> {
charts = [chart1.value.ej2Instances, chart2.value.ej2Instances];
});
</script>
<style>
#container {
height: 350px;
}
#control-container {
padding: 1px !important;
}
.row {
display: flex;
}
.col {
width: 50%;
margin: 10px;
height: 270px;
}
</style><template>
<div class="control-section">
<div class="row">
<div class="col" id="container1">
<ejs-chart style='display:block' align='center' id='chartcontainer1' :title='title1'
:primaryXAxis='primaryXAxis' :primaryYAxis='primaryYAxis1' :zoomSettings='zoomSettings'
:titleStyle='titleStyle' :zoomComplete='zoomComplete' ref="chart1">
<e-series-collection>
<e-series :dataSource='seriesData' type='Line' xName='USD' yName='EUR' width=2
:emptyPointSetting='emptyPointSettings'> </e-series>
</e-series-collection>
</ejs-chart>
</div>
<div class="col" id="container2">
<ejs-chart style='display:block' align='center' id='chartcontainer2' :title='title2'
:primaryXAxis='primaryXAxis' :primaryYAxis='primaryYAxis2' :zoomSettings='zoomSettings'
:titleStyle='titleStyle' :zoomComplete='zoomComplete' ref="chart2">
<e-series-collection>
<e-series :dataSource='seriesData' type='SplineArea' xName='USD' yName='INR' opacity=0.6 :border='border'>
</e-series>
</e-series-collection>
</ejs-chart>
</div>
</div>
</div>
</template>
<script>
import { ChartComponent, SeriesDirective, SeriesCollectionDirective, LineSeries, SplineAreaSeries, DateTime, Zoom } from "@syncfusion/ej2-vue-charts";
import { synchronizedData } from './dataSource.js';
import { Browser } from '@syncfusion/ej2-base';
let zoomFactor = 0;
let zoomPosition = 0;
export default {
name: "App",
components: {
"ejs-chart": ChartComponent,
"e-series-collection": SeriesCollectionDirective,
"e-series": SeriesDirective
},
data() {
return {
seriesData: synchronizedData,
primaryXAxis: {
minimum: new Date(2023, 1, 18),
maximum: new Date(2023, 7, 18),
valueType: 'DateTime',
labelFormat: 'MMM d',
lineStyle: { width: 0 },
majorGridLines: { width: 0 },
interval: Browser.isDevice ? 2 : 1,
edgeLabelPlacement: Browser.isDevice ? 'None' : 'Shift',
labelRotation: Browser.isDevice ? -45 : 0
},
primaryYAxis1: {
labelFormat: 'n2',
majorTickLines: { width: 0 },
lineStyle: { width: 0 },
minimum: 0.86,
maximum: 0.96,
interval: 0.025
},
primaryYAxis2: {
labelFormat: 'n1',
majorTickLines: { width: 0 },
lineStyle: { width: 0 },
minimum: 79,
maximum: 85,
interval: 1.5
},
border: { width: 2 },
zoomSettings: {
enableMouseWheelZooming: true,
enablePinchZooming: true,
enableScrollbar: false,
enableDeferredZooming: false,
enableSelectionZooming: true,
enablePan: true,
mode: 'X',
toolbarItems: ['Pan', 'Reset']
},
emptyPointSettings: { mode: 'Drop' },
titleStyle: { textAlignment: 'Near' },
title1: "US to EURO",
title2: "US to INR",
charts: []
};
},
provide: {
chart: [LineSeries, SplineAreaSeries, DateTime, Zoom]
},
methods: {
zoomComplete: function (args) {
if (args.axis.name === 'primaryXAxis') {
zoomFactor = args.currentZoomFactor;
zoomPosition = args.currentZoomPosition;
this.zoomCompleteFunction(args);
}
},
zoomCompleteFunction: function (args) {
for (var i = 0; i < this.charts.length; i++) {
if (args.axis.series[0].chart.element.id !== this.charts[i].element.id) {
this.charts[i].primaryXAxis.zoomFactor = zoomFactor;
this.charts[i].primaryXAxis.zoomPosition = zoomPosition;
this.charts[i].zoomModule.isZoomed = args.axis.series[0].chart.zoomModule.isZoomed;
this.charts[i].zoomModule.isPanning = args.axis.series[0].chart.zoomModule.isPanning;
}
}
},
},
mounted() {
this.charts = [this.$refs.chart1.ej2Instances, this.$refs.chart2.ej2Instances];
}
};
</script>
<style>
#container {
height: 350px;
}
#control-container {
padding: 1px !important;
}
.row {
display: flex;
}
.col {
width: 50%;
margin: 10px;
height: 270px;
}
</style>Selection synchronization
Selection can be synchronized across multiple charts by using the selectionComplete event. In the selectionComplete event, retrieve the selected data values or region from the active chart and apply the same selection state to the other charts.
This ensures consistent selection behavior across all connected charts and helps maintain a unified analysis experience.
<template>
<div class="control-section">
<div class="row">
<div class="col" id="container1">
<ejs-chart style='display:block' align='center' id='chartcontainer1' :title='title1'
:primaryXAxis='primaryXAxis' :primaryYAxis='primaryYAxis1' :zoomSettings='zoomSettings'
:titleStyle='titleStyle' :zoomComplete='zoomComplete' :selectionComplete='selectionComplete' ref="chart1">
<e-series-collection>
<e-series :dataSource='seriesData' type='Line' xName='USD' yName='EUR' width=2
:emptyPointSetting='emptyPointSettings'> </e-series>
</e-series-collection>
</ejs-chart>
</div>
<div class="col" id="container2">
<ejs-chart style='display:block' align='center' id='chartcontainer2' :title='title2'
:primaryXAxis='primaryXAxis' :primaryYAxis='primaryYAxis2' :zoomSettings='zoomSettings'
:titleStyle='titleStyle' :zoomComplete='zoomComplete' :selectionComplete='selectionComplete' ref="chart2">
<e-series-collection>
<e-series :dataSource='seriesData' type='Spline' xName='USD' yName='INR' width=2 :border='border'>
</e-series>
</e-series-collection>
</ejs-chart>
</div>
</div>
</div>
</template>
<script setup>
import { provide } from "vue";
import { ref, onMounted } from 'vue';
import { ChartComponent as EjsChart, SeriesCollectionDirective as ESeriesCollection, SeriesDirective as ESeries, SplineSeries, LineSeries, DateTime, Zoom, Selection } from "@syncfusion/ej2-vue-charts";
import { synchronizedData } from './dataSource.js';
import { Browser } from '@syncfusion/ej2-base';
const chart1 = ref(null);
const chart2 = ref(null);
let zoomFactor = 0;
let zoomPosition = 0;
let count = 0;
const seriesData = synchronizedData;
const primaryXAxis = {
minimum: new Date(2023, 1, 18),
maximum: new Date(2023, 7, 18),
valueType: 'DateTime',
labelFormat: 'MMM d',
lineStyle: { width: 0 },
majorGridLines: { width: 0 },
interval: Browser.isDevice ? 2 : 1,
edgeLabelPlacement: Browser.isDevice ? 'None' : 'Shift',
labelRotation: Browser.isDevice ? -45 : 0
};
const primaryYAxis1 = {
labelFormat: 'n2',
majorTickLines: { width: 0 },
lineStyle: { width: 0 },
minimum: 0.86,
maximum: 0.96,
interval: 0.025
};
const primaryYAxis2 = {
labelFormat: 'n1',
majorTickLines: { width: 0 },
lineStyle: { width: 0 },
minimum: 79,
maximum: 85,
interval: 1.5
};
const border = { width: 2 };
const zoomSettings = {
enableSelectionZooming: true,
mode: 'X'
};
const emptyPointSettings = { mode: 'Drop' };
const titleStyle = { textAlignment: 'Near' };
const title1 = "US to EURO";
const title2 = "US to INR";
let charts = [];
provide('chart', [SplineSeries, LineSeries, DateTime, Zoom, Selection]);
const zoomComplete = (args) => {
if (args.axis.name === 'primaryXAxis') {
zoomFactor = args.currentZoomFactor;
zoomPosition = args.currentZoomPosition;
zoomCompleteFunction(args);
}
};
const zoomCompleteFunction = (args) => {
for (var i = 0; i < charts.length; i++) {
if (args.axis.series[0].chart.element.id !== charts[i].element.id) {
charts[i].primaryXAxis.zoomFactor = zoomFactor;
charts[i].primaryXAxis.zoomPosition = zoomPosition;
charts[i].zoomModule.isZoomed = args.axis.series[0].chart.zoomModule.isZoomed;
charts[i].zoomModule.isPanning = args.axis.series[0].chart.zoomModule.isPanning;
}
}
};
const selectionComplete = (args) => {
if (count == 0) {
for (var j = 0; j < args.selectedDataValues.length; j++) {
args.selectedDataValues[j].point = args.selectedDataValues[j].pointIndex;
args.selectedDataValues[j].series = args.selectedDataValues[j].seriesIndex;
}
for (var i = 0; i < charts.length; i++) {
if (args.chart.element.id !== charts[i].element.id) {
charts[i].selectedDataIndexes = args.selectedDataValues;
count += 1;
charts[i].dataBind();
}
}
count = 0;
}
};
onMounted(() => {
charts = [chart1.value.ej2Instances, chart2.value.ej2Instances];
})
</script>
<style>
#container {
height: 350px;
}
#control-container {
padding: 1px !important;
}
.row {
display: flex;
}
.col {
width: 50%;
margin: 10px;
height: 270px;
}
</style><template>
<div class="control-section">
<div class="row">
<div class="col" id="container1">
<ejs-chart style='display:block' align='center' id='chartcontainer1' :title='title1'
:primaryXAxis='primaryXAxis' :primaryYAxis='primaryYAxis1' :zoomSettings='zoomSettings'
:titleStyle='titleStyle' :zoomComplete='zoomComplete' :selectionComplete='selectionComplete' ref="chart1">
<e-series-collection>
<e-series :dataSource='seriesData' type='Line' xName='USD' yName='EUR' width=2
:emptyPointSetting='emptyPointSettings'> </e-series>
</e-series-collection>
</ejs-chart>
</div>
<div class="col" id="container2">
<ejs-chart style='display:block' align='center' id='chartcontainer2' :title='title2'
:primaryXAxis='primaryXAxis' :primaryYAxis='primaryYAxis2' :zoomSettings='zoomSettings'
:titleStyle='titleStyle' :zoomComplete='zoomComplete' :selectionComplete='selectionComplete' ref="chart2">
<e-series-collection>
<e-series :dataSource='seriesData' type='Spline' xName='USD' yName='INR' width=2 :border='border'>
</e-series>
</e-series-collection>
</ejs-chart>
</div>
</div>
</div>
</template>
<script>
import { ChartComponent, SeriesDirective, SeriesCollectionDirective, SplineSeries, LineSeries, DateTime, Zoom, Selection } from "@syncfusion/ej2-vue-charts";
import { synchronizedData } from './dataSource.js';
import { Browser } from '@syncfusion/ej2-base';
let zoomFactor = 0;
let zoomPosition = 0;
let count = 0;
export default {
name: "App",
components: {
"ejs-chart": ChartComponent,
"e-series-collection": SeriesCollectionDirective,
"e-series": SeriesDirective
},
data() {
return {
seriesData: synchronizedData,
primaryXAxis: {
minimum: new Date(2023, 1, 18),
maximum: new Date(2023, 7, 18),
valueType: 'DateTime',
labelFormat: 'MMM d',
lineStyle: { width: 0 },
majorGridLines: { width: 0 },
interval: Browser.isDevice ? 2 : 1,
edgeLabelPlacement: Browser.isDevice ? 'None' : 'Shift',
labelRotation: Browser.isDevice ? -45 : 0
},
primaryYAxis1: {
labelFormat: 'n2',
majorTickLines: { width: 0 },
lineStyle: { width: 0 },
minimum: 0.86,
maximum: 0.96,
interval: 0.025
},
primaryYAxis2: {
labelFormat: 'n1',
majorTickLines: { width: 0 },
lineStyle: { width: 0 },
minimum: 79,
maximum: 85,
interval: 1.5
},
border: { width: 2 },
zoomSettings: {
enableSelectionZooming: true,
mode: 'X'
},
emptyPointSettings: { mode: 'Drop' },
titleStyle: { textAlignment: 'Near' },
title1: "US to EURO",
title2: "US to INR",
charts: []
};
},
provide: {
chart: [SplineSeries, LineSeries, DateTime, Zoom, Selection]
},
methods: {
zoomComplete: function (args) {
if (args.axis.name === 'primaryXAxis') {
zoomFactor = args.currentZoomFactor;
zoomPosition = args.currentZoomPosition;
this.zoomCompleteFunction(args);
}
},
zoomCompleteFunction: function (args) {
for (var i = 0; i < this.charts.length; i++) {
if (args.axis.series[0].chart.element.id !== this.charts[i].element.id) {
this.charts[i].primaryXAxis.zoomFactor = zoomFactor;
this.charts[i].primaryXAxis.zoomPosition = zoomPosition;
this.charts[i].zoomModule.isZoomed = args.axis.series[0].chart.zoomModule.isZoomed;
this.charts[i].zoomModule.isPanning = args.axis.series[0].chart.zoomModule.isPanning;
}
}
},
selectionComplete: function (args) {
if (count == 0) {
for (var j = 0; j < args.selectedDataValues.length; j++) {
args.selectedDataValues[j].point = args.selectedDataValues[j].pointIndex;
args.selectedDataValues[j].series = args.selectedDataValues[j].seriesIndex;
}
for (var i = 0; i < this.charts.length; i++) {
if (args.chart.element.id !== this.charts[i].element.id) {
this.charts[i].selectedDataIndexes = args.selectedDataValues;
count += 1;
this.charts[i].dataBind();
}
}
count = 0;
}
},
},
mounted() {
this.charts = [this.$refs.chart1.ej2Instances, this.$refs.chart2.ej2Instances];
}
};
</script>
<style>
#container {
height: 350px;
}
#control-container {
padding: 1px !important;
}
.row {
display: flex;
}
.col {
width: 50%;
margin: 10px;
height: 270px;
}
</style>