diff options
author | Minh Nguyễn <mxn@1ec5.org> | 2016-01-17 17:03:00 -0800 |
---|---|---|
committer | Minh Nguyễn <mxn@1ec5.org> | 2016-01-20 11:02:31 -0800 |
commit | 41ce7b2526ec338a10a1bfcfbee0a30342b2c49a (patch) | |
tree | a9f736d8c33d53620aa2770d94bb6f0f9a119d9f /platform | |
parent | 453000af3b17a8776ff0e78593dd5682c8cdab8d (diff) | |
download | qtlocation-mapboxgl-41ce7b2526ec338a10a1bfcfbee0a30342b2c49a.tar.gz |
[ios] Fly to user location
Fly to the user location when entering user tracking mode. Keep user location updates from interfering with the initial flight.
Diffstat (limited to 'platform')
-rw-r--r-- | platform/ios/src/MGLMapView.mm | 97 |
1 files changed, 54 insertions, 43 deletions
diff --git a/platform/ios/src/MGLMapView.mm b/platform/ios/src/MGLMapView.mm index 046ebfd433..89e1d34503 100644 --- a/platform/ios/src/MGLMapView.mm +++ b/platform/ios/src/MGLMapView.mm @@ -48,6 +48,16 @@ class MBGLView; class MGLAnnotationContext; +/// Indicates the manner in which the map view is tracking the user location. +typedef NS_ENUM(NSUInteger, MGLUserTrackingState) { + /// The map view is not yet tracking the user location. + MGLUserTrackingStatePossible = 0, + /// The map view has begun to move to the first reported user location. + MGLUserTrackingStateBegan = 1, + /// The map view has finished moving to the first reported user location. + MGLUserTrackingStateChanged = 2, +}; + NSString *const MGLMapboxSetupDocumentationURLDisplayString = @"mapbox.com/help/first-steps-ios-sdk"; const NSTimeInterval MGLAnimationDuration = 0.3; @@ -143,8 +153,8 @@ public: /// Currently shown popover representing the selected annotation. @property (nonatomic) UIView<MGLCalloutView> *calloutViewForSelectedAnnotation; @property (nonatomic) MGLUserLocationAnnotationView *userLocationAnnotationView; -/// True if the map view has completed its move to the first reported user location in user tracking mode. -@property (nonatomic) BOOL hasBegunTrackingUserLocation; +/// Indicates how thoroughly the map view is tracking the user location. +@property (nonatomic) MGLUserTrackingState userTrackingState; @property (nonatomic) CLLocationManager *locationManager; @property (nonatomic) CGFloat scale; @property (nonatomic) CGFloat angle; @@ -1930,6 +1940,13 @@ std::chrono::steady_clock::duration MGLDurationInSeconds(float duration) - (void)flyToCamera:(MGLMapCamera *)camera withDuration:(NSTimeInterval)duration peakAltitude:(CLLocationDistance)peakAltitude completionHandler:(nullable void (^)(void))completion { + self.userTrackingMode = MGLUserTrackingModeNone; + + [self _flyToCamera:camera withDuration:duration peakAltitude:peakAltitude completionHandler:completion]; +} + +- (void)_flyToCamera:(MGLMapCamera *)camera withDuration:(NSTimeInterval)duration peakAltitude:(CLLocationDistance)peakAltitude completionHandler:(nullable void (^)(void))completion +{ _mbglMap->cancelTransitions(); if ([self.camera isEqual:camera]) { @@ -2942,7 +2959,11 @@ std::chrono::steady_clock::duration MGLDurationInSeconds(float duration) } _userTrackingMode = mode; - self.hasBegunTrackingUserLocation = NO; + + if (_userTrackingMode == MGLUserTrackingModeNone + || _userTrackingMode == MGLUserTrackingModeFollowWithCourse) { + self.userTrackingState = MGLUserTrackingStatePossible; + } switch (_userTrackingMode) { @@ -3038,8 +3059,9 @@ std::chrono::steady_clock::duration MGLDurationInSeconds(float duration) { // at sufficient detail, just re-center the map; don't zoom // - if (self.hasBegunTrackingUserLocation) + if (self.userTrackingState == MGLUserTrackingStateChanged) { + // Ease incrementally to the new user location. UIEdgeInsets insets = UIEdgeInsetsMake(correctPoint.y, correctPoint.x, CGRectGetHeight(self.bounds) - correctPoint.y, CGRectGetWidth(self.bounds) - correctPoint.x); @@ -3052,51 +3074,39 @@ std::chrono::steady_clock::duration MGLDurationInSeconds(float duration) animationTimingFunction:linearFunction completionHandler:NULL]; } - else + else if (self.userTrackingState == MGLUserTrackingStatePossible) { + // Fly to the first reported location, which may be far away + // from the current viewport. + self.userTrackingState = MGLUserTrackingStateBegan; + + MGLMapCamera *camera = self.camera; + camera.centerCoordinate = self.userLocation.location.coordinate; + camera.heading = course; + __weak MGLMapView *weakSelf = self; - [self _setCenterCoordinate:self.userLocation.location.coordinate - edgePadding:self.contentInset - zoomLevel:self.zoomLevel - direction:course - duration:MGLAnimationDuration - animationTimingFunction:nil - completionHandler:^{ - MGLMapView *strongSelf = weakSelf; - strongSelf.hasBegunTrackingUserLocation = YES; - }]; + [self _flyToCamera:camera withDuration:-1 peakAltitude:-1 completionHandler:^{ + MGLMapView *strongSelf = weakSelf; + strongSelf.userTrackingState = MGLUserTrackingStateChanged; + }]; } } - else + else if (self.userTrackingState == MGLUserTrackingStatePossible) { // otherwise re-center and zoom in to near accuracy confidence // - float delta = (newLocation.horizontalAccuracy / 110000) * 1.2; // approx. meter per degree latitude, plus some margin - - CLLocationCoordinate2D desiredSouthWest = CLLocationCoordinate2DMake(newLocation.coordinate.latitude - delta, - newLocation.coordinate.longitude - delta); - - CLLocationCoordinate2D desiredNorthEast = CLLocationCoordinate2DMake(newLocation.coordinate.latitude + delta, - newLocation.coordinate.longitude + delta); - - CGFloat pixelRadius = fminf(self.bounds.size.width, self.bounds.size.height) / 2; - - CLLocationCoordinate2D actualSouthWest = [self convertPoint:CGPointMake(currentPoint.x - pixelRadius, - currentPoint.y - pixelRadius) - toCoordinateFromView:self]; - - CLLocationCoordinate2D actualNorthEast = [self convertPoint:CGPointMake(currentPoint.x + pixelRadius, - currentPoint.y + pixelRadius) - toCoordinateFromView:self]; - - if (desiredNorthEast.latitude != actualNorthEast.latitude || - desiredNorthEast.longitude != actualNorthEast.longitude || - desiredSouthWest.latitude != actualSouthWest.latitude || - desiredSouthWest.longitude != actualSouthWest.longitude) - { - // assumes we won't disrupt tracking mode - [self setVisibleCoordinateBounds:MGLCoordinateBoundsMake(desiredSouthWest, desiredNorthEast) edgePadding:UIEdgeInsetsZero direction:course animated:YES]; - } + self.userTrackingState = MGLUserTrackingStateBegan; + + MGLMapCamera *camera = self.camera; + camera.centerCoordinate = self.userLocation.location.coordinate; + camera.heading = course; + camera.altitude = newLocation.horizontalAccuracy; + + __weak MGLMapView *weakSelf = self; + [self _flyToCamera:camera withDuration:-1 peakAltitude:-1 completionHandler:^{ + MGLMapView *strongSelf = weakSelf; + strongSelf.userTrackingState = MGLUserTrackingStateChanged; + }]; } [self unrotateIfNeededAnimated:YES]; } @@ -3367,7 +3377,8 @@ std::chrono::steady_clock::duration MGLDurationInSeconds(float duration) if ( ! self.userLocationAnnotationView.superview) [self.glView addSubview:self.userLocationAnnotationView]; CGPoint userPoint; - if (self.userTrackingMode != MGLUserTrackingModeNone && self.hasBegunTrackingUserLocation) + if (self.userTrackingMode != MGLUserTrackingModeNone + && self.userTrackingState == MGLUserTrackingStateChanged) { userPoint = self.userLocationAnnotationViewCenter; } |