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

Split new bounds calculation out of fitBounds into new method #6683

Merged
merged 5 commits into from
Jun 7, 2018
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
71 changes: 49 additions & 22 deletions src/ui/camera.js
Original file line number Diff line number Diff line change
Expand Up @@ -355,35 +355,25 @@ class Camera extends Evented {
return this;
}


/**
* Pans and zooms the map to contain its visible area within the specified geographical bounds.
* This function will also reset the map's bearing to 0 if bearing is nonzero.
*
* @memberof Map#
* @param bounds Center these bounds in the viewport and use the highest
* zoom level up to and including `Map#getMaxZoom()` that fits them in the viewport.
* @param bounds Calculate the center for these bounds in the viewport and use
* the highest zoom level up to and including `Map#getMaxZoom()` that fits
* in the viewport.
* @param options
* @param {number | PaddingOptions} [options.padding] The amount of padding in pixels to add to the given bounds.
* @param {boolean} [options.linear=false] If `true`, the map transitions using
* {@link Map#easeTo}. If `false`, the map transitions using {@link Map#flyTo}. See
* those functions and {@link AnimationOptions} for information about options available.
* @param {Function} [options.easing] An easing function for the animated transition. See {@link AnimationOptions}.
* @param {PointLike} [options.offset=[0, 0]] The center of the given bounds relative to the map's center, measured in pixels.
* @param {number} [options.maxZoom] The maximum zoom level to allow when the map view transitions to the specified bounds.
* @param eventData Additional properties to be added to event objects of events triggered by this method.
* @fires movestart
* @fires moveend
* @returns {Map} `this`
* @example
* @param {number} [options.maxZoom] The maximum zoom level to allow when the camera would transition to the specified bounds.
* @returns {CameraOptions | void} If map is able to fit to provided bounds, returns `CameraOptions` with
* at least `center`, `zoom`, `bearing`, `offset`, `padding`, and `maxZoom`, as well as any other
* `options` provided in arguments. If map is unable to fit, method will warn and return undefined.
* @example
* var bbox = [[-79, 43], [-73, 45]];
* map.fitBounds(bbox, {
* var newCameraTransform = map.cameraForBounds(bbox, {
* padding: {top: 10, bottom:25, left: 15, right: 5}
* });
* @see [Fit a map to a bounding box](https://www.mapbox.com/mapbox-gl-js/example/fitbounds/)
*/
fitBounds(bounds: LngLatBoundsLike, options?: AnimationOptions & CameraOptions, eventData?: Object) {

cameraForBounds(bounds: LngLatBoundsLike, options?: CameraOptions): void | CameraOptions & AnimationOptions {
options = extend({
padding: {
top: 0,
Expand Down Expand Up @@ -412,7 +402,7 @@ class Camera extends Evented {
warnOnce(
"options.padding must be a positive number, or an Object with keys 'bottom', 'left', 'right', 'top'"
);
return this;
return;
}

bounds = LngLatBounds.convert(bounds);
Expand All @@ -438,13 +428,50 @@ class Camera extends Evented {
warnOnce(
'Map cannot fit within canvas with the given bounds, padding, and/or offset.'
);
return this;
return;
}

options.center = tr.unproject(nw.add(se).div(2));
options.zoom = Math.min(tr.scaleZoom(tr.scale * Math.min(scaleX, scaleY)), options.maxZoom);
options.bearing = 0;

return options;
}

/**
* Pans and zooms the map to contain its visible area within the specified geographical bounds.
* This function will also reset the map's bearing to 0 if bearing is nonzero.
*
* @memberof Map#
* @param bounds Center these bounds in the viewport and use the highest
* zoom level up to and including `Map#getMaxZoom()` that fits them in the viewport.
* @param options
* @param {number | PaddingOptions} [options.padding] The amount of padding in pixels to add to the given bounds.
* @param {boolean} [options.linear=false] If `true`, the map transitions using
* {@link Map#easeTo}. If `false`, the map transitions using {@link Map#flyTo}. See
* those functions and {@link AnimationOptions} for information about options available.
* @param {Function} [options.easing] An easing function for the animated transition. See {@link AnimationOptions}.
* @param {PointLike} [options.offset=[0, 0]] The center of the given bounds relative to the map's center, measured in pixels.
* @param {number} [options.maxZoom] The maximum zoom level to allow when the map view transitions to the specified bounds.
* @param eventData Additional properties to be added to event objects of events triggered by this method.
* @fires movestart
* @fires moveend
* @returns {Map} `this`
* @example
* var bbox = [[-79, 43], [-73, 45]];
* map.fitBounds(bbox, {
* padding: {top: 10, bottom:25, left: 15, right: 5}
* });
* @see [Fit a map to a bounding box](https://www.mapbox.com/mapbox-gl-js/example/fitbounds/)
*/
fitBounds(bounds: LngLatBoundsLike, options?: AnimationOptions & CameraOptions, eventData?: Object) {
const calculatedOptions = this.cameraForBounds(bounds, options);

// cameraForBounds warns + returns undefined if unable to fit:
if (!calculatedOptions) return this;

options = extend(calculatedOptions, options);

return options.linear ?
this.easeTo(options, eventData) :
this.flyTo(options, eventData);
Expand Down
33 changes: 33 additions & 0 deletions test/unit/ui/camera.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -1664,6 +1664,39 @@ test('camera', (t) => {
t.end();
});

t.test('#cameraForBounds', (t) => {
t.test('no padding passed', (t) => {
const camera = createCamera();
const bb = [[-133, 16], [-68, 50]];

const transform = camera.cameraForBounds(bb);
t.deepEqual(fixedLngLat(transform.center, 4), { lng: -100.5, lat: 34.7171 }, 'correctly calculates coordinates for new bounds');
t.equal(fixedNum(transform.zoom, 3), 2.469);
t.end();
});

t.test('padding number', (t) => {
const camera = createCamera();
const bb = [[-133, 16], [-68, 50]];

const transform = camera.cameraForBounds(bb, { padding: 15 });
t.deepEqual(fixedLngLat(transform.center, 4), { lng: -100.5, lat: 34.7171 }, 'correctly calculates coordinates for bounds with padding option as number applied');
t.equal(fixedNum(transform.zoom, 3), 2.382);
t.end();
});

t.test('padding object', (t) => {
const camera = createCamera();
const bb = [[-133, 16], [-68, 50]];

const transform = camera.cameraForBounds(bb, { padding: {top: 10, right: 75, bottom: 50, left: 25}, duration: 0 });
t.deepEqual(fixedLngLat(transform.center, 4), { lng: -100.5, lat: 34.7171 }, 'correctly calculates coordinates for bounds with padding option as object applied');
t.end();
});

t.end();
});

t.test('#fitBounds', (t) => {
t.test('no padding passed', (t) => {
const camera = createCamera();
Expand Down