syncfusion / flutter-examples

This repository contains the Syncfusion Flutter UI widgets examples and the guide to use them.
Other
1.98k stars 775 forks source link

Make RadialAxis in SfRadialGauge Draggable #631

Closed Rayyanmaq1 closed 2 years ago

Rayyanmaq1 commented 2 years ago

Is there any way to male RadialAxis in SfRadialGauge draggable in such a way if be tap on the axis and drag it the whole axis as well as both markers should drag with it accordingly.

Minimum sample Code.


class SleepTrackerSample extends StatefulWidget {
  /// Creates the gauge sleep tracker sample.
  const SleepTrackerSample({Key key}) : super(key: key);

  @override
  _SleepTrackerSampleState createState() => _SleepTrackerSampleState();
}

class _SleepTrackerSampleState extends State<SleepTrackerSample> {
  _SleepTrackerSampleState();

  bool isCardView = false;
  @override
  Widget build(BuildContext context) {
    final bool isLandscape =
        MediaQuery.of(context).orientation == Orientation.landscape
            ? true
            : false;
    final bool isDarkTheme =
        Theme.of(context).brightness == Brightness.dark ? true : false;
    return Center(
      child: SingleChildScrollView(
        child: Column(
          children: <Widget>[
            SizedBox(
              width: MediaQuery.of(context).size.width * 0.63,
              child: Stack(
                alignment: Alignment.center,
                children: [
                  SfRadialGauge(
                    axes: <RadialAxis>[
                      RadialAxis(
                          canRotateLabels: true,
                          showFirstLabel: false,
                          showLastLabel: true,
                          useRangeColorForAxis: true,
                          axisLineStyle: AxisLineStyle(
                              thickness: _tickness,
                              thicknessUnit: GaugeSizeUnit.factor,
                              color: Colors.lightBlue[50]),
                          minorTicksPerInterval: 10,
                          majorTickStyle: const MajorTickStyle(length: 10),
                          maximum: 12,
                          interval: 3,
                          startAngle: 90,
                          endAngle: 90,
                          onAxisTapped: (val) {
                            print('Axis tapped on $val');
                          },
                          onLabelCreated: (AxisLabelCreatedArgs args) {
                            if (args.text == '6') {
                              args.text = '12';
                            } else if (args.text == '9') {
                              args.text = '3';
                            } else if (args.text == '12') {
                              args.text = '6';
                            } else if (args.text == '3') {
                              args.text = '9';
                            }
                          },
                          pointers: <GaugePointer>[
                            WidgetPointer(
                                enableDragging: true,
                                value: _wakeupTimeValue,
                                onValueChanged: _handleWakeupTimeValueChanged,
                                onValueChanging: _handleWakeupTimeValueChanging,
                                onValueChangeStart: _handleWakeupTimeValueStart,
                                onValueChangeEnd: _handleWakeupTimeValueEnd,
                                child: Container(
                                  decoration: BoxDecoration(
                                      color: Colors.blue,
                                      shape: BoxShape.circle,
                                      border: Border.all(
                                        color: isDarkTheme
                                            ? Colors.white.withOpacity(0.1)
                                            : Colors.black.withOpacity(0.1),
                                        width: 0.0,
                                      )),
                                  height: _wakeupTimePointerHeight,
                                  width: _wakeupTimePointerWidth,
                                  child: const Center(
                                      child: Icon(
                                    Icons.bedtime,
                                    size: 15,
                                    color: Colors.white,
                                  )),
                                )),
                            WidgetPointer(
                              enableDragging: true,
                              value: _bedTimeValue,
                              onValueChanged: _handleBedTimeValueChanged,
                              onValueChanging: _handleBedTimeValueChanging,
                              onValueChangeStart: _handleBedTimeValueStart,
                              onValueChangeEnd: _handleBedTimeValueEnd,
                              child: Container(
                                decoration: BoxDecoration(
                                    color: Colors.blue,
                                    shape: BoxShape.circle,
                                    border: Border.all(
                                      color: isDarkTheme
                                          ? Colors.white.withOpacity(0.1)
                                          : Colors.black.withOpacity(0.1),
                                      width: 0.0,
                                    )),
                                height: _bedTimePointerHeight,
                                width: _bedTimePointerWidth,
                                child: const Center(
                                    child: Icon(
                                  Icons.wb_sunny,
                                  color: Colors.white,
                                  size: 15,
                                )),
                              ),
                            ),
                          ],
                          ranges: <GaugeRange>[
                            GaugeRange(
                                endValue: _bedTimeValue,
                                sizeUnit: GaugeSizeUnit.factor,
                                startValue: _wakeupTimeValue,
                                color: Colors.red,
                                startWidth: _tickness,
                                endWidth: _tickness)
                          ],
                          annotations: <GaugeAnnotation>[
                            GaugeAnnotation(
                                widget: SizedBox(
                                  width: 300,
                                  height: 200,
                                  child: Stack(
                                    alignment: AlignmentDirectional.center,
                                    children: <Widget>[
                                      AnimatedPositioned(
                                        right: (_isWakeupTime && !_isBedTime)
                                            ? isWebOrDesktop
                                                ? 94
                                                : isCardView
                                                    ? 110
                                                    : 120
                                            : isWebOrDesktop
                                                ? 155
                                                : (isLandscape || isCardView)
                                                    ? 152
                                                    : 180,
                                        duration:
                                            const Duration(milliseconds: 300),
                                        curve: Curves.decelerate,
                                        child: AnimatedOpacity(
                                          opacity: _isWakeupTime ? 1.0 : 0.0,
                                          duration:
                                              (_isWakeupTime && _isBedTime)
                                                  ? const Duration(
                                                      milliseconds: 800)
                                                  : const Duration(
                                                      milliseconds: 200),
                                          child: CustomAnimatedBuilder(
                                            value: !_isBedTime
                                                ? (isWebOrDesktop || isCardView)
                                                    ? 1.1
                                                    : 2.0
                                                : (isWebOrDesktop || isCardView)
                                                    ? 0.6
                                                    : 1.3,
                                            curve: Curves.decelerate,
                                            duration: const Duration(
                                                milliseconds: 300),
                                            builder: (BuildContext context,
                                                    Widget child,
                                                    Animation<dynamic>
                                                        animation) =>
                                                Transform.scale(
                                              scale: animation.value,
                                              child: child,
                                            ),
                                            child: Column(
                                              mainAxisSize: MainAxisSize.min,
                                              children: <Widget>[
                                                Text(
                                                  '4 Apr',
                                                  style: TextStyle(
                                                    fontSize: isWebOrDesktop
                                                        ? 24
                                                        : isCardView
                                                            ? 14
                                                            : 10,
                                                    color: Colors.blue,
                                                  ),
                                                ),
                                                const SizedBox(height: 4),
                                                Text(
                                                  _wakeupTimeAnnotation,
                                                  style: TextStyle(
                                                      color: Colors.blue,
                                                      fontSize: isWebOrDesktop
                                                          ? 28
                                                          : isCardView
                                                              ? 20
                                                              : 16),
                                                ),
                                              ],
                                            ),
                                          ),
                                        ),
                                      ),
                                      AnimatedOpacity(
                                        opacity: (_isBedTime && _isWakeupTime)
                                            ? 1.0
                                            : 0.0,
                                        duration: (_isWakeupTime && _isBedTime)
                                            ? const Duration(milliseconds: 800)
                                            : const Duration(milliseconds: 200),
                                        child: Container(
                                          margin: (isLandscape || isCardView)
                                              ? const EdgeInsets.only(top: 8.0)
                                              : const EdgeInsets.only(
                                                  top: 16.0),
                                          child: const Text(
                                            '-',
                                            textAlign: TextAlign.center,
                                            style: TextStyle(
                                              fontSize: 25,
                                              color: Colors.blue,
                                            ),
                                          ),
                                        ),
                                      ),
                                      AnimatedPositioned(
                                        left: (_isBedTime && !_isWakeupTime)
                                            ? isWebOrDesktop
                                                ? 94
                                                : isCardView
                                                    ? 110
                                                    : 120
                                            : isWebOrDesktop
                                                ? 155
                                                : (isLandscape || isCardView)
                                                    ? 152
                                                    : 180,
                                        duration:
                                            const Duration(milliseconds: 300),
                                        curve: Curves.decelerate,
                                        child: AnimatedOpacity(
                                          opacity: _isBedTime ? 1.0 : 0.0,
                                          duration:
                                              (_isWakeupTime && _isBedTime)
                                                  ? const Duration(
                                                      milliseconds: 800)
                                                  : const Duration(
                                                      milliseconds: 200),
                                          child: CustomAnimatedBuilder(
                                            value: !_isWakeupTime
                                                ? (isWebOrDesktop || isCardView)
                                                    ? 1.1
                                                    : 2.0
                                                : (isWebOrDesktop || isCardView)
                                                    ? 0.6
                                                    : 1.3,
                                            curve: Curves.decelerate,
                                            duration: const Duration(
                                                milliseconds: 300),
                                            builder: (BuildContext context,
                                                    Widget child,
                                                    Animation<dynamic>
                                                        animation) =>
                                                Transform.scale(
                                              scale: animation.value,
                                              child: child,
                                            ),
                                            child: Column(
                                              mainAxisSize: MainAxisSize.min,
                                              children: <Widget>[
                                                Text(
                                                  '5 Apr',
                                                  style: TextStyle(
                                                    fontSize: isWebOrDesktop
                                                        ? 24
                                                        : isCardView
                                                            ? 14
                                                            : 10,
                                                    color: Colors.blue,
                                                  ),
                                                ),
                                                const SizedBox(height: 4),
                                                Text(
                                                  _bedTimeAnnotation,
                                                  style: TextStyle(
                                                      color: Colors.blue,
                                                      fontSize: isWebOrDesktop
                                                          ? 28
                                                          : isCardView
                                                              ? 20
                                                              : 16),
                                                ),
                                              ],
                                            ),
                                          ),
                                        ),
                                      ),
                                    ],
                                  ),
                                ),
                                positionFactor: 0.05,
                                angle: 0),
                          ])
                    ],
                  ),
                ],
              ),
            ),
            if (!isCardView) const SizedBox(height: 15),
            if (!isCardView)
              Text(
                _sleepMinutes == '00'
                    ? '$_sleepHours hrs'
                    : '$_sleepHours hrs ' '$_sleepMinutes mins',
                style: TextStyle(
                    fontSize: isCardView ? 14 : 20,
                    fontWeight: FontWeight.w500),
              ),
            if (!isCardView) const SizedBox(height: 4),
            if (!isCardView)
              Text(
                'Sleep time',
                style: TextStyle(
                    fontSize: isCardView ? 10 : 15,
                    fontWeight: FontWeight.w400),
              )
          ],
        ),
      ),
    );
  }

