Skip to content

Commit

Permalink
Split new bounds calculation out of fitBounds into new method
Browse files Browse the repository at this point in the history
  • Loading branch information
Lauren Budorick authored Jun 7, 2018
1 parent b9e32bf commit 2f3fa2b
Show file tree
Hide file tree
Showing 2 changed files with 82 additions and 22 deletions.
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

0 comments on commit 2f3fa2b

Please sign in to comment.