Skip to content
This repository has been archived by the owner on Jun 14, 2024. It is now read-only.

Blocking map gestures delegate example #65

Merged
merged 3 commits into from
May 5, 2017

Conversation

fabian-guerra
Copy link
Contributor

No description provided.

Copy link
Contributor

@1ec5 1ec5 left a comment

Choose a reason for hiding this comment

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

This assumes the physical distance between the old center and old northeast corner is equal to the physical distance between the new center and the new northeast corner. Because the map uses Mercator projection, the latitude lines aren’t evenly spaced. So the center may change by a different amount than the top and bottom edges of the view. I’d imagine this issue would be most apparent when dramatically swiping the map north or south to either pole. You can mitigate this issue by restricting the map to high zoom levels, but that would limit the example’s usefulness.

Moreover, if the user rotates the map, these calculations can become severely inaccurate. You could mitigate this issue by turning off rotation.

An alternative approach would be to “set and revert” within mapView(_:shouldChangeFrom:to:): store the current camera as camera, set mapView.camera to newCamera, store the visibleCoordinateBounds in a local variable, and set mapView.camera back to camera. (I’d avoid relying on oldCamera to equal mapView.camera, because we may figure out a way to batch up calls to mapView(_:shouldChangeFrom:to:) in the future.)

// Colorado's bounds
let ne = CLLocationCoordinate2D(latitude: 40.989329, longitude: -102.062592)
let sw = CLLocationCoordinate2D(latitude: 36.986207, longitude: -109.049896)
colorado = MGLCoordinateBoundsMake(sw, ne)
Copy link
Contributor

Choose a reason for hiding this comment

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

Use MGLCoordinateBounds(sw:ne:) instead of MGLCoordinateBoundsMake(_:_:).

@boundsj
Copy link

boundsj commented Feb 15, 2017

I think it'd be interesting to do a performance comparison with the approach already in this PR and the approach outlined in #65 (review). A less accurate, limited solution may still be useful for cases involving offline maps that usually involve higher zoom levels.

MGLMapView *mapView = [[MGLMapView alloc] initWithFrame:self.view.bounds];
mapView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
mapView.rotateEnabled = NO;
mapView.minimumZoomLevel = 10;
Copy link
Contributor

Choose a reason for hiding this comment

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

Is it still necessary to disable rotation and cap the zoom level, now that you’re doing the set-and-revert dance?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The example I made deals with rotation but I considered was not important for restricting boundaries, I reverted this.

CLLocationCoordinate2D newCameraCenter = newCamera.centerCoordinate;
MGLMapCamera *camera = mapView.camera;

// Get new bounds
Copy link
Contributor

Choose a reason for hiding this comment

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

These comments say what the developer is expected to do, but not why. An example needs to explain the rationale behind each non-obvious step, in order to avoid the phenomenon of cargo cult programming. In particular, we should be explicit about the fact that we’re changing and resetting the map view’s camera in order to predict the extents of the new viewport.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I changed the comments to make it more explicit.


// Test if the new camera center point and boundaries are inside colorado
BOOL inside = MGLCoordinateInCoordinateBounds(newCameraCenter, self.colorado);
BOOL intersects = MGLCoordinateInCoordinateBounds(newVisibleCoordinates.ne, self.colorado) && MGLCoordinateInCoordinateBounds(newVisibleCoordinates.sw, self.colorado);
Copy link
Contributor

Choose a reason for hiding this comment

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

Ah, I see why you’ve restricted the zoom level and disabled rotation. Can you think of a way to test whether the new viewport would fit inside the allowed region (Colorado) while accounting for rotation? Perhaps the logic in turf-inside would be helpful here, although it might be overkill.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'm already taking a similar approach like function inBBox and also accounts for restricting rotation if its out of boundaries.

Copy link
Contributor

Choose a reason for hiding this comment

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

Yes, this code is fine. I was mistaken previously in thinking that this logic would produce incorrect results when the map is rotated, but the visible coordinate bounds will extend beyond the allowed region. This logic would not work if the map is tilted or if the allowed region itself is rotated.

@fabian-guerra fabian-guerra force-pushed the fabian-block-gesture-delegate branch from 0cb288e to 84d7528 Compare May 4, 2017 15:19
@fabian-guerra
Copy link
Contributor Author

@1ec5 @captainbarbosa @jmkiley could you please take a look.

Copy link
Contributor

@1ec5 1ec5 left a comment

Choose a reason for hiding this comment

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

A couple minor style notes, but otherwise this is good to go.

// Test if the newCameraCenter and newVisibleCoordinates
// are inside self.colorado
let inside: Bool = MGLCoordinateInCoordinateBounds(newCameraCenter, self.colorado)
let intersects: Bool = MGLCoordinateInCoordinateBounds(newVisibleCoordinates.ne, self.colorado) && MGLCoordinateInCoordinateBounds(newVisibleCoordinates.sw, self.colorado)
Copy link
Contributor

Choose a reason for hiding this comment

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

Nit: drop self., since it’s implied.

}

// This example uses Colorado's boundaries to restrict
// the camera movement
Copy link
Contributor

Choose a reason for hiding this comment

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

The use of a period at the end of a comment is inconsistent in this file. Here there’s no period at the end of the sentence; above, “Starting point” does end with a period, even though it isn’t a sentence. Normally I end all the comments with periods if any of them is a sentence.


// From the new camera obtain the center to test
// if it's inside the boundaries
let newCameraCenter: CLLocationCoordinate2D = newCamera.centerCoordinate
Copy link
Contributor

Choose a reason for hiding this comment

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

Nit: centerCoordinate’s type is inferred as CLLocationCoordinate2D, so there’s no need to declare newCameraCenter’s type here. (Same with inside and intersects below.)

@fabian-guerra fabian-guerra merged commit 1a05713 into master May 5, 2017
@fabian-guerra fabian-guerra deleted the fabian-block-gesture-delegate branch May 5, 2017 14:06
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants