Adding the SVG icon in the custom slider using the custom painter

1,120

update

  1. add the path_drawing package
  2. change the size of the svg icon
  3. add following code

enter image description here

import 'package:path_drawing/path_drawing.dart';


// inside the paint method of the CustomLeftPainter class
Paint icon =
    _getPaint(color: Colors.black, width: 20, style: PaintingStyle.fill);
var iconSvg = Path()
  ..addPath(parseSvgPathData(rightPath[0]),
      Offset(leftInitHandler.dx - 10, leftInitHandler.dy - 10))
  ..addPath(parseSvgPathData(rightPath[1]),
      Offset(leftInitHandler.dx - 10, leftInitHandler.dy - 10));
;

canvas.drawPath(iconSvg, icon);


/// add list of paths
List<String> rightPath = <String>[
  'M10 20C8.8 20 7.8 19 7.8 17.8V17.2C7.3 17 6.9 16.8 6.5 16.6L6 17.1C5.6 17.5 5.1 17.7 4.5 17.7 3.9 17.7 3.3 17.5 2.9 17.1 2.1 16.2 2.1 14.8 2.9 14L3.4 13.5C3.2 13.1 3 12.7 2.8 12.2H2.2C1.6 12.2 1.1 12 0.6 11.5 0.2 11.1 0 10.6 0 10 0 8.8 1 7.8 2.2 7.8H2.8C3 7.3 3.2 6.9 3.4 6.5L2.9 6C2.5 5.6 2.3 5.1 2.3 4.5 2.3 3.9 2.5 3.3 2.9 2.9 3.8 2.1 5.2 2.1 6 2.9L6.5 3.4C6.9 3.2 7.3 3 7.8 2.8V2.2C7.8 1.6 8 1.1 8.5 0.6 8.9 0.2 9.4 0 10 0 10.1 0 10.3 0 10.4 0 11.5 0.2 12.2 1.2 12.2 2.2V2.8C12.7 3 13.1 3.2 13.5 3.4L14 2.9C14.4 2.5 14.9 2.3 15.5 2.3 16.1 2.3 16.7 2.5 17.1 2.9 17.9 3.8 17.9 5.2 17.1 6L16.6 6.5C16.8 6.9 17 7.3 17.2 7.8H17.8C18.4 7.8 18.9 8 19.4 8.5 19.8 8.9 20 9.4 20 10 20 11.2 19 12.2 17.8 12.2H17.2C17 12.7 16.8 13.1 16.6 13.5L17.1 14C17.5 14.4 17.7 14.9 17.7 15.5 17.7 16.1 17.5 16.7 17.1 17.1 16.6 17.5 16.1 17.7 15.5 17.7 15 17.7 14.4 17.5 14 17.1L13.5 16.6C13.1 16.8 12.7 17 12.2 17.2V17.8C12.2 18.4 12 18.9 11.5 19.4 11.2 19.7 10.9 19.9 10.4 20 10.4 20 10.4 20 10.4 20 10.3 20 10.1 20 10 20ZM6.4 15.2C6.5 15.2 6.6 15.2 6.7 15.3 7.3 15.7 7.9 15.9 8.6 16.1 8.9 16.2 9.1 16.4 9.1 16.7V17.8C9.1 18.3 9.5 18.8 10 18.8 10.1 18.8 10.1 18.7 10.2 18.7 10.4 18.7 10.5 18.6 10.7 18.5 10.8 18.3 10.9 18.1 10.9 17.8V16.7C10.9 16.4 11.1 16.2 11.4 16.1 12.1 15.9 12.7 15.7 13.3 15.3 13.5 15.2 13.9 15.2 14.1 15.4L14.9 16.2C15.2 16.6 15.8 16.6 16.2 16.2 16.4 16 16.5 15.8 16.5 15.5 16.5 15.3 16.4 15 16.2 14.9L15.4 14.1C15.2 13.9 15.2 13.5 15.3 13.3 15.7 12.7 15.9 12.1 16.1 11.4 16.2 11.1 16.4 10.9 16.7 10.9H17.8C18.3 10.9 18.8 10.5 18.8 10 18.8 9.7 18.7 9.5 18.5 9.3 18.3 9.2 18.1 9.1 17.8 9.1H16.7C16.4 9.1 16.2 8.9 16.1 8.6 15.9 7.9 15.7 7.3 15.3 6.7 15.2 6.5 15.2 6.1 15.4 5.9L16.2 5.1C16.6 4.8 16.6 4.2 16.2 3.8 16 3.6 15.8 3.5 15.5 3.5 15.3 3.5 15 3.6 14.9 3.8L14.1 4.6C13.9 4.8 13.5 4.8 13.3 4.7 12.7 4.3 12.1 4.1 11.4 3.9 11.1 3.8 10.9 3.6 10.9 3.3V2.2C10.9 1.7 10.6 1.4 10.2 1.3 10.1 1.3 10.1 1.3 10 1.3 9.7 1.3 9.5 1.3 9.3 1.5 9.2 1.7 9.1 1.9 9.1 2.2V3.3C9.1 3.6 8.9 3.8 8.6 3.9 7.9 4.1 7.3 4.3 6.7 4.7 6.5 4.8 6.1 4.8 5.9 4.6L5.1 3.8C4.8 3.4 4.2 3.4 3.8 3.8 3.6 4 3.5 4.2 3.5 4.5 3.5 4.7 3.6 5 3.8 5.1L4.6 5.9C4.8 6.1 4.8 6.5 4.7 6.7 4.3 7.3 4.1 7.9 3.9 8.6 3.8 8.9 3.6 9.1 3.3 9.1H2.2C1.7 9.1 1.3 9.5 1.3 10 1.3 10.3 1.3 10.5 1.5 10.7 1.7 10.8 1.9 10.9 2.2 10.9H3.3C3.6 10.9 3.8 11.1 3.9 11.4 4.1 12.1 4.3 12.7 4.7 13.3 4.8 13.5 4.8 13.9 4.6 14.1L3.8 14.9C3.4 15.2 3.4 15.8 3.8 16.2 4 16.4 4.2 16.5 4.5 16.5 4.7 16.5 5 16.4 5.1 16.2L5.9 15.4C6 15.3 6.2 15.2 6.4 15.2Z',
  'M10 14.4C7.6 14.4 5.6 12.4 5.6 10 5.6 7.6 7.6 5.6 10 5.6 10.1 5.6 10.2 5.6 10.4 5.6 11.5 5.7 12.5 6.2 13.2 7 14 7.8 14.4 8.9 14.4 10 14.4 11.1 14 12.2 13.2 13 12.5 13.8 11.5 14.3 10.4 14.4 10.2 14.4 10.1 14.4 10 14.4ZM10 6.9C8.3 6.9 6.9 8.3 6.9 10 6.9 11.7 8.3 13.1 10 13.1 10.1 13.1 10.2 13.1 10.3 13.1 11.9 13 13.1 11.6 13.1 10 13.1 8.4 11.9 7 10.3 6.9 10.2 6.9 10.1 6.9 10 6.9Z'
];
Share:
1,120
Sagar Acharya
Author by

