From a17684e84b367e781622e28a886a389d8a1fc9e9 Mon Sep 17 00:00:00 2001 From: Kristifor Milchev Date: Mon, 6 Feb 2023 17:49:49 +0200 Subject: [PATCH 1/3] Adding on hover events --- lib/chart.dart | 1 + lib/chart/model/theme/chart_behaviour.dart | 19 ++++++++++++++++++- .../render/geometry/child_item_renderer.dart | 10 ++++++++++ .../render/geometry/leaf_item_renderer.dart | 10 ++++++++++ 4 files changed, 39 insertions(+), 1 deletion(-) diff --git a/lib/chart.dart b/lib/chart.dart index dfdb4e0..4832c31 100644 --- a/lib/chart.dart +++ b/lib/chart.dart @@ -9,6 +9,7 @@ import 'package:equatable/equatable.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; +import 'package:flutter/services.dart'; /// State part 'chart/model/chart_state.dart'; diff --git a/lib/chart/model/theme/chart_behaviour.dart b/lib/chart/model/theme/chart_behaviour.dart index 22b480e..44cdcaf 100644 --- a/lib/chart/model/theme/chart_behaviour.dart +++ b/lib/chart/model/theme/chart_behaviour.dart @@ -13,9 +13,16 @@ class ChartBehaviour { const ChartBehaviour({ bool isScrollable = false, this.onItemClicked, + this.onItemHoverEnter, + this.onItemHoverExit, }) : _isScrollable = isScrollable ? 1.0 : 0.0; - ChartBehaviour._lerp(this._isScrollable, this.onItemClicked); + ChartBehaviour._lerp( + this._isScrollable, + this.onItemClicked, + this.onItemHoverEnter, + this.onItemHoverExit, + ); final double _isScrollable; @@ -26,6 +33,14 @@ class ChartBehaviour { /// Return true if chart is currently scrollable bool get isScrollable => _isScrollable > 0.5; + /// Return index of item clicked. Since graph can be multi value, user + /// will have to handle clicked index to show data they want to show + final ValueChanged? onItemHoverEnter; + + /// Return index of item clicked. Since graph can be multi value, user + /// will have to handle clicked index to show data they want to show + final ValueChanged? onItemHoverExit; + /// Animate Behaviour from one state to other static ChartBehaviour lerp(ChartBehaviour a, ChartBehaviour b, double t) { // This values should never return null, this is for null-safety @@ -36,6 +51,8 @@ class ChartBehaviour { return ChartBehaviour._lerp( _scrollableLerp, t > 0.5 ? b.onItemClicked : a.onItemClicked, + t > 0.5 ? b.onItemHoverEnter : a.onItemHoverEnter, + t > 0.5 ? b.onItemHoverExit : a.onItemHoverExit, ); } } diff --git a/lib/chart/render/geometry/child_item_renderer.dart b/lib/chart/render/geometry/child_item_renderer.dart index 8a80eb7..9bf7b9e 100644 --- a/lib/chart/render/geometry/child_item_renderer.dart +++ b/lib/chart/render/geometry/child_item_renderer.dart @@ -144,6 +144,16 @@ class _RenderChildChartItem extends RenderShiftedBox { _state.behaviour.onItemClicked ?.call(ItemBuilderData(item, itemIndex, listIndex)); } + + if (event is PointerHoverEvent) { + _state.behaviour.onItemHoverEnter + ?.call(ItemBuilderData(item, itemIndex, listIndex)); + } + + if (event is PointerHoverEvent) { + _state.behaviour.onItemHoverExit + ?.call(ItemBuilderData(item, itemIndex, listIndex)); + } } @override diff --git a/lib/chart/render/geometry/leaf_item_renderer.dart b/lib/chart/render/geometry/leaf_item_renderer.dart index 5b70ce4..6e3280a 100644 --- a/lib/chart/render/geometry/leaf_item_renderer.dart +++ b/lib/chart/render/geometry/leaf_item_renderer.dart @@ -164,6 +164,16 @@ class _RenderLeafChartItem extends RenderBox { _state.behaviour.onItemClicked ?.call(ItemBuilderData(item, itemIndex, listIndex)); } + + if (event is PointerHoverEvent) { + _state.behaviour.onItemHoverEnter + ?.call(ItemBuilderData(item, itemIndex, listIndex)); + } + + if (event is PointerHoverEvent) { + _state.behaviour.onItemHoverExit + ?.call(ItemBuilderData(item, itemIndex, listIndex)); + } } @override From aefc56b9b00021fafccd2e83f0ed0e701f5f74be Mon Sep 17 00:00:00 2001 From: Kristifor Milchev Date: Mon, 6 Feb 2023 17:52:09 +0200 Subject: [PATCH 2/3] Removing auto imported path --- lib/chart.dart | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/chart.dart b/lib/chart.dart index 4832c31..dfdb4e0 100644 --- a/lib/chart.dart +++ b/lib/chart.dart @@ -9,7 +9,6 @@ import 'package:equatable/equatable.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; -import 'package:flutter/services.dart'; /// State part 'chart/model/chart_state.dart'; From 7084d6974dc9cd42d03566eb4c8afcd5e70546a9 Mon Sep 17 00:00:00 2001 From: itsJoKr Date: Wed, 15 Feb 2023 17:49:29 +0100 Subject: [PATCH 3/3] Fix import --- .../lib/charts/scrollable_chart_screen.dart | 83 +++++++------------ lib/chart.dart | 1 + 2 files changed, 30 insertions(+), 54 deletions(-) diff --git a/example/lib/charts/scrollable_chart_screen.dart b/example/lib/charts/scrollable_chart_screen.dart index 2913567..278b58b 100644 --- a/example/lib/charts/scrollable_chart_screen.dart +++ b/example/lib/charts/scrollable_chart_screen.dart @@ -35,9 +35,7 @@ class _ScrollableChartScreenState extends State { final Random _rand = Random(); final double _difference = _rand.nextDouble() * 15; - targetMax = 3 + - ((_rand.nextDouble() * _difference * 0.75) - (_difference * 0.25)) - .roundToDouble(); + targetMax = 3 + ((_rand.nextDouble() * _difference * 0.75) - (_difference * 0.25)).roundToDouble(); _values.addAll(List.generate(minItems, (index) { return 2 + _rand.nextDouble() * _difference; })); @@ -58,10 +56,7 @@ class _ScrollableChartScreenState extends State { final targetArea = TargetAreaDecoration( targetMax: targetMax + 2, targetMin: targetMax, - colorOverTarget: Theme.of(context) - .colorScheme - .error - .withOpacity(_showBars ? 1.0 : 0.0), + colorOverTarget: Theme.of(context).colorScheme.error.withOpacity(_showBars ? 1.0 : 0.0), targetAreaFillColor: Theme.of(context).colorScheme.error.withOpacity(0.2), targetLineColor: Theme.of(context).colorScheme.error, targetAreaRadius: BorderRadius.circular(12.0), @@ -78,11 +73,7 @@ class _ScrollableChartScreenState extends State { barItemBuilder: (data) { return BarItem( color: targetArea.getTargetItemColor( - Theme.of(context) - .colorScheme - .primary - .withOpacity(_showBars ? 1.0 : 0.0), - data.item), + Theme.of(context).colorScheme.primary.withOpacity(_showBars ? 1.0 : 0.0), data.item), radius: const BorderRadius.vertical( top: Radius.circular(24.0), ), @@ -90,28 +81,32 @@ class _ScrollableChartScreenState extends State { }, ), behaviour: ChartBehaviour( - scrollSettings: - _isScrollable ? ScrollSettings() : ScrollSettings.none(), + scrollSettings: _isScrollable ? ScrollSettings() : ScrollSettings.none(), onItemClicked: (item) { + print('Clciked'); setState(() { _selected = item.itemIndex; }); }, + onItemHoverEnter: (_) { + print('Hover Enter'); + }, + onItemHoverExit: (_) { + print('Hover Enter'); + }, ), backgroundDecorations: [ HorizontalAxisDecoration( endWithChart: false, lineWidth: 2.0, axisStep: 2, - lineColor: - Theme.of(context).colorScheme.primaryContainer.withOpacity(0.2), + lineColor: Theme.of(context).colorScheme.primaryContainer.withOpacity(0.2), ), VerticalAxisDecoration( endWithChart: false, lineWidth: 2.0, axisStep: 7, - lineColor: - Theme.of(context).colorScheme.primaryContainer.withOpacity(0.8), + lineColor: Theme.of(context).colorScheme.primaryContainer.withOpacity(0.8), ), GridDecoration( showVerticalGrid: true, @@ -121,15 +116,12 @@ class _ScrollableChartScreenState extends State { verticalAxisStep: 1, horizontalAxisStep: 1, textStyle: Theme.of(context).textTheme.caption, - gridColor: - Theme.of(context).colorScheme.primaryContainer.withOpacity(0.2), + gridColor: Theme.of(context).colorScheme.primaryContainer.withOpacity(0.2), ), targetArea, SparkLineDecoration( fill: true, - lineColor: Theme.of(context) - .primaryColor - .withOpacity(!_showBars ? 0.2 : 0.0), + lineColor: Theme.of(context).primaryColor.withOpacity(!_showBars ? 0.2 : 0.0), smoothPoints: _smoothPoints, ), ], @@ -137,16 +129,12 @@ class _ScrollableChartScreenState extends State { ValueDecoration( alignment: _showBars ? Alignment.bottomCenter : Alignment(0.0, -1.0), textStyle: Theme.of(context).textTheme.button!.copyWith( - color: (_showBars - ? Theme.of(context).colorScheme.onPrimary - : Theme.of(context).colorScheme.primary) + color: (_showBars ? Theme.of(context).colorScheme.onPrimary : Theme.of(context).colorScheme.primary) .withOpacity(_isScrollable ? 1.0 : 0.0)), ), SparkLineDecoration( lineWidth: 2.0, - lineColor: Theme.of(context) - .primaryColor - .withOpacity(!_showBars ? 1.0 : 0.0), + lineColor: Theme.of(context).primaryColor.withOpacity(!_showBars ? 1.0 : 0.0), smoothPoints: _smoothPoints, ), BorderDecoration( @@ -167,13 +155,10 @@ class _ScrollableChartScreenState extends State { border: Border.all(), shape: BoxShape.circle, ), - child: Text( - '${_selected != null ? _values[_selected!].toStringAsPrecision(2) : '...'}'), + child: Text('${_selected != null ? _values[_selected!].toStringAsPrecision(2) : '...'}'), ), ), - backgroundColor: Theme.of(context) - .scaffoldBackgroundColor - .withOpacity(_isScrollable ? 0.5 : 0.8), + backgroundColor: Theme.of(context).scaffoldBackgroundColor.withOpacity(_isScrollable ? 0.5 : 0.8), ), ], ); @@ -192,9 +177,7 @@ class _ScrollableChartScreenState extends State { children: [ Expanded( child: SingleChildScrollView( - physics: _isScrollable - ? ScrollPhysics() - : NeverScrollableScrollPhysics(), + physics: _isScrollable ? ScrollPhysics() : NeverScrollableScrollPhysics(), controller: _controller, scrollDirection: Axis.horizontal, child: AnimatedChart( @@ -208,17 +191,13 @@ class _ScrollableChartScreenState extends State { AnimatedContainer( duration: Duration(milliseconds: 350), decoration: BoxDecoration( - gradient: LinearGradient( - begin: Alignment.centerRight, - end: Alignment.centerLeft, - colors: [ - Colors.white, - Colors.white.withOpacity(0.0), - ], - stops: [ - 0.5, - 1.0 - ]), + gradient: LinearGradient(begin: Alignment.centerRight, end: Alignment.centerLeft, colors: [ + Colors.white, + Colors.white.withOpacity(0.0), + ], stops: [ + 0.5, + 1.0 + ]), ), width: _fixedAxis ? 34.0 : 0.0, height: MediaQuery.of(context).size.height * 0.4, @@ -232,14 +211,10 @@ class _ScrollableChartScreenState extends State { showValues: true, endWithChart: false, axisValue: (value) => '$value E', - legendFontStyle: - Theme.of(context).textTheme.caption, + legendFontStyle: Theme.of(context).textTheme.caption, valuesAlign: TextAlign.center, valuesPadding: const EdgeInsets.only(right: 8.0), - lineColor: Theme.of(context) - .colorScheme - .primaryContainer - .withOpacity(0.8), + lineColor: Theme.of(context).colorScheme.primaryContainer.withOpacity(0.8), ) ] : [], diff --git a/lib/chart.dart b/lib/chart.dart index 9dc873d..307245a 100644 --- a/lib/chart.dart +++ b/lib/chart.dart @@ -7,6 +7,7 @@ import 'dart:ui'; import 'package:collection/collection.dart'; import 'package:equatable/equatable.dart'; import 'package:flutter/foundation.dart'; +import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart';