-
Notifications
You must be signed in to change notification settings - Fork 1.3k
[ios] shouldChangeFromCamera doesn't allow for constraining the camera to specific bounds #9368
Comments
MGLMapCamera is a value class. Merely modifying its properties won’t cause a map view to change: #8930. So you’d need to set the map view’s |
Setting the map view's - (BOOL)mapView:(MGLMapView *)mapView shouldChangeFromCamera:(MGLMapCamera *)oldCamera toCamera:(MGLMapCamera *)newCamera {
if (MGLCoordinateInCoordinateBounds(newCamera.centerCoordinate, self.mapManager.mapBounds)) {
return YES;
}
MGLMapCamera *camera = newCamera.copy;
CLLocationDegrees lat = camera.centerCoordinate.latitude;
CLLocationDegrees lon = camera.centerCoordinate.longitude;
if (camera.centerCoordinate.latitude < self.mapManager.mapBounds.sw.latitude) {
lat = self.mapManager.mapBounds.sw.latitude;
} else if (camera.centerCoordinate.latitude > self.mapManager.mapBounds.ne.latitude) {
lat = self.mapManager.mapBounds.ne.latitude;
}
if (camera.centerCoordinate.longitude < self.mapManager.mapBounds.sw.longitude) {
lon = self.mapManager.mapBounds.sw.longitude;
} else if (camera.centerCoordinate.longitude > self.mapManager.mapBounds.ne.longitude) {
lon = self.mapManager.mapBounds.ne.longitude;
}
camera.centerCoordinate = CLLocationCoordinate2DMake(lat, lon);
[mapView setCamera:camera animated:NO];
return NO;
} |
I wonder if the glitchy/jumpy behavior is due to #9344. |
Will test with ios-v3.6.0-rc.1 and report back this week |
@1ec5 still seeing the same issues with 3.6 Would it be possible for MapView to have a |
Could you post a screen recording showing the behavior you’re seeing? I tried the code above on both iOS and macOS (which has a slightly different implementation that might be more robust), but it didn’t look jumpy to me, so I’m probably missing something.
Given the existing delegate method, it would be unfortunate to expose a redundant property like the one proposed in #2341. However, I realize that the current workflow is tedious for the simple case of restricting to a particular bounding box. (#8499 would improve the ergonomics around this delegate method.) Hopefully we can make this API work as intended and improve the ergonomics so it feels as natural as a simple property would be. |
Sorry for the long update, but i think we can close this issue. I am able to get what i want by clamping the |
@epau Would you mind sharing your solution? I tried a similar approach, but it resulted in some undesired zooming behavior when hitting the outer bounds. Perhaps my approach was too naive, though. I've put up an example project. At this point, my guess is that the |
@erikvdwal my solution looks almost identical to yours. Here's my clamping logc fwiw. Could you explain the "undesired zooming behavior"? |
@epau Thanks! You should be able to reproduce the behavior I was describing if you run that example project. Basically, If you aren't zoomed out entirely and you pan towards - and hit - one of the edges of the bounding box, the map will start zooming out until you hit the minimum zoom level. Edit: here's a gif |
We're still struggling with a solution here. Is there a way we can properly set a bounding box to restrict the camera to? |
@erikvdwal, that project uses I would recommend an implementation of let clampedCamera = newCamera
// Lots of assumptions; the rest is left as an exercise to the reader.
if oldCamera.altitude == newCamera.altitude && oldCamera.heading == newCamera.heading && newCamera.heading = 0 && oldCamera.pitch == newCamera.pitch && newCamera.pitch == 0 {
// If panning upward beyond the maximum coordinate bounds…
if newCamera.ne.latitude > maximumCoordinateBounds.ne.latitude {
// Where would the northernmost allowed coordinate be on screen before changing the camera?
let clampedTopRight = mapView.convert(maximumCoordinateBounds.ne, toPointTo: mapView)
// The map view is the same size regardless of latitude, so offset the top-right point to find the corresponding center point.
let clampedCenter = CGPoint(x: clampedTopRight.x, y: clampedTopRight.y + mapView.bounds.midY)
// What coordinate would that center point correspond to before changing the camera?
clampedCamera.center = mapView.convert(clampedCenter, toCoordinateFrom: mapView)
}
}
// … Clamping the visible coordinate bounds on a rotated or tilted map would be a particular challenge. There may be an opportunity for Turf to provide helper methods to facilitate these calculations. Not sure if any Turf.js methods can be ported over for that. |
This issue has been automatically detected as stale because it has not had recent activity and will be archived. Thank you for your contributions. |
Platform: iOS
Mapbox SDK version: 3.5
I talked to @1ec5 about this a little bit at WWDC '17, my apologies for posting this so late!!
The Problem
I want to constrain the viewport such as to not allow scrolling past some MGLCoordinateBounds (ie ne = (10,10) and sw = (-10,-10)).
I'm currently trying to implement this using the following delegate method:
- (BOOL)mapView:(MGLMapView *)mapView shouldChangeFromCamera:(MGLMapCamera *)oldCamera toCamera:(MGLMapCamera *)newCamera
This falls short however because I cannot force the camera to move to the bounds, I can only tell it to not move at all (simplified example: bounds = 10, old = 0, new = 15. I'd want to move to 10 but that is not currently possible)
Modifying properties on the
newCamera
instance has no effect since it it's properties aren't used after the delegate call (from MGLMapView.mm handlePanGesture)Potential Solution
It would be great to have modifications to
newCamera
in the delegate method affect the final result or to have some property/delegate method to restrict the viewport.The text was updated successfully, but these errors were encountered: