Trackball and Crosshair in Flutter Cartesian Charts (SfCartesianChart)

11 Apr 202224 minutes to read

Trackball

Trackball feature displays the tooltip for the data points that are closer to the point where you touch on the chart area. This feature, especially, can be used instead of data label feature when you cannot show data labels for all data points due to space constraint. This feature can be enabled using enable property of trackballBehavior. Trackball will be activated once you long-press anywhere on the chart area. Once it is activated, it will appear in the UI and move based on your touch movement until you stop touching on the chart.

The trackball state will be preserved on the device’s orientation change and on browser resize. For example, if the trackball’s hideDelay is set to 10,000ms, and when you change the orientation of your device from portrait to landscape after 5,000ms of trackball display, the trackball will be displayed for the next 5,000ms in landscape mode before disappearing.

You can use the following properties to customize the appearance of trackball tooltip.

  • lineType - specifies the type of trackball line. By default, vertical line will be displayed.
  • lineColor - specifies the color of the trackball line.
  • lineWidth - specifies the stroke width of the trackball line.
  • lineDashArray- used to render trackball line with dashes.
  • shouldAlwaysShow - used to show the trackball even after the touch end.
  • borderWidth - used to change the stroke width of the axis tooltip.
  • borderColor - used to change the stroke color of the axis tooltip.
  • arrowLength - specifies the length of the tooltip arrow.
  • arrowWidth - specifies the width of the tooltip arrow.
  • format - by default, axis value will be displayed in the tooltip, and it can be customized by adding desired text as prefix or suffix.
  • textStyle - used to change the text color, size, font family, fontStyle, and font weight.
  • textStyle.color - used to change the color of the tooltip text.
  • textStyle.fontFamily - used to change the font family for tooltip text.
  • textStyle.fontStyle - used to change the font style for tooltip text.
  • textStyle.fontSize - used to change the font size for tooltip text.
  • hideDelay - used to specify disappear delay for trackball.

Note: The above mentioned properties are only applicable for SfCartesian types of charts.

late TrackballBehavior _trackballBehavior;

    @override
    void initState(){
      _trackballBehavior = TrackballBehavior(
                  // Enables the trackball
                  enable: true,
                  tooltipSettings: InteractiveTooltip(
                    enable: true,
                    color: Colors.red
                  )
                );
      super.initState();
    }

    @override
    Widget build(BuildContext context) {
      return Scaffold(
        body: SafeArea(
          child: Center(
            child: Container(
              child: SfCartesianChart(
                trackballBehavior: _trackballBehavior,
                series: <LineSeries<ChartData, String>>[
                      LineSeries<ChartData, String>(
                          dataSource: ChartData,
                          xValueMapper: (ChartData data, _) => data.x,
                          yValueMapper: (ChartData data, _) => data.y),
                          ]
                      )
                  )
              )
          )
      );
    }

Trackball

Label display mode

The tooltipDisplayMode property is used to specify whether to display label for all the data points along the vertical line or display only single label. Following are the options you can set to this property,

late TrackballBehavior _trackballBehavior;

    @override
    void initState(){
      _trackballBehavior = TrackballBehavior(
                  enable: true,
                  // Display mode of trackball tooltip
                  tooltipDisplayMode: TrackballDisplayMode.floatAllPoints
                );
      super.initState();
    }

    @override
    Widget build(BuildContext context) {
      return Scaffold(
        body: SafeArea(
          child: Center(
            child: Container(
              child: SfCartesianChart(
                trackballBehavior: _trackballBehavior, 
                series: <LineSeries<ChartData, num>>[
                      LineSeries<ChartData, num>(
                          dataSource: ChartData,
                          xValueMapper: (ChartData data, _) => data.x,
                          yValueMapper: (ChartData data, _) => data.y),
                          ]
                      )
                  )
              )
          )
      );
    }

Label display mode

Label alignment

The position of trackball tooltip can be changed using the tooltipAlignment property of trackballBehavior. The following options are available in tooltipAlignment.

Note: The tooltipAlignment is only applicable for trackball display mode TrackballDisplayMode.groupAllPoints.

