Link

Description

This example demonstrates two things:

  • How to add your own vector data to the viewer.
  • How to create an interaction between your own data representation and features in the map.

In this map, a vectorlayer without a data source has been added. This way, you can configure an on-click feature info template and styling.

Demo (click to select/deselect an address from the list)

Code

// Keep reference to vector layer to handle (de)selection of features.
let vectorLayer = null;

function getAddress(feature) {
  const { straat, huisnummer, postcode } = feature.properties;
  return `${straat} ${huisnummer}, ${postcode}`;
}

function createListView(features) {
  const list = document.createElement("ul");
  list.classList.add("data-list");

  // Order features by address.
  features.sort((f1, f2) => getAddress(f1).localeCompare(getAddress(f2)));

  features.forEach((feature) => {
    const listItem = document.createElement("li");
    listItem.classList.add("list-item");
    listItem.innerText = getAddress(feature);

    // Add feature id as data attribute to link back to the feature in the map.
    listItem.setAttribute("data-fid", feature.id);

    // (Un)highlight on mouse enter/leave.
    listItem.addEventListener('mouseenter', evt => {
      evt.target.classList.add('highlighted');
      const fid = evt.target.dataset.fid;
      vectorLayer.highlightFeatures([fid]);
    });

    listItem.addEventListener('mouseleave', evt => {
      evt.target.classList.remove('highlighted');
      const fid = evt.target.dataset.fid;
      vectorLayer.unhighlightFeatures([fid]);
    });

    list.appendChild(listItem);
  });

  // Add a click handler to list items to select/deselect them
  // in the list and in the map.
  list.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]);
    }
  });

  return list;
}

// Load custom geojson.
fetch("data/laadpalen-utrecht.geojson")
  .then((response) => response.json())
  .then((geojson) => {
    // Add geojson feature collection to the empty vector layer.
    vectorLayer = api.map.getLayer("custom-features");
    vectorLayer.addFeatures(geojson);

    // Zoom to fit.
    vectorLayer.zoomToDataExtent();

    // Add list view for data.
    const dataList = createListView(geojson.features);
    const listContainer = document.querySelector(".list-container");
    listContainer.appendChild(dataList);
  });