Skip to content

Commit

Permalink
Fix #7517 - asymmetrical cameraForBounds (#7518)
Browse files Browse the repository at this point in the history
* Fix #7517 - asymmetrical cameraForBounds

* Add tests for asymmetrical cameraForBounds

* Added debug file for #7517

* Fix lint errors in debug file

* Make sure offset can be an object
  • Loading branch information
mike-marcacci authored and mourner committed Oct 31, 2018
1 parent e50fa34 commit ea9fbee
Show file tree
Hide file tree
Showing 3 changed files with 196 additions and 19 deletions.
137 changes: 137 additions & 0 deletions debug/7517.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
<!DOCTYPE html>
<html>

<head>
<title>Mapbox GL JS debug page</title>
<meta charset='utf-8'>
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
<link rel='stylesheet' href='/dist/mapbox-gl.css' />
<style>
body {
margin: 0;
padding: 0;
}

html,
body,
#map {
height: 100%;
}
</style>
</head>

<body>
<div id='map'></div>

<script src='/dist/mapbox-gl-dev.js'></script>
<script src='/debug/access_token_generated.js'></script>
<script>
const data = {
'type': 'Feature',
'geometry': {
'type': 'Polygon',
'coordinates': [
[
[-67.13734351262877, 45.137451890638886],
[-66.96466, 44.8097],
[-68.03252, 44.3252],
[-69.06, 43.98],
[-70.11617, 43.68405],
[-70.64573401557249, 43.090083319667144],
[-70.75102474636725, 43.08003225358635],
[-70.79761105007827, 43.21973948828747],
[-70.98176001655037, 43.36789581966826],
[-70.94416541205806, 43.46633942318431],
[-71.08482, 45.3052400000002],
[-70.6600225491012, 45.46022288673396],
[-70.30495378282376, 45.914794623389355],
[-70.00014034695016, 46.69317088478567],
[-69.23708614772835, 47.44777598732787],
[-68.90478084987546, 47.184794623394396],
[-68.23430497910454, 47.35462921812177],
[-67.79035274928509, 47.066248887716995],
[-67.79141211614706, 45.702585354182816],
[-67.13734351262877, 45.137451890638886]
]
]
}
};

const maineBBox = [-71.08482,
43.08003225358635, -66.96466,
47.44777598732787
];

const maineBBoxPolygon = {
"type": "Feature",
"properties": {},
"geometry": {
"type": "Polygon",
"coordinates": [
[
[-71.08482, 43.08003225358635],
[-66.96466, 43.08003225358635],
[-66.96466, 47.44777598732787],
[-71.08482, 47.44777598732787],
[-71.08482, 43.08003225358635]
]
]
}
};

const map = new mapboxgl.Map({
container: 'map',
style: 'mapbox://styles/mapbox/streets-v9',
center: [-68.13734351262877, 45.137451890638886],
zoom: 5
});

map.on('load', function() {
map.addLayer({
'id': 'maine',
'type': 'fill',
'source': {
'type': 'geojson',
'data': data
},
'layout': {},
'paint': {
'fill-color': '#088',
'fill-opacity': 0.8
}
});
map.addLayer({
'id': 'maine-bbox',
'type': 'line',
'source': {
'type': 'geojson',
'data': maineBBoxPolygon
},
'layout': {},
'paint': {
'line-color': 'red',
'line-width': 2
}
});

const camera = map.cameraForBounds(maineBBox, {
padding: {
top: 0,
right: 20,
bottom: 100,
left: 20
},
offset: [100, 0]
});

map.easeTo({
center: camera.center,
zoom: camera.zoom,
bearing: camera.bearing
});

});
</script>
</body>

</html>
40 changes: 22 additions & 18 deletions src/ui/camera.js
Original file line number Diff line number Diff line change
Expand Up @@ -434,17 +434,9 @@ class Camera extends Evented {
return;
}

