TL;DR: Unlock the power of synchronization in the Syncfusion Flutter Charts! Experience seamless cursor positioning, clicking, and tooltip activation across multiple charts simultaneously. Discover how synchronized trackball, zooming, and selection can elevate data visualization and user interactivity in your Flutter apps.
Synchronized charts provide access and interaction with multiple charts simultaneously. This means that actions performed on one chart, such as positioning a cursor, clicking on a specific point, or activating a tooltip, are reflected simultaneously on corresponding positions or data points across other synchronized charts based on their x- and y-coordinates.
In this blog, we’ll explore the user-friendly synchronization feature in the Syncfusion Flutter Charts widget with code examples!
Usage of chart synchronization
Charts synchronization is a powerful technique used in data visualization to ensure that multiple charts work together in harmony. This synchronization allows for a more comprehensive and interactive view of the data, enhancing the ability to analyze and interpret complex datasets. Here are some key usages of chart synchronization:
- Comparative analysis: Chart synchronization is especially useful in comparative analysis, where users must compare data from different sources or periods.
- Detailed data insights: Chart synchronization enables users to drill down into specific data points across different charts simultaneously, allowing for a more detailed examination of how different factors interact.
- Consistent data representation: Ensuring that all charts are synchronized means maintaining a consistent scale and time frame across all visualizations.
- Enhanced user interactivity: Synchronized charts improve user interactivity by allowing unified interactions across multiple charts. Actions such as zooming, panning, and data point selection on one chart are reflected across all linked charts.
- Real-time data monitoring: Charts synchronization is particularly valuable for real-time data monitoring, where it’s crucial to see how different data points change over time simultaneously.
Synchronizing elements in Syncfusion Flutter Charts
Let’s see how to synchronize the following elements in the Flutter Charts:
Synchronized trackball
Synchronized trackballs display an interactive tooltip when users hover over data points in one chart. This tooltip dynamically shows detailed information about corresponding data points aligned along a common horizontal line across all synchronized charts. One of the primary benefits of synchronized trackballs is their ability to facilitate comparative analysis effortlessly. Users can compare data points from multiple charts, quickly identifying similarities, differences, and relationships.
We can enable trackball synchronization by using the show and hide methods in the TrackballBehavior class. Define trackball behaviors for the required charts. The TrackballBehavior is configured with the enable property set to true and the activationMode set to ActivationMode.singleTap. This will allow users to activate the trackball with a single tap.
When the user taps on a data point in either chart, the trackball is activated and shows detailed information about the data point. The onTrackballPositionChanging callback ensures that when the trackball’s position changes in one chart, it is reflected in the other. This is achieved by converting the data point to pixel coordinates with the help of the pointToPixel method and using these coordinates to position the trackball in the synchronized charts. Then, it will call the show method to display the trackball with the given touch position.
To implement the show method for a trackball, we need to specify the following parameters:
- x: Represents the x-axis value of the point or its x-coordinate value.
- y: Represents the y-axis value of the point or its y-coordinate value.
- coordinateUnit: Represents the type of x- and y-axis values given as pixel or point for logical pixel and chart data point, respectively.
Refer to the following code example.
TrackballBehavior _baseTrackball =
TrackballBehavior(enable: true, activationMode: ActivationMode.singleTap);
TrackballBehavior _targetTrackball =
TrackballBehavior(enable: true, activationMode: ActivationMode.singleTap);
ChartSeriesController? _baseSeriesController;
ChartSeriesController? _targetSeriesController;
Offset? _position;
class FirstChart extends StatelessWidget {
bool _isInteractive = false;
@override
Widget build(BuildContext context) {
return SfCartesianChart(
onChartTouchInteractionDown: (ChartTouchInteractionArgs tapArgs) {
_isInteractive = true;
},
onChartTouchInteractionUp: (ChartTouchInteractionArgs tapArgs) {
_isInteractive = false;
_targetTrackball.hide();
},
onTrackballPositionChanging: (TrackballArgs trackballArgs) {
if (_isInteractive) {
_position = _baseSeriesController!.pointToPixel(
trackballArgs.chartPointInfo.chartPoint!,
);
_targetTrackball.show(_position!.dx, _position!.dy, 'pixel');
}
},
trackballBehavior: _baseTrackball,
series: <LineSeries<SalesData, DateTime>>[
LineSeries<SalesData, DateTime>(
dataSource: dataModel.data,
xValueMapper: (SalesData sales, int index) => sales.dateTime,
yValueMapper: (SalesData sales, int index) => sales.y,
onRendererCreated: (ChartSeriesController controller) {
_targetSeriesController = controller;
},
),
],
);
}
}
class SecondChart extends StatelessWidget {
bool _isInteractive = false;
@override
Widget build(BuildContext context) {
return SfCartesianChart(
onChartTouchInteractionDown: (ChartTouchInteractionArgs tapArgs) {
_isInteractive = true;
},
onChartTouchInteractionUp: (ChartTouchInteractionArgs tapArgs) {
_isInteractive = false;
_baseTrackball.hide();
},
onTrackballPositionChanging: (TrackballArgs trackballArgs) {
if (_isInteractive) {
_position = _targetSeriesController!.pointToPixel(
trackballArgs.chartPointInfo.chartPoint!,
);
_baseTrackball.show(_position!.dx, _position!.dy, 'pixel');
}
},
trackballBehavior: _targetTrackball,
series: <LineSeries<SalesData, DateTime>>[
LineSeries<SalesData, DateTime>(
…
onRendererCreated: (ChartSeriesController controller) {
_baseSeriesController = controller;
},
),
],
);
}
}
Refer to the following image.
Synchronized zooming and panning
Synchronized zooming and panning in multiple charts is an advanced feature that enhances data visualization and analysis. When charts are synchronized, any zooming or panning action performed on one chart is replicated on the other. This is particularly useful in scenarios where users need to analyze multiple datasets or track changes in data over time. Users can make more accurate and meaningful comparisons by maintaining the same zoom level and position across charts.
In the multiple chart synchronization, each chart is equipped with zoom and pan behaviors, and the zooming state is shared between charts using a shared zoom factor and zoom position. When the user performs a zoom or pan action on the first chart, the onZooming callback captures the current zoom state based on the axis name, and the primary axis’ default name is primaryXAxis. The zoom state is updated using the zoomPosition and zoomFactor properties. The first chart’s zoom state is updated to match the second one using the onRendererCreated axis controller.
Refer to the following code example.
DateTimeAxisController? _firstAxisController;
DateTimeAxisController? _secondAxisController;
class FirstChart extends StatelessWidget {
final ZoomPanBehavior _zoomPanBehavior = ZoomPanBehavior(
enablePanning: true,
enablePinching: true,
zoomMode: ZoomMode.x);
@override
Widget build(BuildContext context) {
return SfCartesianChart(
zoomPanBehavior: _zoomPanBehavior,
onZooming: (ZoomPanArgs args) {
if (args.axis!.name == 'primaryXAxis') {
_secondAxisController!.zoomFactor = args.currentZoomFactor;
_secondAxisController!.zoomPosition = args.currentZoomPosition;
}
},
primaryXAxis: DateTimeAxis(
…
onRendererCreated: (DateTimeAxisController controller) {
_firstAxisController = controller;
},
initialZoomFactor: 1,
initialZoomPosition: 0),
…
);
}
}
class SecondChart extends StatelessWidget {
@override
Widget build(BuildContext context) {
return SfCartesianChart(
zoomPanBehavior: _zoomPanBehavior,
onZooming: (ZoomPanArgs args) {
if (args.axis!.name == 'primaryXAxis') {
_firstAxisController!.zoomFactor = args.currentZoomFactor;
_firstAxisController!.zoomPosition = args.currentZoomPosition;
}
},
primaryXAxis: DateTimeAxis(
…
onRendererCreated: (DateTimeAxisController controller) {
_secondAxisController = controller;
},
initialZoomFactor: 1,
initialZoomPosition: 0),
…
);
}
}
Refer to the following image.
Synchronized selection
Selection behavior in synchronized charts is essential for simultaneously enabling interactive data exploration and analysis across multiple charts. This functionality allows users to highlight and compare specific data points within one chart and see corresponding selections reflected in other synchronized charts.
Implementing selection behavior in chart synchronization involves using the SelectionBehavior class from the Syncfusion Flutter Charts package. The key parameters include enabling the selection capability and controlling whether selecting a data point toggles its selection state. For instance, setting the enable property to true activates the selection behavior, and setting the toggleSelection to false ensures that selections are exclusive and not toggled on repeated clicks.
The interaction flow for selection behavior in chart synchronization is straightforward. When a user interacts with either chart 1 or chart 2 by tapping or clicking, the onChartTouchInteractionDown callback sets the isInteractive flag to true. Upon selecting a data point in one chart, the onSelectionChanged callback updates the selected index. This updated index is then used to synchronize the selection in the corresponding chart by calling the selectDataPoints method of another chart’s SelectionBehavior.
Refer to the following code example.
SelectionBehavior _baseSelection =
SelectionBehavior(enable: true, toggleSelection: false);
SelectionBehavior _targetSelection =
SelectionBehavior(enable: true, toggleSelection: false);
int _selectedIndex = -1;
class FirstChart extends StatelessWidget {
bool _isInteractive = false;
@override
Widget build(BuildContext context) {
return SfCartesianChart(
onChartTouchInteractionDown: (ChartTouchInteractionArgs tapArgs) {
_isInteractive = true;
},
onSelectionChanged: (selectionArgs) {
if (_isInteractive && _selectedIndex != selectionArgs.pointIndex) {
_selectedIndex = selectionArgs.pointIndex;
_targetSelection.selectDataPoints(_selectedIndex);
_isInteractive = false;
}
},
…
series: <ColumnSeries<SalesData, String>>[
ColumnSeries<SalesData, String>(
…
selectionBehavior: _baseSelection,
),
],
);
}
}
class SecondChart extends StatelessWidget {
bool _isInteractive = false;
@override
Widget build(BuildContext context) {
return SfCartesianChart(
onChartTouchInteractionDown: (ChartTouchInteractionArgs tapArgs) {
_isInteractive = true;
},
onSelectionChanged: (selectionArgs) {
if (_isInteractive && _selectedIndex != selectionArgs.pointIndex) {
_selectedIndex = selectionArgs.pointIndex;
_baseSelection.selectDataPoints(_selectedIndex);
_isInteractive = false;
}
},
…
series: <ColumnSeries<SalesData, String>>[
ColumnSeries<SalesData, String>(
…
selectionBehavior: _targetSelection,
),
],
);
}
}
Refer to the following image.
GitHub references
For more details, refer to the GitHub demo for multiple charts synchronization in Flutter.
Conclusion
Thanks for reading! This blog explored the synchronization feature in the Syncfusion Flutter Charts widget. This feature significantly improves the user experience and analytical capabilities of data visualization apps. We can interact with multiple datasets seamlessly and maintain context and coherence across charts. Give it a try, and leave your feedback in the comment section below.
The existing customers can download the new version of Essential Studio on the License and Downloads page. If you are not a Syncfusion customer, try our 30-day free trial to check out our incredible features.
If you need a new widget for the Flutter framework or new features in our existing widgets, you can contact us through our support forums, support portal, or feedback portal. As always, we are happy to assist you!
Top comments (0)