Articles in this section
Category / Section

How to customize the trackball in Flutter CartesianChart?

7 mins read

The TrackballBehavior supports the onPaint public method to customize the label, position, and style of the trackball tooltip.

In this article, we will explain how to customize the trackball tooltip’s label, position, and style by extending the TrackballBehavior and using its public methods in Flutter CartesianChart

The chartPointInfo field is available in the TrackballBehavior. By using this list, you can access the position of the trackball and override the onPaint method to customize the trackball line drawing. Additionally, you can customize the appearance of the trackball line and the tooltip rendering.

The following steps explain how to customize the trackball tooltip’s label, position, and style.

Step 1: Initialize the list chartData which stores the data source. Then create the SfCartesianChart widget with the SplineAreaSeries and assign the chartData to the dataSource property and map the x, y values to xValueMapper, yValueMapper properties respectively. Additionally, apply the gradient from top to bottom of the series by using the gradient property available in the SplineAreaSeries.

   final List<ChartData> chartData =  [
       ChartData(DateTime(2024, 2, 1), 21),
       ChartData(DateTime(2024, 2, 2), 34),
       ChartData(DateTime(2024, 2, 3), 30),
       .....
   ];
   

 @override
 Widget build(BuildContext context) {
   return Scaffold(
     body: SfCartesianChart(
       isTransposed: isTransposed,
       primaryXAxis: DateTimeAxis(dateFormat: DateFormat.MEd()),
       series: <CartesianSeries<ChartData, DateTime>>[
         SplineAreaSeries(
           dataSource: chartData,
           xValueMapper: (ChartData sales, int index) => sales.x,
           yValueMapper: (ChartData sales, int index) => sales.y,
           borderColor: Colors.blue,
           markerSettings: const MarkerSettings(
               isVisible: true,
               borderColor: Colors.blue,
           ),
           gradient: const LinearGradient(
               colors: <Color>[Color.fromARGB(255, 151, 208, 234), Colors.white],
               stops: <double>[0.65, 1],
               begin: isTransposed ? Alignment.centerRight : Alignment.topCenter,
               end: isTransposed ? Alignment.bottomLeft : Alignment.bottomCenter,
           ),
       ),
      ],
     ),
   );
 } 

class ChartData {
 ChartData(this.x, this.y);
 final DateTime x;
 final double y;
} 

Step 2: Create a _CustomTrackballBehavior class and extends from TrackballBehavior. Then set the enable property to true and set activationMode getter field to ActivationMode.singleTap.

class _CustomTrackballBehavior extends TrackballBehavior {
 @override
 bool get enable => true;

 @override
 ActivationMode get activationMode => ActivationMode.singleTap;
} 

Step 3: Expose the _drawCustomTrackballLine method to draw a custom line along the trackball, including additional visual elements like circles at the start point of the line. This method handles both normal and transposed cases, ensuring the correct orientation of the line based on the chart’s (isTransposed) configuration.

 void _drawCustomTrackballLine(PaintingContext context, Offset position, Rect plotAreaBounds) {
   if (lineType != TrackballLineType.none) {
     final Offset startPos = position;
     Offset endPos = Offset.zero;
     if (isTransposed) {
       endPos = Offset(plotAreaBounds.left, position.dy);
     } else {
       endPos = Offset(position.dx, plotAreaBounds.bottom);
     }

     final Paint fillPaint = Paint()
       ..color = Colors.blueGrey
       ..style = PaintingStyle.fill;
     final Paint linePaint = Paint()
       ..isAntiAlias = true
       ..color = Colors.red
       ..strokeWidth = 2
       ..style = PaintingStyle.stroke
       ..shader = ui.Gradient.linear(
         startPos,
         endPos,
         <Color>[Colors.blueGrey, Colors.white],
         <double>[0.65, 1],
       );

     context.canvas.drawLine(startPos, endPos, linePaint);
     context.canvas.drawCircle(startPos, 5, fillPaint);
   }
 }

Step 4: Expose the _drawCustomTooltip method to draw the customized tooltip text along with the trackball line. The text position is calculated using the X and Y coordinates obtained from the chartPointInfo and considered the plotAreaBounds for the text position calculation.

