Flutter charts — line charts

Daniel Llewellyn
3 min readDec 6, 2019

--

In this series of articles, I’m going to show you how to use the charts_flutter library in order to build some charts — starting with a line chart. First, we want some data, and we’re going to use some fake account data for a transaction list. Start with this function,

And here is the line to add to your pubspec

charts_common: ^0.8.1
charts_flutter: ^0.8.1

Now, let’s start with our widget

class SimpleTimeSeriesChart extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container();
}
}

And add a simple class to hold the data

class TimeSeriesSimple {
final DateTime time;
final int item;

TimeSeriesSimple(this.time, this.item);
}

Then let’s add these as parameters to our list which is what will define what data goes into the graph

final List<charts.Series> seriesList;SimpleTimeSeriesChart(this.seriesList);

And we’re going to try and create a graph which has the date / time at the bottom, and the amount of money in your account along the side, so we need to map our current data into a ‘List<charts.Series>’ let’s start by adding a factory method and map our data into our TimeSeriesSimple class we created before

factory SimpleTimeSeriesChart.withTransactionData(
List<Transaction> transactions) {
var runningTotal = 0;

List<TimeSeriesSimple> mapped = transactions.map((item) {
runningTotal += int.parse(item.amount);
return TimeSeriesSimple(time: item.date, sales: runningTotal);
}).toList();
return // TODO}

So this will simply convert our list into a list of <DateTime, int> starting at 0 — the starting amount of any bank account — and adding / subtracting data as we go through.

Now, we need to convert this list into a list like this

List<charts.Series<TimeSeriesSimple, DateTime>>

To clarify: in this sample, we are creating a list with only one line in it.

Replace the TODO in the code above with the following

List<charts.Series<TimeSeriesSimple, DateTime>> list = [
charts.Series<TimeSeriesSimple, DateTime>(
id: 'Balance',
colorFn: (_, __) => charts.MaterialPalette.red.shadeDefault,
domainFn: (TimeSeriesSimple transaction, _) => transaction.time,
measureFn: (TimeSeriesSimple transaction, _) => transaction.sales,
data: mapped,
)
];

return SimpleTimeSeriesChart(list);

What we’re doing here is making the time bar (along the bottom) the ‘time’ that we mapped above, i.e. the date of the transaction, and the value bar (along the side) the current balance.

Hop over to our currently boring ‘Build’ function and replace with this

@override
Widget build(BuildContext context) {
return charts.TimeSeriesChart(
seriesList,
animationDuration: Duration(seconds: 2),
dateTimeFactory: const charts.LocalDateTimeFactory(),
);
}

So what we’re doing here is setting our list (serliesList) to be plotted on the graph, enabling animation and setting the duration to 2 seconds — so it’s really obvious to see — we’re also setting the dateTimeFactory to use the local time, rather than UTC. Our result is this

Selecting a plot item from the chart

So moving on; we want to show a dialog when the user selects a certain position in the chart and display the date. To do this, we can add the following code to our widget

selectionModels: [
charts.SelectionModelConfig(
type: charts.SelectionModelType.info,
changedListener: _onSelectionChanged
)
],

Your whole build method would look like this

@override
Widget build(BuildContext context) {
return Column(
children: <Widget>[
SizedBox(
height: MediaQuery.of(context).size.height * 0.3,
child: charts.TimeSeriesChart(
seriesList,
animationDuration: Duration(seconds: 2),
dateTimeFactory: const charts.LocalDateTimeFactory(),
animate: true,
selectionModels: [
charts.SelectionModelConfig(
type: charts.SelectionModelType.info,
changedListener: _onSelectionChanged)
],
),
),
],
);
}

And then also add a function to handle when an item is selected.

_onSelectionChanged(charts.SelectionModel<DateTime> model) {
onItemClicked(model.selectedDatum.first.datum.time);
}

The syntax for this is a bit clunky — model.selectedDataum.first.dataum will basically be of the type of the object your time series is based on. E.g in our case it’s TimeSeriesSimple. So, .time will give us the time. If you use a different object, it’ll be a dynamic type, but basically it’ll be whatever type you make it.

You might also notice that onTimeClicked doesn’t exist at the moment, so let’s make that a Function that’s passed in

final Function(DateTime) onItemClicked;

You can use this to create a dialog box, or indeed change any other value in the calling widget. After everything, you’ll end up with a class that looks something like this

In the next part of this series, we’ll make the selected date scroll to the item in a transaction list when it is selected.

--

--