How to customise chart using charts_flutter package – tutorial
In this tutorial, I’ll show you how you can customise a bar chart using charts_flutter package. Halloween is around the corner, so let’s create a chart which designs will allude to these event and the end of this tutorial will look like this:
To generate a chart, we are going to use a charts_flutter package which the documentation available in the link below:
https://pub.dev/packages/charts_flutter
Let’s begin.
Step. 1 – config
First of all, we have to init our flutter project. Run the following command in your terminal:
1 |
flutter create <name_of_your_project> |
After our project is initialized, open it in your IDE and then:
- Create an assets folder in the root directory – it will be necessary to use the halloween font. Here is the one I’ve been using, but feel free to choose whichever you like:
https://www.1001fonts.com/feast-of-flesh-bb-font.html
- Download the fonts package and paste .otf and .ttf files in the assets folder
- Go to pubspec.yaml file and under the dependencies paste the version of package which Flutter has to install. Currently it’s 0.9.0:
1 2 3 4 |
dependencies: flutter: sdk: flutter charts_flutter: ^0.9.0 |
- Add assets folder to make it available in the project:
1 2 3 4 5 6 7 8 9 10 |
# The following section is specific to Flutter. flutter: # The following line ensures that the Material Icons font is # included with your application, so that you can use the icons in # the material Icons class. uses-material-design: true # To add assets to your application, add an assets section, like this: assets: - assets/ |
With that setup, we’re good to go to the next step and start to create the Halloween chart.
Step. 2 – main.dart
Let’s add some code to the root file. Replace defaulted code in main.dart with the following one:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
void main() => runApp(App()); class App extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( debugShowCheckedModeBanner: false, theme: ThemeData( primaryColor: Color(0xFFEB6123), fontFamily: 'fofbb_reg', ), home: Scaffold( appBar: AppBar( title: Text( 'Flutter Halloween chart', ), ), body: Text('Chart')), ); } } |
For now, we’ve returned a simple text in the scaffold body to avoid an error, but later on, we’ll replace it with our Halloween chart. Remember to import material package.
Step. 3 – create scary model
Halloween is all about collecting as many candies as possible, so let’s create a model with our candy stats.
- In the /lib folder create a subfolder called models with scary_statistics.dart file and paste the code below:
1 2 3 4 5 6 |
class ScaryStatics { final int house; final int candy; ScaryStatics(this.house, this.candy); } |
Step. 4 – create basis bar chart
Now, we can create our first simple bar chart, using the installed package.
- In the /lib directory, create a subfolder called widgets and create halloween_bar_chart.dart file inside it.
Below is the code snippet which will generate the basic bar chart:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
class HalloweenBarChart extends StatelessWidget { final List<Series> seriesList; final bool animate; HalloweenBarChart(this.seriesList, {this.animate}); factory HalloweenBarChart.withSampleData() { return HalloweenBarChart(_createSampleData(), animate: false); } static List<Series<ScaryStatics, String>> _createSampleData() { return []; } @override Widget build(BuildContext context) { return BarChart( seriesList, animate: animate, ); } } |
The only thing left is to import that class.
- In the main.dart file replace the scaffold body Text we previously put in it with the following lines:
1 2 3 4 5 |
body: Container( height: 200, padding: const EdgeInsets.all(15), child: HalloweenBarChart.withSampleData(), ), |
Now our chart needs to be fed with some Halloween data.
Inside _createSampleData method we’ll create some dummy data. Create a variable that holds some amount of instances of ScaryStatistics in mine version it looks like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
final data = [ ScaryStatics(1, 11), ScaryStatics(2, 14), ScaryStatics(3, 8), ScaryStatics(4, 10), ScaryStatics(5, 15), ScaryStatics(6, 1), ScaryStatics(7, 9), ScaryStatics(8, 3), ScaryStatics(9, 9), ScaryStatics(10, 12), ScaryStatics(11, 18), ScaryStatics(12, 8), ScaryStatics(13, 3), ScaryStatics(14, 4), ScaryStatics(15, 10), ScaryStatics(16, 12), ScaryStatics(17, 10), ScaryStatics(18, 8), ScaryStatics(19, 15), ScaryStatics(20, 12), ]; |
- Return this data in List of Series – which is the model delivered from charts_flutter package:
1 2 3 4 5 6 7 8 |
return [ Series( id: 'Data', data: data, domainFn: (ScaryStatics data, _) => data.house.toString(), measureFn: (ScaryStatics data, _) => data.candy, ), ]; |
Important notice: toString() called on data.house is necessary, because we provide a number of houses as integers, but it’s required to provide it as a String value.
Step. 5 – change basic styles of labels
Now our chart has a default look and the only difference is that our custom fonts are already loaded and applied on the x and y-axis labels. But we can go further and customize it independently.
So let’s start with the x-axis.
- Under animate property in BarChart you can define domainAxis and provide some custom options:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
@override Widget build(BuildContext context) { return BarChart( seriesList, animate: animate, domainAxis: OrdinalAxisSpec( renderSpec: SmallTickRendererSpec( labelStyle: TextStyleSpec( fontSize: 11, color: Color.fromHex(code: '#5E32BA'), ), lineStyle: LineStyleSpec( color: Color.transparent, ), ), ), ); } |
This will change the color and font-size of the label and hide the bottom line.
For the y-axis you can define primaryMeasureAxis property:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
@override Widget build(BuildContext context) { return BarChart( seriesList, animate: animate, domainAxis: OrdinalAxisSpec( renderSpec: SmallTickRendererSpec( labelStyle: TextStyleSpec( fontSize: 11, color: Color.fromHex(code: '#5E32BA'), ), lineStyle: LineStyleSpec( color: Color.transparent, ), ), ), primaryMeasureAxis: NumericAxisSpec( tickFormatterSpec: BasicNumericTickFormatterSpec((num value) => "$value 🍬"), renderSpec: GridlineRendererSpec( labelStyle: TextStyleSpec( fontSize: 11, color: Color.fromHex(code: '#96C457'), ), labelAnchor: TickLabelAnchor.after, ), ), ); } |
To display text-like labels we need BasicNumericTickFormatterSpec function and with little string interpolation and Halloween candy Unicode, we can display a pleasant-looking label.
We can customize also in what order our label and grid line are displayed. We can use the TickLabelAnchor enum for that.
Step. 6 – static chart labels
Currently, our chart starts from zero and on the x-axis, every house we visited is displayed in a row. We can also change that behavior and display more static labels.
- Create a final variable with our label’s:
1 2 3 4 5 6 7 8 9 10 11 12 |
@override Widget build(BuildContext context) { final staticLabels = <TickSpec<int>>[ // Possible to define style of labels directly inside TickSpec(5, style: TextStyleSpec(fontFamily: 'fofbb_reg')), TickSpec(10), TickSpec(15), TickSpec(20), ]; return BarChart( // Rest of the code |
- In primaryMeasureAxis inside NumericAxisSpec add the following property:
1 2 3 4 5 6 7 8 9 10 11 |
primaryMeasureAxis: NumericAxisSpec( tickProviderSpec: StaticNumericTickProviderSpec(staticLabels), tickFormatterSpec: BasicNumericTickFormatterSpec((num value) => "$value 🍬"), renderSpec: GridlineRendererSpec( labelStyle: TextStyleSpec( fontSize: 11, color: Color.fromHex(code: '#96C457'), ), labelAnchor: TickLabelAnchor.after, ), ), |
Now our y-axis labels start from 5 and display only provided labels.
We can do similar with the x-axis:
- Create a final variable with our label’s under staticLabels variable:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
@override Widget build(BuildContext context) { final staticLabels = <TickSpec<int>>[ // Possible to define style of labels directly inside TickSpec(5, style: TextStyleSpec(fontFamily: 'fofbb_reg')), TickSpec(10), TickSpec(15), TickSpec(20), ]; final staticTicks = <TickSpec<String>>[ // Possible to define style of labels directly inside TickSpec("1", label: "1 house", style: TextStyleSpec(fontFamily: 'fofbb_reg')), TickSpec("10", label: "10 house"), TickSpec("20", label: "20 house"), ]; |
- Then inside in domainAxis in OrdinalAxisSpec add the following line:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
domainAxis: OrdinalAxisSpec( tickProviderSpec: StaticOrdinalTickProviderSpec(staticTicks), renderSpec: SmallTickRendererSpec( labelStyle: TextStyleSpec( lineHeight: 3, fontSize: 11, color: Color.fromHex(code: '#5E32BA'), ), lineStyle: LineStyleSpec( color: Color.transparent, ), ), ), |
With that, we have customized x and y-axis labels.
Step. 7 – default selected (min/max)
Now let’s make a default selected bars with the minimum and maximum values in different colors.
- Inside _createSampleData method paste before return statement below code:
1 2 3 4 5 6 7 8 9 10 11 |
final highestValue = data.reduce((curr, next) => curr.candy > next.candy ? curr : next); final smallestValue = data.reduce((curr, next) => curr.candy < next.candy ? curr : next); return [ Series( id: 'Data', data: data, domainFn: (ScaryStatics data, _) => data.house.toString(), measureFn: (ScaryStatics data, _) => data.candy, ), ]; |
- Inside of the return, we can add colorFn property and with a little conditioning we can customize our bars colors depend on values:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
return [ Series( id: 'Data', data: data, domainFn: (ScaryStatics data, _) => data.house.toString(), measureFn: (ScaryStatics data, _) => data.candy, colorFn: (data, _) { if (data.candy == highestValue.candy) { return Color.fromHex(code: '#18181A'); } if (data.candy == smallestValue.candy) { return Color.fromHex(code: '#5E32BA'); } return Color.fromHex(code: '#EB6123'); }, ), ]; |
- Finally, as a little polishing let’s add some line-height between x-axis labels and columns. Inside OrdinalAxisSpec add the following line:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
return BarChart( seriesList, animate: animate, domainAxis: OrdinalAxisSpec( tickProviderSpec: StaticOrdinalTickProviderSpec(staticTicks), renderSpec: SmallTickRendererSpec( labelStyle: TextStyleSpec( lineHeight: 3, fontSize: 11, color: Color.fromHex(code: '#5E32BA'), ), lineStyle: LineStyleSpec( color: Color.transparent, ), ), ), |
- To make bars a little rounded add the following property:
1 2 3 4 5 6 |
return BarChart( seriesList, animate: animate, defaultRenderer: BarRendererConfig( cornerStrategy: const ConstCornerStrategy(7), ), |
And that’s all. Our halloween bar chart is ready, we now know how many candies we collect in which house and we can now eat our sweets. Enjoy Halloween 🙂