diff --git a/CHANGELOG.md b/CHANGELOG.md index 5c0743203..28b154403 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,6 @@ ## newVersion * **IMPROVEMENT** (by @JoshMart) Remove references to deprecated `axisTitleData` property from code and docs, #1259, #1201 +* **Improvement** (by @imaNNeo) Update LineChartSample6 to implement a way to show a tooltip on a single spot, #1620 ## 0.67.0 * **FEATURE** (by @julien4215) Add direction property to the [HorizontalLineLabel](https://github.com/imaNNeo/fl_chart/blob/main/repo_files/documentations/base_chart.md#horizontallinelabel) and [VerticalLineLabel](https://github.com/imaNNeo/fl_chart/blob/main/repo_files/documentations/base_chart.md#verticallinelabel), #1574 diff --git a/example/lib/presentation/samples/line/line_chart_sample6.dart b/example/lib/presentation/samples/line/line_chart_sample6.dart index d9561af4d..149f3b4ba 100644 --- a/example/lib/presentation/samples/line/line_chart_sample6.dart +++ b/example/lib/presentation/samples/line/line_chart_sample6.dart @@ -123,7 +123,39 @@ class LineChartSample6 extends StatelessWidget { aspectRatio: 2, child: LineChart( LineChartData( - lineTouchData: const LineTouchData(enabled: false), + lineTouchData: LineTouchData( + touchTooltipData: LineTouchTooltipData( + tooltipRoundedRadius: 0, + getTooltipColor: (spot) => Colors.white, + getTooltipItems: (List touchedSpots) { + return touchedSpots.map((LineBarSpot touchedSpot) { + return LineTooltipItem( + touchedSpot.y.toString(), + TextStyle( + color: touchedSpot.bar.gradient!.colors.first, + fontWeight: FontWeight.bold, + fontSize: 20, + ), + ); + }).toList(); + }, + ), + getTouchedSpotIndicator: ( + _, + indicators, + ) { + return indicators + .map((int index) => const TouchedSpotIndicatorData( + FlLine(color: Colors.transparent), + FlDotData(show: false), + )) + .toList(); + }, + touchSpotThreshold: 12, + distanceCalculator: + (Offset touchPoint, Offset spotPixelCoordinates) => + (touchPoint - spotPixelCoordinates).distance, + ), lineBarsData: [ LineChartBarData( gradient: LinearGradient( @@ -141,12 +173,18 @@ class LineChartSample6 extends StatelessWidget { ), dotData: FlDotData( show: true, - getDotPainter: (spot, percent, barData, index) => - FlDotCirclePainter( - radius: 12, - color: Colors.transparent, - strokeColor: AppColors.mainTextColor2, - ), + getDotPainter: (spot, percent, barData, index) { + return FlDotCirclePainter( + radius: 12, + color: Color.lerp( + line1Color1, + line1Color2, + percent / 100, + )!, + strokeColor: Colors.white, + strokeWidth: 1, + ); + }, ), ), LineChartBarData( @@ -165,12 +203,18 @@ class LineChartSample6 extends StatelessWidget { ), dotData: FlDotData( show: true, - getDotPainter: (spot, percent, barData, index) => - FlDotCirclePainter( - radius: 12, - color: Colors.transparent, - strokeColor: AppColors.mainTextColor2, - ), + getDotPainter: (spot, percent, barData, index) { + return FlDotCirclePainter( + radius: 12, + color: Color.lerp( + line2Color1, + line2Color2, + percent / 100, + )!, + strokeColor: Colors.white, + strokeWidth: 1, + ); + }, ), ), ], diff --git a/example/macos/Runner.xcodeproj/project.pbxproj b/example/macos/Runner.xcodeproj/project.pbxproj index 9b6f9c6b6..d31292a04 100644 --- a/example/macos/Runner.xcodeproj/project.pbxproj +++ b/example/macos/Runner.xcodeproj/project.pbxproj @@ -203,7 +203,7 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0920; - LastUpgradeCheck = 1430; + LastUpgradeCheck = 1510; ORGANIZATIONNAME = ""; TargetAttributes = { 33CC10EC2044A3C60003C045 = { diff --git a/example/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/example/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index 6ff55107b..5c4cd8578 100644 --- a/example/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/example/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -1,6 +1,6 @@ showingTooltipIndicators; /// width of the group (sum of all [BarChartRodData]'s width and spaces) 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 8ff0b6743..78ca3007d 100644 --- a/lib/src/chart/base/axis_chart/axis_chart_data.dart +++ b/lib/src/chart/base/axis_chart/axis_chart_data.dart @@ -439,7 +439,8 @@ class FlTitlesData with EquatableMixin { } /// Represents a conceptual position in cartesian (axis based) space. -class FlSpot with EquatableMixin { +@immutable +class FlSpot { /// [x] determines cartesian (axis based) horizontally position /// 0 means most left point of the chart /// @@ -477,13 +478,6 @@ class FlSpot with EquatableMixin { /// Determines if [x] and [y] is not null. bool isNotNull() => !isNull(); - /// Used for equality check, see [EquatableMixin]. - @override - List get props => [ - x, - y, - ]; - /// Lerps a [FlSpot] based on [t] value, check [Tween.lerp]. static FlSpot lerp(FlSpot a, FlSpot b, double t) { if (a == FlSpot.nullSpot) { @@ -499,6 +493,25 @@ class FlSpot with EquatableMixin { lerpDouble(a.y, b.y, t)!, ); } + + /// Two [FlSpot] are equal if their [x] and [y] are equal. + @override + bool operator ==(Object other) { + if (identical(this, other)) return true; + if (other is! FlSpot) { + return false; + } + + if (x.isNaN && y.isNaN && other.x.isNaN && other.y.isNaN) { + return true; + } + + return other.x == x && other.y == y; + } + + /// Override hashCode + @override + int get hashCode => x.hashCode ^ y.hashCode; } /// Responsible to hold grid data, diff --git a/lib/src/chart/line_chart/line_chart_data.dart b/lib/src/chart/line_chart/line_chart_data.dart index fe3809865..28ec600d3 100644 --- a/lib/src/chart/line_chart/line_chart_data.dart +++ b/lib/src/chart/line_chart/line_chart_data.dart @@ -77,6 +77,9 @@ class LineChartData extends AxisChartData with EquatableMixin { /// You can show some tooltipIndicators (a popup with an information) /// on top of each [LineChartBarData.spots] using [showingTooltipIndicators], /// just put line indicator number and spots indices you want to show it on top of them. + /// + /// An important point is that you have to disable the default touch behaviour + /// to show the tooltip manually, see [LineTouchData.handleBuiltInTouches]. final List showingTooltipIndicators; /// Lerps a [BaseChartData] based on [t] value, check [Tween.lerp]. diff --git a/lib/src/chart/scatter_chart/scatter_chart_data.dart b/lib/src/chart/scatter_chart/scatter_chart_data.dart index 81a04feef..9d9c7c39e 100644 --- a/lib/src/chart/scatter_chart/scatter_chart_data.dart +++ b/lib/src/chart/scatter_chart/scatter_chart_data.dart @@ -76,7 +76,15 @@ class ScatterChartData extends AxisChartData with EquatableMixin { ); final List scatterSpots; final ScatterTouchData scatterTouchData; + + /// you can show some tooltipIndicators (a popup with an information) + /// on top of each [ScatterSpot] using [showingTooltipIndicators], + /// just put indices you want to show it on top of them. + /// + /// An important point is that you have to disable the default touch behaviour + /// to show the tooltip manually, see [ScatterTouchData.handleBuiltInTouches]. final List showingTooltipIndicators; + final ScatterLabelSettings scatterLabelSettings; /// Lerps a [ScatterChartData] based on [t] value, check [Tween.lerp]. diff --git a/lib/src/utils/utils.dart b/lib/src/utils/utils.dart index 21b8ffa12..dc5cdffc8 100644 --- a/lib/src/utils/utils.dart +++ b/lib/src/utils/utils.dart @@ -304,7 +304,7 @@ class Utils { /// Finds the best initial interval value /// - /// If there is a zero point in the axis, we a value that passes through it. + /// If there is a zero point in the axis, we want to have a value that passes through it. /// For example if we have -3 to +3, with interval 2. if we start from -3, we get something like this: -3, -1, +1, +3 /// But the most important point is zero in most cases. with this logic we get this: -2, 0, 2 double getBestInitialIntervalValue( diff --git a/pub_screenshots/logo_1024.png b/pub_screenshots/logo_1024.png new file mode 100644 index 000000000..2e9c3b14a Binary files /dev/null and b/pub_screenshots/logo_1024.png differ diff --git a/pubspec.yaml b/pubspec.yaml index cab8f6a0d..e7a7e1468 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -28,6 +28,8 @@ dev_dependencies: very_good_analysis: ^5.1.0 screenshots: + - description: 'FL Chart Logo' + path: pub_screenshots/logo_1024.png - description: 'LineChartSample1 and LineChartSample2' path: pub_screenshots/line_chart.jpg - description: 'LineChartSample10' diff --git a/repo_files/documentations/bar_chart.md b/repo_files/documentations/bar_chart.md index cb1491940..ec5766aeb 100644 --- a/repo_files/documentations/bar_chart.md +++ b/repo_files/documentations/bar_chart.md @@ -1,6 +1,4 @@ -# BarChart - - + ### How to use ```dart @@ -40,7 +38,7 @@ When you change the chart's state, it animates to the new state internally (usin |x| x position of the group on horizontal axis|null| |barRods| list of [BarChartRodData](#BarChartRodData) that are a bar line| [] |barsSpace| the space between barRods of the group|2| -|showingTooltipIndicators| indexes of barRods to show the tooltip on top of them | []| +|showingTooltipIndicators| indexes of barRods to show the tooltip on top of them, The point is that you need to disable touches to show these tooltips manually | []| ### BarChartAlignment diff --git a/repo_files/documentations/line_chart.md b/repo_files/documentations/line_chart.md index 52d84b888..be5ab9dbf 100644 --- a/repo_files/documentations/line_chart.md +++ b/repo_files/documentations/line_chart.md @@ -1,6 +1,4 @@ -# LineChart - - + ### How to use ```dart @@ -25,7 +23,7 @@ When you change the chart's state, it animates to the new state internally (usin |extraLinesData| [ExtraLinesData](base_chart.md#ExtraLinesData) object to hold drawing details of extra horizontal and vertical lines. Check [ExtraLinesData](base_chart.md#ExtraLinesData)|ExtraLinesData()| |lineTouchData| [LineTouchData](#linetouchdata-read-about-touch-handling) holds the touch interactivity details| LineTouchData()| |rangeAnnotations| show range annotations behind the chart, check [RangeAnnotations](base_chart.md#RangeAnnotations) | RangeAnnotations()| -|showingTooltipIndicators| show the tooltip based on provided list of [LineBarSpot](#LineBarSpot)| [] | +|showingTooltipIndicators| show the tooltip based on provided list of [LineBarSpot](#LineBarSpot), The point is that you need to disable touches to show these tooltips manually| [] | |gridData| check the [FlGridData](base_chart.md#FlGridData)|FlGridData()| |borderData| check the [FlBorderData](base_chart.md#FlBorderData)|FlBorderData()| |minX| gets minimum x of x axis, if null, value will read from the input lineBars |null| diff --git a/repo_files/documentations/scatter_chart.md b/repo_files/documentations/scatter_chart.md index a448b031c..8e895dcff 100644 --- a/repo_files/documentations/scatter_chart.md +++ b/repo_files/documentations/scatter_chart.md @@ -22,7 +22,7 @@ When you change the chart's state, it animates to the new state internally (usin |scatterSpots| list of [ScatterSpot ](#ScatterSpot ) to show the scatter spots on the chart|[]| |titlesData| check the [FlTitlesData](base_chart.md#FlTitlesData)| FlTitlesData()| |scatterTouchData| [ScatterTouchData](#scattertouchdata-read-about-touch-handling) holds the touch interactivity details| ScatterTouchData()| -|showingTooltipIndicators| indices of showing tooltip|[]| +|showingTooltipIndicators| indices of showing tooltip, The point is that you need to disable touches to show these tooltips manually|[]| diff --git a/repo_files/images/bar_chart/bar_chart_video_thumbnail.png b/repo_files/images/bar_chart/bar_chart_video_thumbnail.png new file mode 100644 index 000000000..c075253be Binary files /dev/null and b/repo_files/images/bar_chart/bar_chart_video_thumbnail.png differ diff --git a/repo_files/images/line_chart/line_chart.jpg b/repo_files/images/line_chart/line_chart.jpg deleted file mode 100644 index 2710ff12a..000000000 Binary files a/repo_files/images/line_chart/line_chart.jpg and /dev/null differ diff --git a/repo_files/images/line_chart/line_chart_video_thumbnail.png b/repo_files/images/line_chart/line_chart_video_thumbnail.png new file mode 100644 index 000000000..cc1eac654 Binary files /dev/null and b/repo_files/images/line_chart/line_chart_video_thumbnail.png differ diff --git a/test/chart/base/axis_chart/axis_chart_data_test.dart b/test/chart/base/axis_chart/axis_chart_data_test.dart index dbe5eef6b..98d028ced 100644 --- a/test/chart/base/axis_chart/axis_chart_data_test.dart +++ b/test/chart/base/axis_chart/axis_chart_data_test.dart @@ -65,6 +65,12 @@ void main() { expect(flSpot1 == flSpot2, false); expect(flSpot2 == flSpot2Clone, true); + + expect(nullSpot1 == nullSpot2, true); + + expect(nullSpot2 == nullSpot3, true); + + expect(nullSpot1 == nullSpot3, true); }); test('FlGridData equality test', () { diff --git a/test/chart/base/axis_chart/axis_chart_helper_test.dart b/test/chart/base/axis_chart/axis_chart_helper_test.dart index 8bdb4201a..8f49e844c 100644 --- a/test/chart/base/axis_chart/axis_chart_helper_test.dart +++ b/test/chart/base/axis_chart/axis_chart_helper_test.dart @@ -76,7 +76,7 @@ void main() { expect(results[4], 10); }); - test('test 4', () { + test('test 5', () { final results = []; final axisValues = AxisChartHelper().iterateThroughAxis( min: 0, @@ -95,7 +95,7 @@ void main() { expect(results[2], 9); }); - test('test 4', () { + test('test 6', () { final results = []; final axisValues = AxisChartHelper().iterateThroughAxis( min: 35, @@ -112,6 +112,24 @@ void main() { expect(results[2], 100); expect(results[3], 130); }); + + test('test 7', () { + final results = []; + final axisValues = AxisChartHelper().iterateThroughAxis( + min: 5, + max: 35, + interval: 10, + baseLine: 5, + ); + for (final axisValue in axisValues) { + results.add(axisValue); + } + expect(results.length, 4); + expect(results[0], 5); + expect(results[1], 15); + expect(results[2], 25); + expect(results[3], 35); + }); }); group('calcFitInsideOffset', () { diff --git a/test/chart/data_pool.dart b/test/chart/data_pool.dart index 9dac57ad8..ec64dd6cd 100644 --- a/test/chart/data_pool.dart +++ b/test/chart/data_pool.dart @@ -575,6 +575,10 @@ final FlSpot flSpot1Clone = flSpot1.copyWith(); const FlSpot flSpot2 = FlSpot(4, 2); final FlSpot flSpot2Clone = flSpot2.copyWith(); +const nullSpot1 = FlSpot.nullSpot; +final nullSpot2 = nullSpot1.copyWith(); +const nullSpot3 = FlSpot.nullSpot; + Widget getTitles(double value, TitleMeta meta) => const Text('sallam'); TextStyle getTextStyles(BuildContext context, double value) =>