// we separate the passed padding option into two parts, the part that does not affect the map's center
// (lateral and vertical padding), and the part that does (paddingOffset). We add the padding offset
// to the options `offset` object where it can alter the map's center in the subsequent calls to
// `easeTo` and `flyTo`.
const paddingOffset = [(options.padding.left - options.padding.right) / 2, (options.padding.top - options.padding.bottom) / 2],
lateralPadding = Math.min(options.padding.right, options.padding.left),
verticalPadding = Math.min(options.padding.top, options.padding.bottom);
options.offset = [options.offset[0] + paddingOffset[0], options.offset[1] + paddingOffset[1]];

const tr = this.transform;
// we want to calculate the upper right and lower left of the box defined by p0 and p1

// We want to calculate the upper right and lower left of the box defined by p0 and p1
// in a coordinate system rotate to match the destination bearing.
const p0world = tr.project(LngLat.convert(p0));
const p1world = tr.project(LngLat.convert(p1));
Expand All @@ -454,22 +446,34 @@ class Camera extends Evented {
const upperRight = new Point(Math.max(p0rotated.x, p1rotated.x), Math.max(p0rotated.y, p1rotated.y));
const lowerLeft = new Point(Math.min(p0rotated.x, p1rotated.x), Math.min(p0rotated.y, p1rotated.y));

const offset = Point.convert(options.offset),
size = upperRight.sub(lowerLeft),
scaleX = (tr.width - lateralPadding * 2 - Math.abs(offset.x) * 2) / size.x,
scaleY = (tr.height - verticalPadding * 2 - Math.abs(offset.y) * 2) / size.y;
// Calculate zoom: consider the original bbox and padding.
const size = upperRight.sub(lowerLeft);
const scaleX = (tr.width - options.padding.left - options.padding.right) / size.x;
const scaleY = (tr.height - options.padding.top - options.padding.bottom) / size.y;

if (scaleY < 0 || scaleX < 0) {
warnOnce(
'Map cannot fit within canvas with the given bounds, padding, and/or offset.'
);
return;
}
options.center = tr.unproject(p0world.add(p1world).div(2));
options.zoom = Math.min(tr.scaleZoom(tr.scale * Math.min(scaleX, scaleY)), options.maxZoom);
options.bearing = bearing;

return options;
const zoom = Math.min(tr.scaleZoom(tr.scale * Math.min(scaleX, scaleY)), options.maxZoom);

// Calculate center: apply the zoom, the configured offset, as well as offset that exists as a result of padding.
const offset = Point.convert(options.offset);
const paddingOffsetX = (options.padding.left - options.padding.right) / 2;
const paddingOffsetY = (options.padding.top - options.padding.bottom) / 2;
const offsetAtInitialZoom = new Point(offset.x + paddingOffsetX, offset.y + paddingOffsetY);
const offsetAtFinalZoom = offsetAtInitialZoom.mult(tr.scale / tr.zoomScale(zoom));

const center = tr.unproject(p0world.add(p1world).div(2).sub(offsetAtFinalZoom));

return {
center,
zoom,
bearing
};
}

/**
Expand Down
38 changes: 37 additions & 1 deletion test/unit/ui/camera.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -1714,11 +1714,47 @@ test('camera', (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 });
const transform = camera.cameraForBounds(bb, { padding: {top: 15, right: 15, bottom: 15, left: 15}, 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.test('asymetrical padding', (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: -96.5558, lat: 32.0833 }, 'correctly calculates coordinates for bounds with padding option as object applied');
t.end();
});

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

const transform = camera.cameraForBounds(bb, { offset: [0, 100] });
t.deepEqual(fixedLngLat(transform.center, 4), { lng: -100.5, lat: 44.4717 }, 'correctly calculates coordinates for bounds with padding option as object applied');
t.end();
});

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

const transform = camera.cameraForBounds(bb, { offset: { x: 0, y: 100 } });
t.deepEqual(fixedLngLat(transform.center, 4), { lng: -100.5, lat: 44.4717 }, 'correctly calculates coordinates for bounds with padding option as object applied');
t.end();
});

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

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

t.end();
});

Expand Down

0 comments on commit ea9fbee

Please sign in to comment.