Skip to content

Commit

Permalink
both scaleable and draggable chart implemented
Browse files Browse the repository at this point in the history
  • Loading branch information
adamsocrat committed Aug 14, 2024
1 parent 71aa763 commit 89faa36
Show file tree
Hide file tree
Showing 2 changed files with 106 additions and 32 deletions.
78 changes: 66 additions & 12 deletions lib/src/chart/base/base_chart/fl_touch_event.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@ abstract class FlTouchEvent {
/// That's why this field is nullable
Offset? get localPosition => null;

/// Represents the count of pointers that is in contact with the screen
///
/// Default is 0, nothing is in contact with the screen
int get pointerCount => 0;

/// excludes exit or up events to show interactions on charts
bool get isInterestedForInteractions {
final isLinux = defaultTargetPlatform == TargetPlatform.linux;
Expand All @@ -38,22 +43,62 @@ abstract class FlTouchEvent {
}
}

/// When a pointers has contacted the screen and might begin to move
class FlScaleStartEvent extends FlTouchEvent {
const FlScaleStartEvent(this.details);

/// Contains information of happened touch gesture
final ScaleStartDetails details;

/// Represents the position of happened touch/pointer events and count of pointers
@override
Offset get localPosition => details.focalPoint;
int get pointerCount => details.pointerCount;
}

/// When a pointers that is in contact with the screen and has moved again.
class FlScaleUpdateEvent extends FlTouchEvent {
const FlScaleUpdateEvent(this.details);

/// Contains information of happened touch gesture
final ScaleUpdateDetails details;

/// Represents the position of happened touch/pointer events and count of pointers
@override
Offset get localPosition => details.focalPoint;
int get pointerCount => details.pointerCount;
}

/// When a pointers has stopped contacting the screen and the scale gesture has ended.
class FlScaleEndEvent extends FlTouchEvent {
const FlScaleEndEvent(this.details);

final ScaleEndDetails details;

@override
Offset get localPosition => Offset.zero;
int get pointerCount => 0;
}

/// When a pointer has contacted the screen and might begin to move
/// Uses [ScaleStartDetails] to provide the position of the touch.
///
/// The [details] object provides the position of the touch.
/// Inspired from [GestureDragDownCallback]
class FlPanDownEvent extends FlTouchEvent {
const FlPanDownEvent(this.details);

/// Contains information of happened touch gesture
final DragDownDetails details;
final ScaleStartDetails details;

/// Represents the position of happened touch/pointer event
/// Represents the position of happened touch/pointer events and count of pointers
@override
Offset get localPosition => details.localPosition;
Offset get localPosition => details.focalPoint;
int get pointerCount => details.pointerCount;
}

/// When a pointer has contacted the screen and has begun to move.
/// Uses [ScaleStartDetails] to provide the position of the touch.
///
/// The [details] object provides the position of the touch when it first
/// touched the surface.
Expand All @@ -63,15 +108,16 @@ class FlPanStartEvent extends FlTouchEvent {
const FlPanStartEvent(this.details);

/// Contains information of happened touch gesture
final DragStartDetails details;
final ScaleStartDetails details;

/// Represents the position of happened touch/pointer event
/// Represents the position of happened touch/pointer event and count of pointers
@override
Offset get localPosition => details.localPosition;
Offset get localPosition => details.localFocalPoint;
int get pointerCount => details.pointerCount;
}

/// When a pointer that is in contact with the screen and moving
/// has moved again.
/// When a pointer that is in contact with the screen and has moved again.
/// Uses [ScaleStartDetails] to provide the position of the touch.
///
/// The [details] object provides the position of the touch and the distance it
/// has traveled since the last update.
Expand All @@ -80,11 +126,12 @@ class FlPanUpdateEvent extends FlTouchEvent {
const FlPanUpdateEvent(this.details);

/// Contains information of happened touch gesture
final DragUpdateDetails details;
final ScaleUpdateDetails details;

/// Represents the position of happened touch/pointer event
/// Represents the position of happened touch/pointer event and count of pointers
@override
Offset get localPosition => details.localPosition;
Offset get localPosition => details.localFocalPoint;
int get pointerCount => details.pointerCount;
}

/// When the pointer that previously triggered a [FlPanStartEvent] did not complete.
Expand All @@ -103,7 +150,7 @@ class FlPanEndEvent extends FlTouchEvent {
const FlPanEndEvent(this.details);

/// Contains information of happened touch gesture
final DragEndDetails details;
final ScaleEndDetails details;
}

/// When a pointer that might cause a tap has contacted the
Expand All @@ -121,6 +168,7 @@ class FlTapDownEvent extends FlTouchEvent {
/// Represents the position of happened touch/pointer event
@override
Offset get localPosition => details.localPosition;
int get pointerCount => 1;
}

/// When the pointer that previously triggered a [FlTapDownEvent] will not end up causing a tap.
Expand Down Expand Up @@ -161,6 +209,7 @@ class FlLongPressStart extends FlTouchEvent {
/// Represents the position of happened touch/pointer event
@override
Offset get localPosition => details.localPosition;
int get pointerCount => 1;
}

/// When a pointer is moving after being held in contact at the same
Expand All @@ -179,6 +228,7 @@ class FlLongPressMoveUpdate extends FlTouchEvent {
/// Represents the position of happened touch/pointer event
@override
Offset get localPosition => details.localPosition;
int get pointerCount => 1;
}

/// When a pointer stops contacting the screen after a long press
Expand All @@ -197,6 +247,7 @@ class FlLongPressEnd extends FlTouchEvent {
/// Represents the position of happened touch/pointer event
@override
Offset get localPosition => details.localPosition;
int get pointerCount => 1;
}

/// The pointer has moved with respect to the device while the pointer is or is
Expand All @@ -214,6 +265,7 @@ class FlPointerEnterEvent extends FlTouchEvent {
/// Represents the position of happened touch/pointer event
@override
Offset get localPosition => event.localPosition;
int get pointerCount => 1;
}

/// The pointer has moved with respect to the device while the pointer is not
Expand All @@ -231,6 +283,7 @@ class FlPointerHoverEvent extends FlTouchEvent {
/// Represents the position of happened touch/pointer event
@override
Offset get localPosition => event.localPosition;
int get pointerCount => 1;
}

/// The pointer has moved with respect to the device while the pointer is or is
Expand All @@ -246,4 +299,5 @@ class FlPointerExitEvent extends FlTouchEvent {
/// Represents the position of happened touch/pointer event
@override
Offset get localPosition => event.localPosition;
int get pointerCount => 1;
}
60 changes: 40 additions & 20 deletions lib/src/chart/base/base_chart/render_base_chart.dart
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,10 @@ abstract class RenderBaseChart<R extends BaseTouchResponse> extends RenderBox

late bool _validForMouseTracker;

/// Recognizes pan gestures, such as onDown, onStart, onUpdate, onCancel, ...
late PanGestureRecognizer _panGestureRecognizer;
// Instead of drag we use scale which also includes pan gestures
// Recognizes pan gestures, such as onDown, onStart, onUpdate, onCancel, ...
// and detects scale gestures scroll, pinch in out, such as onStart, onUpdate, onEnd, ...
late ScaleGestureRecognizer _scaleGestureRecognizer;

/// Recognizes tap gestures, such as onTapDown, onTapCancel and onTapUp
late TapGestureRecognizer _tapGestureRecognizer;
Expand All @@ -50,22 +52,20 @@ abstract class RenderBaseChart<R extends BaseTouchResponse> extends RenderBox

/// Initializes our recognizers and implement their callbacks.
void initGestureRecognizers() {
_panGestureRecognizer = PanGestureRecognizer();
_panGestureRecognizer
..onDown = (dragDownDetails) {
_notifyTouchEvent(FlPanDownEvent(dragDownDetails));
_scaleGestureRecognizer = ScaleGestureRecognizer();
_scaleGestureRecognizer
..onStart = (details) {
_notifyScaleEvent(FlScaleStartEvent(details));
_notifyTouchEvent(FlPanDownEvent(details));
_notifyTouchEvent(FlPanStartEvent(details));
}
..onStart = (dragStartDetails) {
_notifyTouchEvent(FlPanStartEvent(dragStartDetails));
..onUpdate = (details) {
_notifyScaleEvent(FlScaleUpdateEvent(details));
_notifyTouchEvent(FlPanUpdateEvent(details));
}
..onUpdate = (dragUpdateDetails) {
_notifyTouchEvent(FlPanUpdateEvent(dragUpdateDetails));
}
..onCancel = () {
_notifyTouchEvent(const FlPanCancelEvent());
}
..onEnd = (dragEndDetails) {
_notifyTouchEvent(FlPanEndEvent(dragEndDetails));
..onEnd = (details) {
_notifyScaleEvent(FlScaleEndEvent(details));
_notifyTouchEvent(FlPanEndEvent(details));
};

_tapGestureRecognizer = TapGestureRecognizer();
Expand Down Expand Up @@ -124,7 +124,7 @@ abstract class RenderBaseChart<R extends BaseTouchResponse> extends RenderBox
if (event is PointerDownEvent) {
_longPressGestureRecognizer.addPointer(event);
_tapGestureRecognizer.addPointer(event);
_panGestureRecognizer.addPointer(event);
_scaleGestureRecognizer.addPointer(event);
} else if (event is PointerHoverEvent) {
_notifyTouchEvent(FlPointerHoverEvent(event));
}
Expand All @@ -140,7 +140,7 @@ abstract class RenderBaseChart<R extends BaseTouchResponse> extends RenderBox
PointerExitEventListener? get onExit =>
(event) => _notifyTouchEvent(FlPointerExitEvent(event));

/// Invokes the [_touchCallback] to notify listeners of this [FlTouchEvent]
/// Invokes the [_touchCallback] to notify listeners of this [FlTouchEvent] if the pointer is one or zero(exit events).
///
/// We get a [BaseTouchResponse] using [getResponseAtLocation] for events which contains a localPosition.
/// Then we invoke [_touchCallback] using the [event] and [response].
Expand All @@ -149,11 +149,14 @@ abstract class RenderBaseChart<R extends BaseTouchResponse> extends RenderBox
return;
}
final localPosition = event.localPosition;
final pointerCount = event.pointerCount;

R? response;
if (localPosition != null) {
if (localPosition != null && pointerCount == 1) {
response = getResponseAtLocation(localPosition);
}
_touchCallback!(event, response);

if (pointerCount <= 1) _touchCallback!(event, response);

if (_mouseCursorResolver == null) {
_latestMouseCursor = MouseCursor.defer;
Expand All @@ -162,6 +165,23 @@ abstract class RenderBaseChart<R extends BaseTouchResponse> extends RenderBox
}
}

/// Invokes the [_touchCallback] to notify listeners of this [FlTouchEvent]
///
/// We don't get a response for events which contains a localPosition because they are scale events.
/// Then we invoke [_touchCallback] using the [event] and null [response].
void _notifyScaleEvent(FlTouchEvent event) {
if (_touchCallback == null) {
return;
}
final localPosition = event.localPosition;
final pointerCount = event.pointerCount;

R? response;
if (pointerCount > 1) {
_touchCallback!(event, response);
}
}

/// Represents the mouse cursor style when hovers on our chart
/// In the future we can change it runtime, for example we can turn it to
/// [SystemMouseCursors.click] when mouse hovers a specific point of our chart.
Expand Down

0 comments on commit 89faa36

Please sign in to comment.