Description
This example demonstrates two things:
- Displaying feature attributes as info cards next to the map.
- Only showing features visible in the map viewport. Moving/zooming/filtering the map will dynamically update the list of visible features.
- Selecting (and de-selecting) features by clicking on the list items, and keeping the selected features highlighted when the list updates.
Demo
Code
document.onreadystatechange = () => {
if (document.readyState === "complete") {
window.initMap("demo-viewport-filter").then(initDemo);
}
};
function createListView(features) {
const vectorLayer = api.map.getLayer("bag-pand-wfs-3");
// Get selected feature id's to (re-)apply selected status to list items.
const selectedFids = new Set(
vectorLayer.getSelectedFeatures().features.map((f) => f.id)
);
if (!(features && features.length > 0)) {
const noDataElement = document.createElement("p");
noDataElement.innerText = "No objects in viewport";
return noDataElement;
}
const list = document.createElement("ul");
list.classList.add("data-list");
// Order features by construction year, then by id.
features.sort((f1, f2) => {
if (f1.properties.bouwjaar === f2.properties.bouwjaar) {
return f1.id.localeCompare(f2.id);
}
return f1.properties.bouwjaar - f2.properties.bouwjaar;
});
features.forEach((feature) => {
const listItem = document.createElement("li");
listItem.classList.add("list-item");
const props = feature.properties;
listItem.innerText = `Bouwjaar: ${props.bouwjaar}, Status: ${props.status}`;
// Add feature id as data attribute to link back to the feature in the map.
listItem.setAttribute("data-fid", feature.id);
// Add selected class to list item if the feature has selected state.
if (selectedFids.has(feature.id)) {
listItem.classList.add("selected");
}
// Add a click handler to list items to select/deselect them
// in the list and in the map.
listItem.addEventListener("click", (evt) => {
if (!(evt.target && evt.target.classList.contains("list-item"))) {
return;
}
// Grab feature id from data attribute.
const listNode = evt.target;
const fid = listNode.dataset.fid;
const isSelected = evt.target.classList.contains("selected");
if (isSelected) {
evt.target.classList.remove("selected");
vectorLayer.unselectFeatures([fid]);
} else {
evt.target.classList.add("selected");
vectorLayer.selectFeatures([fid]);
}
});
list.appendChild(listItem);
});
return list;
}
function refreshFeatureList() {
// Obtain current map viewport extent and use the bbox option to
// get only the features intersecting the viewport.
const vectorLayer = api.map.getLayer("bag-pand-wfs-3");
const viewportExtent = api.map.getViewParams().extent;
const featuresInViewport = vectorLayer.getFeatures({
bbox: viewportExtent,
}).features;
const dataList = document.querySelector("#data-list");
const listContainer = dataList.querySelector(".list-container");
const featureListHtml = createListView(featuresInViewport);
listContainer.innerHTML = "";
listContainer.appendChild(featureListHtml);
}
function initDemo(api) {
api.events.on("map.move", refreshFeatureList);
api.events.on("layer.loadEnd", (evt) => {
if (evt.layerId === "bag-pand-wfs-3") {
refreshFeatureList();
}
});
}