@@ -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