How to customize the trackball in Flutter CartesianChart?
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:
Transposed chart:
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!