Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 10 additions & 5 deletions src/ui/popup.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import {extend, bindAll} from '../util/util.js';
import {Event, Evented} from '../util/evented.js';
import {MapMouseEvent} from '../ui/events.js';
import {MapMouseEvent} from './events.js';
import DOM from '../util/dom.js';
import LngLat from '../geo/lng_lat.js';
import Point from '@mapbox/point-geometry';
Expand All @@ -19,7 +19,8 @@ const defaultOptions = {
closeOnClick: true,
focusAfterOpen: true,
className: '',
maxWidth: "240px"
maxWidth: "240px",
anchorPreference: 'bottom'
};

export type Offset = number | PointLike | {[_: Anchor]: PointLike};
Expand All @@ -32,7 +33,8 @@ export type PopupOptions = {
anchor?: Anchor,
offset?: Offset,
className?: string,
maxWidth?: string
maxWidth?: string,
anchorPreference: Anchor
};

const focusQuerySelector = [
Expand All @@ -57,6 +59,9 @@ const focusQuerySelector = [
* map moves.
* @param {boolean} [options.focusAfterOpen=true] If `true`, the popup will try to focus the
* first focusable element inside the popup.
* @param {string} [options.anchorPreference='bottom'] - A string to set the preference for where the anchor will be
* dynamically set. Options are `'center'`, `'top'`, `'bottom'`, `'left'`, `'right'`, `'top-left'`, `'top-right'`,
* `'bottom-left'`, and `'bottom-right'`.
* @param {string} [options.anchor] - A string indicating the part of the popup that should
* be positioned closest to the coordinate, set via {@link Popup#setLngLat}.
* Options are `'center'`, `'top'`, `'bottom'`, `'left'`, `'right'`, `'top-left'`,
Expand All @@ -67,7 +72,7 @@ const focusQuerySelector = [
* A pixel offset applied to the popup's location specified as:
* - a single number specifying a distance from the popup's location
* - a {@link PointLike} specifying a constant offset
* - an object of {@link Point}s specifing an offset for each anchor position.
* - an object of {@link Point}s specifying an offset for each anchor position.
*
* Negative offsets indicate left and up.
* @param {string} [options.className] Space-separated CSS class names to add to popup container.
Expand Down Expand Up @@ -575,7 +580,7 @@ export default class Popup extends Evented {
}

if (anchorComponents.length === 0) {
return 'bottom';
return this.options.anchorPreference;
}
return ((anchorComponents.join('-'): any): Anchor);

Expand Down
24 changes: 24 additions & 0 deletions test/unit/ui/popup.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -480,6 +480,30 @@ test('Popup automatically anchors to top if its bottom offset would push it off-
t.end();
});

test('Popup automatically anchors to the user specified preferred position if will be on-screen', (t) => {
const map = createMap(t);
const point = new Point(containerWidth / 2, containerHeight / 2);
const options = {offset: {
'bottom': [0, 0],
'top': [0, 0]
}, anchorPreference: 'left'};
const popup = new Popup(options)
.setLngLat([0, 0])
.setText('Test')
.addTo(map);
map._domRenderTaskQueue.run();

Object.defineProperty(popup.getElement(), 'offsetWidth', {value: containerWidth / 2});
Object.defineProperty(popup.getElement(), 'offsetHeight', {value: containerHeight / 2});

t.stub(map, 'project').returns(point);
popup.setLngLat([0, 0]);
map._domRenderTaskQueue.run();

t.ok(popup.getElement().classList.contains('mapboxgl-popup-anchor-left'));
t.end();
});

test('Popup is offset via a PointLike offset option', (t) => {
const map = createMap(t);
t.stub(map, 'project').returns(new Point(0, 0));
Expand Down