Articles in this section
Category / Section

How to synchronize panning in multiple charts (SfCartesianChart) ?

3 mins read

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

 

Synchronized panning

View the sample in GitHub

 

 

 

Did you find this information helpful?
Yes
No
Help us improve this page
Please provide feedback or comments
Comments (0)
Please sign in to leave a comment