Sagar Acharya

Working as a mobile Developer.

Updated on December 20, 2022

Comments

  • Sagar Acharya
    Sagar Acharya over 1 year

    I am implementing the custom slider, where I have completed the gesture detection on the slider , now I want to add the SVG icon on the knob to drag, cannot find any resource. I just want to add the SVG to any idea of how to implement it. I have put my code and let me know any suggestion if you people have.

    Main ui file

    import 'package:animations_sample/custom_slider.dart';
    import 'package:flutter/material.dart';
    
    void main() => runApp(MyApp());
    
    class MyApp extends StatefulWidget {
      MyApp({Key key}) : super(key: key);
    
      @override
      _MyAppState createState() => _MyAppState();
    }
    
    class _MyAppState extends State<MyApp> {
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          home: Scaffold(
            body: Center(
              child: Container(
                width: 200,
                height: 200,
                child: LeftSlider(),
              ),
            ),
          ),
        );
      }
    }
    
    

    Custom Slider file

    import 'dart:io';
    
    import 'package:animations_sample/base_painter.dart';
    import 'package:animations_sample/customleftPainter.dart';
    import 'package:animations_sample/utils.dart';
    import 'package:flutter/material.dart';
    import 'package:flutter_svg/flutter_svg.dart';
    import 'dart:async';
    import 'dart:typed_data';
    import 'dart:ui' as UI;
    
    import 'package:flutter/services.dart' show rootBundle;
    import 'package:path_provider/path_provider.dart';
    
    import 'package:flutter/services.dart';
    
    class LeftSlider extends StatefulWidget {
      LeftSlider({Key key}) : super(key: key);
    
      @override
      _LeftSliderState createState() => _LeftSliderState();
    }
    
    class _LeftSliderState extends State<LeftSlider> {
      //intial Values coming
      int leftEnd = 12;
      String rawLeftSvg =
          '''<svg xmlns="http://www.w3.org/2000/svg" height="512px" viewBox="0 0 32 32" width="512px"><g><path d="m8 0c-4.41113 0-8 3.58887-8 8s3.58887 8 8 8 8-3.58887 8-8-3.58887-8-8-8zm0 15c-3.85986 0-7-3.14014-7-7s3.14014-7 7-7 7 3.14014 7 7-3.14014 7-7 7z" data-original="#000000" class="active-path" data-old_color="#000000" fill="#2184C4"/><path d="m9 3c-1.04364 0-1.9624.536926-2.5 1.34772v-3.84772c0-.276367-.223633-.5-.5-.5-1.6543 0-3 1.3457-3 3 0 1.04364.536926 1.9624 1.34772 2.5h-3.84772c-.276367 0-.5.223633-.5.5 0 1.6543 1.3457 3 3 3 1.04364 0 1.9624-.536926 2.5-1.34772v3.84772c0 .276367.223633.5.5.5 1.6543 0 3-1.3457 3-3 0-1.04364-.536926-1.9624-1.34772-2.5h3.84772c.276367 0 .5-.223633.5-.5 0-1.6543-1.3457-3-3-3zm-6 5c-.930176 0-1.71436-.638184-1.93652-1.5h3.87305c-.222168.861816-1.00635 1.5-1.93652 1.5zm1-5c0-.930176.638184-1.71436 1.5-1.93652v3.87305c-.861816-.222168-1.5-1.00635-1.5-1.93652zm2 3.5c-.276123 0-.5-.223877-.5-.5 0-.276184.223877-.5.5-.5s.5.223816.5.5c0 .276123-.223877.5-.5.5zm2 2.5c0 .930176-.638184 1.71436-1.5 1.93652v-3.87305c.861816.222168 1.5 1.00635 1.5 1.93652zm-.936523-3.5c.222168-.861816 1.00635-1.5 1.93652-1.5.930176 0 1.71436.638184 1.93652 1.5h-3.87305z" transform="translate(2 2)" data-original="#000000" class="active-path" data-old_color="#000000" fill="#2184C4"/></g> </svg>''';
      DrawableRoot svgRoot;
      UI.Image image;
      @override
      void initState() {
        super.initState();
        getLeftIcon();
      }
        // this is for the Ui.Image
      Future<UI.Image> loadUiImage(String imageAssetPath) async {
        final ByteData data = await rootBundle.load(imageAssetPath);
    
        final Completer<UI.Image> completer = Completer();
        UI.decodeImageFromList(Uint8List.view(data.buffer), (UI.Image img) {
          return completer.complete(img);
        });
        return completer.future;
      }
       //Please Ignore
      /* Future<File> getImageFileFromAssets(String path) async {
        final byteData = await rootBundle.load('assets/$path');
    
        final file = File('${(await getTemporaryDirectory()).path}/$path');
        await file.writeAsBytes(byteData.buffer
            .asUint8List(byteData.offsetInBytes, byteData.lengthInBytes));
    
        return file;
      } */
    
      getLeftIcon() async {
        /*  svgRoot= await svg.fromSvgString(rawLeftSvg, rawLeftSvg); */
        //File file = await getImageFileFromAssets('icon.png');
    
        image = await loadUiImage('assets/snowflake.png');
        svgRoot = await svg.fromSvgString(rawLeftSvg, rawLeftSvg);
        print('sucess');
      }
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          backgroundColor: Colors.transparent,
          body: SliderLeftPaint(
            leftsvgIcon: svgRoot,
            leftIcon: image,
            leftInitial: 0,
            leftEnd: leftEnd,
            onSelectionChange: (int left) {
              setState(() {
                leftEnd = left;
              });
            },
            child: Center(
                child: Row(
              mainAxisAlignment: MainAxisAlignment.center,
              children: <Widget>[
                Padding(
                  padding: const EdgeInsets.only(right: 10),
                  child: Text(
                    '$leftEnd\u00B0',
                  ),
                ),
              ],
            )),
          ),
        );
      }
    }
    
    class SliderLeftPaint extends StatefulWidget {
      final DrawableRoot leftsvgIcon;
      final UI.Image leftIcon;
      final int leftInitial;
      final int leftEnd;
    
      final Function onSelectionChange;
      final Widget child;
    
      const SliderLeftPaint(
          {Key key,
          this.leftsvgIcon,
          @required this.leftIcon,
          @required this.leftInitial,
          @required this.leftEnd,
          @required this.onSelectionChange,
          this.child})
          : super(key: key);
    
      @override
      _SliderLeftPaintState createState() => _SliderLeftPaintState();
    }
    
    class _SliderLeftPaintState extends State<SliderLeftPaint> {
      bool _isInitLeftHandlerSelected = false;
    
      CustomLeftPainter customLeftPainter;
    
      /// start angle in radians where we need to locate the initial left handler
      double _leftStartAngle;
    
      /// end angle in radians where we need to locate the end left  handler
      double _leftEndAngle;
    
      /// the absolute angle in radians representing the selection
      double _leftSweepAngle;
    
    // we need to update this widget both with gesture detector but
      // also when the parent widget rebuilds itself
      @override
      void didUpdateWidget(SliderLeftPaint oldWidget) {
        super.didUpdateWidget(oldWidget);
        if (oldWidget.leftInitial != widget.leftInitial ||
            oldWidget.leftEnd != widget.leftEnd) {
          _calculatePercentage();
        }
      }
    
      void _calculatePercentage() {
        if (_isInitLeftHandlerSelected) {
          // This is for left inti and end percentage and the sweep Angle
          // TODO That it should be in a limit of half circle
    
          double initLeftPercentage = valueToPercentage(widget.leftInitial, 100);
          print('This is initial Left Percentge $initLeftPercentage');
          double endLeftPercentage = valueToPercentage(widget.leftEnd, 100);
          print('This is  End  Left Percentage $endLeftPercentage');
    
          double sweepLeftAngle =
              getSweepAngle(initLeftPercentage, endLeftPercentage);
          print('This is the sweep angle for the left hand side $sweepLeftAngle');
          _leftStartAngle = percentageToRadians(initLeftPercentage);
          print('This is the Left Start Angle $_leftStartAngle');
          _leftEndAngle = percentageToRadians(endLeftPercentage);
          print('This is the Left End Angle $_leftEndAngle');
    
          _leftSweepAngle = percentageToRadians(sweepLeftAngle.abs());
          print('This is the Left Sweep Angle $_leftSweepAngle');
        }
    
        customLeftPainter = CustomLeftPainter(
          leftdrawablesvgIcon: widget.leftsvgIcon,
          leftSvgIcon: widget.leftIcon,
          startLeftAngle: _leftStartAngle,
          endLeftAngle: _leftEndAngle,
          leftSweepAngle: _leftSweepAngle,
          selectionLeftColor: Colors.blueAccent,
        );
      }
    
      @override
      void initState() {
        // TODO: implement initState
        super.initState();
        _calculatePaintData();
      }
    
      void _calculatePaintData() {
        // This is for the right init and end percentage and the sweepangle
    
        // This is for left inti and end percentage and the sweep Angle
        double initLeftPercentage = valueToPercentage(widget.leftInitial, 100);
        print('This is initial Left Percentge $initLeftPercentage');
        double endLeftPercentage = valueToPercentage(widget.leftEnd, 100);
        print('This is  End  Left Percentage $endLeftPercentage');
    
        double sweepLeftAngle =
            getSweepAngle(initLeftPercentage, endLeftPercentage);
        print('This is the sweep angle for the left hand side $sweepLeftAngle');
        _leftStartAngle = percentageToRadians(initLeftPercentage);
        print('This is the Left Start Angle $_leftStartAngle');
        _leftEndAngle = percentageToRadians(endLeftPercentage);
        print('This is the Left End Angle $_leftEndAngle');
    
        _leftSweepAngle = percentageToRadians(sweepLeftAngle.abs());
        print('This is the Left Sweep Angle $_leftSweepAngle');
    
        customLeftPainter = CustomLeftPainter(
          leftdrawablesvgIcon: widget.leftsvgIcon,
          leftSvgIcon: widget.leftIcon,
          startLeftAngle: _leftStartAngle,
          endLeftAngle: _leftEndAngle,
          leftSweepAngle: _leftSweepAngle,
          selectionLeftColor: Colors.blue,
        );
      }
    
      @override
      Widget build(BuildContext context) {
        return GestureDetector(
          onPanUpdate: _onPanUpdate,
          onPanEnd: _onPanEnd,
          onPanDown: _onPanDown,
          child: CustomPaint(
            painter: BasePainter(
              baseColor: Color(0XFF5E5C5D),
            ),
            foregroundPainter: customLeftPainter,
            child: Padding(
              padding: const EdgeInsets.all(12.0),
              child: widget.child,
            ),
          ),
        );
      }
    
      _onPanUpdate(DragUpdateDetails details) {
        if (!_isInitLeftHandlerSelected) {
          return;
        }
        if (customLeftPainter.leftcenter == null) {
          return;
        }
    
        RenderBox renderBox = context.findRenderObject();
        var position = renderBox.globalToLocal(details.globalPosition);
        var leftAngle;
    
        var leftPercent;
    
        var newLeftValue;
    
        if (_leftSweepAngle >= 0) {
          leftAngle = coordinatesToRadians(customLeftPainter.leftcenter, position);
          leftPercent = radianstoPercentageLeft(leftAngle);
          newLeftValue = percentageToValue(leftPercent, 100);
          if (_isInitLeftHandlerSelected) {
            widget.onSelectionChange(newLeftValue);
          }
        }
      }
    
      _onPanDown(DragDownDetails details) {
        if (customLeftPainter == null) {
          return;
        }
        RenderBox renderBox = context.findRenderObject();
        var position = renderBox.globalToLocal(details.globalPosition);
        if (position != null) {
          _isInitLeftHandlerSelected = isPointInsideCircle(
              position, customLeftPainter.leftInitHandler, 12.0);
        }
      }
    
      _onPanEnd(_) {
        _isInitLeftHandlerSelected = false;
      }
    }
    
    

    Left Painter

    import 'dart:math';
    import 'dart:ui' as UI;
    
    import 'package:animations_sample/utils.dart';
    import 'package:flutter/material.dart';
    import 'package:flutter_svg/flutter_svg.dart';
    
    class CustomLeftPainter extends CustomPainter {
      DrawableRoot leftdrawablesvgIcon;
      UI.Image leftSvgIcon;
      double startLeftAngle;
      double endLeftAngle;
      double leftSweepAngle;
      Color selectionLeftColor;
      Size actuallsize = Size(30, 30);
    
      Offset leftcenter;
    
      double leftradius;
    
      Offset leftInitHandler;
    
      CustomLeftPainter({
        @required this.leftdrawablesvgIcon,
        @required this.leftSvgIcon,
        @required this.startLeftAngle,
        @required this.endLeftAngle,
        @required this.leftSweepAngle,
        @required this.selectionLeftColor,
      });
    
      @override
      void paint(Canvas canvas, Size size) {
        //This was the problem when all the both left and right angles are 0 then it will return with no points
        /* if (startLeftAngle == 0.0 &&
            endLeftAngle == 0.0 &&
            startRightAngle == 0.0 &&
            endRightAngle == 0.0) return;
     */
    
        Paint leftprogress = _getPaint(color: selectionLeftColor, width: 20);
    
        leftcenter = Offset(size.width / 2, size.height / 2);
    
        leftradius = min(size.width / 2, size.height / 2);
    
        canvas.drawArc(Rect.fromCircle(center: leftcenter, radius: leftradius),
            pi / 2 + startLeftAngle, leftSweepAngle, false, leftprogress);
    
        Paint lefthandler =
            _getPaint(color: Colors.white, style: PaintingStyle.fill);
        Paint lefthandlerOutter = _getPaint(color: selectionLeftColor);
    
        leftInitHandler =
            radiansToCoordinates(leftcenter, pi / 2 + endLeftAngle, leftradius);
        canvas.drawCircle(leftInitHandler, 8.0, lefthandler);
        canvas.drawCircle(leftInitHandler, 12.0, lefthandlerOutter);
    
    
    
        // To draw image but problem is it has scalling problem
    
        /* canvas.drawImage(
            leftSvgIcon,
            Offset(leftInitHandler.dx - 12, leftInitHandler.dy - 12),
            lefthandlerOutter); */
        //
    
    
        leftdrawablesvgIcon.scaleCanvasToViewBox(canvas, size);
    
        leftdrawablesvgIcon.clipCanvasToViewBox(canvas);
    
           //This is the add part for the edit
        Rect myRect = Offset(leftInitHandler.dx,leftInitHandler.dy) & const Size(50.0, 50.0);
    
        leftdrawablesvgIcon.draw(
            canvas,myRect);
      }
    
      Paint _getPaint({@required Color color, double width, PaintingStyle style}) =>
          Paint()
            ..color = color
            ..strokeCap = StrokeCap.square
            ..style = style ?? PaintingStyle.stroke
            ..strokeWidth = width ?? 8.0;
    
      @override
      bool shouldRepaint(CustomPainter oldDelegate) {
        return true;
      }
    }
    
    
    

    utils file for conversions.

    import 'dart:math';
    import 'dart:ui';
    
    double percentageToRadians(double percentage) => ((pi * percentage) / 100);
    
    double radiansToPercentage(double radians) {
      var normalized = radians < 0 ? -radians : pi - radians;
      var percentage = ((100 * normalized) / (pi));
      // TODO we have an inconsistency of pi/2 in terms of percentage and radians
      return (percentage + 50) % 100;
    }
    
    double radianstoPercentageLeft(double radians) {
      var normalized = radians < 0 ? -radians : pi - radians;
      print('************This is left normalized $normalized');
      var percentage = ((100 * normalized) / (pi));
      return (percentage - 50) % 100;
    }
    
    double coordinatesToRadians(Offset center, Offset coords) {
      var a = coords.dx - center.dx;
      var b = center.dy - coords.dy;
      return atan2(b, a);
    }
    
    Offset radiansToCoordinates(Offset center, double radians, double radius) {
      var dx = center.dx + radius * cos(radians);
      var dy = center.dy + radius * sin(radians);
      return Offset(dx, dy);
    }
    
    double valueToPercentage(int time, int intervals) => (time / intervals) * 100;
    
    int percentageToValue(double percentage, int intervals) =>
        ((percentage * intervals) / 100).round();
    
    bool isPointInsideCircle(Offset point, Offset center, double rradius) {
      if(center ==Offset(0,0))
      {
        return false;
      }
      var radius = rradius * 1.2;
      return point.dx < (center.dx + radius) &&
          point.dx > (center.dx - radius) &&
          point.dy < (center.dy + radius) &&
          point.dy > (center.dy - radius);
    }
    
    bool isPointAlongCircle(Offset point, Offset center, double radius) {
      // distance is root(sqr(x2 - x1) + sqr(y2 - y1))
      // i.e., (7,8) and (3,2) -> 7.21
      var d1 = pow(point.dx - center.dx, 2);
      var d2 = pow(point.dy - center.dy, 2);
      var distance = sqrt(d1 + d2);
      return (distance - radius).abs() < 10;
    }
    
    double getSweepAngle(double init, double end) {
      if (end > init) {
        return end - init;
      }
      if(end == init)
      {
        return 0;
      }
      return (100 - init + end).abs();
    }
    
    List<Offset> getSectionsCoordinatesInCircle(
        Offset center, double radius, int sections) {
      var intervalAngle = (pi * 2) / sections;
      return List<int>.generate(sections, (int index) => index).map((i) {
        var radians = (pi / 2) + (intervalAngle * i);
        return radiansToCoordinates(center, radians, radius);
      }).toList();
    }
    
    bool isAngleInsideRadiansSelection(double angle, double start, double sweep) {
      var normalized = angle > pi / 2 ? 5 * pi / 2 - angle : pi / 2 - angle;
      var end = (start + sweep) % (2 * pi);
      return end > start
          ? normalized > start && normalized < end
          : normalized > start || normalized < end;
    }
    
    // this is not 100% accurate but it works
    // we just want to see if a value changed drastically its value
    bool radiansWasModuloed(double current, double previous) {
      return (previous - current).abs() > (3 * pi / 2);
    }
    
    

    enter image description here

    Would like to add this small svg icon on the knob

      List<String> rightPath = <String>[
        "m256 512c-30.879 0-56-25.122-56-56v-16.298c-11.863-3.606-23.331-8.359-34.292-14.212l-11.534 11.534c-10.574 10.573-24.635 16.396-39.594 16.396-14.966 0-29.031-5.823-39.604-16.396-21.829-21.843-21.827-57.37.001-79.197l11.534-11.534c-5.853-10.961-10.605-22.43-14.212-34.292h-16.299c-14.953 0-29.014-5.827-39.594-16.407s-16.406-24.642-16.406-39.594c0-30.878 25.121-56 56-56h16.299c3.606-11.863 8.359-23.331 14.212-34.292l-11.534-11.534c-10.574-10.574-16.397-24.635-16.397-39.594 0-14.965 5.823-29.03 16.396-39.604 21.844-21.831 57.37-21.828 79.198 0l11.534 11.534c10.961-5.853 22.429-10.605 34.292-14.212v-16.298c0-14.952 5.826-29.013 16.405-39.593 10.581-10.58 24.642-16.407 39.595-16.407 3.721 0 7.472.375 11.149 1.113 26.004 5.283 44.851 28.364 44.851 54.887v16.298c11.863 3.606 23.331 8.359 34.292 14.212l11.534-11.534c10.574-10.573 24.635-16.396 39.594-16.396 14.966 0 29.031 5.823 39.604 16.396 21.829 21.843 21.827 57.37-.001 79.197l-11.534 11.534c5.853 10.961 10.605 22.43 14.212 34.292h16.299c14.953 0 29.014 5.827 39.594 16.407s16.406 24.642 16.406 39.594c0 30.878-25.121 56-56 56h-16.299c-3.606 11.863-8.359 23.331-14.212 34.292l11.534 11.534c10.573 10.574 16.396 24.635 16.396 39.594 0 14.965-5.823 29.03-16.396 39.604-10.921 10.914-25.266 16.371-39.604 16.372-14.343.001-28.679-5.456-39.594-16.371l-11.534-11.534c-10.961 5.853-22.429 10.605-34.292 14.212v16.297c0 14.952-5.826 29.013-16.405 39.593-7.813 7.813-17.637 13.099-28.41 15.287-.012.002-.023.005-.035.007-3.677.738-7.428 1.113-11.149 1.113zm8-16.8h.01zm-100.925-105.7c2.913 0 5.843.793 8.453 2.419 14.892 9.274 31.071 15.978 48.088 19.926 7.251 1.682 12.384 8.143 12.384 15.586v28.569c0 13.233 10.767 24 24 24 1.601 0 3.222-.162 4.821-.481 4.592-.934 8.792-3.2 12.146-6.553 4.535-4.536 7.033-10.561 7.033-16.966v-28.57c0-7.443 5.133-13.904 12.384-15.586 17.017-3.948 33.196-10.652 48.088-19.926 6.314-3.933 14.511-2.994 19.771 2.268l20.21 20.21c9.355 9.354 24.583 9.354 33.946-.004 4.526-4.526 7.021-10.555 7.021-16.973 0-6.411-2.494-12.437-7.024-16.966l-20.209-20.209c-5.262-5.262-6.201-13.456-2.269-19.771 9.274-14.893 15.979-31.072 19.926-48.088 1.682-7.251 8.143-12.384 15.586-12.384h28.57c13.233 0 24-10.767 24-24 0-6.405-2.498-12.43-7.034-16.966-4.535-4.537-10.561-7.035-16.966-7.035h-28.57c-7.443 0-13.904-5.133-15.586-12.384-3.947-17.016-10.651-33.195-19.926-48.088-3.933-6.316-2.993-14.51 2.269-19.771l20.21-20.209c9.355-9.355 9.354-24.583-.004-33.946-4.525-4.526-10.555-7.02-16.973-7.02-6.411 0-12.438 2.495-16.967 7.024l-20.21 20.209c-5.262 5.263-13.456 6.201-19.771 2.268-14.892-9.274-31.071-15.978-48.088-19.926-7.251-1.683-12.384-8.144-12.384-15.587v-28.57c0-11.37-8.068-21.262-19.186-23.521-1.572-.315-3.204-.479-4.814-.479-6.405 0-12.431 2.498-16.967 7.034-4.535 4.536-7.033 10.561-7.033 16.966v28.57c0 7.443-5.133 13.904-12.384 15.586-17.017 3.948-33.196 10.652-48.088 19.926-6.313 3.934-14.51 2.994-19.771-2.268l-20.21-20.21c-9.355-9.355-24.583-9.353-33.946.004-4.526 4.526-7.021 10.555-7.021 16.973 0 6.411 2.494 12.437 7.024 16.966l20.209 20.209c5.262 5.262 6.201 13.456 2.269 19.771-9.274 14.893-15.979 31.072-19.926 48.088-1.681 7.252-8.142 12.385-15.586 12.385h-28.57c-13.233 0-24 10.767-24 24 0 6.405 2.498 12.43 7.034 16.966 4.535 4.536 10.561 7.034 16.966 7.034h28.57c7.443 0 13.904 5.133 15.586 12.384 3.947 17.016 10.651 33.195 19.926 48.088 3.933 6.316 2.993 14.51-2.269 19.771l-20.21 20.209c-9.355 9.355-9.354 24.583.004 33.946 4.525 4.526 10.555 7.02 16.973 7.02 6.411 0 12.438-2.495 16.967-7.024l20.21-20.209c3.087-3.086 7.184-4.685 11.318-4.685z"
      ];
    
    trying too add the above list<String> but it is not scaling
    
    
    This the svg : 
    <?xml version="1.0"?>
    <svg xmlns="http://www.w3.org/2000/svg" id="Layer_1" enable-background="new 0 0 512 512" height="512px" viewBox="0 0 512 512" width="512px" class=""><g><g>
    <path d="m256 512c-30.879 0-56-25.122-56-56v-16.298c-11.863-3.606-23.331-8.359-34.292-14.212l-11.534 11.534c-10.574 10.573-24.635 16.396-39.594 16.396-14.966 0-29.031-5.823-39.604-16.396-21.829-21.843-21.827-57.37.001-79.197l11.534-11.534c-5.853-10.961-10.605-22.43-14.212-34.292h-16.299c-14.953 0-29.014-5.827-39.594-16.407s-16.406-24.642-16.406-39.594c0-30.878 25.121-56 56-56h16.299c3.606-11.863 8.359-23.331 14.212-34.292l-11.534-11.534c-10.574-10.574-16.397-24.635-16.397-39.594 0-14.965 5.823-29.03 16.396-39.604 21.844-21.831 57.37-21.828 79.198 0l11.534 11.534c10.961-5.853 22.429-10.605 34.292-14.212v-16.298c0-14.952 5.826-29.013 16.405-39.593 10.581-10.58 24.642-16.407 39.595-16.407 3.721 0 7.472.375 11.149 1.113 26.004 5.283 44.851 28.364 44.851 54.887v16.298c11.863 3.606 23.331 8.359 34.292 14.212l11.534-11.534c10.574-10.573 24.635-16.396 39.594-16.396 14.966 0 29.031 5.823 39.604 16.396 21.829 21.843 21.827 57.37-.001 79.197l-11.534 11.534c5.853 10.961 10.605 22.43 14.212 34.292h16.299c14.953 0 29.014 5.827 39.594 16.407s16.406 24.642 16.406 39.594c0 30.878-25.121 56-56 56h-16.299c-3.606 11.863-8.359 23.331-14.212 34.292l11.534 11.534c10.573 10.574 16.396 24.635 16.396 39.594 0 14.965-5.823 29.03-16.396 39.604-10.921 10.914-25.266 16.371-39.604 16.372-14.343.001-28.679-5.456-39.594-16.371l-11.534-11.534c-10.961 5.853-22.429 10.605-34.292 14.212v16.297c0 14.952-5.826 29.013-16.405 39.593-7.813 7.813-17.637 13.099-28.41 15.287-.012.002-.023.005-.035.007-3.677.738-7.428 1.113-11.149 1.113zm8-16.8h.01zm-100.925-105.7c2.913 0 5.843.793 8.453 2.419 14.892 9.274 31.071 15.978 48.088 19.926 7.251 1.682 12.384 8.143 12.384 15.586v28.569c0 13.233 10.767 24 24 24 1.601 0 3.222-.162 4.821-.481 4.592-.934 8.792-3.2 12.146-6.553 4.535-4.536 7.033-10.561 7.033-16.966v-28.57c0-7.443 5.133-13.904 12.384-15.586 17.017-3.948 33.196-10.652 48.088-19.926 6.314-3.933 14.511-2.994 19.771 2.268l20.21 20.21c9.355 9.354 24.583 9.354 33.946-.004 4.526-4.526 7.021-10.555 7.021-16.973 0-6.411-2.494-12.437-7.024-16.966l-20.209-20.209c-5.262-5.262-6.201-13.456-2.269-19.771 9.274-14.893 15.979-31.072 19.926-48.088 1.682-7.251 8.143-12.384 15.586-12.384h28.57c13.233 0 24-10.767 24-24 0-6.405-2.498-12.43-7.034-16.966-4.535-4.537-10.561-7.035-16.966-7.035h-28.57c-7.443 0-13.904-5.133-15.586-12.384-3.947-17.016-10.651-33.195-19.926-48.088-3.933-6.316-2.993-14.51 2.269-19.771l20.21-20.209c9.355-9.355 9.354-24.583-.004-33.946-4.525-4.526-10.555-7.02-16.973-7.02-6.411 0-12.438 2.495-16.967 7.024l-20.21 20.209c-5.262 5.263-13.456 6.201-19.771 2.268-14.892-9.274-31.071-15.978-48.088-19.926-7.251-1.683-12.384-8.144-12.384-15.587v-28.57c0-11.37-8.068-21.262-19.186-23.521-1.572-.315-3.204-.479-4.814-.479-6.405 0-12.431 2.498-16.967 7.034-4.535 4.536-7.033 10.561-7.033 16.966v28.57c0 7.443-5.133 13.904-12.384 15.586-17.017 3.948-33.196 10.652-48.088 19.926-6.313 3.934-14.51 2.994-19.771-2.268l-20.21-20.21c-9.355-9.355-24.583-9.353-33.946.004-4.526 4.526-7.021 10.555-7.021 16.973 0 6.411 2.494 12.437 7.024 16.966l20.209 20.209c5.262 5.262 6.201 13.456 2.269 19.771-9.274 14.893-15.979 31.072-19.926 48.088-1.681 7.252-8.142 12.385-15.586 12.385h-28.57c-13.233 0-24 10.767-24 24 0 6.405 2.498 12.43 7.034 16.966 4.535 4.536 10.561 7.034 16.966 7.034h28.57c7.443 0 13.904 5.133 15.586 12.384 3.947 17.016 10.651 33.195 19.926 48.088 3.933 6.316 2.993 14.51-2.269 19.771l-20.21 20.209c-9.355 9.355-9.354 24.583.004 33.946 4.525 4.526 10.555 7.02 16.973 7.02 6.411 0 12.438-2.495 16.967-7.024l20.21-20.209c3.087-3.086 7.184-4.685 11.318-4.685z" data-original="#000000" class="active-path" data-old_color="#000000" fill="#EE2C5E"/><path d="m256 368c-61.757 0-112-50.243-112-112s50.243-112 112-112c3.181 0 6.339.135 9.389.4 27.848 2.289 53.742 14.915 72.835 35.548 19.201 20.75 29.776 47.76 29.776 76.052s-10.575 55.302-29.776 76.052c-19.093 20.633-44.987 33.259-72.913 35.555-2.972.258-6.13.393-9.311.393zm0-192c-44.112 0-80 35.888-80 80s35.888 80 80 80c2.258 0 4.482-.094 6.611-.279 41.187-3.386 73.389-38.4 73.389-79.721s-32.202-76.335-73.311-79.714c-2.207-.192-4.431-.286-6.689-.286z" data-original="#000000" class="active-path" data-old_color="#000000" fill="#EE2C5E"/></g></g> </svg>