diff --git a/example/lib/main.dart b/example/lib/main.dart index 30e7c13..0c2af6d 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -6,7 +6,7 @@ void main() { runApp( const MaterialApp( debugShowCheckedModeBanner: false, - home: MyVerticalGauge(), + home: LinearGaugeExample(), ), ); } @@ -23,6 +23,7 @@ class LinearGaugeExample extends StatefulWidget { } class _LinearGaugeExampleState extends State { + double value = 20; @override Widget build(BuildContext context) { return Scaffold( @@ -33,6 +34,16 @@ class _LinearGaugeExampleState extends State { rulers: RulerStyle( rulerPosition: RulerPosition.bottom, ), + valueBar: [ + ValueBar( + value: 20, + offset: 300, + ) + ], + customLabels: [ + CustomRulerLabel(text: "Hello One", value: value), + CustomRulerLabel(text: "Hello Two", value: 60), + ], pointers: const [ Pointer( value: 50, diff --git a/example/pubspec.lock b/example/pubspec.lock index 7ead57d..a66fc33 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -81,7 +81,7 @@ packages: path: ".." relative: true source: path - version: "1.0.3" + version: "1.0.4" leak_tracker: dependency: transitive description: diff --git a/lib/src/linear_gauge/gauge_container/linear_gauge_container.dart b/lib/src/linear_gauge/gauge_container/linear_gauge_container.dart index 15486ee..4812736 100644 --- a/lib/src/linear_gauge/gauge_container/linear_gauge_container.dart +++ b/lib/src/linear_gauge/gauge_container/linear_gauge_container.dart @@ -19,6 +19,8 @@ class LinearGaugeContainer extends LeafRenderObjectWidget { return RenderLinearGaugeContainer( start: linearGauge.start!, end: linearGauge.end!, + trackLabelFormat: linearGauge.trackLabelFormat ?? + (double value) => ((value * 10).round() / 10).toString(), value: linearGauge.value!, steps: linearGauge.steps!, gaugeOrientation: linearGauge.gaugeOrientation!, @@ -59,6 +61,8 @@ class LinearGaugeContainer extends LeafRenderObjectWidget { renderObject ..setStart = linearGauge.start! ..setEnd = linearGauge.end! + ..setTrackLabelFormat = linearGauge.trackLabelFormat ?? + ((double value) => ((value * 10).round() / 10).toString()) ..setValue = linearGauge.value! ..setSteps = linearGauge.steps! ..setGaugeOrientation = linearGauge.gaugeOrientation! @@ -98,6 +102,7 @@ class RenderLinearGaugeContainer extends RenderBox { RenderLinearGaugeContainer({ required double start, required double end, + required final String Function(double)? trackLabelFormat, required double steps, required double value, required GaugeOrientation gaugeOrientation, @@ -130,6 +135,7 @@ class RenderLinearGaugeContainer extends RenderBox { required LinearGradient? linearGradient, }) : _start = start, _end = end, + _trackLabelFormat = trackLabelFormat, _value = value, _steps = steps, _gaugeOrientation = gaugeOrientation, @@ -182,6 +188,7 @@ class RenderLinearGaugeContainer extends RenderBox { if (_start == start) return; _start = start; markNeedsPaint(); + markNeedsLayout(); } /// @@ -193,6 +200,15 @@ class RenderLinearGaugeContainer extends RenderBox { if (_end == end) return; _end = end; markNeedsPaint(); + markNeedsLayout(); + } + + get trackLabelFormat => _trackLabelFormat; + String Function(double)? _trackLabelFormat; + set setTrackLabelFormat(String Function(double)? trackLabelFormat) { + if (_trackLabelFormat == trackLabelFormat) return; + _trackLabelFormat = trackLabelFormat; + markNeedsPaint(); } double get getValue => _value; @@ -656,21 +672,6 @@ class RenderLinearGaugeContainer extends RenderBox { return largestPointer; } - // double getLargestWidgetPointerSize() { - // if (RenderLinearGauge.getWidgetPointers!.isNotEmpty) { - // RenderLinearGaugeWidgetPointer? largestPointer = - // getLargestWidgetPointer(RenderLinearGauge.getWidgetPointers); - - // if (getGaugeOrientation == GaugeOrientation.vertical) { - // return largestPointer?.size.width ?? 0; - // } else { - // return largestPointer?.size.width ?? 0; - // } - // } else { - // return 0; - // } - // } - void _setLinearGaugeContainerPaint() { _linearGaugeContainerPaint.color = setAnimatedColor(getLinearGaugeContainerBgColor); @@ -700,6 +701,7 @@ class RenderLinearGaugeContainer extends RenderBox { } _linearGaugeLabel.addLabels( + trackLabelFormat: trackLabelFormat, distanceValueInRangeOfHundred: getSteps == 0.0 ? interval : getSteps, start: getStart, end: getEnd, diff --git a/lib/src/linear_gauge/linear_gauge.dart b/lib/src/linear_gauge/linear_gauge.dart index 0b45332..9543fa1 100644 --- a/lib/src/linear_gauge/linear_gauge.dart +++ b/lib/src/linear_gauge/linear_gauge.dart @@ -45,6 +45,7 @@ class LinearGauge extends StatefulWidget { this.start = 0, this.end = 100, this.steps = 0, + this.trackLabelFormat, @Deprecated('Use ValueBar instead') this.value = 0, this.gaugeOrientation = GaugeOrientation.horizontal, this.showLinearGaugeContainer = true, @@ -65,6 +66,12 @@ class LinearGauge extends StatefulWidget { this.curves = const [], }) : assert(() { if (customLabels!.isNotEmpty) { + if (valueBar != []) { + assert( + valueBar!.every( + (element) => element.value >= customLabels.first.value!), + "Valuebar value should be greater than or equal to customLabels start value"); + } assert(customLabels.length >= 2, "At least two CustomRulerLabel should be added"); @@ -144,6 +151,19 @@ class LinearGauge extends StatefulWidget { /// final double? end; + /// + /// `trackLabelFormat` Sets the format of the label of the [LinearGauge] labels + /// + /// ```dart + /// const LinearGauge( + /// trackLabelFormat : value) { + /// return '\$ ${value.toStringAsFixed(1)}'; + /// }, + /// ), + /// ``` + /// + final String Function(double)? trackLabelFormat; + /// /// `steps` Sets the interval between label of the [LinearGauge] Container /// @@ -712,6 +732,7 @@ class _RLinearGauge extends MultiChildRenderObjectWidget { return RenderLinearGauge( start: lGauge.start!, end: lGauge.end!, + trackLabelFormat: lGauge.trackLabelFormat, steps: lGauge.steps!, gaugeOrientation: lGauge.gaugeOrientation!, primaryRulersWidth: lGauge.rulers!.primaryRulersWidth!, @@ -741,6 +762,7 @@ class _RLinearGauge extends MultiChildRenderObjectWidget { BuildContext context, RenderLinearGauge renderObject) { renderObject ..setCustomLabels = lGauge.customLabels! + ..setTrackLabelFormat = lGauge.trackLabelFormat ..setGaugeOrientation = lGauge.gaugeOrientation! ..setPrimaryRulersHeight = lGauge.rulers!.primaryRulersHeight! ..setPrimaryRulersWidth = lGauge.rulers!.primaryRulersWidth! @@ -810,6 +832,8 @@ class RenderLinearGaugeElement extends MultiChildRenderObjectElement { renderObject.removeValueBar(child); } else if (child is RenderCurve) { renderObject.removeCurve(child); + } else if (child is RenderRulerLabel) { + renderObject.removeRulerLabel(child); } } } diff --git a/lib/src/linear_gauge/linear_gauge_label.dart b/lib/src/linear_gauge/linear_gauge_label.dart index 140d7a4..e0d5979 100644 --- a/lib/src/linear_gauge/linear_gauge_label.dart +++ b/lib/src/linear_gauge/linear_gauge_label.dart @@ -18,6 +18,7 @@ class LinearGaugeLabel { TextPainter(textDirection: TextDirection.ltr); void addLabels({ + required trackLabelFormat, required double distanceValueInRangeOfHundred, required double start, required double end, @@ -25,13 +26,16 @@ class LinearGaugeLabel { _linearGaugeLabel.clear(); for (double i = start; i <= end; i += distanceValueInRangeOfHundred) { - _linearGaugeLabel.add(LinearGaugeLabel(text: i.toString(), value: i)); + text = trackLabelFormat(i); + + _linearGaugeLabel.add(LinearGaugeLabel(text: text, value: i)); } final LinearGaugeLabel localLabel = _linearGaugeLabel[_linearGaugeLabel.length - 1]; if (localLabel.value != end && localLabel.value! < end) { - _linearGaugeLabel.add(LinearGaugeLabel(text: end.toString(), value: end)); + String text = trackLabelFormat(end); + _linearGaugeLabel.add(LinearGaugeLabel(text: text, value: end)); } } diff --git a/lib/src/linear_gauge/linear_gauge_painter.dart b/lib/src/linear_gauge/linear_gauge_painter.dart index 3058d88..8222eba 100644 --- a/lib/src/linear_gauge/linear_gauge_painter.dart +++ b/lib/src/linear_gauge/linear_gauge_painter.dart @@ -18,6 +18,7 @@ class RenderLinearGauge extends RenderBox RenderLinearGauge({ required double start, required double end, + required String Function(double)? trackLabelFormat, required double steps, required GaugeOrientation gaugeOrientation, required TextStyle textStyle, @@ -42,6 +43,7 @@ class RenderLinearGauge extends RenderBox }) : assert(start < end, "Start should be grater then end"), _start = start, _end = end, + _trackLabelFormat = trackLabelFormat, _steps = steps, _gaugeOrientation = gaugeOrientation, _textStyle = textStyle, @@ -267,6 +269,14 @@ class RenderLinearGauge extends RenderBox markNeedsLayout(); } + String Function(double)? get getTrackLabelFormat => _trackLabelFormat; + String Function(double)? _trackLabelFormat; + set setTrackLabelFormat(String Function(double)? val) { + if (_trackLabelFormat == val) return; + _trackLabelFormat = val; + markNeedsPaint(); + } + double get getLabelOffset => _labelOffset; double _labelOffset; set setLabelOffset(double val) { @@ -327,9 +337,19 @@ class RenderLinearGauge extends RenderBox } LinearGaugeLabel get getLinearGaugeLabel { + markNeedsPaint(); + markNeedsLayout(); return _linearGaugeLabel; } + LinearGaugeLabel _linearGaugeLabel = LinearGaugeLabel(); + set setLinearGaugeLabel(LinearGaugeLabel val) { + if (_linearGaugeLabel == val) return; + _linearGaugeLabel = val; + markNeedsPaint(); + markNeedsLayout(); + } + /// /// Getter and Setter for the [valueBar] parameter. /// @@ -398,7 +418,6 @@ class RenderLinearGauge extends RenderBox /// double get getPointerSpace => _pointerSpace; final double _pointerSpace = 0; - LinearGaugeLabel _linearGaugeLabel = LinearGaugeLabel(); late Size _axisActualSize; late final List _widgetPointers; @@ -449,6 +468,12 @@ class RenderLinearGauge extends RenderBox markNeedsLayout(); } + /// Remove the ruler label render object from widget . + void removeRulerLabel(RenderRulerLabel label) { + _renderRulerLabel = null; + markNeedsLayout(); + } + /// Adds the valuebar render object to widget . void addValueBar(RenderValueBar ruler) { _valueBarRenderObject.add(ruler); @@ -2231,5 +2256,3 @@ class LinearGaugeParentData extends MultiChildLayoutParentData { this.gaugeEnd, this.linearGaugeLabel); } - -// class Temp implements MouseTrackerAnnotation {} diff --git a/lib/src/radial_gauge/pointer/needle_pointer_painter.dart b/lib/src/radial_gauge/pointer/needle_pointer_painter.dart index d02753d..b9069a4 100644 --- a/lib/src/radial_gauge/pointer/needle_pointer_painter.dart +++ b/lib/src/radial_gauge/pointer/needle_pointer_painter.dart @@ -144,6 +144,7 @@ class RenderNeedlePointer extends RenderBox { @override bool hitTestSelf(Offset position) { Offset calulatedPosition = localToGlobal(position); + if (needlePointerRect.contains(calulatedPosition)) { return true; } else if (needlePointerRect.contains(position)) { @@ -156,7 +157,6 @@ class RenderNeedlePointer extends RenderBox { @override void performLayout() { - // size = Size(_needleWidth + _tailRadius, _needleHeight); size = Size(constraints.maxWidth, constraints.maxHeight); } @@ -227,8 +227,25 @@ class RenderNeedlePointer extends RenderBox { needlePath.close(); - needlePointerRect = needlePath; - // canvas.drawPath(needlePath, Paint()..color = Colors.green); + final hitTestWidth = _needleWidth; + + final dx = needleEndX - needleStartX; + final dy = needleEndY - needleStartY; + + final norm = sqrt(dx * dx + dy * dy); + final perpX = -dy / norm * hitTestWidth / 2; + final perpY = dx / norm * hitTestWidth / 2; + + final hitTestPath = Path() + ..moveTo(needleStartX + perpX, needleStartY + perpY) + ..lineTo(needleEndX + perpX, needleEndY + perpY) + ..lineTo(needleEndX - perpX, needleEndY - perpY) + ..lineTo(needleStartX - perpX, needleStartY - perpY) + ..close(); + + needlePointerRect = + _needleStyle == NeedleStyle.gaugeNeedle ? needlePath : hitTestPath; + // Needle Pointer paint if (getNeedleStyle == NeedleStyle.gaugeNeedle) { canvas.drawPath(needlePath, needlePaint); @@ -247,26 +264,3 @@ class RenderNeedlePointer extends RenderBox { return newValue; } } - -// @override -// void applyPaintTransform(RenderBox child, Matrix4 transform) { -// if (child is RenderNeedlePointer) { -// final centerX = size.width / 2; -// final centerY = size.height / 2; - -// transform.translate(centerX, centerY); -// double value = calculateValueAngle( -// child.getValue, getRadialGauge.track.start, getRadialGauge.track.end); -// double startAngle = (getRadialGauge.track.startAngle - 180) * (pi / 180); -// double endAngle = (getRadialGauge.track.endAngle - 180) * (pi / 180); -// double angle = startAngle + (value / 100) * (endAngle - startAngle); -// double toRotateAngle = angle - (pi / 2); -// transform.rotateZ(toRotateAngle); // Specify the rotation in radians -// transform.translate( -// -centerX - child.getNeedleWidth / 2 - child.getTailRadius / 2, -// -centerY - child.getNeedleHeight + child.getTailRadius / 2); - -// super.applyPaintTransform(child, transform); -// markNeedsLayout(); -// } -// } diff --git a/lib/src/radial_gauge/pointer/radial_widget_painter.dart b/lib/src/radial_gauge/pointer/radial_widget_painter.dart index fd14135..2c45e28 100644 --- a/lib/src/radial_gauge/pointer/radial_widget_painter.dart +++ b/lib/src/radial_gauge/pointer/radial_widget_painter.dart @@ -69,12 +69,18 @@ class RenderRadialWidgetPointer extends RenderProxyBox { void paint(PaintingContext context, Offset offset) { double gaugeStart = _radialGauge.track.start; double gaugeEnd = _radialGauge.track.end; + double containerWidth = constraints.maxWidth; + double containerHeight = constraints.maxHeight; + double containerShortestSide = min(containerWidth, containerHeight); + + final childSize = child?.computeDryLayout(constraints); + final childOffsetX = (childSize?.width ?? 0.0) / 2; + final childOffsetY = (childSize?.height ?? 0.0) / 2; - // final center = Offset(offset.dx, offset.dy); final center = Offset( - 1440 * _radialGauge.xCenterCoordinate - - 2 * _radialGauge.track.thickness, - 900 * _radialGauge.yCenterCoordinate - _radialGauge.track.thickness); + containerWidth * _radialGauge.xCenterCoordinate + offset.dx, + containerHeight * _radialGauge.yCenterCoordinate + offset.dy); + double value = calculateValueAngle(_value, gaugeStart, gaugeEnd); double startAngle = (_radialGauge.track.startAngle - 180) * (pi / 180); double endAngle = (_radialGauge.track.endAngle - 180) * (pi / 180); @@ -82,12 +88,14 @@ class RenderRadialWidgetPointer extends RenderProxyBox { final double angle = startAngle + (value / 100) * (endAngle - startAngle); double circlePointerOffset = - (900 / 2 - _radialGauge.track.thickness) * _radialGauge.radiusFactor; + (containerShortestSide / 2 - _radialGauge.track.thickness) * + _radialGauge.radiusFactor; + + double circlePointerEndX = + center.dx + circlePointerOffset * cos(angle) - childOffsetX; + double circlePointerEndY = + center.dy + circlePointerOffset * sin(angle) - childOffsetY; - double circlePointerEndX = center.dx + circlePointerOffset * cos(angle); - double circlePointerEndY = center.dy + circlePointerOffset * sin(angle); - // canvas.drawCircle(Offset(circlePointerEndX, circlePointerEndY), 30, - // Paint()..color = Colors.red); super.paint(context, Offset(circlePointerEndX, circlePointerEndY)); }