late TrackballBehavior _trackballBehavior;

    @override
    void initState(){
      _trackballBehavior = TrackballBehavior(
                  enable: true,
                  tooltipAlignment: ChartAlignment.near,
                  tooltipDisplayMode: TrackballDisplayMode.groupAllPoints
                );
      super.initState();
    }

    @override
    Widget build(BuildContext context) {
      return Scaffold(
        body: SafeArea(
          child: Center(
            child: Container(
              child: SfCartesianChart(
                trackballBehavior: _trackballBehavior,
                series: <LineSeries<ChartData, num>>[
                      LineSeries<ChartData, num>(
                          dataSource: ChartData,
                          xValueMapper: (ChartData data, _) => data.x,
                          yValueMapper: (ChartData data, _) => data.y),
                          ]
                      )
                  )
              )
          )
      );
    }

Label alignment

Note: This is applicable only when the tooltipDisplayMode is set to TrackballDisplayMode.groupAllPoints.

Label format

By default, axis value will be displayed in the tooltip, and it can be customized using format property by adding desired text as prefix or suffix.

late TrackballBehavior _trackballBehavior;

    @override
    void initState(){
      _trackballBehavior = TrackballBehavior(
                  enable: true,
                  tooltipSettings: InteractiveTooltip(
                    // Formatting trackball tooltip text
                    format: 'point.x : point.y%'
                  )
                );
      super.initState();
    }

    @override
    Widget build(BuildContext context) {
      return Scaffold(
        body: SafeArea(
          child: Center(
            child: Container(
              child: SfCartesianChart(
                trackballBehavior: _trackballBehavior,
                series: <LineSeries<ChartData, String>>[
                      LineSeries<ChartData, String>(
                          dataSource: ChartData,
                          xValueMapper: (ChartData data, _) => data.x,
                          yValueMapper: (ChartData data, _) => data.y),
                          ]
                      )
                  )
              )
          )
      );
    }

Label format

Activation mode

The activationMode property is used to restrict the visibility of trackball based on the touch actions. The default value of this property is ActivationMode.longPress.

The ActivationMode enum contains the following values:

late TrackballBehavior _trackballBehavior;

    @override
    void initState(){
      _trackballBehavior = TrackballBehavior(
                  enable: true,
                    // Displays the trackball on single tap
                    activationMode: ActivationMode.singleTap
                );
      super.initState();
    }

    @override
    Widget build(BuildContext context) {
      return Scaffold(
        body: SafeArea(
          child: Center(
            child: Container(
              child: SfCartesianChart(
                primaryXAxis: DateTimeAxis(),
                trackballBehavior: _trackballBehavior,
                series: <LineSeries<ChartData, DateTime>>[
                      LineSeries<ChartData, DateTime>(
                          dataSource: ChartData,
                          xValueMapper: (ChartData data, _) => data.x,
                          yValueMapper: (ChartData data, _) => data.y),
                          ]
                      )
                  )
              )
          )
      );
    }

Trackball tooltip overlap

SfCartesianChart provides support to avoid the overlapping of two or more tooltips of the trackball and no API is required for this feature as it will be done by default. For example, If we have 2 or more series data points rendered close to each other then, the trackball tooltips of each data point will not be overlap with each other.

late TrackballBehavior _trackballBehavior;

    @override
    void initState(){
      _trackballBehavior = TrackballBehavior(
                  enable: true);
      super.initState();
    }

    @override
    Widget build(BuildContext context) {
      return Scaffold(
          child: Center(
            child: Container(
              child: SfCartesianChart(
                primaryXAxis: DateTimeAxis(),
                trackballBehavior: _trackballBehavior,
                series: <LineSeries<ChartData, DateTime>>[
                      LineSeries<ChartData, DateTime>(
                          dataSource: ChartData,
                          markerSettings: MarkerSettings(isVisible: true),
                          xValueMapper: (ChartData data, _) => data.x,
                          yValueMapper: (ChartData data, _) => data.y),
                      LineSeries<ChartData, DateTime>(
                          dataSource: ChartData,
                          markerSettings: MarkerSettings(isVisible: true),
                          xValueMapper: (ChartData data, _) => data.x,
                          yValueMapper: (ChartData data, _) => data.y1),
                      LineSeries<ChartData, DateTime>(
                          dataSource: ChartData,
                          markerSettings: MarkerSettings(isVisible: true),
                          xValueMapper: (ChartData data, _) => data.x,
                          yValueMapper: (ChartData data, _) => data.y2),
                      LineSeries<ChartData, DateTime>(
                          dataSource: ChartData,
                          markerSettings: MarkerSettings(isVisible: true),
                          xValueMapper: (ChartData data, _) => data.x,
                          yValueMapper: (ChartData data, _) => data.y3)
                ]
              )
            )
        )
      );
    }

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

