feat: indicate clickable map features
This commit is contained in:
@@ -111,6 +111,9 @@ let pendingCompassHeading;
|
||||
let compassAnimationFrame;
|
||||
let deviceCompassFallbackTimer;
|
||||
let modalDrag;
|
||||
let featureHoverRequest;
|
||||
let featureHoverRequestId = 0;
|
||||
let featureHoverTimer;
|
||||
|
||||
const map = new ol.Map({
|
||||
target: "map",
|
||||
@@ -173,6 +176,8 @@ document.addEventListener("keydown", (event) => {
|
||||
});
|
||||
window.addEventListener("resize", keepFeatureModalInViewport);
|
||||
map.on("singleclick", showFeatureInformation);
|
||||
map.on("pointermove", updateFeatureCursor);
|
||||
map.getViewport().addEventListener("pointerleave", clearFeatureCursor);
|
||||
areaZoomInteraction.on("boxend", zoomToSelectedArea);
|
||||
areaZoomInteraction.on("boxcancel", () => {
|
||||
// A click or a very short drag is not a selection. Exit on the next frame so
|
||||
@@ -450,6 +455,7 @@ function setAreaZoomMode(active) {
|
||||
);
|
||||
|
||||
if (active) {
|
||||
clearFeatureCursor();
|
||||
closeFeatureModal();
|
||||
}
|
||||
}
|
||||
@@ -655,6 +661,7 @@ function syncSelectedLayers() {
|
||||
return layerName === "parcelas" || layerName === unqualifiedLayerName(DWELLING_PARCEL_LAYER_NAME);
|
||||
}),
|
||||
);
|
||||
clearFeatureCursor();
|
||||
}
|
||||
|
||||
function isInternalLayer(name) {
|
||||
@@ -704,6 +711,51 @@ async function showFeatureInformation(event) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const feature = await getFeatureAtCoordinate(event.coordinate);
|
||||
if (feature) {
|
||||
openFeatureModal(feature);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
}
|
||||
|
||||
function updateFeatureCursor(event) {
|
||||
if (event.dragging || areaZoomInteraction.getActive()) {
|
||||
clearFeatureCursor();
|
||||
return;
|
||||
}
|
||||
|
||||
window.clearTimeout(featureHoverTimer);
|
||||
const requestId = ++featureHoverRequestId;
|
||||
const coordinate = [...event.coordinate];
|
||||
featureHoverTimer = window.setTimeout(async () => {
|
||||
featureHoverRequest?.abort();
|
||||
featureHoverRequest = new AbortController();
|
||||
|
||||
try {
|
||||
const feature = await getFeatureAtCoordinate(coordinate, featureHoverRequest.signal);
|
||||
if (requestId === featureHoverRequestId) {
|
||||
map.getViewport().style.cursor = feature ? "pointer" : "";
|
||||
}
|
||||
} catch (error) {
|
||||
if (error.name !== "AbortError" && requestId === featureHoverRequestId) {
|
||||
map.getViewport().style.cursor = "";
|
||||
}
|
||||
}
|
||||
}, 120);
|
||||
}
|
||||
|
||||
function clearFeatureCursor() {
|
||||
window.clearTimeout(featureHoverTimer);
|
||||
featureHoverRequestId += 1;
|
||||
featureHoverRequest?.abort();
|
||||
featureHoverRequest = undefined;
|
||||
map.getViewport().style.cursor = "";
|
||||
}
|
||||
|
||||
async function getFeatureAtCoordinate(coordinate, signal) {
|
||||
const queryLayers = availableLayers
|
||||
.map((layer) => layer.name)
|
||||
.filter(
|
||||
@@ -711,32 +763,25 @@ async function showFeatureInformation(event) {
|
||||
);
|
||||
|
||||
if (!queryLayers.length) {
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
|
||||
const url = wmsSource.getFeatureInfoUrl(event.coordinate, map.getView().getResolution(), "EPSG:3857", {
|
||||
const url = wmsSource.getFeatureInfoUrl(coordinate, map.getView().getResolution(), "EPSG:3857", {
|
||||
INFO_FORMAT: "application/json",
|
||||
QUERY_LAYERS: queryLayers.join(","),
|
||||
FEATURE_COUNT: 1,
|
||||
});
|
||||
|
||||
if (!url) {
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await fetch(url);
|
||||
if (!response.ok) {
|
||||
throw new Error(`Feature information failed with status ${response.status}.`);
|
||||
}
|
||||
|
||||
const feature = (await response.json()).features?.[0];
|
||||
if (feature) {
|
||||
openFeatureModal(feature);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
const response = await fetch(url, { signal });
|
||||
if (!response.ok) {
|
||||
throw new Error(`Feature information failed with status ${response.status}.`);
|
||||
}
|
||||
|
||||
return (await response.json()).features?.[0] || null;
|
||||
}
|
||||
|
||||
function openFeatureModal(feature) {
|
||||
|
||||
Reference in New Issue
Block a user