How to synchronize panning in multiple charts (SfCartesianChart) ?
In this article, we described how to do synchronized panning in multiple charts.
Flutter Cartesian Chart widget can be used to do synchronized panning in multiple charts using the callback events available in the chart. Callback events are callback function or a method, which you pass as an argument into another function or method and can perform an action when you require it. The callback used for the synchronized panning is the onZooming event available in the chart and onRendererCreated event available in the axis.
The following steps explain how to do synchronized panning in multiple charts.
Step 1: Initialize a Cartesian chart (First chart) as an individual StatefulWidget, in which the initialZoomFactor and the initialZoomPosition values are got from the onZooming event and stored globally in the variables for the second chart to use for synchronized panning by updating the axis controller's zoomFactor and zoomPosition.
class Chart extends StatefulWidget { late ZoomPanBehavior _zoomPanBehavior; late TooltipBehavior _tooltipBehavior;
CategoryAxisController? axisController1; // create instance to axis controller for first chart
CategoryAxisController? axisController2; // create instance to axis controller for second chart @override State<StatefulWidget> createState() { return ChartState(); } } @override Void initState(){ _zoomPanBehavior = ZoomPanBehavior( enablePanning: true, enablePinching: true, enableDoubleTapZooming: true, ); _tooltipBehavior = TooltipBehavior(enable: true); super.initState(); } class ChartState extends State<Chart> { @override Widget build(BuildContext context) { return SfCartesianChart( zoomPanBehavior: _zoomPanBehavior, onZooming: (ZoomPanArgs args) { if (args.axis.name == 'primaryXAxis') { zoomP = args.currentZoomPosition; // Storing the zoomPosition and the zoomFactor zoomF = args.currentZoomFactor; // of the first chart.
// Updating zoomFactor and zoomPosition for second chart by using axis controller.
axisController2!.zoomPosition = zoomP; axisController2!.zoomFactor = zoomF; } }, primaryXAxis: CategoryAxis(
// To set value for first chart axis controller
onRenderCreated (CategoryAxisController controller) {
axisController1 = controller;
} initialZoomFactor: 0.2,
initialZoomPosition: 0.5,
name: 'primaryXAxis'), primaryYAxis: NumericAxis(name: 'primaryYAxis'), title: ChartTitle(text: 'Chart 1'), tooltipBehavior: _tooltipBehavior, series: <LineSeries<SalesData, String>>[ LineSeries<SalesData, String>( dataSource: chartData, xValueMapper: (SalesData sales, _) => sales.year, yValueMapper: (SalesData sales, _) => sales.sales ) ]); } }
Step 2: Initialize another Cartesian chart (second chart) as an individual StatefulWidget, the synchronized panning is done with the zoomFactor and zoomPosition values obtained from the onZooming event, callback events are used to update the axis controller's zoomFactor and zoomPosition. Thus, simultaneously synchronized panning can be done in multiple charts.
class CartesianChart extends StatefulWidget { CartesianChart({Key? key}) : super(key: key); @override State<StatefulWidget> createState() { return CartesianChartState(); } } class CartesianChartState extends State<CartesianChart> { CartesianChartState({Key key}); late ZoomPanBehavior _zoomPanBehavior; late TooltipBehavior _tooltipBehavior; @override Void initState(){ _zoomPanBehavior = ZoomPanBehavior( enablePanning: true, enablePinching: true, enableDoubleTapZooming: true, ); _tooltipBehavior = TooltipBehavior(enable: true); super.initState(); } @override Widget build(BuildContext context) { return SfCartesianChart( zoomPanBehavior: _zoomPanBehavior, onZooming: (ZoomPanArgs args) { if (args.axis.name == 'primaryXAxis') { zoomP = args.currentZoomPosition; // Storing the zoomPosition and the zoomFactor zoomF = args.currentZoomFactor; // of the first chart.
// Updating the zoomFactor and zoomPosition for first chart by using axis controller. axisController1!.zoomPosition = zoomP;
axisController1!.zoomFactor = zoomF; } }, primaryXAxis: CategoryAxis(
onRendererCreated (CategoryAxisController controller){
axisController2 = controller;
}
initialZoomFactor: zoomF,
initialZoomPosition: zoomP), title: ChartTitle(text: 'Chart 2'), tooltipBehavior: _tooltipBehavior, series: <LineSeries<SalesData, String>>[ LineSeries<SalesData, String>( dataSource: chartData, xValueMapper: (SalesData sales, _) => sales.year, yValueMapper: (SalesData sales, _) => sales.sales) ]); } }
Screenshots
Synchronized panning