Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Camera Pan Fix #120

Merged
merged 18 commits into from
Feb 24, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 20 additions & 4 deletions Sources/MapboxMaps/Foundation/Camera/CameraManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -399,14 +399,15 @@ public class CameraManager {
- Parameter pitch: The degrees to adjust the map's tilt by.
- Parameter zoom: The amount to adjust the camera's zoom level by.
- Parameter animated: Indicates whether the camera changes should be animated.
- Parameter pitchedDrift: This hack indicates that the calling function wants to simulate drift. Therefore we need to do some additional calculations
*/
public func moveCamera(by offset: CGPoint? = nil, rotation: CGFloat? = nil, pitch: CGFloat? = nil, zoom: CGFloat? = nil, animated: Bool = false) {
public func moveCamera(by offset: CGPoint? = nil, rotation: CGFloat? = nil, pitch: CGFloat? = nil, zoom: CGFloat? = nil, animated: Bool = false, pitchedDrift: Bool = false) {
guard let mapView = mapView else {
assertionFailure("MapView is nil.")
return
}

let centerCoordinate = self.shiftCenterCoordinate(by: offset ?? .zero)
let centerCoordinate = self.shiftCenterCoordinate(by: offset ?? .zero, pitchedDrift: pitchedDrift)

var newBearing: CGFloat = 0
if let angle = rotation {
Expand Down Expand Up @@ -454,8 +455,9 @@ public class CameraManager {
/**
Return a new center coordinate shifted by a given offset value.
- Parameter offset: The `CGPoint` value to shift the map's center by.
- Parameter pitchedDrift: This hack indicates that the calling function wants to simulate drift. Therefore we need to do some additional calculations
*/
func shiftCenterCoordinate(by offset: CGPoint) -> CLLocationCoordinate2D {
func shiftCenterCoordinate(by offset: CGPoint, pitchedDrift: Bool = false) -> CLLocationCoordinate2D {
guard let mapView = mapView else {
assertionFailure("MapView is nil.")
return CLLocationCoordinate2D(latitude: 0, longitude: 0)
Expand All @@ -464,13 +466,27 @@ public class CameraManager {
return CLLocationCoordinate2D(latitude: 0, longitude: 0)
}

/// Stop gap solution until we land on a fix all
var pitchFactor: CGFloat = mapView.pitch
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It'd be good to get an explanation of what this math is trying to do in the comments here.

if pitchedDrift {
if pitchFactor != 0.0 {
// These calculations are creating a multiplier for the offset to normalize the offset for pitched maps
pitchFactor /= 10.0
pitchFactor += 1.5
} else {
pitchFactor = 1.0 // We do not want divide by 0
}
} else {
pitchFactor = 1.0 // We do not want divide by 0
}

let cameraViewSize = mapView.cameraView.frame.size
let cameraPadding = mapView.cameraView.padding
let viewPortSize = CGSize(width: cameraViewSize.width - cameraPadding.left - cameraPadding.right,
height: cameraViewSize.height - cameraPadding.top - cameraPadding.bottom)
let viewPortCenter = CGPoint(x: (viewPortSize.width / 2) + cameraPadding.left,
y: (viewPortSize.height / 2) + cameraPadding.top)
let newViewPortCenter = CGPoint(x: viewPortCenter.x - offset.x, y: viewPortCenter.y - offset.y)
let newViewPortCenter = CGPoint(x: viewPortCenter.x - (offset.x / pitchFactor), y: viewPortCenter.y - (offset.y / pitchFactor))
var centerCoordinate = mapView.coordinate(for: newViewPortCenter)

var newLong: Double
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,9 @@ internal class PanGestureHandler: GestureHandler {
pan.setTranslation(.zero, in: pan.view)
case .ended, .cancelled:
var velocity = pan.velocity(in: pan.view)
if self.decelerationRate == 0.0
|| (sqrt(pow(velocity.x, 2) + pow(velocity.y, 2)) < 100) {
let velocityHypot = sqrt(pow(velocity.x, 2) + pow(velocity.y, 2))

// Not enough velocity to overcome friction
if self.decelerationRate == 0.0 || velocityHypot < 1000 {
velocity = CGPoint.zero
}

Expand All @@ -43,7 +42,6 @@ internal class PanGestureHandler: GestureHandler {

self.delegate.panEnded(with: offset)
}

default:
break
}
Expand Down
11 changes: 5 additions & 6 deletions Sources/MapboxMaps/Gestures/GestureManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -119,11 +119,13 @@ internal protocol CameraManagerProtocol: AnyObject {
duration: TimeInterval,
completion: ((Bool) -> Void)?)

//swiftlint:disable function_parameter_count
func moveCamera(by offset: CGPoint?,
rotation: CGFloat?,
pitch: CGFloat?,
zoom: CGFloat?,
animated: Bool)
animated: Bool,
pitchedDrift: Bool)

func cancelTransitions()
}
Expand Down Expand Up @@ -311,15 +313,12 @@ extension GestureManager: GestureHandlerDelegate {

// MapView has been panned
internal func panned(by displacement: CGPoint) {
self.cameraManager.moveCamera(by: displacement, rotation: nil, pitch: nil, zoom: nil, animated: false)
self.cameraManager.moveCamera(by: displacement, rotation: nil, pitch: nil, zoom: nil, animated: false, pitchedDrift: false)
}

// Pan has ended on the MapView with a residual `offset`
internal func panEnded(with offset: CGPoint) {
if let pitch = self.cameraManager.mapView?.pitch,
pitch == 0.0 {
self.cameraManager.moveCamera(by: offset, rotation: nil, pitch: nil, zoom: nil, animated: true)
}
self.cameraManager.moveCamera(by: offset, rotation: nil, pitch: nil, zoom: nil, animated: true, pitchedDrift: true)
}

internal func cancelGestureTransitions() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -321,7 +321,7 @@ class CameraManagerTests: XCTestCase {
bearing: bearing,
animated: false)

let shiftedCenterCoordinate = cameraManager.shiftCenterCoordinate(by: offset)
let shiftedCenterCoordinate = cameraManager.shiftCenterCoordinate(by: offset, pitchedDrift: false)

XCTAssertGreaterThan(shiftedCenterCoordinate.longitude, 180, line: line)
}
Expand All @@ -337,7 +337,7 @@ class CameraManagerTests: XCTestCase {
bearing: bearing,
animated: false)

let shiftedCenterCoordinate = cameraManager.shiftCenterCoordinate(by: offset)
let shiftedCenterCoordinate = cameraManager.shiftCenterCoordinate(by: offset, pitchedDrift: false)

XCTAssertLessThan(shiftedCenterCoordinate.longitude, -180, line: line)
}
Expand Down
4 changes: 3 additions & 1 deletion Tests/MapboxMapsTests/Gestures/MockCameraManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,13 @@ final class MockCameraManager: CameraManagerProtocol {
completion: completion))
}

//swiftlint:disable function_parameter_count
func moveCamera(by offset: CGPoint?,
rotation: CGFloat?,
pitch: CGFloat?,
zoom: CGFloat?,
animated: Bool) {
animated: Bool,
pitchedDrift: Bool) {
}

func cancelTransitions() {
Expand Down