  /// Dragged pointer new value is updated to range.
  void _handleWakeupTimeValueChanged(double value) {
    print(value);
    setState(() {
      _wakeupTimeValue = value;
      // ignore: no_leading_underscores_for_local_identifiers
      final int _value = _wakeupTimeValue.abs().toInt();
      // ignore: no_leading_underscores_for_local_identifiers
      final int _hourValue = _value;
      final List<String> minList =
          _wakeupTimeValue.toStringAsFixed(2).split('.');
      double currentMinutes = double.parse(minList[1]);
      currentMinutes = (currentMinutes * 60) / 100;
      final String minutesValue = currentMinutes.toStringAsFixed(0);

      final double hour = (_hourValue >= 0 && _hourValue <= 6)
          ? (_hourValue + 6).toDouble()
          : (_hourValue >= 6 && _hourValue <= 12)
              ? (_hourValue - 6).toDouble()
              : 0;
      final String hourValue = hour.toString().split('.')[0];

      _wakeupTimeAnnotation =
          ((hour >= 6 && hour < 10) ? '0' + hourValue : hourValue) +
              ':' +
              (minutesValue.length == 1 ? '0' + minutesValue : minutesValue) +
              (_hourValue >= 6 ? ' pm' : ' pm');

      _wakeupTime = (_hourValue + 6 < 10
              ? '0' + _hourValue.toString()
              : _hourValue.toString()) +
          ':' +
          (minutesValue.length == 1 ? '0' + minutesValue : minutesValue);

      final DateFormat dateFormat = DateFormat('HH:mm');
      final DateTime wakeup = dateFormat.parse(_wakeupTime);
      final DateTime sleep =
          dateFormat.parse(_bedTime == '09:00 pm' ? '12:00' : _bedTime);
      final String sleepDuration = sleep.difference(wakeup).toString();
      _sleepHours = sleepDuration.split(':')[0];
      _sleepMinutes = sleepDuration.split(':')[1];
    });
  }

