From c145fb7050bf4014969cf9030ff4a717c7eea354 Mon Sep 17 00:00:00 2001 From: imaNNeoFighT Date: Sat, 7 Oct 2023 02:45:53 +0200 Subject: [PATCH] Test commit --- example/lib/main.dart | 118 ++++++++++++++++-- lib/src/chart/bar_chart/bar_chart_data.dart | 10 +- .../chart/bar_chart/bar_chart_renderer.dart | 6 +- .../base/axis_chart/axis_chart_painter.dart | 20 +++ lib/src/chart/line_chart/line_chart_data.dart | 10 +- .../chart/line_chart/line_chart_renderer.dart | 6 +- .../chart/pie_chart/pie_chart_renderer.dart | 3 + .../radar_chart/radar_chart_renderer.dart | 3 + .../scatter_chart/scatter_chart_data.dart | 11 +- .../scatter_chart/scatter_chart_renderer.dart | 6 +- 10 files changed, 175 insertions(+), 18 deletions(-) diff --git a/example/lib/main.dart b/example/lib/main.dart index c217f30fd..feb8eba52 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -1,3 +1,4 @@ +import 'package:fl_chart/fl_chart.dart'; import 'package:fl_chart_app/presentation/resources/app_resources.dart'; import 'package:flutter/material.dart'; import 'package:google_fonts/google_fonts.dart'; @@ -13,19 +14,114 @@ class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { - return MaterialApp.router( - title: AppTexts.appName, - theme: ThemeData( - brightness: Brightness.dark, - useMaterial3: true, - textTheme: GoogleFonts.assistantTextTheme( - Theme.of(context).textTheme.apply( - bodyColor: AppColors.mainTextColor3, - ), + return const MaterialApp( + home: HomePage(), + ); + } +} + +class HomePage extends StatefulWidget { + const HomePage({super.key}); + + @override + State createState() => _HomePageState(); +} + +class _HomePageState extends State { + + List lines = [ + LineChartBarData( + spots: const [ + FlSpot(0, 0), + FlSpot(1, 10), + FlSpot(2, 4), + FlSpot(3, 9), + ], + isCurved: true, + ), + LineChartBarData( + spots: const [ + FlSpot(0, 5), + FlSpot(1, 3), + FlSpot(2, 9), + FlSpot(3, 4), + ], + isCurved: true, + ), + ]; + + @override + Widget build(BuildContext context) { + return Scaffold( + body: Center( + child: AspectRatio( + aspectRatio: 2, + child: LineChart( + LineChartData( + minX: 0, + maxX: 3, + minY: 0, + maxY: 10, + lineBarsData: lines, + gridData: const FlGridData(show: false), + lineTouchData: LineTouchData( + handleBuiltInTouches: false, + touchCallback: _handleTouch, + ) + ), + ), ), - scaffoldBackgroundColor: AppColors.pageBackground, ), - routerConfig: appRouterConfig, ); } + + TouchLineBarSpot? _draggingSpot; + + void _handleTouch(FlTouchEvent event, LineTouchResponse? response) { + print('_handleTouch 1'); + if (response == null) { + _draggingSpot = null; + print('_handleTouch 1 - null'); + return; + } + + print('_handleTouch 2'); + if ((event is FlPanDownEvent || + event is FlPanStartEvent || + event is FlLongPressStart || + event is FlTapDownEvent) && + response.lineBarSpots != null && + response.lineBarSpots!.isNotEmpty && + _draggingSpot == null) { + setState(() { + _draggingSpot = response.lineBarSpots!.first; + }); + print('_handleTouch 2 - $_draggingSpot'); + } + + print('_handleTouch 3'); + if (event is FlPanUpdateEvent || event is FlLongPressMoveUpdate) { + setState(() { + final line = lines[_draggingSpot!.barIndex]; + final newSpots = List.of(line.spots); + newSpots[_draggingSpot!.spotIndex] = FlSpot( + response.touchedChartPosition.dx, + response.touchedChartPosition.dy, + ); + lines[_draggingSpot!.barIndex] = + lines[_draggingSpot!.barIndex].copyWith( + spots: newSpots, + ); + }); + } + + print('_handleTouch 4'); + if (event is FlPanEndEvent || + event is FlPanCancelEvent || + event is FlLongPressEnd || + event is FlTapUpEvent) { + print('_handleTouch 4 - null'); + _draggingSpot = null; + } + } } diff --git a/lib/src/chart/bar_chart/bar_chart_data.dart b/lib/src/chart/bar_chart/bar_chart_data.dart index 6292faf92..2a0dd2763 100644 --- a/lib/src/chart/bar_chart/bar_chart_data.dart +++ b/lib/src/chart/bar_chart/bar_chart_data.dart @@ -852,18 +852,26 @@ class BarTooltipItem with EquatableMixin { class BarTouchResponse extends BaseTouchResponse { /// If touch happens, [BarChart] processes it internally and passes out a BarTouchedSpot /// that contains a [spot], it gives you information about the touched spot. - BarTouchResponse(this.spot) : super(); + BarTouchResponse( + this.spot, + this.touchedChartPosition, + ) : super(); /// Gives information about the touched spot final BarTouchedSpot? spot; + /// Touched position in the chart's axis scale + final Offset touchedChartPosition; + /// Copies current [BarTouchResponse] to a new [BarTouchResponse], /// and replaces provided values. BarTouchResponse copyWith({ BarTouchedSpot? spot, + Offset? touchedChartPosition, }) { return BarTouchResponse( spot ?? this.spot, + touchedChartPosition ?? this.touchedChartPosition, ); } } diff --git a/lib/src/chart/bar_chart/bar_chart_renderer.dart b/lib/src/chart/bar_chart/bar_chart_renderer.dart index 41bdb957c..9ea03ca3c 100644 --- a/lib/src/chart/bar_chart/bar_chart_renderer.dart +++ b/lib/src/chart/bar_chart/bar_chart_renderer.dart @@ -104,6 +104,10 @@ class RenderBarChart extends RenderBaseChart { mockTestSize ?? size, paintHolder, ); - return BarTouchResponse(touchedSpot); + final touchedPosition = Offset( + painter.getXByPixel(localPosition.dx, size, paintHolder), + painter.getYByPixel(localPosition.dy, size, paintHolder), + ); + return BarTouchResponse(touchedSpot, touchedPosition); } } diff --git a/lib/src/chart/base/axis_chart/axis_chart_painter.dart b/lib/src/chart/base/axis_chart/axis_chart_painter.dart index 610e0dac5..a98e051b0 100644 --- a/lib/src/chart/base/axis_chart/axis_chart_painter.dart +++ b/lib/src/chart/base/axis_chart/axis_chart_painter.dart @@ -399,6 +399,16 @@ abstract class AxisChartPainter return ((spotX - data.minX) / deltaX) * viewSize.width; } + /// Returns a value in chart's x-coordinate based on the provided [pixelX] + double getXByPixel(double pixelX, Size viewSize, PaintHolder holder) { + final data = holder.data; + final deltaX = data.maxX - data.minX; + if (deltaX == 0.0) { + return 0; + } + return (pixelX / viewSize.width) * deltaX + data.minX; + } + /// With this function we can convert our [FlSpot] y /// to the view base axis y. double getPixelY(double spotY, Size viewSize, PaintHolder holder) { @@ -410,6 +420,16 @@ abstract class AxisChartPainter return viewSize.height - (((spotY - data.minY) / deltaY) * viewSize.height); } + /// Returns a value in chart's y-coordinate based on the provided [pixelY] + double getYByPixel(double pixelY, Size viewSize, PaintHolder holder) { + final data = holder.data; + final deltaY = data.maxY - data.minY; + if (deltaY == 0.0) { + return 0; + } + return data.maxY - (pixelY / viewSize.height) * deltaY; + } + /// With this function we can get horizontal /// position for the tooltip. double getTooltipLeft( diff --git a/lib/src/chart/line_chart/line_chart_data.dart b/lib/src/chart/line_chart/line_chart_data.dart index 6c2b7d18f..46dfd64f7 100644 --- a/lib/src/chart/line_chart/line_chart_data.dart +++ b/lib/src/chart/line_chart/line_chart_data.dart @@ -1470,19 +1470,27 @@ class LineTouchResponse extends BaseTouchResponse { /// If touch happens, [LineChart] processes it internally and /// passes out a list of [lineBarSpots] it gives you information about the touched spot. /// They are sorted based on their distance to the touch event - const LineTouchResponse(this.lineBarSpots); + const LineTouchResponse( + this.lineBarSpots, + this.touchedChartPosition, + ); /// touch happened on these spots /// (if a single line provided on the chart, [lineBarSpots]'s length will be 1 always) final List? lineBarSpots; + /// Touched position in the chart's axis scale + final Offset touchedChartPosition; + /// Copies current [LineTouchResponse] to a new [LineTouchResponse], /// and replaces provided values. LineTouchResponse copyWith({ List? lineBarSpots, + Offset? touchedChartPosition, }) { return LineTouchResponse( lineBarSpots ?? this.lineBarSpots, + touchedChartPosition ?? this.touchedChartPosition, ); } } diff --git a/lib/src/chart/line_chart/line_chart_renderer.dart b/lib/src/chart/line_chart/line_chart_renderer.dart index dfae057dd..2031f0b00 100644 --- a/lib/src/chart/line_chart/line_chart_renderer.dart +++ b/lib/src/chart/line_chart/line_chart_renderer.dart @@ -109,6 +109,10 @@ class RenderLineChart extends RenderBaseChart { mockTestSize ?? size, paintHolder, ); - return LineTouchResponse(touchedSpots); + final touchedPosition = Offset( + painter.getXByPixel(localPosition.dx, size, paintHolder), + painter.getYByPixel(localPosition.dy, size, paintHolder), + ); + return LineTouchResponse(touchedSpots, touchedPosition); } } diff --git a/lib/src/chart/pie_chart/pie_chart_renderer.dart b/lib/src/chart/pie_chart/pie_chart_renderer.dart index 52ba7f8a4..2e574a12b 100644 --- a/lib/src/chart/pie_chart/pie_chart_renderer.dart +++ b/lib/src/chart/pie_chart/pie_chart_renderer.dart @@ -168,4 +168,7 @@ class RenderPieChart extends RenderBaseChart /// /// I don't know how to solve this error. That's why we disabled semantics for now. } + + @override + Offset? getChartPositionByPixel(Offset pixelPosition) => null; } diff --git a/lib/src/chart/radar_chart/radar_chart_renderer.dart b/lib/src/chart/radar_chart/radar_chart_renderer.dart index c89d7f30a..f085b0938 100644 --- a/lib/src/chart/radar_chart/radar_chart_renderer.dart +++ b/lib/src/chart/radar_chart/radar_chart_renderer.dart @@ -110,4 +110,7 @@ class RenderRadarChart extends RenderBaseChart { ); return RadarTouchResponse(touchedSpot); } + + @override + Offset? getChartPositionByPixel(Offset pixelPosition) => null; } diff --git a/lib/src/chart/scatter_chart/scatter_chart_data.dart b/lib/src/chart/scatter_chart/scatter_chart_data.dart index 10ef2ded7..42eeb4d97 100644 --- a/lib/src/chart/scatter_chart/scatter_chart_data.dart +++ b/lib/src/chart/scatter_chart/scatter_chart_data.dart @@ -339,15 +339,22 @@ class ScatterTouchResponse extends BaseTouchResponse { /// /// [touchedSpot] tells you /// in which spot (of [ScatterChartData.scatterSpots]) touch happened. - ScatterTouchResponse(this.touchedSpot) : super(); + ScatterTouchResponse(this.touchedSpot, this.touchedChartPosition) : super(); final ScatterTouchedSpot? touchedSpot; + /// Touched position in the chart's axis scale + final Offset touchedChartPosition; + /// Copies current [ScatterTouchResponse] to a new [ScatterTouchResponse], /// and replaces provided values. ScatterTouchResponse copyWith({ ScatterTouchedSpot? touchedSpot, + Offset? touchedChartPosition, }) { - return ScatterTouchResponse(touchedSpot ?? this.touchedSpot); + return ScatterTouchResponse( + touchedSpot ?? this.touchedSpot, + touchedChartPosition ?? this.touchedChartPosition, + ); } } diff --git a/lib/src/chart/scatter_chart/scatter_chart_renderer.dart b/lib/src/chart/scatter_chart/scatter_chart_renderer.dart index 6ff2d760c..78f2c291c 100644 --- a/lib/src/chart/scatter_chart/scatter_chart_renderer.dart +++ b/lib/src/chart/scatter_chart/scatter_chart_renderer.dart @@ -112,6 +112,10 @@ class RenderScatterChart extends RenderBaseChart { mockTestSize ?? size, paintHolder, ); - return ScatterTouchResponse(touchedSpot); + final touchedPosition = Offset( + painter.getXByPixel(localPosition.dx, size, paintHolder), + painter.getYByPixel(localPosition.dy, size, paintHolder), + ); + return ScatterTouchResponse(touchedSpot, touchedPosition); } }