Skip to content

[Flutter] Use fl_chart Package To Implement Pie Chart

Last Updated on 2021-10-14 by Clay

If you have a requirement for plotting a pie chart when you developing via Flutter, I can recommend a useful plotting package: fl_chart.

According to the information on Flutter pub (https://pub.dev/packages/fl_chart), there are several types of charts that fl_chart can plot:

  • Line chart
  • Bar chart
  • Pie chart
  • Scatter chart

It is even expected to add support for radar chart. It is really a very full-featured package.

However, the most important thing is that I need to use fl_chart to draw a pie chart. The official description, some simple personal description, and sample code are recorded below.


Introduction to the PieChart parameter of fl_chart

As can be seen from the diagram on GitHub, fl_chart not only provides an interface for drawing pie charts, but also provides many ways to customize pie charts.

I quote the instructions on GitHub for introducing the parameters.


PieChartData

This is the basic parameter of PieChartData.

PropNameDescriptiondefault value
sectionsDisplay the list of PieChartSectionData (the parameters of PieChartSectionData are described below)[]
centerSpaceRadiusThe available space in the center of the PieChart. (If you want to adjust with the visual size, you must set double.infinity)double.nan
centerSpaceColorPie Chart The color of the usable space in the center of the PieChartColors.transparent
sectionsSpaceInterval between sections2
startDegreeOffsetOffset of pie chart rotation (0-360)0
pieTouchDataUse PieTouchData class to control "touch interaction" (PieTouchData parameters are described below)PieTouchData()
borderDataUse FlBorderData to control the border information of the chart (the parameters of FlBorderData are described below)FlBorderData()


PieChartSectionData

PieChartSectionData is a section class of pie chart. We can configure PieChartSectionData to customize any section area.

PropNameDescriptiondefault value
valuevalue is the weight of each section. (The greater the weight, the larger the area occupied by the sector of a pie chart)10
colorsection colorColors.red
radiussection radius width40
showTitleShow or hide the title of each sectiontrue
titleStyletitle styleTextStyle(
color: Colors.white,
fontSize: 16,
fontWeight: FontWeight.bold
)
titlesection titlevalue
badgeWidgetsection badgenull
titlePositionPercentageOffsetsection title percentage (0 - 1)0.5
badgePositionPercentageOffsetsection badge percentage (0 - 1)0.5


PieTouchData

PropNameDescriptiondefault value
enableEnable or disable touch behaviortrue
touchCallbackListen to the callback to retrieve touch events. PieTouchResponse will be provided (the parameters of PieTouchResponse are described below)null


PieTouchResponse

PropNameDescriptiondefault value
sectionDataPieChartSectionData touched by the usernull
touchedSectionIndexThe section number touched by the usernull
touchAngleThe angle touched by the usernull
touchRadiusThe radius the user touchesnull
touchInputA touch behavior encapsulated in the FlTouchInput class (this article will not use it, you can go to FlTouchInput to view if you are interested)null


FlBorderData

PropNameDescriptiondefault value
showShow or hide the bordertrue
borderUse the Border class to set the details of the drawing borderBorder.all(color: Colors.black, width: 1.0,
style: BorderStyle.bold
)

Preparation

First we need to get the fl_chart package. Write in the project's pubspec.yaml:

dependencies:
  flutter:
    sdk: flutter
  fl_chart: ^0.12.3


Then use the following command to get package:

flutter pub get


By the way, 0.12.3 is the version I used, if your version is mismatch with Flutter version, you need to go to the fl_chart package page to confirm which version is correct.


Sampel Code Explanation

Import package and build main() entry point

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

import 'package:fl_chart/fl_chart.dart';


// Main
void main() => runApp(MyApp());


class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: PieChartPage(),
    );
  }
}


class PieChartPage extends StatefulWidget {
  @override
  State<StatefulWidget> createState() => _PieChartPageState();
}


After that, the main program starts with _PieChartPageState(). But before that, according to the official sample code, we can write the Indicator class to create a small icon description of the pie chart.


Indicator

// Indicator
class Indicator extends StatelessWidget {
  final Color color;
  final Color textColor;
  final String text;
  final bool isSquare;
  final double size;

  const Indicator({
    Key key,
    this.color,
    this.textColor = Colors.white,
    this.text,
    this.isSquare,
    this.size = 16,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Row(
      children: <Widget>[
        Container(
          width: size,
          height: size,
          decoration: BoxDecoration(
            shape: isSquare ? BoxShape.rectangle : BoxShape.circle,
            color: color,
          ),
        ),
        const SizedBox(
          width: 3,
        ),
        Text(
          text,
          style: TextStyle(
            fontSize: 16,
            fontWeight: FontWeight.bold,
            color: textColor,
          ),
        )
      ],
    );
  }
}


The effect is roughly as follows:

就是這種小圖示


_PieChartPageState()

class _PieChartPageState extends State {
  int touchedIndex;

