Search code examples
fluttersyncfusiongaugeradianssyncfusion-chart

how to make this type gauge in flutter with dynamic section


    return SfRadialGauge(
    title: GaugeTitle(
        text: 'Speedometer',
        textStyle:
            const TextStyle(fontSize: 14.0, fontWeight: FontWeight.bold)),
    axes: <RadialAxis>[
      RadialAxis(
        minimum: 0,
        maximum: 320,
        startAngle: 180,
        endAngle: 0,
        // showLabels: false,
        maximumLabels: 320,
        onLabelCreated: _handleLabelCreated,
        canRotateLabels: true,
        labelsPosition: ElementsPosition.outside,
        ticksPosition: ElementsPosition.outside,
        showTicks: false,
        radiusFactor: 1.1,
        axisLineStyle: AxisLineStyle(
            thickness: 5,
            dashArray: <double>[(320+100) / 5, 3],
            // color: Color(0xFF66BB6A)
            gradient: SweepGradient(colors: <Color>[
              Color(0xFFE7627D),
              Color(0xFF231557),
              Color(0xFF44107A),
              Color(0xFFFF1361),
              Color(0xFFFFF800),
            ], stops: <double>[
              0,
              100,
              190,
              240,
              320
            ])
        ),
        /*   ranges: <GaugeRange>[
          GaugeRange(
            startValue: 0,
            endValue: 100,
            color: Colors.green,
          ),
          GaugeRange(
            startValue: 100,
            endValue: 210,
            color: Colors.orange,
          ),
          GaugeRange(
            startValue: 210,
            endValue: 320,
            color: Colors.red,
          )
        ],*/
        annotations: <GaugeAnnotation>[
          GaugeAnnotation(
              angle: 180,
              horizontalAlignment: GaugeAlignment.near,
              positionFactor: 0.78,
              verticalAlignment: GaugeAlignment.near,
              widget: Text(
                "0",
                style: TextStyle(
                  color: Colors.black,
                  fontWeight: FontWeight.bold,
                  fontSize: 14,
                ),
              )),
          GaugeAnnotation(
              angle: 0,
              horizontalAlignment: GaugeAlignment.far,
              positionFactor: 0.85,
              verticalAlignment: GaugeAlignment.near,
              widget: Text(
                "320",
                style: TextStyle(
                  color: Colors.black,
                  fontWeight: FontWeight.bold,
                  fontSize: 14,
                ),
              )),
          GaugeAnnotation(
              axisValue: 100,
              positionFactor: 0.5,
              angle: 90,
              widget: Column(children: [
                Center(
                  child: RichText(
                      textAlign: TextAlign.center,
                      text: TextSpan(
                        text: '223\n',
                        style: TextStyle(
                          color: Colors.black,
                          fontWeight: FontWeight.bold,
                          fontSize: 30,
                        ),
                        children: [
                          TextSpan(
                            text: 'Points earned this month',
                            style: TextStyle(
                              color: Colors.black,
                              fontWeight: FontWeight.normal,
                              fontSize: 12,
                            ),
                          )
                        ],
                      )),
                )
              ]))
        ],
        pointers: <GaugePointer>[
          MarkerPointer(
              value: 223,
              markerHeight: 15,
              markerWidth: 15,
              enableDragging: true,
              overlayRadius: 12,
              borderColor: Colors.green,
              borderWidth: 2,
              color: Colors.white,
              markerType: MarkerType.circle)
        ],
      )
    ]);

 void _handleLabelCreated(AxisLabelCreatedArgs args) {
if (args.text == '30') {
  args.text = '£0 - £4';
} else if (args.text == '100') {
  args.text = '£4 - £8';
} else if (args.text == '165') {
  args.text = '£8 - £12';
} else if (args.text == '235') {
  args.text = '£12 - £16';
} else if (args.text == '290') {
  args.text = '£16 - £20';
} else {
  args.text = '';
}

guage chart

I have to develop this type of UI using plugin.but there is some point remaining like color we are not achieve after pointer and how equally segment divided and how responsive for all device that need to check.

I have done below part from my side and remaining thing need to add that i mention .So suggest me how can i achieve . i done this


Solution

  • Your requirement can be achieved with help of the ranges property, MarkerPointer onValueChanging callback in the SfRadialGauge. Added _buildRanges method to find the segment length based on the max value and return the list of the GaugeRange, and added _buildGaugeRange method to create GaugeRange based on the given start, end, and _pointerValue value. The minimum value to the marker range is considered an active range, and the maximum value to the marker range is considered an inactive range in the _buildGaugeRange method. The GaugeRange is colored based on the active and inactive range.

    We have prepared and shared a code snippet below for your reference.

    class _MyHomePageState extends State<MyHomePage> {
      double _pointerValue = 256;
      int _segmentsCount = 5;
      late List<LabelDetails> _labels;
    
      @override
      void initState() {
        _labels = [];
        _calculateLabelsPosition();
        super.initState();
      }
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          body: Column(
            children: [
              SfRadialGauge(
                  title: const GaugeTitle(
                      text: 'Speedometer',
                      textStyle:
                          TextStyle(fontSize: 14.0, fontWeight: FontWeight.bold)),
                  axes: <RadialAxis>[
                    RadialAxis(
                      minimum: 0,
                      maximum: 320,
                      startAngle: 180,
                      endAngle: 0,
                      maximumLabels: 320,
                      canScaleToFit: true,
                      interval: 1,
                      onLabelCreated: _handleLabelCreated,
                      canRotateLabels: true,
                      labelsPosition: ElementsPosition.outside,
                      showTicks: false,
                      radiusFactor: 1.1,
                      pointers: <GaugePointer>[
                        MarkerPointer(
                          onValueChanging: (dynamic args) {
                            setState(() {
                              _pointerValue = args.value;
                            });
                          },
                          value: _pointerValue,
                          enableDragging: true,
                          color: Colors.white,
                          borderColor: Colors.green,
                          borderWidth: 3,
                          markerType: MarkerType.circle,
                          markerHeight: 15,
                          markerWidth: 15,
                          overlayRadius: 0,
                        )
                      ],
                      ranges: _buildRanges(),
                      annotations: <GaugeAnnotation>[
                        const GaugeAnnotation(
                            angle: 180,
                            horizontalAlignment: GaugeAlignment.far,
                            positionFactor: 0.75,
                            verticalAlignment: GaugeAlignment.near,
                            widget: Padding(
                              padding: EdgeInsets.only(top: 5),
                              child: Text(
                                "0",
                                style: TextStyle(
                                  color: Colors.black,
                                  fontWeight: FontWeight.bold,
                                  fontSize: 14,
                                ),
                              ),
                            )),
                        const GaugeAnnotation(
                            angle: 0,
                            horizontalAlignment: GaugeAlignment.far,
                            positionFactor: 0.85,
                            verticalAlignment: GaugeAlignment.near,
                            widget: Padding(
                              padding: EdgeInsets.only(top: 5),
                              child: Text(
                                "320",
                                style: TextStyle(
                                  color: Colors.black,
                                  fontWeight: FontWeight.bold,
                                  fontSize: 14,
                                ),
                              ),
                            )),
                        GaugeAnnotation(
                            widget:
                                Column(mainAxisSize: MainAxisSize.min, children: [
                          Center(
                            child: RichText(
                                textAlign: TextAlign.center,
                                text: TextSpan(
                                  text: '${_pointerValue.round()}\n',
                                  style: const TextStyle(
                                    color: Colors.black,
                                    fontWeight: FontWeight.bold,
                                    fontSize: 30,
                                  ),
                                  children: const [
                                    TextSpan(
                                      text: 'Points earned this month',
                                      style: TextStyle(
                                        color: Colors.black,
                                        fontWeight: FontWeight.normal,
                                        fontSize: 12,
                                      ),
                                    )
                                  ],
                                )),
                          )
                        ]))
                      ],
                    ),
                  ]),
              ElevatedButton(
                  onPressed: () {
                    setState(() {
                      _segmentsCount = 7;
                      _calculateLabelsPosition();
                    });
                  },
                  child: const Text('Update Segment count'))
            ],
          ),
        );
      }
    
      void _calculateLabelsPosition() {
        _labels.clear();
        // Length of the each segment.
        double segmentLength = 320 / _segmentsCount;
        double start = segmentLength / 2;
        for (int i = 0; i < _segmentsCount; i++) {
          _labels.add(LabelDetails(start.toInt(), '£${i * 4} - £${(i + 1) * 4}'));
          start += segmentLength;
        }
      }
    
      void _handleLabelCreated(AxisLabelCreatedArgs args) {
        for (int i = 0; i < _segmentsCount; i++) {
          LabelDetails details = _labels[i];
          if (details.labelPoint == int.parse(args.text)) {
            args.text = details.customizedLabel;
            return;
          }
        }
    
        args.text = '';
      }
    
      // Return the list of gauge range
      List<GaugeRange> _buildRanges() {
        List<GaugeRange> ranges = [];
        // Gap value between two range
        int gap = 2;
        // Length of the each segment without gap.
        double segmentLength =
            (320 - ((_segmentsCount - 1) * gap)) / _segmentsCount;
        double start = 0;
        for (int i = 0; i < _segmentsCount; i++) {
          _buildGaugeRange(start, start + segmentLength, ranges);
          start += segmentLength + gap;
        }
    
        return ranges;
      }
    
      // Method to create a GaugeRange based on start, end and pointerValue and assigned
      // color based on active and inactive range.
      void _buildGaugeRange(double start, double end, List<GaugeRange> ranges) {
        if (_pointerValue >= start && _pointerValue <= end) {
          ranges.add(GaugeRange(
              startValue: start, endValue: _pointerValue, color: Colors.green));
          ranges.add(GaugeRange(
            startValue: _pointerValue,
            endValue: end,
            color: const Color.fromARGB(255, 82, 86, 97),
          ));
        } else if (_pointerValue >= end) {
          ranges.add(GaugeRange(
            startValue: start,
            endValue: end,
            color: Colors.green,
          ));
        } else {
          ranges.add(GaugeRange(
            startValue: start,
            endValue: end,
            color: const Color.fromARGB(255, 82, 86, 97),
          ));
        }
      }
    }
    
    class LabelDetails {
      LabelDetails(this.labelPoint, this.customizedLabel);
      int labelPoint;
      String customizedLabel;
    }
    
    

    Screenshot:

    enter image description here