Trackball tooltip overlap

And moreover, the trackball tooltip will render on the right side of the trackball line if adequate space is available else will be moved to the left by default. The trackball tooltip is smartly positioned above the trackball line if there is no space on the right and left sides of the trackball line. However, the trackball tooltip size must be smaller than the chart’s plot area size.

late TrackballBehavior _trackballBehavior;
    final List<ChartData> data = <ChartData>[
      ChartData('Jan', 15, 39, 60),
      ChartData('Feb', 20, 30, 55),
      ChartData('Mar', 25, 28, 48),
      ChartData('Apr', 21, 35, 57),
      ChartData('May', 13, 39, 62),
      ChartData('Jun', 18, 41, 64),
      ChartData('Jul', 24, 45, 57),
      ChartData('Aug', 23, 48, 53),
      ChartData('Sep', 19, 54, 63),
      ChartData('Oct', 31, 55, 50),
      ChartData('Nov', 39, 57, 66),
      ChartData('Dec', 50, 60, 65),
    ];

    @override
    void initState(){
      _trackballBehavior = TrackballBehavior(
        enable: true,
        tooltipDisplayMode: TrackballDisplayMode.groupAllPoints
      );
      super.initState();
    }

    @override
    Widget build(BuildContext context) {
      return SfCartesianChart(
        primaryXAxis: CategoryAxis(),
        trackballBehavior: _trackballBehavior,
        series: <LineSeries<ChartData, String>>[
          LineSeries<ChartData, String>(
            dataSource: data,
            markerSettings: MarkerSettings(isVisible: true),
            name: 'United States of America',
            xValueMapper: (ChartData sales, _) => sales.month,
            yValueMapper: (ChartData sales, _) => sales.firstSale,
          ),
          LineSeries<ChartData, String>(
            dataSource: data,
            markerSettings: MarkerSettings(isVisible: true),
            name: 'Germany',
            xValueMapper: (ChartData sales, _) => sales.month,
            yValueMapper: (ChartData sales, _) => sales.secondSale,
          ),
          LineSeries<ChartData, String>(
            dataSource: data,
            markerSettings: MarkerSettings(isVisible: true),
            name: 'United Kingdom',
            xValueMapper: (ChartData sales, _) => sales.month,
            yValueMapper: (ChartData sales, _) => sales.thirdSale,
          )
        ]
      );
    }

    class ChartData {
      ChartData(
        this.month, 
        this.firstSale, 
        this.secondSale, 
        this.thirdSale
      );

      final String month;
      final double firstSale;
      final double secondSale;
      final double thirdSale;
    }

Trackball tooltip smart positioning

Trackball marker settings

Trackball markers are used to provide information about the exact point location. You can add a shape to adorn each data point when the trackball is visible. Trackball markers can be enabled by using the markerVisibility property of TrackballMarkerSettings. The below markerVisibility property determines whether the trackball marker should be visible or not when the trackball is enabled in the chart

Also refer, marker customization for customizing the appearance of trackball marker.

late TrackballBehavior _trackballBehavior;

    @override
    void initState(){
      _trackballBehavior = TrackballBehavior(
                  enable: true,
                  markerSettings: TrackballMarkerSettings(markerVisibility: TrackballVisibilityMode.visible)
                );
      super.initState();
    }

    @override
    Widget build(BuildContext context) {
      return Scaffold(
          child: Center(
            child: Container(
              child: SfCartesianChart(
                primaryXAxis: DateTimeAxis(),
                trackballBehavior: _trackballBehavior,
                <LineSeries<ChartData, DateTime>>[
                      LineSeries<ChartData, DateTime>(
                          dataSource: ChartData,
                          xValueMapper: (ChartData data, _) => data.x,
                          yValueMapper: (ChartData data, _) => data.y)
                      LineSeries<ChartData, DateTime>(
                          dataSource: ChartData1,
                          xValueMapper: (ChartData data, _) => data.x,
                          yValueMapper: (ChartData data, _) => data.y),
                      LineSeries<ChartData, DateTime>(
                          dataSource: ChartData2,
                          xValueMapper: (ChartData data, _) => data.x,
                          yValueMapper: (ChartData data, _) => data.y),
                ]
              )
            )
          )
      );
    }

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