  @override
  Widget build(BuildContext context) {
    SystemChrome.setEnabledSystemUIOverlays([SystemUiOverlay.bottom]);
    return AspectRatio(
      aspectRatio: 1.3,
      child: Card(
        color: Colors.white,
        child: Column(
          children: <Widget>[
            const SizedBox(
              height: 28,
            ),
            Row(
              mainAxisSize: MainAxisSize.max,
              mainAxisAlignment: MainAxisAlignment.spaceEvenly,
              children: <Widget>[
                Indicator(
                  color: Colors.blue,
                  text: "One",
                  isSquare: false,
                  size: touchedIndex == 0 ? 18 : 16,
                  textColor: touchedIndex == 0
                    ? Colors.black
                    : Colors.grey,
                ),
                Indicator(
                  color: Colors.red,
                  text: "Two",
                  isSquare: false,
                  size: touchedIndex == 1 ? 18 : 16,
                  textColor: touchedIndex == 1
                    ? Colors.black
                    : Colors.grey,
                ),
                Indicator(
                  color: Colors.green,
                  text: "Three",
                  isSquare: false,
                  size: touchedIndex == 2 ? 18 : 16,
                  textColor: touchedIndex == 2
                    ? Colors.black
                    : Colors.grey,
                ),
                Indicator(
                  color: Colors.yellow,
                  text: "Four",
                  isSquare: false,
                  size: touchedIndex == 3 ? 18 : 16,
                  textColor: touchedIndex == 3
                    ? Colors.black
                    : Colors.grey,
                ),
              ],
            ),
            const SizedBox(
              height: 18,
            ),

            // Pie chart
            Expanded(
              child: AspectRatio(
                aspectRatio: 1,
                child: PieChart(
                  PieChartData(
                    pieTouchData: PieTouchData(touchCallback: (pieTouchResponse) {
                      setState(() {
                        if (pieTouchResponse.touchInput is FlLongPressEnd ||
                            pieTouchResponse.touchInput is FlPanEnd) {
                          touchedIndex = -1;
                        }
                        else {
                          touchedIndex = pieTouchResponse.touchedSectionIndex;
                        }
                      });
                    }),
                    startDegreeOffset: 270,
                    borderData: FlBorderData(
                      show: false,
                    ),
                    sectionsSpace: 1,
                    centerSpaceRadius: 0,
                    sections: showingSections()
                  ),
                ),
              )
            )
          ],
        ),
      ),
    );
  }

  List<PieChartSectionData> showingSections() {
    return List.generate(
      4,
      (index) {
        final isTouched = index == touchedIndex;
        final double opacity = isTouched ? 1 : 0.6;

        // Condition
        switch (index) {
          case 0:
            return PieChartSectionData(
              color: Colors.blue.withOpacity(opacity),
              value: 1,
              title: "blue pie",
              radius: 80,
              titleStyle: TextStyle(
                fontSize: 18,
                fontWeight: FontWeight.bold,
                color: Colors.black,
              ),
              titlePositionPercentageOffset: 0.99,
            );
          case 1:
            return PieChartSectionData(
              color: Colors.red.withOpacity(opacity),
              value: 1,
              title: "red pie",
              radius: 65,
              titleStyle: TextStyle(
                fontSize: 18,
                fontWeight: FontWeight.bold,
                color: Colors.black
              ),
              titlePositionPercentageOffset: 0.99,
            );
          case 2:
            return PieChartSectionData(
              color: Colors.green.withOpacity(opacity),
              value: 1,
              title: "green pie",
              radius: 60,
              titleStyle: TextStyle(
                fontSize: 18,
                fontWeight: FontWeight.bold,
                color: Colors.black
              ),
              titlePositionPercentageOffset: 0.99,
            );
          case 3:
            return PieChartSectionData(
              color: Colors.yellow.withOpacity(opacity),
              value: 1,
              title: "yellow pie",
              radius: 100,
              titleStyle: TextStyle(
                fontSize: 18,
                fontWeight: FontWeight.bold,
                color: Colors.black
              ),
              titlePositionPercentageOffset: 0.99,
            );
          default:
            return null;
        }
      }
    );
  }
}


It is roughly divided into two parts:

  • The small icon description
  • The section setting of the pie chart (including the section is no longer transparent when the user touches it)

The complete sample code is as follows.


Complete Code

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

import 'package:fl_chart/fl_chart.dart';


// Main
void main() => runApp(MyApp());


// Indicator
class Indicator extends StatelessWidget {
  final Color color;
  final Color textColor;
  final String text;
  final bool isSquare;
  final double size;

