Synchronized Charts in Vue Chart component
13 Jun 202424 minutes to read
Tooltip synchronization
The tooltip can be synchronized across multiple charts using the showTooltip
and hideTooltip
methods. When we hover over a data point in one chart, we call the showTooltip
method for the other charts to display related information in other connected charts simultaneously.
In the showTooltip
method, specify the following parameters programmatically to enable tooltip for a particular chart:
-
x
- Data point x-value or x-coordinate value. -
y
- Data point y-value or y-coordinate value.
<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 using the showCrosshair
and hideCrosshair
methods. When we hover over one chart, we call the showCrosshair
method for the other charts to align with data points in other connected charts, simplifying data comparison and analysis.
In the showCrosshair
method, specify the following parameters programmatically to enable crosshair for a particular chart:
-
x
- Specifies the x-value of the point or x-coordinate. -
y
- Specifies the y-value of the point or 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
You can maintain constant zoom levels across multiple charts using the zoomComplete
event. In the zoomComplete
event, obtain the zoomFactor
and zoomPosition
values of the particular chart, and then apply those values to the other charts.
<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
You can select the data across multiple charts using the selectionComplete
event. In the selectionComplete
event, obtain the selected values of the particular chart, and then apply those values to the other charts.
<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>