Pan and Zoom in time-series bar chart - charts_flutter

Viewed 1874

I'm using charts_flutter to create some time-series bar graphs in flutter. I was looking for a way to display a controlled number of zoomed bars at a time and provide a slider for rest of the bars. I was able to do the above with BarCharts() but not with TimeSeriesCharts(). I tried the suggestions given in the following links where the similar issue was raised:

  1. Here
  2. Here
  3. Here

But none of them had any effect on the view. Is there a way to show bars for only 5 days?

Here is my code,

import 'package:bar_wow/subscriber_series.dart';
import 'package:charts_flutter/flutter.dart' as charts;
import 'package:flutter/material.dart';


class SubscriberChart extends StatefulWidget{
  final List<charts.Series<SubscriberSeries, DateTime>> data;
  final bool animate;

  SubscriberChart(this.data, this.animate);
  
  @override
  State<StatefulWidget> createState() => new _SelectionCallbackState();

}

class _SelectionCallbackState extends State<SubscriberChart> {
  DateTime _time;
  Map<String, num> _measures;
  
  _onSelectionChanged(charts.SelectionModel model) {
    final selectedDatum = model.selectedDatum;

    DateTime time;
    final measures = <String, num>{};

    if (selectedDatum.isNotEmpty) {
      time = selectedDatum.first.datum.time;
      selectedDatum.forEach((charts.SeriesDatum datumPair) {
        measures[datumPair.series.displayName] = datumPair.datum.subscribers;
      });
    }

    setState(() {
      _time = time;
      _measures = measures;
    });
  }

  @override
  Widget build(BuildContext context) {
    final children = <Widget>[
      new Container(
        height: 400,
        padding: EdgeInsets.all(20),
        child: Card(
          child: Padding(
            padding: const EdgeInsets.all(8.0),
            child: Column(
              children: <Widget>[
                Expanded(
                  child: new charts.TimeSeriesChart(
                    widget.data,
                    animate: widget.animate,
                    defaultRenderer: new charts.BarRendererConfig<DateTime>(
                      groupingType: charts.BarGroupingType.groupedStacked,
                      //barRendererDecorator: new charts.BarLabelDecorator<String>(),
                    ),
                    defaultInteractions: false,
                    behaviors: [
                      new charts.SelectNearest(), new charts.DomainHighlighter(),
                      new charts.ChartTitle(
                        'Response Time',
                        behaviorPosition: charts.BehaviorPosition.top,
                        titleOutsideJustification: charts.OutsideJustification.start,
                        innerPadding: 18
                      ),
                      new charts.ChartTitle(
                        'Time →',
                        behaviorPosition: charts.BehaviorPosition.bottom,
                        titleOutsideJustification:
                        charts.OutsideJustification.middleDrawArea),
                      new charts.ChartTitle(
                        'Aggregate →',
                        behaviorPosition: charts.BehaviorPosition.start,
                        titleOutsideJustification:
                        charts.OutsideJustification.middleDrawArea),
                      new charts.SeriesLegend(),
                      new charts.SlidingViewport(),
                      new charts.PanAndZoomBehavior(),
                    ],
                    domainAxis: new DateTimeAxisSpec(
                      viewport: charts.DateTimeExtents(start: DateTime(2020,5,7), end: DateTime.now().add(Duration(days: 5 ))),
                    ),
                    selectionModels: [
                      new charts.SelectionModelConfig(
                        type: charts.SelectionModelType.info,
                        changedListener: _onSelectionChanged,
                      )
                    ],
                  ),
                ),
              ],
            ),
          ),
        ),
      ),
    ];

    if (_time != null) {
      children.add(new Padding(
          padding: new EdgeInsets.only(top: 5.0),
          child: new Text(_time.toString())));
    }
    _measures?.forEach((String series, num value) {
      children.add(new Text('$series: $value'));
    });

    return new Container(child:Padding(padding:EdgeInsets.all(10),child:Column(children: children),),);
  }
}
1 Answers

You need to override axis.autoViewport in DateTimeAxisSpec.configure and set it to false. To do this, you can extend DateTimeAxisSpec to update the config.

class DateTimeAxisSpecManualViewport extends DateTimeAxisSpec {

  const DateTimeAxisSpecManualViewport ({
    RenderSpec<DateTime> renderSpec,
    DateTimeTickProviderSpec tickProviderSpec,
    DateTimeTickFormatterSpec tickFormatterSpec,
    bool showAxisLine,
  }) : super(
            renderSpec: renderSpec,
            tickProviderSpec: tickProviderSpec,
            tickFormatterSpec: tickFormatterSpec,
            showAxisLine: showAxisLine);

  @override
  configure(Axis<DateTime> axis, ChartContext context,
      GraphicsFactory graphicsFactory) {
    super.configure(axis, context, graphicsFactory);
    
    // Disable autoViewport
    axis.autoViewport = false;
  }
}

Then set DateTimeAxisSpecManualViewport in charts.TimeSeriesChart.domainAxis() and configure the start and end date of the axis.

charts.TimeSeriesChart(
  domainAxis: DateTimeAxisSpecManualViewport(...),
)
Related