Trackball marker

See Also

Trackball tooltip template

You can customize the appearance of the trackball tooltip with your own widgets by using the builder property of trackballBehavior.

late TrackballBehavior _trackballBehavior;

    @override
    void initState() {
      _trackballBehavior = TrackballBehavior(
        enable: true,
        builder: (BuildContext context, TrackballDetails trackballDetails) {
          return Container(
            height: 50,
            width: 150,
            decoration: BoxDecoration(
              color: Color.fromRGBO(0, 8, 22, 0.75),
              borderRadius: BorderRadius.all(Radius.circular(6.0)),
            ),
            child: Row(
              children: [
                Padding(
                    padding: EdgeInsets.only(left: 5),
                    child: SizedBox(
                      child: Image.asset('images/People_Circle16.png'),
                      height: 30,
                      width: 30,
                    )
                  ),
                Center(
                    child: Container(
                        padding: EdgeInsets.only(top: 11, left: 7),
                        height: 40,
                        width: 100,
                        child: Text(
                            '${trackballDetails.point!.x.toString()} : \$${trackballDetails.point!.y.toString()}',
                            style: TextStyle(
                                fontSize: 13,
                                color: Color.fromRGBO(255, 255, 255, 1)
                              )
                            )
                          )
                        )
                    ],
                ),
            );
        },
      );
      super.initState();
    }

    @override
    Widget build(BuildContext context) {
      return Scaffold(
        body: Center(
          child: Container(
            child: SfCartesianChart(
              primaryXAxis: CategoryAxis(),
              trackballBehavior: _trackballBehavior,
              series: <ChartSeries<ChartData, String>>[
                SplineSeries<ChartData, String>(
                    dataSource: chartData,
                    xValueMapper: (ChartData data, _) => data.x,
                    yValueMapper: (ChartData data, _) => data.y)
              ],
            ),
          ),
        ),
      );
    }

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

Trackball template

Trackball grouping mode info

TrackballGroupingModeInfo is store the group mode details of trackball template.

The following properties are available in TrackballGroupingModeInfo:

Trackball tooltip Marker

The canShowMarker is used to toggle the visibility of the marker in the trackball tooltip.

Markers are rendered with the series color and placed near the value in trackball tooltip to convey which value belongs to which series.

Trackball tooltip marker uses the same shape specified for the series marker. But trackball tooltip marker will render based on the value specified to this property irrespective of considering the series marker’s visibility.

Defaults to true.

late TrackballBehavior _trackballBehavior;

    @override
    void initState(){
      _trackballBehavior = TrackballBehavior(
                      enable: true,
                    );
      super.initState();
    }
    
    @override
    Widget build(BuildContext context) {
      return Scaffold(
        child: Center(
            child: Container(
                child: SfCartesianChart(
                    primaryXAxis: CategoryAxis(),
                    trackballBehavior: _trackballBehavior,
                    series: <LineSeries<ChartData, String>>[
                      LineSeries<ChartData, String>(
                          dataSource: chartData,
                          xValueMapper: (ChartData data, _) => data.x,
                          yValueMapper: (ChartData data, _) => data.y),
                      LineSeries<ChartData, String>(
                          dataSource: chartData,
                          xValueMapper: (ChartData data, _) => data.x,
                          yValueMapper: (ChartData data, _) => data.y1),
                      LineSeries<ChartData, String>(
                          dataSource: chartData,
                          xValueMapper: (ChartData data, _) => data.x,
                          yValueMapper: (ChartData data, _) => data.y2),
                      LineSeries<ChartData, String>(
                          dataSource: chartData,
                          xValueMapper: (ChartData data, _) => data.x,
                          yValueMapper: (ChartData data, _) => data.y3),
                    ]
                )
            )
        )
      );
    }

    class ChartData {
      ChartData(this.x, this.y, this,y1, this.y2, this.y3);
      final String x;
      final double? y;
      final double? y1;
      final double? y2;
      final double? y3;
    }

