skip to Main Content

I would like to add a Pie Chart to my App in Flutter which is only a semicircle / half donut or whatever you call it.
It should be look like this:

enter image description here

But at the moment it looks like this and i don’t know if there’s a way to fix it:

enter image description here

Main:

body: Center(
      //mainAxisAlignment: MainAxisAlignment.center,
      child: Column(
        children: [
          Stack(
            children: [
              const Align(
                alignment: Alignment.topCenter,
                child: Padding(
                  padding: EdgeInsets.only(top: 5.0),
                  child: Text(
                    "Status",
                    style: TextStyle(
                      color: Colors.white,
                      fontSize: 25,
                    ),
                  ),
                ),
              ),
              Align(
                alignment: Alignment.topRight,
                child: Padding(
                  padding: const EdgeInsets.only(right: 8, top: 5),
                  child: CircleAvatar(
                    radius: 17,
                    backgroundColor: Colors.lightBlue,
                    child: IconButton(
                        tooltip:
                            "Show tooltip",
                        onPressed: () {},
                        icon: const Icon(
                          Icons.question_mark,
                          color: Colors.white,
                          size: 18,
                        )),
                  ),
                ),
              ),
            ],
          ),
          Container(
              width: 300.0,
              height: 300.0,
              //color: const Color.fromRGBO(72, 75, 80, 1),
              color: const Color.fromRGBO(72, 75, 80, 1),
              child: Stack(
                alignment: Alignment.center,
                children: [
                  // icon, svg, image

                  (isSwitched)
                      ? Padding(
                          //padding: EdgeInsets.only(
                          // right: 8.0, left: 8.0, bottom: 75),
                          padding: EdgeInsets.all(8),
                          child: Text(
                            "Moderate",
                            style: TextStyle(
                              color: Colors.white,
                              fontSize: 23,
                            ),
                          ),
                        )
                      : Padding(
                          //padding: EdgeInsets.only(
                          // right: 8.0, left: 8.0, bottom: 75),
                          padding: EdgeInsets.all(8),
                          child: Text(
                            "Excellent",
                            style: TextStyle(
                              color: Colors.white,
                              fontSize: 23,
                            ),
                          ),
                        ),
                  (isSwitched) ? MyPieChartYellow() : MyPieChart(),
                ],
              )),

Pie-Chart:

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

class MyPieChart extends StatelessWidget {
  const MyPieChart({super.key});

  @override
  Widget build(BuildContext context) {
    return PieChart(
        swapAnimationDuration: const Duration(milliseconds: 750),
        swapAnimationCurve: Curves.easeInQuint,
        PieChartData(centerSpaceRadius: 85.0, sections: [
          PieChartSectionData(
            value: 0,
            color: Colors.red,
            showTitle: false,
            radius: 42,
          ),
          PieChartSectionData(
            value: 0,
            color: Colors.yellow,
            showTitle: false,
            radius: 42,
          ),
          PieChartSectionData(
            value: 10,
            color: Colors.green,
            showTitle: false,
            radius: 42,
          )
        ]));
  }
}

Has anyone an idea how to create a half diagram? I couldnt find anything yet.

3

Answers


  1. In this case fl_chart is not the right tool for the job. You can use a custom painter to draw your own chart.

    Here is a possible implementation:

    class GaugeChart extends StatelessWidget {
      const GaugeChart({
        super.key,
        required this.percent,
        required this.color,
        required this.backgroundColor,
        this.strokeWidth = 10,
        this.unitText,
        required this.centerTextStyle,
      });
    
      /// percent is between 0 and 100
      final double percent;
    
      /// percentile arc color
      final Color color;
    
      /// background arc color
      final Color backgroundColor;
    
      /// arc stroke width
      final double strokeWidth;
    
      /// text shown after the text in center
      final String? unitText;
    
      /// text style of the text in center
      final TextStyle centerTextStyle;
    
      @override
      Widget build(BuildContext context) {
        return AspectRatio(
          aspectRatio: 2,
          child: CustomPaint(
            painter: GaugePainter(
              percent: percent,
              color: color,
              backgroundColor: backgroundColor,
              strokeWidth: strokeWidth,
              unitText: unitText,
              centerTextStyle: centerTextStyle,
            ),
          ),
        );
      }
    }
    
    class GaugePainter extends CustomPainter {
      GaugePainter({
        required this.percent,
        required this.color,
        required this.backgroundColor,
        this.strokeWidth = 10.0,
        this.unitText,
        required this.centerTextStyle,
      });
    
      /// percent is between 0 and 100
      final double percent;
    
      /// percentile arc color
      final Color color;
    
      /// background arc color
      final Color backgroundColor;
    
      /// arc stroke width
      final double strokeWidth;
    
      /// text shown after the text in center
      final String? unitText;
    
      /// text style of the text in center
      final TextStyle centerTextStyle;
    
      @override
      void paint(Canvas canvas, Size size) {
        // calculate center and radius of circle
        final center = Offset(size.width / 2, size.height);
        final radius = size.width / 2 - strokeWidth / 2;
    
        final fullArcPainter = Paint()
          ..color = backgroundColor
          ..strokeWidth = strokeWidth
          ..style = PaintingStyle.stroke
          ..strokeCap = StrokeCap.round;
    
        // when painter stroke cap is StrokeCap.round, it will add half of the
        // stroke width to the start and end of arc. Therefore the angle is bigger
        // then 2 * pi (=180) degree.
        // This formula calculates the angle of the arc so the arc will be 180
        // degree including the stroke width.
        final angleWithRoundStroke = pi - strokeWidth / radius;
    
        // This formula calculates the offset angle of the arc so the arc will be
        // 180 degree including the stroke width.
        final offsetAngle = pi + (strokeWidth / (2 * radius));
    
        // Draw background arc
        canvas.drawArc(
          Rect.fromCircle(center: center, radius: radius),
          offsetAngle,
          angleWithRoundStroke,
          false,
          fullArcPainter,
        );
    
        final percentPainter = Paint()
          ..color = color
          ..strokeWidth = strokeWidth
          ..style = PaintingStyle.stroke
          ..strokeCap = StrokeCap.round;
    
        double percentAngle;
        if (percent >= 100) {
          // catch case when percent is bigger than 100
          percentAngle = angleWithRoundStroke;
        } else {
          // calculate angle of percent arc
          percentAngle = percent * angleWithRoundStroke / 100;
        }
    
        // Draw percent arc
        canvas.drawArc(
          Rect.fromCircle(center: center, radius: radius),
          offsetAngle,
          percentAngle,
          false,
          percentPainter,
        );
    
        // paint text
        TextSpan textSpan = TextSpan(
          text: percent.round().toString() + (unitText ?? ''),
          style: centerTextStyle,
        );
        final textPainter = TextPainter(
          text: textSpan,
          textDirection: TextDirection.ltr,
        );
        textPainter.layout(
          minWidth: 0,
          maxWidth: size.width,
        );
    
        final xTextPosition = (size.width - textPainter.width) / 2;
        final yTextPosition = (size.height - textPainter.height) * 3 / 4;
        final textOffset = Offset(xTextPosition, yTextPosition);
        textPainter.paint(canvas, textOffset);
      }
    
      @override
      bool shouldRepaint(covariant GaugePainter oldDelegate) {
        return oldDelegate.percent != percent;
      }
    }
    

    Note that you also can animate changes by using an animation controller. There should be guides around.

    Login or Signup to reply.
  2. i don’t know if fl_chart can handle this, but it can be done with syncfusion package.
    check this example semi_doughnut_chart

    Login or Signup to reply.
  3. You can use Transform code for a half donut shape, Adjust the angle as needed

    import 'package:fl_chart/fl_chart.dart';
    import 'package:flutter/material.dart';
    import 'dart:math' as math;
        
        class HalfPieChart extends StatelessWidget {
          const HalfPieChart({Key? key}) : super(key: key);
        
          @override
          Widget build(BuildContext context) {
            return Transform.rotate(
              angle: -math.pi / 2,
              child: PieChart(
                PieChartData(
                  startDegreeOffset: 180,
                  sectionsSpace: 0,
                  centerSpaceRadius: 85.0,
                  sections: [
                    PieChartSectionData(
                      value: 10,
                      color: Colors.green,
                      showTitle: false,
                      radius: 42,
                    ),
                    PieChartSectionData(
                      value: 10,
                      color: Colors.yellow,
                      showTitle: false,
                      radius: 42,
                    ),
                    PieChartSectionData(
                      value: 10,
                      color: Colors.red,
                      showTitle: false,
                      radius: 42,
                    ),
                    PieChartSectionData(
                      value: 30,
                      color: Colors.transparent,
                      showTitle: false,
                      radius: 42,
                    ),
                  ],
                ),
              ),
            );
          }
        }`
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search