summaryrefslogtreecommitdiff
path: root/platform/ios/MGLMapView.mm
diff options
context:
space:
mode:
authorJason Wray <jason@kulturny.com>2015-08-18 16:25:40 -0400
committerJason Wray <jason@kulturny.com>2015-08-26 11:23:03 -0700
commit42dc5336db5179c50b8d1edeca0bef7a27c8cefd (patch)
tree601c4117661e9aaed3ffd17660946476cf7eb238 /platform/ios/MGLMapView.mm
parentd8ed33c7d48dbabe7e6f5e48f148ea2bec823a07 (diff)
downloadqtlocation-mapboxgl-42dc5336db5179c50b8d1edeca0bef7a27c8cefd.tar.gz
iOS perspective gesture support
Drag two fingers upward to tilt the map. Implements #2116
Diffstat (limited to 'platform/ios/MGLMapView.mm')
-rw-r--r--platform/ios/MGLMapView.mm111
1 files changed, 107 insertions, 4 deletions
diff --git a/platform/ios/MGLMapView.mm b/platform/ios/MGLMapView.mm
index f12836b057..4f3e903074 100644
--- a/platform/ios/MGLMapView.mm
+++ b/platform/ios/MGLMapView.mm
@@ -85,6 +85,7 @@ CLLocationDegrees MGLDegreesFromRadians(CGFloat radians)
@property (nonatomic) UIPinchGestureRecognizer *pinch;
@property (nonatomic) UIRotationGestureRecognizer *rotate;
@property (nonatomic) UILongPressGestureRecognizer *quickZoom;
+@property (nonatomic) UIPanGestureRecognizer *twoFingerDrag;
@property (nonatomic) NSMapTable *annotationIDsByAnnotation;
@property (nonatomic) NS_MUTABLE_DICTIONARY_OF(NSString *, MGLAnnotationImage *) *annotationImages;
@property (nonatomic) std::vector<uint32_t> annotationsNearbyLastTap;
@@ -338,6 +339,15 @@ std::chrono::steady_clock::duration secondsAsDuration(float duration)
[twoFingerTap requireGestureRecognizerToFail:_pinch];
[twoFingerTap requireGestureRecognizerToFail:_rotate];
[self addGestureRecognizer:twoFingerTap];
+
+ _twoFingerDrag = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handleTwoFingerDragGesture:)];
+ _twoFingerDrag.minimumNumberOfTouches = 2;
+ _twoFingerDrag.maximumNumberOfTouches = 2;
+ _twoFingerDrag.delegate = self;
+ [_twoFingerDrag requireGestureRecognizerToFail:twoFingerTap];
+ [_twoFingerDrag requireGestureRecognizerToFail:_pan];
+ [self addGestureRecognizer:_twoFingerDrag];
+ _pitchEnabled = YES;
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone)
{
@@ -1326,6 +1336,59 @@ std::chrono::steady_clock::duration secondsAsDuration(float duration)
}
}
+- (void)handleTwoFingerDragGesture:(UIPanGestureRecognizer *)twoFingerDrag
+{
+ if ( ! self.isPitchEnabled) return;
+
+ _mbglMap->cancelTransitions();
+
+ if (twoFingerDrag.state == UIGestureRecognizerStateBegan)
+ {
+ [self trackGestureEvent:MGLEventGesturePitchStart forRecognizer:twoFingerDrag];
+ }
+ else if (twoFingerDrag.state == UIGestureRecognizerStateBegan || twoFingerDrag.state == UIGestureRecognizerStateChanged)
+ {
+ CGFloat gestureDistance = CGPoint([twoFingerDrag translationInView:twoFingerDrag.view]).y;
+ double currentPitch = _mbglMap->getPitch();
+ double minPitch = 0;
+ double maxPitch = 60.0;
+ double slowdown = 20.0;
+
+ double pitchNew = fmax(fmin(currentPitch - (gestureDistance / slowdown), maxPitch), minPitch);
+
+ _mbglMap->setPitch(pitchNew);
+ }
+ else if (twoFingerDrag.state == UIGestureRecognizerStateEnded || twoFingerDrag.state == UIGestureRecognizerStateCancelled)
+ {
+ [self unrotateIfNeededAnimated:YES];
+
+ //[self notifyMapChange:(mbgl::MapChangeRegionDidChange)];
+ }
+
+}
+
+- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer
+{
+ if ([gestureRecognizer isKindOfClass:[UIPanGestureRecognizer class]])
+ {
+ UIPanGestureRecognizer *panGesture = (UIPanGestureRecognizer *)gestureRecognizer;
+
+ if (panGesture.minimumNumberOfTouches == 2)
+ {
+ CGPoint velocity = [panGesture velocityInView:panGesture.view];
+ double gestureAngle = MGLDegreesFromRadians(atan(velocity.y / velocity.x));
+ double horizontalToleranceDegrees = 20.0;
+
+ // cancel if gesture angle is not 90º±20º (more or less vertical)
+ if ( ! (fabs((fabs(gestureAngle) - 90.0)) < horizontalToleranceDegrees))
+ {
+ return NO;
+ }
+ }
+ }
+ return YES;
+}
+
- (void)handleCalloutAccessoryTapGesture:(UITapGestureRecognizer *)tap
{
if ([self.delegate respondsToSelector:@selector(mapView:annotation:calloutAccessoryControlTapped:)])
@@ -1419,6 +1482,11 @@ std::chrono::steady_clock::duration secondsAsDuration(float duration)
return [NSSet setWithObject:@"allowsRotating"];
}
++ (NS_SET_OF(NSString *) *)keyPathsForValuesAffectingPitchEnabled
+{
+ return [NSSet setWithObject:@"allowsPitching"];
+}
+
- (void)setDebugActive:(BOOL)debugActive
{
_mbglMap->setDebug(debugActive);
@@ -1617,6 +1685,25 @@ mbgl::LatLngBounds MGLLatLngBoundsFromCoordinateBounds(MGLCoordinateBounds coord
[self setDirection:direction animated:NO];
}
+- (double)pitch
+{
+ return _mbglMap->getPitch();
+}
+
+- (void)setPitch:(double)pitch
+{
+ // constrain pitch to between 0º and 60º
+ //
+ _mbglMap->setPitch(fmax(fmin(pitch, 60), 0));
+
+ //[self notifyMapChange:(mbgl::MapChangeRegionDidChange)];
+}
+
+- (void)resetPitch
+{
+ [self setPitch:0];
+}
+
- (CLLocationCoordinate2D)convertPoint:(CGPoint)point toCoordinateFromView:(nullable UIView *)view
{
CGPoint convertedPoint = [self convertPoint:point fromView:view];
@@ -2630,10 +2717,11 @@ CLLocationCoordinate2D MGLLocationCoordinate2DFromLatLng(mbgl::LatLng latLng)
{
[self updateCompass];
- if (self.pan.state == UIGestureRecognizerStateChanged ||
- self.pinch.state == UIGestureRecognizerStateChanged ||
- self.rotate.state == UIGestureRecognizerStateChanged ||
- self.quickZoom.state == UIGestureRecognizerStateChanged) return;
+ if (self.pan.state == UIGestureRecognizerStateChanged ||
+ self.pinch.state == UIGestureRecognizerStateChanged ||
+ self.rotate.state == UIGestureRecognizerStateChanged ||
+ self.quickZoom.state == UIGestureRecognizerStateChanged ||
+ self.twoFingerDrag.state == UIGestureRecognizerStateChanged) return;
if (self.isAnimatingGesture) return;
@@ -3062,6 +3150,21 @@ class MBGLView : public mbgl::View
self.rotateEnabled = allowsRotating;
}
++ (NS_SET_OF(NSString *) *)keyPathsForValuesAffectingAllowsPitching
+{
+ return [NSSet setWithObject:@"pitchEnabled"];
+}
+
+- (BOOL)allowsPitching
+{
+ return self.pitchEnabled;
+}
+
+- (void)setAllowsPitching:(BOOL)allowsPitching
+{
+ self.pitchEnabled = allowsPitching;
+}
+
- (void)didReceiveMemoryWarning
{
_mbglMap->onLowMemory();