diff --git a/src/ui/popup.js b/src/ui/popup.js index c41e0cb90f6..7006e260bb7 100644 --- a/src/ui/popup.js +++ b/src/ui/popup.js @@ -577,27 +577,34 @@ export default class Popup extends Evented { if (!map || !container || !pos) return 'bottom'; + const padding = map.transform.padding; + const paddingTop = (padding.top || 0); + const paddingBottom = (padding.bottom || 0); + const paddingLeft = (padding.left || 0); + const paddingRight = (padding.right || 0); + const width = container.offsetWidth; const height = container.offsetHeight; - const isTop = pos.y + bottomY < height; - const isBottom = pos.y > map.transform.height - height; - const isLeft = pos.x < width / 2; - const isRight = pos.x > map.transform.width - width / 2; + const isTop = pos.y + bottomY < height + paddingTop; + const isLeft = pos.x < width / 2 + paddingLeft; + const isRight = pos.x > map.transform.width - width / 2 - paddingRight; + const isTopOnEitherSide = pos.y + bottomY < height / 2 + paddingTop; + const isBottomOnEitherSide = pos.y > map.transform.height - height / 2 - paddingBottom; - if (isTop) { - if (isLeft) return 'top-left'; - if (isRight) return 'top-right'; - return 'top'; + if (isLeft) { + if (isTopOnEitherSide) return 'top-left'; + if (isBottomOnEitherSide) return 'bottom-left'; + return 'left'; } - if (isBottom) { - if (isLeft) return 'bottom-left'; - if (isRight) return 'bottom-right'; + + if (isRight) { + if (isTopOnEitherSide) return 'top-right'; + if (isBottomOnEitherSide) return 'bottom-right'; + return 'right'; } - if (isLeft) return 'left'; - if (isRight) return 'right'; - return 'bottom'; + return isTop ? 'top' : 'bottom'; } _updateClassList() { diff --git a/test/unit/ui/popup.test.js b/test/unit/ui/popup.test.js index d01373e1fb0..94e0d16242f 100644 --- a/test/unit/ui/popup.test.js +++ b/test/unit/ui/popup.test.js @@ -479,6 +479,27 @@ test('Popup', (t) => { const point = args[1]; const transform = args[2]; + test('Popup respects padding and changes anchor accordingly', (t) => { + const map = createMap(t); + map.setPadding({top: 10, bottom: 10, left: 10, right: 10}); + const popup = new Popup() + .setText('Test') + .setLngLat([0, 0]) + .addTo(map); + map._domRenderTaskQueue.run(); + + Object.defineProperty(popup.getElement(), 'offsetWidth', {value: 5}); + Object.defineProperty(popup.getElement(), 'offsetHeight', {value: 5}); + + t.stub(map, 'project').returns(point); + t.stub(map.transform, 'locationPoint3D').returns(point); + popup.setLngLat([0, 0]); + map._domRenderTaskQueue.run(); + + t.ok(popup.getElement().classList.contains(`mapboxgl-popup-anchor-${anchor}`)); + t.end(); + }); + test(`Popup automatically anchors to ${anchor}`, (t) => { const map = createMap(t); const popup = new Popup()