Skip to content
This repository has been archived by the owner on Aug 8, 2023. It is now read-only.

Commit

Permalink
[ios] Support for a customizable zoom gesture centering strategy. (#5302
Browse files Browse the repository at this point in the history
)

* [ios] Support for a customizable zoom gesture centering strategy.

We introduce a new MGLZoomGestureCentering enum and corresponding zoomGestureCentering property on MGLMapView.

Currently, Mapbox automatically adjusts the center of the map relative to the user's gesture location, but for some applications (e.g Uber, Lyft) it is preferable to keep the map center "locked" in response to zoom gestures.

Exisiting code will retain its current behavior without modification and will implicitly use the default value of MGLZoomGestureCenteringFollowsTouch. New code can specify MGLZoomGestureCenteringLockedInPlace to get the new "locked" behavior.

* [ios] Added -anchorPointForGesture: to MGLMapView

Cherry-picked from b915f05.
  • Loading branch information
revetkn authored and 1ec5 committed Jun 10, 2016
1 parent 4e80899 commit dd565b7
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 31 deletions.
19 changes: 19 additions & 0 deletions platform/ios/src/MGLMapView.h
Original file line number Diff line number Diff line change
Expand Up @@ -762,6 +762,25 @@ IB_DESIGNABLE
*/
- (MGLMapCamera *)cameraThatFitsCoordinateBounds:(MGLCoordinateBounds)bounds edgePadding:(UIEdgeInsets)insets;

/**
Returns the point in this view's coordinate system on which to "anchor" in
response to a user-initiated gesture.
For example, a pinch-to-zoom gesture would anchor the map at the midpoint of
the pinch.
If the `userTrackingMode` property is not `MGLUserTrackingModeNone`, the
user annotation is used as the anchor point.
Subclasses may override this method to provide specialized behavior - for
example, anchoring on the map's center point to provide a "locked" zooming
mode.
@param gesture An anchorable user gesture.
@return The point on which to anchor in response to the gesture.
*/
- (CGPoint)anchorPointForGesture:(UIGestureRecognizer *)gesture;

/**
The distance from the edges of the map view’s frame to the edges of the map
view’s logical viewport.
Expand Down
54 changes: 23 additions & 31 deletions platform/ios/src/MGLMapView.mm
Original file line number Diff line number Diff line change
Expand Up @@ -1235,11 +1235,7 @@ - (void)handlePinchGesture:(UIPinchGestureRecognizer *)pinch

_mbglMap->cancelTransitions();

CGPoint centerPoint = [pinch locationInView:pinch.view];
if (self.userTrackingMode != MGLUserTrackingModeNone)
{
centerPoint = self.userLocationAnnotationViewCenter;
}
CGPoint centerPoint = [self anchorPointForGesture:pinch];

if (pinch.state == UIGestureRecognizerStateBegan)
{
Expand Down Expand Up @@ -1311,7 +1307,7 @@ - (void)handlePinchGesture:(UIPinchGestureRecognizer *)pinch
[self unrotateIfNeededForGesture];
}

_previousPinchCenterCoordinate = [self convertPoint:[pinch locationInView:pinch.view] toCoordinateFromView:self];
_previousPinchCenterCoordinate = [self convertPoint:centerPoint toCoordinateFromView:self];
_previousPinchNumberOfTouches = pinch.numberOfTouches;
}

Expand All @@ -1321,11 +1317,7 @@ - (void)handleRotateGesture:(UIRotationGestureRecognizer *)rotate

_mbglMap->cancelTransitions();

CGPoint centerPoint = [rotate locationInView:rotate.view];
if (self.userTrackingMode != MGLUserTrackingModeNone)
{
centerPoint = self.userLocationAnnotationViewCenter;
}
CGPoint centerPoint = [self anchorPointForGesture:rotate];

if (rotate.state == UIGestureRecognizerStateBegan)
{
Expand Down Expand Up @@ -1454,11 +1446,7 @@ - (void)handleDoubleTapGesture:(UITapGestureRecognizer *)doubleTap
if (doubleTap.state == UIGestureRecognizerStateEnded)
{
[self trackGestureEvent:MGLEventGestureDoubleTap forRecognizer:doubleTap];
CGPoint gesturePoint = [doubleTap locationInView:doubleTap.view];
if (self.userTrackingMode != MGLUserTrackingModeNone)
{
gesturePoint = self.userLocationAnnotationViewCenter;
}
CGPoint gesturePoint = [self anchorPointForGesture:doubleTap];

mbgl::ScreenCoordinate center(gesturePoint.x, gesturePoint.y);
_mbglMap->scaleBy(2, center, MGLDurationInSeconds(MGLAnimationDuration));
Expand Down Expand Up @@ -1486,11 +1474,7 @@ - (void)handleTwoFingerTapGesture:(UITapGestureRecognizer *)twoFingerTap
}
else if (twoFingerTap.state == UIGestureRecognizerStateEnded)
{
CGPoint gesturePoint = [twoFingerTap locationInView:twoFingerTap.view];
if (self.userTrackingMode != MGLUserTrackingModeNone)
{
gesturePoint = self.userLocationAnnotationViewCenter;
}
CGPoint gesturePoint = [self anchorPointForGesture:twoFingerTap];

mbgl::ScreenCoordinate center(gesturePoint.x, gesturePoint.y);
_mbglMap->scaleBy(0.5, center, MGLDurationInSeconds(MGLAnimationDuration));
Expand Down Expand Up @@ -1528,11 +1512,8 @@ - (void)handleQuickZoomGesture:(UILongPressGestureRecognizer *)quickZoom

if (newZoom < _mbglMap->getMinZoom()) return;

CGPoint centerPoint = self.contentCenter;
if (self.userTrackingMode != MGLUserTrackingModeNone)
{
centerPoint = self.userLocationAnnotationViewCenter;
}
CGPoint centerPoint = [self anchorPointForGesture:quickZoom];

_mbglMap->scaleBy(powf(2, newZoom) / _mbglMap->getScale(),
mbgl::ScreenCoordinate { centerPoint.x, centerPoint.y });

Expand Down Expand Up @@ -1564,11 +1545,8 @@ - (void)handleTwoFingerDragGesture:(UIPanGestureRecognizer *)twoFingerDrag

CGFloat pitchNew = currentPitch - (gestureDistance / slowdown);

CGPoint centerPoint = self.contentCenter;
if (self.userTrackingMode != MGLUserTrackingModeNone)
{
centerPoint = self.userLocationAnnotationViewCenter;
}
CGPoint centerPoint = [self anchorPointForGesture:twoFingerDrag];

_mbglMap->setPitch(pitchNew, mbgl::ScreenCoordinate { centerPoint.x, centerPoint.y });

[self notifyMapChange:mbgl::MapChangeRegionIsChanging];
Expand All @@ -1578,7 +1556,21 @@ - (void)handleTwoFingerDragGesture:(UIPanGestureRecognizer *)twoFingerDrag
[self notifyGestureDidEndWithDrift:NO];
[self unrotateIfNeededForGesture];
}
}

- (CGPoint)anchorPointForGesture:(UIGestureRecognizer *)gesture {
if (self.userTrackingMode != MGLUserTrackingModeNone)
{
return self.userLocationAnnotationViewCenter;
}

// Special case for two-finger drag and quickzoom
if ([gesture isKindOfClass:[UIPanGestureRecognizer class]] || [gesture isKindOfClass:[UILongPressGestureRecognizer class]])
{
return self.contentCenter;
}

return [gesture locationInView:gesture.view];
}

- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer
Expand Down

0 comments on commit dd565b7

Please sign in to comment.