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

Commit

Permalink
Adjustable map deceleration rate (#5504)
Browse files Browse the repository at this point in the history
* [ios] Adds the ability to customize map deceleration speed

* [ios] Made pinch, rotation deceleration adjustable too

Drift zooming and drift rotation also respect the deceleration rate. A side effect of this change is that drift zooming will come to a stop ever-so-slightly sooner now.

* [ios] Documented deceleration rates

Added documentation for deceleration rate constants. Also updated the changelog.
  • Loading branch information
1ec5 authored Jun 29, 2016
1 parent f7b646c commit 5389f04
Show file tree
Hide file tree
Showing 4 changed files with 41 additions and 13 deletions.
1 change: 1 addition & 0 deletions platform/ios/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ Mapbox welcomes participation and contributions from everyone. Please read [CON
- `MGLOfflinePackProgress` now indicates how many tiles have been downloaded and how much space they take up. ([#4874](https://github.com/mapbox/mapbox-gl-native/pull/4874))
- The compass, user dot, and visible annotations are now accessible to VoiceOver users. ([#1496](https://github.com/mapbox/mapbox-gl-native/pull/1496))
- Added a method to MGLMapView, `-anchorPointForGesture:`, that you can override to anchor gestures at a point other than the user location. ([#5302](https://github.com/mapbox/mapbox-gl-native/pull/5302))
- Added a property to MGLMapView, `decelerationRate`, that allows you to speed up or slow down the drift animation at the end of a user gesture. You can also use this property to disable the drift animation entirely. ([#5504](https://github.com/mapbox/mapbox-gl-native/pull/5504))
- Fixed an issue (speculatively) where the tile cache could be included in iCloud backups. ([#5124](https://github.com/mapbox/mapbox-gl-native/pull/5124))
- Improved performance viewing regions with large landcover polygons when viewing a style that uses the Mapbox Streets source. ([#2444](https://github.com/mapbox/mapbox-gl-native/pull/2444))
- Fixed a memory leak when using raster resources. ([#5141](https://github.com/mapbox/mapbox-gl-native/pull/5141))
Expand Down
3 changes: 3 additions & 0 deletions platform/ios/jazzy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ custom_categories:
- MGLMapCamera
- MGLMapDebugMaskOptions
- MGLMapView
- MGLMapViewDecelerationRateFast
- MGLMapViewDecelerationRateImmediate
- MGLMapViewDecelerationRateNormal
- MGLMapViewDelegate
- MGLStyle
- MGLStyleDefaultVersion
Expand Down
20 changes: 20 additions & 0 deletions platform/ios/src/MGLMapView.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,15 @@ NS_ASSUME_NONNULL_BEGIN
@protocol MGLCalloutView;
@protocol MGLFeature;

/** The default deceleration rate for a map view. */
extern const CGFloat MGLMapViewDecelerationRateNormal;

/** A fast deceleration rate for a map view. */
extern const CGFloat MGLMapViewDecelerationRateFast;

/** Disables decleration in a map view. */
extern const CGFloat MGLMapViewDecelerationRateImmediate;

/** The vertical alignment of an annotation within a map view. */
typedef NS_ENUM(NSUInteger, MGLAnnotationVerticalAlignment) {
/** Aligns the annotation vertically in the center of the map view. */
Expand Down Expand Up @@ -404,6 +413,17 @@ IB_DESIGNABLE
*/
@property(nonatomic, getter=isPitchEnabled) BOOL pitchEnabled;

/**
A floating-point value that determines the rate of deceleration after the user
lifts their finger.
Your application can use the `MGLMapViewDecelerationRateNormal` and
`MGLMapViewDecelerationRateFast` constants as reference points for reasonable
deceleration rates. `MGLMapViewDecelerationRateImmediate` can be used to
disable deceleration entirely.
*/
@property(nonatomic) CGFloat decelerationRate;

#pragma mark Manipulating the Viewpoint

/**
Expand Down
30 changes: 17 additions & 13 deletions platform/ios/src/MGLMapView.mm
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,10 @@
class MBGLView;
class MGLAnnotationContext;

const CGFloat MGLMapViewDecelerationRateNormal = UIScrollViewDecelerationRateNormal;
const CGFloat MGLMapViewDecelerationRateFast = UIScrollViewDecelerationRateFast;
const CGFloat MGLMapViewDecelerationRateImmediate = 0.0;

/// 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.
Expand Down Expand Up @@ -500,6 +504,8 @@ - (void)commonInit
[self addGestureRecognizer:_twoFingerDrag];
_pitchEnabled = YES;

_decelerationRate = MGLMapViewDecelerationRateNormal;

if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone)
{
_quickZoom = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(handleQuickZoomGesture:)];
Expand Down Expand Up @@ -1202,18 +1208,17 @@ - (void)handlePanGesture:(UIPanGestureRecognizer *)pan
else if (pan.state == UIGestureRecognizerStateEnded || pan.state == UIGestureRecognizerStateCancelled)
{
CGPoint velocity = [pan velocityInView:pan.view];
if (sqrtf(velocity.x * velocity.x + velocity.y * velocity.y) < 100)
if (self.decelerationRate == MGLMapViewDecelerationRateImmediate || sqrtf(velocity.x * velocity.x + velocity.y * velocity.y) < 100)
{
// Not enough velocity to overcome friction
velocity = CGPointZero;
}

NSTimeInterval duration = UIScrollViewDecelerationRateNormal;
BOOL drift = ! CGPointEqualToPoint(velocity, CGPointZero);
if (drift)
{
CGPoint offset = CGPointMake(velocity.x * duration / 4, velocity.y * duration / 4);
_mbglMap->moveBy({ offset.x, offset.y }, MGLDurationInSeconds(duration));
CGPoint offset = CGPointMake(velocity.x * self.decelerationRate / 4, velocity.y * self.decelerationRate / 4);
_mbglMap->moveBy({ offset.x, offset.y }, MGLDurationInSeconds(self.decelerationRate));
}

[self notifyGestureDidEndWithDrift:drift];
Expand Down Expand Up @@ -1283,7 +1288,7 @@ - (void)handlePinchGesture:(UIPinchGestureRecognizer *)pinch
velocity = 0;
}

NSTimeInterval duration = velocity > 0 ? 1 : 0.25;
NSTimeInterval duration = (velocity > 0 ? 1 : 0.25) * self.decelerationRate;

CGFloat scale = self.scale * pinch.scale;
CGFloat newScale = scale;
Expand All @@ -1301,12 +1306,12 @@ - (void)handlePinchGesture:(UIPinchGestureRecognizer *)pinch
velocity = 0;
}

if (velocity)
if (velocity && duration)
{
_mbglMap->setScale(newScale, mbgl::ScreenCoordinate { centerPoint.x, centerPoint.y }, MGLDurationInSeconds(duration));
}

[self notifyGestureDidEndWithDrift:velocity];
[self notifyGestureDidEndWithDrift:velocity && duration];

[self unrotateIfNeededForGesture];
}
Expand Down Expand Up @@ -1355,21 +1360,20 @@ - (void)handleRotateGesture:(UIRotationGestureRecognizer *)rotate
else if (rotate.state == UIGestureRecognizerStateEnded || rotate.state == UIGestureRecognizerStateCancelled)
{
CGFloat velocity = rotate.velocity;

if (fabs(velocity) > 3)
CGFloat decelerationRate = self.decelerationRate;
if (decelerationRate != MGLMapViewDecelerationRateImmediate && fabs(velocity) > 3)
{
CGFloat radians = self.angle + rotate.rotation;
NSTimeInterval duration = UIScrollViewDecelerationRateNormal;
CGFloat newRadians = radians + velocity * duration * 0.1;
CGFloat newRadians = radians + velocity * decelerationRate * 0.1;
CGFloat newDegrees = MGLDegreesFromRadians(newRadians) * -1;

_mbglMap->setBearing(newDegrees, mbgl::ScreenCoordinate { centerPoint.x, centerPoint.y }, MGLDurationInSeconds(duration));
_mbglMap->setBearing(newDegrees, mbgl::ScreenCoordinate { centerPoint.x, centerPoint.y }, MGLDurationInSeconds(decelerationRate));

[self notifyGestureDidEndWithDrift:YES];

__weak MGLMapView *weakSelf = self;

[self animateWithDelay:duration animations:^
[self animateWithDelay:decelerationRate animations:^
{
[weakSelf unrotateIfNeededForGesture];
}];
Expand Down

0 comments on commit 5389f04

Please sign in to comment.