Trackball tooltip marker

See Also

Crosshair

Crosshair has a vertical and horizontal line to view the value of the axis.

Crosshair lines can be enabled by using enable property in the crosshairBehavior. Likewise tooltip label for an axis can be enabled by using enable property of interactiveTooltip in the corresponding axis. The hideDelay property can be used to specify a disappear delay for the crosshair.

The crosshair state will be preserved on the device’s orientation change and on browser resize. For example, if the crosshair’s ‘hideDelay’ is set to 10,000ms, and when you change the orientation of your device from portrait to landscape after 5,000ms of crosshair display, the crosshair will be displayed for the next 5,000ms in landscape mode before disappearing.

Note: The above mentioned properties are only applicable for SfCartesian types of charts.

late CrosshairBehavior _crosshairBehavior;

    @override
    void initState(){
      _crosshairBehavior = CrosshairBehavior(
                  // Enables the crosshair
                  enable: true
                );
      super.initState();
    }

    @override
    Widget build(BuildContext context) {
      return Scaffold(
        body: SafeArea(
          child: Center(
            child: Container(
              child: SfCartesianChart(
                primaryXAxis: NumericAxis(
                  interactiveTooltip: InteractiveTooltip(
                    // Enables the crosshair tooltip
                    enable: true
                  )
                ),
                crosshairBehavior: _crosshairBehavior
              )
            )
          )
        )
      );
    }

Crosshair

Track line customization

The appearance of the track line in crosshair can be customized using the following properties.

  • lineType - specifies the type of crosshair line.
  • lineColor - specifies the color of the crosshair line.
  • lineWidth - specifies the stroke width of the crosshair line.
  • lineDashArray - used to render crosshair line with dashes.
  • shouldAlwaysShow - enables or disables the crosshair. Defaults to false.
late CrosshairBehavior _crosshairBehavior;

    @override
    void initState(){
      _crosshairBehavior = CrosshairBehavior(
                  enable: true,
                  lineColor: Colors.red,
                  lineDashArray: <double>[5,5],
                  lineWidth: 2,
                  lineType: CrosshairLineType.vertical
                );
      super.initState();
    }

    @override
    Widget build(BuildContext context) {
      return Scaffold(
        body: SafeArea(
        child: Center(
          child: Container(
            child: SfCartesianChart(
              crosshairBehavior: _crosshairBehavior
              )
            )
          )
        )
      );
    }

Customized trackline

Show axis tooltip

The axis tooltip can be enabled using enable property of interactiveTooltip. You can customize the appearance of axis tooltip using the following properties.

  • enable - used to enable the axis tooltip.
  • borderWidth - used to change the stroke width of the axis tooltip.
  • borderColor - used to change the stroke color of the axis tooltip.
  • format - by default, axis value will be displayed in the tooltip, and it can be customized by adding desired text as prefix or suffix.
  • textStyle - used to change the text color, size, font family, fontStyle, and font weight.
  • textStyle.color - used to change the color of the text.
  • textStyle.fontFamily - used to change the font family for chart title.
  • textStyle.fontStyle - used to change the font style for the chart title.
  • textStyle.fontSize - used to change the font size for the chart title.

Activation mode

The activationMode property is used to restrict the visibility of trackball based on the touch actions. The default value of this property is ActivationMode.longPress.

The ActivationMode enum contains the following values:

late CrosshairBehavior _crosshairBehavior;

    @override
    void initState(){
      _crosshairBehavior = CrosshairBehavior(
                  enable: true,
                  // Displays the crosshair on single tap
                  activationMode: ActivationMode.singleTap
                );
      super.initState();
    }

    @override
    Widget build(BuildContext context) {
      return Scaffold(
        body: SafeArea(
          child: Center(
            child: Container(
              child: SfCartesianChart(
                crosshairBehavior: _crosshairBehavior
              )
            )
          )
        )
      );
    }

Also refer crosshair and trackball events for customizing the crosshair and trackball further.

See Also

Note: chartData in the above code snippets is a class type list and holds the data for binding to the chart series. Refer Bind data source topic for more details.