  const Indicator({
    Key key,
    this.color,
    this.textColor = Colors.white,
    this.text,
    this.isSquare,
    this.size = 16,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Row(
      children: <Widget>[
        Container(
          width: size,
          height: size,
          decoration: BoxDecoration(
            shape: isSquare ? BoxShape.rectangle : BoxShape.circle,
            color: color,
          ),
        ),
        const SizedBox(
          width: 3,
        ),
        Text(
          text,
          style: TextStyle(
            fontSize: 16,
            fontWeight: FontWeight.bold,
            color: textColor,
          ),
        )
      ],
    );
  }
}


class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: PieChartPage(),
    );
  }
}


class PieChartPage extends StatefulWidget {
  @override
  State<StatefulWidget> createState() => _PieChartPageState();
}


class _PieChartPageState extends State {
  int touchedIndex;

  @override
  Widget build(BuildContext context) {
    SystemChrome.setEnabledSystemUIOverlays([SystemUiOverlay.bottom]);
    return AspectRatio(
      aspectRatio: 1.3,
      child: Card(
        color: Colors.white,
        child: Column(
          children: <Widget>[
            const SizedBox(
              height: 28,
            ),
            Row(
              mainAxisSize: MainAxisSize.max,
              mainAxisAlignment: MainAxisAlignment.spaceEvenly,
              children: <Widget>[
                Indicator(
                  color: Colors.blue,
                  text: "One",
                  isSquare: false,
                  size: touchedIndex == 0 ? 18 : 16,
                  textColor: touchedIndex == 0
                    ? Colors.black
                    : Colors.grey,
                ),
                Indicator(
                  color: Colors.red,
                  text: "Two",
                  isSquare: false,
                  size: touchedIndex == 1 ? 18 : 16,
                  textColor: touchedIndex == 1
                    ? Colors.black
                    : Colors.grey,
                ),
                Indicator(
                  color: Colors.green,
                  text: "Three",
                  isSquare: false,
                  size: touchedIndex == 2 ? 18 : 16,
                  textColor: touchedIndex == 2
                    ? Colors.black
                    : Colors.grey,
                ),
                Indicator(
                  color: Colors.yellow,
                  text: "Four",
                  isSquare: false,
                  size: touchedIndex == 3 ? 18 : 16,
                  textColor: touchedIndex == 3
                    ? Colors.black
                    : Colors.grey,
                ),
              ],
            ),
            const SizedBox(
              height: 18,
            ),

            // Pie chart
            Expanded(
              child: AspectRatio(
                aspectRatio: 1,
                child: PieChart(
                  PieChartData(
                    pieTouchData: PieTouchData(touchCallback: (pieTouchResponse) {
                      setState(() {
                        if (pieTouchResponse.touchInput is FlLongPressEnd ||
                            pieTouchResponse.touchInput is FlPanEnd) {
                          touchedIndex = -1;
                        }
                        else {
                          touchedIndex = pieTouchResponse.touchedSectionIndex;
                        }
                      });
                    }),
                    startDegreeOffset: 270,
                    borderData: FlBorderData(
                      show: false,
                    ),
                    sectionsSpace: 1,
                    centerSpaceRadius: 0,
                    sections: showingSections()
                  ),
                ),
              )
            )
          ],
        ),
      ),
    );
  }

  List<PieChartSectionData> showingSections() {
    return List.generate(
      4,
      (index) {
        final isTouched = index == touchedIndex;
        final double opacity = isTouched ? 1 : 0.6;

        // Condition
        switch (index) {
          case 0:
            return PieChartSectionData(
              color: Colors.blue.withOpacity(opacity),
              value: 1,
              title: "blue pie",
              radius: 80,
              titleStyle: TextStyle(
                fontSize: 18,
                fontWeight: FontWeight.bold,
                color: Colors.black,
              ),
              titlePositionPercentageOffset: 0.99,
            );
          case 1:
            return PieChartSectionData(
              color: Colors.red.withOpacity(opacity),
              value: 1,
              title: "red pie",
              radius: 65,
              titleStyle: TextStyle(
                fontSize: 18,
                fontWeight: FontWeight.bold,
                color: Colors.black
              ),
              titlePositionPercentageOffset: 0.99,
            );
          case 2:
            return PieChartSectionData(
              color: Colors.green.withOpacity(opacity),
              value: 1,
              title: "green pie",
              radius: 60,
              titleStyle: TextStyle(
                fontSize: 18,
                fontWeight: FontWeight.bold,
                color: Colors.black
              ),
              titlePositionPercentageOffset: 0.99,
            );
          case 3:
            return PieChartSectionData(
              color: Colors.yellow.withOpacity(opacity),
              value: 1,
              title: "yellow pie",
              radius: 100,
              titleStyle: TextStyle(
                fontSize: 18,
                fontWeight: FontWeight.bold,
                color: Colors.black
              ),
              titlePositionPercentageOffset: 0.99,
            );
          default:
            return null;
        }
      }
    );
  }
}


Output:


The above is a simple tutorial about how to use fl_chart for drawing a pie chart in Flutter.


References


Read More

Tags:

Leave a Reply