@geogirafe/lib-geoportal
Version:
GeoGirafe is a flexible application to build online geoportals.
172 lines (171 loc) • 5.63 kB
JavaScript
import { Overlay } from 'ol';
import UserInteractionManager from '../../../tools/state/userInteractionManager';
import MapManager from '../../../tools/state/mapManager';
import { v4 as uuidv4 } from 'uuid';
/**
* Show a simple context menu when clicking on the map
*/
export class ContextMenu {
constructor(menuEntries = [], isExclusive = false, openCondition = () => true) {
Object.defineProperty(this, "name", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
Object.defineProperty(this, "_active", {
enumerable: true,
configurable: true,
writable: true,
value: false
});
Object.defineProperty(this, "isExclusive", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
Object.defineProperty(this, "map", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
Object.defineProperty(this, "overlay", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
Object.defineProperty(this, "container", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
Object.defineProperty(this, "userInteractionManager", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
Object.defineProperty(this, "openEventListener", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
Object.defineProperty(this, "closeEventListener", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
this.name = `contextmenu-${uuidv4()}`;
this.map = MapManager.getInstance().getMap();
this.userInteractionManager = UserInteractionManager.getInstance();
this.isExclusive = isExclusive;
this.container = document.createElement('div');
this.container.classList.add('contextmenu');
this.container.classList.add('hidden');
this.updateMenuEntries(menuEntries);
this.overlay = new Overlay({
element: this.container,
position: undefined
});
this.map.addOverlay(this.overlay);
this.openEventListener = (evt) => {
if (this.userInteractionManager.canListenerExecute('map.contextmenu', this.name)) {
this.handleContextmenuEvent(evt, openCondition);
}
};
this.closeEventListener = (_evt) => {
if (!this.active) {
return;
}
if (this.visible) {
this.closeMenu();
}
};
this.enable();
}
get visible() {
return !!this.overlay.getPosition();
}
get active() {
return this._active;
}
setActive(active) {
if (active) {
this.enable();
}
else {
this.disable();
}
}
enable() {
if (this.userInteractionManager.registerListener('map.contextmenu', this.isExclusive, this.name)) {
this.map.getViewport().addEventListener('contextmenu', this.openEventListener);
}
this.map.getViewport().addEventListener('click', this.closeEventListener);
this._active = true;
}
disable() {
this._active = false;
this.userInteractionManager.unregisterAllListenersOfTool(this.name);
this.map.getViewport().removeEventListener('contextmenu', this.openEventListener);
this.map.getViewport().removeEventListener('click', this.closeEventListener);
}
handleContextmenuEvent(evt, openCondition) {
if (!this._active) {
return;
}
if (this.visible) {
this.closeMenu();
}
evt.preventDefault();
const mapCoordinate = this.map.getCoordinateFromPixel([evt.offsetX, evt.offsetY]);
if (openCondition(evt, mapCoordinate)) {
this.openMenu(mapCoordinate);
}
else {
evt.stopPropagation();
}
}
updateMenuEntries(menuEntries) {
this.container.replaceChildren('');
menuEntries.forEach((entry) => {
const div = document.createElement('div');
div.classList.add('menu-entry');
div.innerHTML = entry.entry;
div.addEventListener('click', (evt) => this.onClickMenuEntry(evt, entry.callback));
this.container.appendChild(div);
});
}
openMenu(mapCoordinates) {
if (!this.container.parentNode) {
// Add menu to the DOM
const popupDiv = document.getElementById('map-contextmenu');
popupDiv?.appendChild(this.container);
}
this.overlay.setPosition(mapCoordinates);
this.container.classList.remove('hidden');
}
closeMenu() {
this.overlay.setPosition(undefined);
this.container.classList.add('hidden');
}
onClickMenuEntry(evt, callback) {
try {
callback(evt, this.overlay.getPosition());
}
finally {
this.closeMenu();
}
}
remove() {
this.disable();
this.map.removeOverlay(this.overlay);
this.container.remove();
}
}