diff --git a/CHANGELOG.md b/CHANGELOG.md index e5f65fe23..3bb658e66 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## 0.12.1 +* [Bugfix] Fixed PieChart badges bug with re-implementing the solution, #507 +* [Bugfix] Fix the setState issue using PieChart in the ListView, #467 +* [Bugfix] Fixed formatNumber bug for negative numbers, #486. +* [Improvement] Added applyCutOffY property in [BarAreaSpotsLine](https://github.com/imaNNeoFighT/fl_chart/blob/master/repo_files/documentations/line_chart.md#barareaspotsline) to inherit cutOffY property of its parent, #478. + ## 0.12.0 * [Improvement] [BREAKING] Replaced `color` property with `colors` in [BarChartRodData](https://github.com/imaNNeoFighT/fl_chart/blob/master/repo_files/documentations/bar_chart.md#barchartroddata), and [BackgroundBarChartRodData](https://github.com/imaNNeoFighT/fl_chart/blob/master/repo_files/documentations/bar_chart.md#backgroundbarchartroddata) to support gradient in BarChart, instead of solid color, #166. Check [BarChartSample3](https://github.com/imaNNeoFighT/fl_chart/blob/master/repo_files/documentations/bar_chart.md#sample-3-source-code) * [Improvement] Improved gradient stops calculating algorithm. diff --git a/README.md b/README.md index 04163bb04..3f74f94de 100644 --- a/README.md +++ b/README.md @@ -41,7 +41,7 @@ Thank you all! ```yml dependencies: - fl_chart: ^0.12.0 + fl_chart: ^0.12.1 ``` diff --git a/lib/src/chart/base/axis_chart/axis_chart_data.dart b/lib/src/chart/base/axis_chart/axis_chart_data.dart index 16b8dc8b3..9143c0165 100644 --- a/lib/src/chart/base/axis_chart/axis_chart_data.dart +++ b/lib/src/chart/base/axis_chart/axis_chart_data.dart @@ -351,6 +351,12 @@ class FlSpot with EquatableMixin { ); } + ///Prints x and y coordinates of FlSpot list + @override + String toString() { + return '(' + x.toString() + ', ' + y.toString() + ')'; + } + /// Used for splitting lines, or maybe other concepts. static FlSpot nullSpot = FlSpot(null, null); diff --git a/lib/src/chart/base/base_chart/base_chart_data.dart b/lib/src/chart/base/base_chart/base_chart_data.dart index 80940a48a..83e6b0164 100644 --- a/lib/src/chart/base/base_chart/base_chart_data.dart +++ b/lib/src/chart/base/base_chart/base_chart_data.dart @@ -147,9 +147,6 @@ TextStyle defaultGetTitleTextStyle(double value) { ); } -/// The signature for a callback that provides a map of position offsets. -typedef GetPositionOffsetsFunction = void Function(Map offsetsMap); - /// This class holds the touch response details. /// /// Specific touch details should be hold on the concrete child classes. diff --git a/lib/src/chart/line_chart/line_chart_data.dart b/lib/src/chart/line_chart/line_chart_data.dart index b806c3f3b..320d41505 100644 --- a/lib/src/chart/line_chart/line_chart_data.dart +++ b/lib/src/chart/line_chart/line_chart_data.dart @@ -688,6 +688,9 @@ class BarAreaSpotsLine with EquatableMixin { /// Checks to show or hide lines on the spots. final CheckToShowSpotLine checkToShowSpotLine; + /// Determines to inherit the cutOff properties from its parent [BarAreaData] + final bool applyCutOffY; + /// If [show] is true, [LineChart] draws some lines on above or below the spots, /// you can customize the appearance of the lines using [flLineStyle] /// and you can decide to show or hide the lines on each spot using [checkToShowSpotLine]. @@ -695,9 +698,11 @@ class BarAreaSpotsLine with EquatableMixin { bool show, FlLine flLineStyle, CheckToShowSpotLine checkToShowSpotLine, + bool applyCutOffY, }) : show = show ?? false, flLineStyle = flLineStyle ?? FlLine(), - checkToShowSpotLine = checkToShowSpotLine ?? showAllSpotsBelowLine; + checkToShowSpotLine = checkToShowSpotLine ?? showAllSpotsBelowLine, + applyCutOffY = applyCutOffY ?? true; /// Lerps a [BarAreaSpotsLine] based on [t] value, check [Tween.lerp]. static BarAreaSpotsLine lerp(BarAreaSpotsLine a, BarAreaSpotsLine b, double t) { @@ -705,6 +710,7 @@ class BarAreaSpotsLine with EquatableMixin { show: b.show, checkToShowSpotLine: b.checkToShowSpotLine, flLineStyle: FlLine.lerp(a.flLineStyle, b.flLineStyle, t), + applyCutOffY: b.applyCutOffY, ); } @@ -714,6 +720,7 @@ class BarAreaSpotsLine with EquatableMixin { show, flLineStyle, checkToShowSpotLine, + applyCutOffY, ]; } diff --git a/lib/src/chart/line_chart/line_chart_painter.dart b/lib/src/chart/line_chart/line_chart_painter.dart index 984822968..0defc222d 100644 --- a/lib/src/chart/line_chart/line_chart_painter.dart +++ b/lib/src/chart/line_chart/line_chart_painter.dart @@ -590,10 +590,20 @@ class LineChartPainter extends AxisChartPainter ); final double bottomPadding = getExtraNeededVerticalSpace() - getTopOffsetDrawSize(); - final Offset to = Offset( - getPixelX(spot.x, chartViewSize), - viewSize.height - bottomPadding, - ); + Offset to; + + // Check applyCutOffY + if (barData.belowBarData.spotsLine.applyCutOffY && barData.belowBarData.applyCutOffY) { + to = Offset( + getPixelX(spot.x, chartViewSize), + getPixelY(barData.belowBarData.cutOffY, chartViewSize), + ); + } else { + to = Offset( + getPixelX(spot.x, chartViewSize), + viewSize.height - bottomPadding, + ); + } _barAreaLinesPaint.color = barData.belowBarData.spotsLine.flLineStyle.color; _barAreaLinesPaint.strokeWidth = barData.belowBarData.spotsLine.flLineStyle.strokeWidth; @@ -670,10 +680,20 @@ class LineChartPainter extends AxisChartPainter getPixelY(spot.y, chartViewSize), ); - final Offset to = Offset( - getPixelX(spot.x, chartViewSize), - getTopOffsetDrawSize(), - ); + Offset to; + + // Check applyCutOffY + if (barData.aboveBarData.spotsLine.applyCutOffY && barData.aboveBarData.applyCutOffY) { + to = Offset( + getPixelX(spot.x, chartViewSize), + getPixelY(barData.aboveBarData.cutOffY, chartViewSize), + ); + } else { + to = Offset( + getPixelX(spot.x, chartViewSize), + getTopOffsetDrawSize(), + ); + } _barAreaLinesPaint.color = barData.aboveBarData.spotsLine.flLineStyle.color; _barAreaLinesPaint.strokeWidth = barData.aboveBarData.spotsLine.flLineStyle.strokeWidth; diff --git a/lib/src/chart/pie_chart/pie_chart.dart b/lib/src/chart/pie_chart/pie_chart.dart index 9d3f69655..45133fc65 100644 --- a/lib/src/chart/pie_chart/pie_chart.dart +++ b/lib/src/chart/pie_chart/pie_chart.dart @@ -36,21 +36,14 @@ class _PieChartState extends AnimatedWidgetBaseState { /// This is used to map the touch events to [PieTouchResponse] TouchHandler _touchHandler; - /// For storing the badge widgets' offsets. - Map _badgeWidgetsOffsets = {}; + /// This is used to retrieve the offsets for puting widgets upon the chart. + /// + /// exposes [PieChartWidgetsPositionHandler.getBadgeOffsets] to retrieve the badge widgets position. + PieChartWidgetsPositionHandler _widgetsPositionHandler; /// this is used to retrieve the chart size to handle the touches final GlobalKey _chartKey = GlobalKey(); - @override - void initState() { - /// Make sure that [_badgeWidgetsOffsets] is updated. - WidgetsBinding.instance.addPostFrameCallback((_) { - setState(() {}); - }); - super.initState(); - } - @override Widget build(BuildContext context) { final PieChartData showingData = _getData(); @@ -152,39 +145,61 @@ class _PieChartState extends AnimatedWidgetBaseState { }); }, textScale: MediaQuery.of(context).textScaleFactor, - badgeWidgetsOffsetsProvider: (offsetsMap) { - /// Store badge widget offsets from painter. - _badgeWidgetsOffsets = Map.from(offsetsMap); + widgetsPositionHandler: (widgetPositionHandler) { + setState(() { + _widgetsPositionHandler = widgetPositionHandler; + }); }, ), - child: _badgeWidgetsOffsets.isEmpty - ? null - : CustomMultiChildLayout( - delegate: BadgeWidgetsDelegate( - badgeWidgetsCount: _badgeWidgetsOffsets.length, - badgeWidgetsOffsets: _badgeWidgetsOffsets, - ), - children: List.generate( - _badgeWidgetsOffsets.length, - (index) { - final int _key = _badgeWidgetsOffsets.keys.elementAt(index); - final Widget _badgeWidget = widget.data.sections[_key].badgeWidget; - - if (_badgeWidget == null) { - return null; - } - - return LayoutId( - id: _key, - child: _badgeWidget, - ); - }, - ), - ), + child: badgeWidgets(), ), ); } + Widget badgeWidgets() { + final chartSize = _getChartSize(); + if (chartSize != null && _widgetsPositionHandler != null) { + final offsetsMap = _widgetsPositionHandler.getBadgeOffsets(chartSize); + if (offsetsMap.isNotEmpty) { + return CustomMultiChildLayout( + delegate: BadgeWidgetsDelegate( + badgeWidgetsCount: offsetsMap.length, + badgeWidgetsOffsets: offsetsMap, + ), + children: List.generate( + offsetsMap.length, + (index) { + final int _key = offsetsMap.keys.elementAt(index); + + if (offsetsMap.length != _getData().sections.length) { + return LayoutId( + id: _key, + child: Container(), + ); + } + + final Widget _badgeWidget = _getData().sections[_key].badgeWidget; + + if (_badgeWidget == null) { + return LayoutId( + id: _key, + child: Container(), + ); + } + + return LayoutId( + id: _key, + child: _badgeWidget, + ); + }, + ), + ); + } + } + + return null; + } + bool _canHandleTouch(PieTouchResponse response, PieTouchData touchData) { return response != null && touchData != null && touchData.touchCallback != null; } diff --git a/lib/src/chart/pie_chart/pie_chart_painter.dart b/lib/src/chart/pie_chart/pie_chart_painter.dart index 9af407814..aa777c688 100644 --- a/lib/src/chart/pie_chart/pie_chart_painter.dart +++ b/lib/src/chart/pie_chart/pie_chart_painter.dart @@ -9,12 +9,10 @@ import 'package:flutter/widgets.dart'; import 'pie_chart_data.dart'; /// Paints [PieChartData] in the canvas, it can be used in a [CustomPainter] -class PieChartPainter extends BaseChartPainter with TouchHandler { +class PieChartPainter extends BaseChartPainter + with TouchHandler, PieChartWidgetsPositionHandler { Paint _sectionPaint, _sectionsSpaceClearPaint, _centerSpacePaint; - /// A callback that provides position offsets for the badge widgets. - GetPositionOffsetsFunction _badgeWidgetsOffsetsProvider; - /// Paints [data] into canvas, it is the animating [PieChartData], /// [targetData] is the animation's target and remains the same /// during animation, then we should use it when we need to show @@ -26,20 +24,18 @@ class PieChartPainter extends BaseChartPainter with TouchHandler

