Mapbox-gl-js: Allow "fitBounds" to span the date line

Created on 9 Apr 2016  Â·  7Comments  Â·  Source: mapbox/mapbox-gl-js

mapbox-gl-js version:

Steps to Trigger Behavior

  1. Use fitBounds with correct SW/NE argument ordering and expect that a dateline-crossing bounds is accepted

    Expected Behavior

The map is centered over the dateline over a certain polygon.

Actual Behavior

The fitBounds constructor calls LatLngBounds convert, which claims to support a specific argument order but really doesn't differentiate if the arguments are flipped ( see https://github.com/mapbox/mapbox-gl-js/pull/2414 for a PR). Even when the arguments are treated as strict, the fitBounds algorithm also doesn't handle the case of a dateline-crossing extent.

bug

Most helpful comment

Thanks @mollymerp!
It'd be nice if fitBounds would take care of this step as we most always want to frame the bounds accross the smallest area possibility.

All 7 comments

related to #2112

Example of _fitBounds_ around Alaska, since Alaska crosses the antimeridian:

map.fitBounds([[172.461667,71.365162],[-129.979511,51.214183]])

The above does not fit bounds around the given coordinates.

Needed this fixed and came up with the following solution (//! marks the changed lines):

In camera.js:

fitBounds: function(bounds, options, eventData) {

        options = util.extend({
            padding: 0,
            offset: [0, 0],
            maxZoom: Infinity
        }, options);

        bounds = LngLatBounds.convert(bounds);

        //! Fix to allow fitting bounds that cross the antimeridian
        var w = bounds.getWest(), //!
            e = bounds.getEast(), //!
            n = bounds.getNorth(), //!
            s = bounds.getSouth(); //!

        var offset = Point.convert(options.offset), //!
            tr = this.transform, //!
            y1 = tr.project(new LngLat(0, s)), //!
            y2 = tr.project(new LngLat(0, n)), //!
            sizeY = y1.sub(y2), //!
            scaleY = (tr.height - options.padding * 2 - Math.abs(offset.y) * 2) / sizeY.y, //!
            x1 = tr.project(new LngLat(e, 0)), //!
            x2 = w < e ? tr.project(new LngLat(w, 0)) : tr.project(new LngLat(-360 + w, 0)), //!
            sizeX = x1.sub(x2), //!
            scaleX = (tr.width - options.padding * 2 - Math.abs(offset.x) * 2) / sizeX.x; //!

        var lat = tr.unproject(y1.add(y2).div(2)).lat; //!

        var lng = w < e ? (w + e) / 2 : (-360 + w + e) / 2; //!
        lng = lng < -180 ? (lng + 360) % 180 : lng; //!

        options.center = new LngLat(lng, lat); //!
        options.zoom = Math.min(tr.scaleZoom(tr.scale * Math.min(scaleX, scaleY)), options.maxZoom);
        options.bearing = 0;

        return options.linear ?
            this.easeTo(options, eventData) :
            this.flyTo(options, eventData);
    },

Also needed to change lng_lat_bounds.js as not to be too smart about what's west and what's east:

        } else {
            sw.lng = sw.lng; //!
            sw.lat = Math.min(sw2.lat, sw.lat);
            ne.lng = ne2.lng; //!
            ne.lat = Math.max(ne2.lat, ne.lat);
        }

The above fix in lng_lat_bounds.js is a breaking change depending on how people had used this function, i.e. if they relied on this functionality that east and west are swapped. Using LngLat and LngLatBounds as arguments to _fitBounds_ will work even without that fix.

This is quick and dirty, but solves the problem temporarily for me. There is obviously an intrinsic problem in mapbox-gl-js with LngLatBounds that cross the antimeridian and should be solved deeper in the core.

Is there a solution planned to fix this bug?
There doesn't seem to be any viable alternative solutions and it's quite an important feature (we're holding up our release of flight maps because they don't work for Flights across the Pacific ocean).
If it's not planned anytime soon, we'd rather know. thanks,

@iplanwebsites this was fixed in #2414 – you do have to add/subtract 180 to one of the points depending on which way you want to cross the date line http://jsbin.com/newaguliju/1/edit?html,output

Thanks @mollymerp!
It'd be nice if fitBounds would take care of this step as we most always want to frame the bounds accross the smallest area possibility.

you do have to add/subtract 180

It would be 360 degrees, right? And can you do that to all lat/lon pairs to force this behavior, or do you generally need to pay attention to whether a particular bounding box crosses the date line and only make the modification in that case?

Was this page helpful?
0 / 5 - 0 ratings

Related issues

foundryspatial-duncan picture foundryspatial-duncan  Â·  3Comments

PBrockmann picture PBrockmann  Â·  3Comments

aaronlidman picture aaronlidman  Â·  3Comments

mollymerp picture mollymerp  Â·  3Comments

shotor picture shotor  Â·  3Comments