Skip to content

Commit 0f293f6

Browse files
committed
integrate gesture options
1 parent 2a24b2e commit 0f293f6

File tree

1 file changed

+107
-76
lines changed

1 file changed

+107
-76
lines changed

maplibre/lib/src/map_state.dart

Lines changed: 107 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,10 @@ abstract class MapLibreMapState extends State<MapLibreMap>
3333
/// is set.
3434
bool isInitialized = false;
3535

36-
late final _animationController = AnimationController(vsync: this)
37-
..addListener(_onAnimation);
36+
late final _animationController = AnimationController(
37+
vsync: this,
38+
duration: const Duration(milliseconds: 300),
39+
)..addListener(_onAnimation);
3840
Animation<MapCamera>? _animation;
3941
ScaleStartDetails? _onScaleStartEvent;
4042
TapDownDetails? _doubleTapDownDetails;
@@ -98,28 +100,34 @@ abstract class MapLibreMapState extends State<MapLibreMap>
98100

99101
void _onDoubleTap() {
100102
debugPrint('Double tap detected');
103+
101104
final details = _doubleTapDownDetails;
102105
_doubleTapDownDetails = null;
103106
if (details == null) return;
104-
final camera = this.camera!;
105107

106-
// zoom in on double tap
107-
final tweens = _MapCameraTween(
108-
begin: camera,
109-
end: camera.copyWith(
110-
zoom: camera.zoom + 1,
111-
center: (_targetCamera?.center ?? camera.center).intermediatePointTo(
112-
toLngLat(details.localPosition),
113-
fraction: 0.5,
108+
if (options.gestures.zoom) {
109+
final camera = this.camera!;
110+
final newCenter = (_targetCamera?.center ?? camera.center)
111+
.intermediatePointTo(
112+
toLngLat(details.localPosition),
113+
fraction: 0.5,
114+
);
115+
116+
// zoom in on double tap
117+
final tweens = _MapCameraTween(
118+
begin: camera,
119+
end: camera.copyWith(
120+
zoom: camera.zoom + 1,
121+
center: newCenter,
114122
),
115-
),
116-
);
117-
_animation = tweens.animate(
118-
CurvedAnimation(parent: _animationController, curve: Curves.easeInOut),
119-
);
120-
_animationController
121-
..duration = const Duration(milliseconds: 300)
122-
..forward(from: 0);
123+
);
124+
_animation = tweens.animate(
125+
CurvedAnimation(parent: _animationController, curve: Curves.easeInOut),
126+
);
127+
_animationController
128+
..duration = const Duration(milliseconds: 300)
129+
..forward(from: 0);
130+
}
123131
}
124132

125133
void _onAnimation() => moveCamera(
@@ -154,23 +162,35 @@ abstract class MapLibreMapState extends State<MapLibreMap>
154162

155163
void _scrollWheelZoom(PointerScrollEvent event) {
156164
// debugPrint('Scroll wheel event: ${event.scrollDelta.dy}');
157-
final camera = this.camera!;
158-
final zoomChange = -event.scrollDelta.dy / 300; // sensitivity
159-
160-
final target = _targetCamera = camera.copyWith(
161-
zoom: (_targetCamera?.zoom ?? camera.zoom) + zoomChange,
162-
center: (_targetCamera?.center ?? camera.center).intermediatePointTo(
163-
toLngLat(event.localPosition),
164-
fraction: zoomChange > 0 ? 0.2 : -0.2,
165-
),
166-
);
167-
final tweens = _MapCameraTween(begin: camera, end: target);
168-
_animation = tweens.animate(
169-
CurvedAnimation(parent: _animationController, curve: Curves.easeOut),
170-
);
171-
_animationController.forward(from: 0);
165+
if (options.gestures.zoom) {
166+
final currCamera = camera!;
167+
final zoomChange = -event.scrollDelta.dy / 300; // sensitivity
168+
final prevTarget = _targetCamera ?? currCamera;
169+
170+
var targetZoom = prevTarget.zoom;
171+
if (options.gestures.zoom) {
172+
targetZoom = prevTarget.zoom + zoomChange;
173+
}
174+
var targetCenter = prevTarget.center;
175+
if (options.gestures.pan) {
176+
targetCenter = prevTarget.center.intermediatePointTo(
177+
toLngLat(event.localPosition),
178+
fraction: zoomChange > 0 ? 0.2 : -0.2,
179+
);
180+
}
181+
final targetCamera = _targetCamera = currCamera.copyWith(
182+
zoom: targetZoom,
183+
center: targetCenter,
184+
);
185+
final tweens = _MapCameraTween(begin: currCamera, end: targetCamera);
186+
_animation = tweens.animate(
187+
CurvedAnimation(parent: _animationController, curve: Curves.easeOut),
188+
);
189+
_animationController.forward(from: 0);
190+
}
172191
}
173192

193+
// ignore: use_setters_to_change_properties
174194
void _onScaleStart(ScaleStartDetails details) {
175195
// debugPrint('Scale start: $details');
176196
_onScaleStartEvent = details;
@@ -186,60 +206,67 @@ abstract class MapLibreMapState extends State<MapLibreMap>
186206
final lastEvent = _lastScaleUpdateDetails;
187207
_secondToLastScaleUpdateDetails = _lastScaleUpdateDetails;
188208
_lastScaleUpdateDetails = details;
209+
final ctrlPressed = HardwareKeyboard.instance.isControlPressed;
210+
final buttons = pointerDownEvent.buttons;
189211

190-
if (doubleTapDown != null) {
212+
if (doubleTapDown != null && options.gestures.zoom) {
191213
// double tap drag: zoom
192214
debugPrint('Double tap drag zoom detected $doubleTapDown');
193215
final lastY = lastEvent?.focalPoint.dy ?? startEvent.focalPoint.dy;
194216
final iOS = Theme.of(context).platform == TargetPlatform.iOS;
195217
var deltaY = details.focalPoint.dy - lastY;
196218
if (iOS) deltaY = -deltaY;
197219
final newZoom = camera.zoom + deltaY * 0.01; // sensitivity
198-
moveCamera(
199-
zoom: newZoom.clamp(options.minZoom, options.maxZoom),
200-
);
201-
return;
202-
}
203-
204-
final ctrlPressed = HardwareKeyboard.instance.isControlPressed;
205-
final buttons = pointerDownEvent.buttons;
206-
if ((buttons & kSecondaryMouseButton) != 0 || ctrlPressed) {
220+
moveCamera(zoom: newZoom.clamp(options.minZoom, options.maxZoom));
221+
} else if ((buttons & kSecondaryMouseButton) != 0 || ctrlPressed) {
207222
// secondary button: pitch and bearing
208223
final lastPointerOffset = lastEvent?.focalPoint ?? startEvent.focalPoint;
209224
final delta = details.focalPoint - lastPointerOffset;
210-
211-
moveCamera(
212-
bearing: camera.bearing + delta.dx * 0.5, // sensitivity
213-
pitch: camera.pitch - delta.dy * 0.5, // sensitivity
214-
zoom: camera.zoom, // TODO adjust for globe projection
215-
);
225+
var newBearing = camera.bearing;
226+
if (options.gestures.rotate) {
227+
newBearing = camera.bearing + delta.dx * 0.5; // sensitivity
228+
}
229+
var newPitch = camera.pitch;
230+
if (options.gestures.pitch) {
231+
newPitch = camera.pitch - delta.dy * 0.5; // sensitivity;
232+
}
233+
final newZoom = camera.zoom;
234+
if (options.gestures.zoom) {
235+
// TODO adjust for globe projection
236+
}
237+
moveCamera(bearing: newBearing, pitch: newPitch, zoom: newZoom);
216238
} else if ((buttons & kPrimaryMouseButton) != 0) {
217239
// primary button: pan, zoom, bearing
218240

219241
// zoom
242+
var newZoom = camera.zoom;
220243
final lastScale = lastEvent?.scale ?? 1.0;
221244
final scaleDelta = details.scale - lastScale;
222-
final targetZoom = switch (scaleDelta) {
223-
0.0 => camera.zoom,
224-
_ => camera.zoom + scaleDelta * 1, // sensitivity
225-
};
245+
if (scaleDelta != 0 && options.gestures.zoom) {
246+
const scaleSensitivity = 1.0;
247+
newZoom = camera.zoom + scaleDelta * scaleSensitivity;
248+
}
226249

227250
// center
228-
final lastPointerOffset = lastEvent?.focalPoint ?? startEvent.focalPoint;
229-
final delta = details.focalPoint - lastPointerOffset;
230-
final centerOffset = toScreenLocation(camera.center);
231-
final newCenterOffset = centerOffset - delta;
232-
final newCenter = toLngLat(newCenterOffset);
251+
var newCenter = camera.center;
252+
if (options.gestures.pan) {
253+
final lastPointerOffset =
254+
lastEvent?.focalPoint ?? startEvent.focalPoint;
255+
final delta = details.focalPoint - lastPointerOffset;
256+
final centerOffset = toScreenLocation(camera.center);
257+
final newCenterOffset = centerOffset - delta;
258+
newCenter = toLngLat(newCenterOffset);
259+
}
233260

234261
// bearing
235-
final rotationDelta = details.rotation - (lastEvent?.rotation ?? 0.0);
236-
final newBearing = camera.bearing - rotationDelta * radian2Degree;
262+
var newBearing = camera.bearing;
263+
if (options.gestures.rotate && details.rotation != 0.0) {
264+
final lastRotation = lastEvent?.rotation ?? 0.0;
265+
final rotationDelta = details.rotation - lastRotation;
266+
newBearing = camera.bearing - rotationDelta * radian2Degree;
267+
}
237268

238-
moveCamera(
239-
zoom: targetZoom.clamp(options.minZoom, options.maxZoom),
240-
center: newCenter,
241-
bearing: newBearing,
242-
);
269+
moveCamera(zoom: newZoom, center: newCenter, bearing: newBearing);
243270
}
244271
}
245272

@@ -252,22 +279,26 @@ abstract class MapLibreMapState extends State<MapLibreMap>
252279
if (firstEvent == null) return;
253280

254281
// zoom out
255-
if (lastEvent == null) {
282+
if (lastEvent == null && options.gestures.zoom) {
256283
debugPrint('### Zoom out on scale end');
257-
animateCamera(
258-
zoom: (camera.zoom - 1).clamp(options.minZoom, options.maxZoom),
259-
center: camera.center.intermediatePointTo(
260-
toLngLat(firstEvent.focalPoint),
261-
fraction: -0.8,
262-
),
263-
);
264-
} else if (secondToLastEvent != null) {
284+
var newCenter = camera.center;
285+
if (options.gestures.pan) {
286+
newCenter = toLngLat(
287+
firstEvent.focalPoint,
288+
).intermediatePointTo(camera.center, fraction: 0.2);
289+
}
290+
animateCamera(zoom: camera.zoom - 1, center: newCenter);
291+
292+
} else if (secondToLastEvent != null &&
293+
lastEvent != null &&
294+
options.gestures.pan) {
265295
// fling animation
266296
final velocity = details.velocity.pixelsPerSecond.distance;
267297
if (velocity >= 800) {
268298
final offset = secondToLastEvent.focalPoint - lastEvent.focalPoint;
269299
final distance = offset.distance;
270-
final direction = offset.direction * radian2Degree + 90 + camera.bearing;
300+
final direction =
301+
offset.direction * radian2Degree + 90 + camera.bearing;
271302
final tweens = _MapCameraTween(
272303
begin: camera,
273304
end: camera.copyWith(

0 commit comments

Comments
 (0)