Finally, the _drawText method is invoked to render the label on the canvas at the determined position, making adjustments if the chart is transposed, and styling the text with a white color and a blue-grey background.

void _drawCustomTooltip(PaintingContext context, Offset position, Rect plotAreaBounds) {
   final TextStyle textStyle = TextStyle(
     color: Colors.white,
     fontSize: 12,
     fontWeight: FontWeight.bold,
     background: Paint()
       ..color = Colors.blueGrey
       ..strokeWidth = 17
       ..strokeJoin = StrokeJoin.round
       ..strokeCap = StrokeCap.round
       ..style = PaintingStyle.stroke,
   );

   final String label = chartPointInfo[0].label!;
   final Size labelSize = measureText(label, textStyle);
   final Offset customPos = isTransposed
       ? position.translate((labelSize.height + 5), -((labelSize.width / 2)))
       : position.translate(-(labelSize.width / 2),
           -((labelSize.height + 10) + (labelSize.height / 2)));
   final Offset textPos =
       _withInBounds(customPos, label, labelSize, plotAreaBounds);
   _drawText(context.canvas, label, textPos, textStyle);
 } 
 
Offset _withInBounds(Offset position, String label, Size labelSize, Rect plotAreaBounds) {
   double xPos = position.dx;
   double yPos = position.dy;
   const double padding = 5;
   if (xPos + labelSize.width > plotAreaBounds.right) {
     xPos = plotAreaBounds.right - padding - labelSize.width;
   }
   if (xPos <= plotAreaBounds.left) {
     xPos = plotAreaBounds.left + labelSize.width;
   }

   if (yPos - labelSize.height <= plotAreaBounds.top) {
     yPos = plotAreaBounds.top + labelSize.height;
   }
   if (yPos + labelSize.height >= plotAreaBounds.bottom) {
     yPos = plotAreaBounds.bottom - padding - labelSize.height;
   }

   return Offset(xPos, yPos);
 }
 
void _drawText(Canvas canvas, String text, Offset point, TextStyle style) {
   final TextPainter textPainter = TextPainter(
     text: TextSpan(text: text, style: style),
     textAlign: TextAlign.center,
     textDirection: TextDirection.ltr,
   );

   textPainter
     ..layout()
     ..paint(canvas, point);
 }

Step 5: In the onPaint override method, invoke the _drawCustomTrackballLine and _drawCustomTooltip methods to draw custom trackball line and tooltip text.

 @override
 void onPaint(PaintingContext context, Offset offset, SfChartThemeData chartThemeData, ThemeData themeData) {
   if (chartPointInfo.isEmpty || parentBox == null) {
     return;
   }

   final Rect plotAreaBounds = parentBox!.paintBounds;
   final Offset position = Offset(chartPointInfo[0].xPosition!, chartPointInfo[0].yPosition!);

   // Draws custom trackball line.
   _drawCustomTrackballLine(context, position, plotAreaBounds);
   // Draws custom trackball text.
   _drawCustomTooltip(context, position, plotAreaBounds);
 }

Step 5: Initialize this _CustomTrackballBehavior class to TrackballBehavior property which is available in the SfCartesianChart.

@override
Widget build(BuildContext context) {
   return Scaffold(
       body: SfCartesianChart(
           trackballBehavior: _CustomTrackballBehavior(),
           series: <CartesianSeries<ChartData, DateTime>>[
           ..... 

Now, the customized label, position, and style of the trackball tooltip functionality have been implemented as shown below.

Non-Transposed chart:

Customized_trackball_non_transposed.gif

Transposed chart:

Customized_trackball_is_transposed.gif

View the sample in GitHub.

Conclusion

I hope you enjoyed learning about how to customize the trackball in Flutter CartesianChart

You can refer to our Flutter CartesianChart feature tour page to learn about its other groundbreaking feature representations. You can also explore our Flutter CartesianChart documentation to understand how to create and manipulate data.

For current customers, you can check out our components from the License and Downloads page. If you are new to Syncfusion, you can try our 30-day free trial to check out our other controls.

If you have any queries or require clarifications, please let us know in the comments section below. You can also contact us through our
support forums, Direct-Trac, or feedback portal. We are always happy to assist you!

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