  /// Cancelled the dragging when pointer value reaching the axis end/start value, greater/less than another
  /// pointer value
  void _handleWakeupTimeValueChanging(ValueChangingArgs args) {
    if (args.value >= 6 && args.value < 12) {
      args.cancel = true;
    }

    _wakeupTimePointerWidth = _wakeupTimePointerHeight = 40.0;
  }

  /// Cancelled the dragging when pointer value reaching the axis end/start value, greater/less than another
  /// pointer value
  void _handleBedTimeValueChanging(ValueChangingArgs args) {
    if (args.value >= 0 && args.value < 6) {
      args.cancel = true;
    }

    _bedTimePointerWidth = _bedTimePointerHeight = 40.0;
  }

  /// Dragged pointer new value is updated to range.
  void _handleBedTimeValueChanged(double value) {
    setState(() {
      _bedTimeValue = value;
      // ignore: no_leading_underscores_for_local_identifiers
      final int _value = _bedTimeValue.abs().toInt();
      // ignore: no_leading_underscores_for_local_identifiers
      final int _hourValue = _value;

      final List<String> minList = _bedTimeValue.toStringAsFixed(2).split('.');
      double currentMinutes = double.parse(minList[1]);
      currentMinutes = (currentMinutes * 60) / 100;
      final String minutesValue = currentMinutes.toStringAsFixed(0);

      _bedTimeAnnotation = ((_hourValue >= 0 && _hourValue <= 6)
              ? (_hourValue + 6).toString()
              : (_hourValue >= 6 && _hourValue <= 12)
                  ? '0' + (_hourValue - 6).toString()
                  : '') +
          ':' +
          (minutesValue.length == 1 ? '0' + minutesValue : minutesValue) +
          (_value >= 6 ? ' am' : ' pm');

      _bedTime = (_hourValue < 10
              ? '0' + _hourValue.toString()
              : _hourValue.toString()) +
          ':' +
          (minutesValue.length == 1 ? '0' + minutesValue : minutesValue);

      final DateFormat dateFormat = DateFormat('HH:mm');
      final DateTime wakeup =
          dateFormat.parse(_wakeupTime == '06:00 am' ? '03:00' : _wakeupTime);
      final DateTime sleep = dateFormat.parse(_bedTime);
      final String sleepDuration = sleep.difference(wakeup).toString();
      _sleepHours = sleepDuration.split(':')[0];
      _sleepMinutes = sleepDuration.split(':')[1];
    });
  }