with TouchHandler

_calculateSectionsAngle(List sections, double sumValue) { @@ -168,9 +164,8 @@ class PieChartPainter extends BaseChartPainter with TouchHandler

badgeWidgetsOffsets = {}; double tempAngle = data.startDegreeOffset; @@ -192,8 +187,6 @@ class PieChartPainter extends BaseChartPainter with TouchHandler

with TouchHandler

with TouchHandler

getBadgeOffsets(Size viewSize) { + final Offset center = Offset(viewSize.width / 2, viewSize.height / 2); + final Map badgeWidgetsOffsets = {}; + + double tempAngle = data.startDegreeOffset; + + for (int i = 0; i < data.sections.length; i++) { + final PieChartSectionData section = data.sections[i]; + final double startAngle = tempAngle; + final double sweepAngle = 360 * (section.value / data.sumValue); + final double sectionCenterAngle = startAngle + (sweepAngle / 2); + + Offset sectionCenter(double percentageOffset) => + center + + Offset( + math.cos(radians(sectionCenterAngle)) * + (_calculateCenterRadius(viewSize, data.centerSpaceRadius) + + (section.radius * percentageOffset)), + math.sin(radians(sectionCenterAngle)) * + (_calculateCenterRadius(viewSize, data.centerSpaceRadius) + + (section.radius * percentageOffset)), + ); + + final Offset sectionCenterOffsetBadgeWidget = + sectionCenter(section.badgePositionPercentageOffset); + + if (section.badgeWidget != null) { + badgeWidgetsOffsets[i] = sectionCenterOffsetBadgeWidget; + } + + tempAngle += sweepAngle; + } + + return badgeWidgetsOffsets; + } + /// Determines should it redraw the chart or not. /// /// If there is a change in the [PieChartData], @@ -315,3 +340,9 @@ class PieChartPainter extends BaseChartPainter with TouchHandler

oldDelegate.data != data; } + +/// Responsible to expose offset positions for laying out the widgets upon the chart. +mixin PieChartWidgetsPositionHandler { + /// Exposes offset for laying out the badge widgets upon the chart. + Map getBadgeOffsets(Size size) => throw UnsupportedError('not implemented'); +} diff --git a/lib/src/utils/utils.dart b/lib/src/utils/utils.dart index 76f9b7dd6..78930423f 100644 --- a/lib/src/utils/utils.dart +++ b/lib/src/utils/utils.dart @@ -153,6 +153,12 @@ const double kilo = 1000; /// otherwise it returns number itself. /// also it removes .0, at the end of number for simplicity. String formatNumber(double number) { + final isNegative = number < 0; + + if (isNegative) { + number = number.abs(); + } + String resultNumber; String symbol; if (number >= billion) { @@ -173,5 +179,9 @@ String formatNumber(double number) { resultNumber = resultNumber.substring(0, resultNumber.length - 2); } + if (isNegative) { + resultNumber = '-$resultNumber'; + } + return resultNumber + symbol; } diff --git a/pubspec.yaml b/pubspec.yaml index efbab817c..625db23a9 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: fl_chart description: A powerful Flutter chart library, currently supporting Line Chart, Bar Chart and Pie Chart. -version: 0.12.0 +version: 0.12.1 homepage: https://github.com/imaNNeoFighT/fl_chart environment: diff --git a/repo_files/documentations/line_chart.md b/repo_files/documentations/line_chart.md index 740b0c9ce..4145d7988 100644 --- a/repo_files/documentations/line_chart.md +++ b/repo_files/documentations/line_chart.md @@ -90,7 +90,7 @@ LineChart( |show|determines show or hide the below, or above spots line|true| |flLineStyle|a [FlLine](base_chart.md#FlLine) object that determines style of the line|[Colors.blueGrey]| |checkToShowSpotLine|a function to determine whether to show or hide the below or above line on the given spot|showAllSpotsBelowLine| - +|applyCutOffY|Determines to inherit the cutOff properties from its parent [BarAreaData](#BarAreaData)|true| ### FlDotData |PropName|Description|default value| diff --git a/test/utils/utils_test.dart b/test/utils/utils_test.dart index e5850993b..4c946116b 100644 --- a/test/utils/utils_test.dart +++ b/test/utils/utils_test.dart @@ -63,6 +63,7 @@ void main() { test('test formatNumber', () { expect(formatNumber(0), '0'); expect(formatNumber(423), '423'); + expect(formatNumber(-423), '-423'); expect(formatNumber(1000), '1K'); expect(formatNumber(1234), '1.2K'); expect(formatNumber(10000), '10K'); @@ -70,14 +71,18 @@ void main() { expect(formatNumber(82349), '82.3K'); expect(formatNumber(82350), '82.3K'); expect(formatNumber(82351), '82.4K'); + expect(formatNumber(-82351), '-82.4K'); expect(formatNumber(100000), '100K'); expect(formatNumber(101000), '101K'); expect(formatNumber(2345123), '2.3M'); expect(formatNumber(2352123), '2.4M'); + expect(formatNumber(-2352123), '-2.4M'); expect(formatNumber(521000000), '521M'); expect(formatNumber(4324512345), '4.3B'); expect(formatNumber(4000000000), '4B'); + expect(formatNumber(-4000000000), '-4B'); expect(formatNumber(823147521343), '823.1B'); expect(formatNumber(8231475213435), '8231.5B'); + expect(formatNumber(-8231475213435), '-8231.5B'); }); }