From aaab62f6a031781df2d5121dac3ce991f19deec7 Mon Sep 17 00:00:00 2001 From: Lauren Budorick Date: Wed, 16 May 2018 11:44:34 -0700 Subject: [PATCH 1/5] Break bounds calculation out of fitBounds --- src/ui/camera.js | 69 ++++++++++++++++++++++++++----------- test/unit/ui/camera.test.js | 33 ++++++++++++++++++ 2 files changed, 81 insertions(+), 21 deletions(-) diff --git a/src/ui/camera.js b/src/ui/camera.js index 5987a8312c5..f1588a06e1e 100644 --- a/src/ui/camera.js +++ b/src/ui/camera.js @@ -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 options + * @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 {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 + * @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.getFitBoundsTransform(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) { - + getFitBoundsTransform(bounds: LngLatBoundsLike, options?: CameraOptions): void | CameraOptions & AnimationOptions { options = extend({ padding: { top: 0, @@ -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); @@ -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 calculatedBounds = this.getFitBoundsTransform(bounds, options); + + // getFitBoundsTransform warns + returns undefined if unable to fit: + if (!calculatedBounds) return this; + + options = extend(calculatedBounds, options); + return options.linear ? this.easeTo(options, eventData) : this.flyTo(options, eventData); diff --git a/test/unit/ui/camera.test.js b/test/unit/ui/camera.test.js index 161a6aed921..cf45c89269d 100644 --- a/test/unit/ui/camera.test.js +++ b/test/unit/ui/camera.test.js @@ -1664,6 +1664,39 @@ test('camera', (t) => { t.end(); }); + t.test('#getFitBoundsTransform', (t) => { + t.test('no padding passed', (t) => { + const camera = createCamera(); + const bb = [[-133, 16], [-68, 50]]; + + const transform = camera.getFitBoundsTransform(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.getFitBoundsTransform(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.getFitBoundsTransform(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(); From a8d261a8977e73495ab166bfb57ea93b4fbda65f Mon Sep 17 00:00:00 2001 From: Lauren Budorick Date: Wed, 16 May 2018 13:58:08 -0700 Subject: [PATCH 2/5] fix docs --- src/ui/camera.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ui/camera.js b/src/ui/camera.js index f1588a06e1e..d2905ef176e 100644 --- a/src/ui/camera.js +++ b/src/ui/camera.js @@ -360,10 +360,10 @@ class Camera extends Evented { * @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 {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. + * @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. From 7e644a3e506fd5832323aa691e91237fafd9bd0e Mon Sep 17 00:00:00 2001 From: Lauren Budorick Date: Wed, 16 May 2018 22:11:17 -0700 Subject: [PATCH 3/5] code formatting for doc string --- src/ui/camera.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ui/camera.js b/src/ui/camera.js index d2905ef176e..87a6e692f2d 100644 --- a/src/ui/camera.js +++ b/src/ui/camera.js @@ -364,7 +364,7 @@ class Camera extends Evented { * @param {number | PaddingOptions} [options.padding] The amount of padding in pixels to add to the given bounds. * @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 camera would transition to the specified bounds. - * @returns {CameraOptions | void} If map is able to fit to provided bounds, returns CameraOptions with + * @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 From fe53494956bbf7af27b6e3277c9622b7a9da3a66 Mon Sep 17 00:00:00 2001 From: Lauren Budorick Date: Wed, 6 Jun 2018 11:37:51 -0700 Subject: [PATCH 4/5] rename getFitBoundsTransform -> cameraForBounds --- src/ui/camera.js | 8 ++++---- test/unit/ui/camera.test.js | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/ui/camera.js b/src/ui/camera.js index 87a6e692f2d..ae850423ce5 100644 --- a/src/ui/camera.js +++ b/src/ui/camera.js @@ -369,11 +369,11 @@ class Camera extends Evented { * `options` provided in arguments. If map is unable to fit, method will warn and return undefined. * @example * var bbox = [[-79, 43], [-73, 45]]; - * var newCameraTransform = map.getFitBoundsTransform(bbox, { + * var newCameraTransform = map.cameraForBounds(bbox, { * padding: {top: 10, bottom:25, left: 15, right: 5} * }); */ - getFitBoundsTransform(bounds: LngLatBoundsLike, options?: CameraOptions): void | CameraOptions & AnimationOptions { + cameraForBounds(bounds: LngLatBoundsLike, options?: CameraOptions): void | CameraOptions & AnimationOptions { options = extend({ padding: { top: 0, @@ -465,9 +465,9 @@ class Camera extends Evented { * @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 calculatedBounds = this.getFitBoundsTransform(bounds, options); + const calculatedBounds = this.cameraForBounds(bounds, options); - // getFitBoundsTransform warns + returns undefined if unable to fit: + // cameraForBounds warns + returns undefined if unable to fit: if (!calculatedBounds) return this; options = extend(calculatedBounds, options); diff --git a/test/unit/ui/camera.test.js b/test/unit/ui/camera.test.js index cf45c89269d..5efba5f8aa1 100644 --- a/test/unit/ui/camera.test.js +++ b/test/unit/ui/camera.test.js @@ -1664,12 +1664,12 @@ test('camera', (t) => { t.end(); }); - t.test('#getFitBoundsTransform', (t) => { + t.test('#cameraForBounds', (t) => { t.test('no padding passed', (t) => { const camera = createCamera(); const bb = [[-133, 16], [-68, 50]]; - const transform = camera.getFitBoundsTransform(bb); + 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(); @@ -1679,7 +1679,7 @@ test('camera', (t) => { const camera = createCamera(); const bb = [[-133, 16], [-68, 50]]; - const transform = camera.getFitBoundsTransform(bb, { padding: 15 }); + 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(); @@ -1689,7 +1689,7 @@ test('camera', (t) => { const camera = createCamera(); const bb = [[-133, 16], [-68, 50]]; - const transform = camera.getFitBoundsTransform(bb, { padding: {top: 10, right: 75, bottom: 50, left: 25}, duration: 0 }); + 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(); }); From c23a94287d6dde2d533b2342e574c763cc754ad1 Mon Sep 17 00:00:00 2001 From: Lauren Budorick Date: Thu, 7 Jun 2018 14:38:43 -0700 Subject: [PATCH 5/5] calculatedBounds -> calculatedOptions --- src/ui/camera.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ui/camera.js b/src/ui/camera.js index ae850423ce5..6216369aa25 100644 --- a/src/ui/camera.js +++ b/src/ui/camera.js @@ -465,12 +465,12 @@ class Camera extends Evented { * @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 calculatedBounds = this.cameraForBounds(bounds, options); + const calculatedOptions = this.cameraForBounds(bounds, options); // cameraForBounds warns + returns undefined if unable to fit: - if (!calculatedBounds) return this; + if (!calculatedOptions) return this; - options = extend(calculatedBounds, options); + options = extend(calculatedOptions, options); return options.linear ? this.easeTo(options, eventData) :