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 and keys available in Flutter framework. 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 and a key is an identifier for widgets, elements, and semantics nodes. The callback used for the synchronized panning is the onZooming event available in the chart and the GlobalKey (subclass of Key class) is used as identifier.
The following steps explain how to do synchronized panning in multiple charts.
Step 1: First, create two GlobalKey identifiers for the first and second chart’s state classes, respectively.
final cartesianChartKey = GlobalKey<CartesianChartState>(); final chartKey = GlobalKey<ChartState>();
Step 2: Initialize a Cartesian chart (First chart) as an individual StatefulWidget, in which the zoomFactor and the zoomPosition values are got from the onZooming event and stored globally in the variables for the second chart to use for synchronized panning by calling the refresh method of the second chart to refresh the current state of it.
class Chart extends StatefulWidget { late ZoomPanBehavior _zoomPanBehavior; late TooltipBehavior _tooltipBehavior; @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. cartesianChartKey.currentState!.chartRefresh(); // To refresh the second chart current State } }, primaryXAxis: CategoryAxis( zoomFactor: 0.2, zoomPosition: 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 ) ]); } }
The method used for refreshing the first chart is defined in the first charts state class.
class ChartState extends State<Chart> { void refreshChart() { setState(() {}); } }
Step 3: 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 refresh the current state of first chart. 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. chartKey.currentState.refreshChart();// To refresh the first chart current State } }, primaryXAxis: CategoryAxis(zoomFactor: zoomF, zoomPosition: 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) ]); } }
The method used for refreshing the second chart is defined in the second charts state class.
class CartesianChartState extends State<CartesianChart> { CartesianChartState({Key key}); void chartRefresh() { setState(() {}); } }
Screenshots
Synchronized panning