  void _handleWakeupTimeValueStart(double value) {
    _isBedTime = false;
  }

  void _handleWakeupTimeValueEnd(double value) {
    setState(() {
      _isBedTime = true;
    });

    _wakeupTimePointerWidth = _wakeupTimePointerHeight = 30.0;
  }

  void _handleBedTimeValueStart(double value) {
    _isWakeupTime = false;
  }

  void _handleBedTimeValueEnd(double value) {
    setState(() {
      _isWakeupTime = true;
    });

    _bedTimePointerWidth = _bedTimePointerHeight = 40.0;
  }

  /// Renders a given fixed size widget
  bool get isWebOrDesktop {
    return defaultTargetPlatform == TargetPlatform.windows ||
        defaultTargetPlatform == TargetPlatform.linux ||
        defaultTargetPlatform == TargetPlatform.macOS ||
        kIsWeb;
  }

  double _wakeupTimeValue = 3;
  double _bedTimeValue = 12;
  String _wakeupTimeAnnotation = '09:00 pm';
  String _bedTimeAnnotation = '06:00 am';
  bool _isWakeupTime = true;
  bool _isBedTime = true;
  String _sleepHours = '9';
  String _sleepMinutes = '00';
  String _bedTime = '09:00 pm';
  String _wakeupTime = '06:00 am';
  double _bedTimePointerWidth = 40.0;
  double _bedTimePointerHeight = 40.0;
  double _wakeupTimePointerWidth = 30.0;
  double _wakeupTimePointerHeight = 30.0;
  double _tickness = 0.2;
}

/// Widget of custom animated builder.
class CustomAnimatedBuilder extends StatefulWidget {
  /// Creates a instance for [CustomAnimatedBuilder].
  const CustomAnimatedBuilder({
    Key key,
    this.value,
    this.builder,
    this.duration = const Duration(milliseconds: 200),
    this.curve = Curves.easeInOut,
    this.child,
  }) : super(key: key);

  /// Specifies the animation duration.
  final Duration duration;

  /// Specifies the curve of animation.
  final Curve curve;

  /// Specifies the animation controller value.
  final double value;

  /// Specifies the child widget.
  final Widget child;

  /// Specifies the builder function.
  final Widget Function(
    BuildContext context,
    Widget child,
    Animation<dynamic> animation,
  ) builder;

  @override
  _CustomAnimatedBuilderState createState() => _CustomAnimatedBuilderState();
}

class _CustomAnimatedBuilderState extends State<CustomAnimatedBuilder>
    with SingleTickerProviderStateMixin {
  AnimationController _animationController;

  @override
  void initState() {
    _animationController = AnimationController(
      vsync: this,
      value: widget.value,
      lowerBound: double.negativeInfinity,
      upperBound: double.infinity,
    );
    super.initState();
  }

  @override
  void dispose() {
    _animationController.dispose();
    super.dispose();
  }

  @override
  void didUpdateWidget(CustomAnimatedBuilder oldWidget) {
    super.didUpdateWidget(oldWidget);

    if (oldWidget.value != widget.value) {
      _animationController.animateTo(
        widget.value,
        duration: widget.duration,
        curve: widget.curve,
      );
    }
  }

  @override
  Widget build(BuildContext context) {
    return AnimatedBuilder(
      animation: _animationController,
      builder: (BuildContext context, Widget child) => widget.builder(
        context,
        widget.child,
        _animationController,
      ),
    );
  }
}
Marismathan commented 2 years ago

Hi @Rayyanmaq1 ,

Greetings from Syncfusion. We understand that you want to make the tap and drag support for the radial gauge’s axis (which is in white color in the shared gauge’s image) as same as the dragging behavior of the marker. But as of now, we have no idea of implementing the drag support for the radial axis of the radial bar. It may be implemented based on demands. Kindly revert us if need further assistance.

SFRadialGauge

Thanks, Marismathan G