import { WMSLayer } from '../../map/layer/WMSLayer/WMSLayer.js';
import { Map2D } from '../../map/Map2D.js';
import { MapPopup } from '../../map/popup/MapPopup.js';
import { BaselayerSwitcher } from '../../map/tools/BaselayerSwitcher.js';
import { ProjectionSwitcher } from '../../map/tools/ProjectionSwitcher.js';
import { CoordinateControl } from '../../map/tools/CoordinateControl.js';
import { DrawTools } from '../../map/tools/DrawTools.js';
import { FitToScreenButton } from '../../map/tools/FitToScreenButton.js';
import { LayerLegendButton } from '../../map/tools/LayerLegendButton.js';
import { ScreenshotButton } from '../../map/tools/ScreenshotButton.js';
import { ZoomButton } from '../../map/tools/ZoomButton.js';
import { Attribution } from '../../map/tools/Attribution.js';
import { ScaleControl } from '../../map/tools/ScaleControl.js';
/**
* Loader for the Map module
*
* @author sjaswal <shahzeib.jaswal@awi.de>
* @author rhess <robin.hess@awi.de>
*/
/**
* A function that loads the Map
*
* @memberof vef.viewer.loader
*
* @param {object} options
* @param {Viewer} viewer
*/
export function Map(options, viewer) {
const map = new Map2D(null, options.options);
initActiveArea_(map, options, viewer);
if (options.popup) initPopup_(map, options, viewer);
setBaseLayer_(map, viewer);
initTools_(map, options.tools, viewer);
viewer.addElement(options.id, map);
};
function initPopup_(map, options, viewer) {
let sidebar = null;
let sidebarGroup = null;
let clickPopupVisible = false;
const popup = new MapPopup(map, {
showMore: !!(options.popup.targetSidebar && options.popup.sidebarGroup)
});
const clickListener = e => {
if (map.editing) return;
// sort layers according to LayerTree order (Feature based layers are always on top)
const layers = map.getLayers();
layers.sort((a, b) => {
if ((a instanceof WMSLayer) && !(b instanceof WMSLayer)) return 1;
if (!(a instanceof WMSLayer) && (b instanceof WMSLayer)) return -1;
// index order needs to be inverted, because higher index layers are on top
if ((a.zIndex_ < b.zIndex_)) return 1;
if ((a.zIndex_ > b.zIndex_)) return -1;
return 0;
});
popup.requestPopup(layers, e.lat, e.lng);
}
// dont open popup when clicking too fast (moslty double click)
let previousClick = performance.now();
let popupTimeout = null;
map.on("click", e => {
if (popupTimeout) {
clearTimeout(popupTimeout);
popupTimeout = null;
}
map.closePopup();
const currentClick = performance.now();
if ((currentClick - previousClick) > 500) {
popupTimeout = setTimeout(() => clickListener(e), 200);
}
previousClick = currentClick;
});
// init the popup sidebar
if (options?.popup?.targetSidebar && options?.popup?.sidebarGroup) {
sidebar = viewer.elements[options.popup.targetSidebar];
sidebarGroup = options.popup.sidebarGroup;
}
popup.on("show_popup", item => {
if (sidebar && sidebarGroup) {
sidebar.setContent(sidebarGroup, item.sidebar, true);
sidebar.setTitle(sidebarGroup, item.sidebar.dataset.title || item.content.title || item.content.layer.title);
item.onShowMore = () => sidebar.show(sidebarGroup);
}
clickPopupVisible = true;
});
// highlighting selected feature
let popupVisible = false;
map.addLayer(popup.selectedFeature);
map.on("hide_popup", () => {
if (!sidebar?.isOpen()) popup.selectedFeature.setData(null);
popupVisible = false;
clickPopupVisible = false;
});
map.on("show_popup", () => {
popupVisible = true;
});
sidebar?.on("close", () => {
if (!popupVisible) popup.selectedFeature.setData(null);
})
// feature hover popup
const hoverPopup = new MapPopup(map, { showMore: false });
viewer.layerManager.on("layermanager_layer_mouseover", e => {
if (e.layer.hoverEvents && !clickPopupVisible) {
const latlng = e.mouseEvent.latlng;
hoverPopup.requestPopup([e.layer], latlng.lat, latlng.lng, map);
}
});
viewer.layerManager.on("layermanager_layer_mouseout", e => {
if (e.layer.hoverEvents && !clickPopupVisible) map.closePopup();
});
viewer.filters.on("change", () => map.closePopup());
viewer.filters.setMap(map);
}
function initTools_(map, tools, viewer) {
// push to the end of the current eventqueue to allow loading all other events
// because a some tools rely on other Ui Elements already being initialized
setTimeout(() => {
for (let i = 0; i < tools.length; ++i) {
switch (tools[i].type.toLowerCase()) {
case "attribution":
new Attribution(map, tools[i].position);
break;
case "zoom":
new ZoomButton(map, tools[i].position);
break;
case "fittoscreen":
new FitToScreenButton(map, tools[i].position);
break;
case "layerlegends":
if (viewer.elements[tools[i].targetTree]) {
new LayerLegendButton(map, tools[i].position, viewer.elements[tools[i].targetTree]);
}
break;
case "screenshot":
new ScreenshotButton(map, tools[i].position);
break;
case "drawtools":
new DrawTools(map, tools[i].position);
break;
case "coordinatecontrol":
new CoordinateControl(map, tools[i].position);
break;
case "baselayerswitcher":
const baselayerSwitcher = new BaselayerSwitcher(map, tools[i].position, viewer.baseLayers);
const infoSidebar = viewer.elements[tools[i].infoSidebar];
if (infoSidebar && tools[i].infoSidebarGroup) {
baselayerSwitcher.enableInfoButton();
baselayerSwitcher.on("show_info", (layer) => {
infoSidebar.setContent(tools[i].infoSidebarGroup, layer.printMetadata());
infoSidebar.setTitle(tools[i].infoSidebarGroup, layer.title);
infoSidebar.show(tools[i].infoSidebarGroup);
});
}
break;
case "projectionswitcher":
new ProjectionSwitcher(map, tools[i].position, viewer.baseLayers, tools[i].projections);
break;
case "scalecontrol":
new ScaleControl(map, tools[i].position);
break;
}
}
}, 0);
}
function initActiveArea_(map, options, viewer) {
if (options.activeAreaSidebar) {
let sidebar = viewer.elements[options.activeAreaSidebar];
let sidebarOpen = !sidebar.getElement().classList.contains("collapsed");
const showActiveArea = (ignoreSidebarOpen = false, centerMap = false) => {
if (ignoreSidebarOpen || !sidebarOpen) {
map.setActiveArea("sidebar-active-area", centerMap);
}
sidebarOpen = true;
};
const showActiveAreaAlt = (ignoreSidebarOpen = false, centerMap = false) => {
if (ignoreSidebarOpen || sidebarOpen) {
map.setActiveArea("sidebar-active-area-alt", centerMap);
}
sidebarOpen = false;
}
sidebar.on("show", () => showActiveArea());
sidebar.on("close", () => showActiveAreaAlt());
sidebarOpen ? showActiveArea(true, true) : showActiveAreaAlt(true, true);
}
}
// set initial baselayer as defined in the map config
function setBaseLayer_(map, viewer) {
const key = map.options.baseLayer || Object.keys(viewer.baseLayers)[0];
const crs = map.options.crs;
if ((key in viewer.baseLayers) && (crs in viewer.baseLayers[key])) {
const layer = viewer.baseLayers[key][crs];
map.setBaseLayer(layer, null);
}
}