Interact with cadastral map information effectively
In this detailed example, you will learn how to interact with cadastral map information effectively. You will learn how to highlight specific parcels by hovering over them and displaying a pop-up window to access more complete details when you click on a parcel. Check out the MapTiler Cadastre schema for more details on the available information (layers, attributes, etc.).
In this example, clicking on the map displays the information about the plot and the building. For demonstration purposes, we have implemented a link to access and download official plot information (only for the Canton of Bern) in PDF format.
NPM module setup
npm install --save @maptiler/sdk
import { Map, config } from '@maptiler/sdk';
import '@maptiler/sdk/dist/maptiler-sdk.css';
config.apiKey = 'YOUR_MAPTILER_API_KEY_HERE';
async function loadMap() {
const json = await fetch(`https://api.maptiler.com/maps/cadastre/style.json?key=${config.apiKey}`);
const style = await json.json();
//set cadastre source promotedId property (necessary for setFeatureState)
const cadastre = style.sources.cadastre;
cadastre.promoteId = 'id';
const map = new Map({
container: 'map', // container id
style: style,
center: [lng, lat], // starting position [lng, lat]
zoom: zoom, // starting zoom
maxBounds: [7.383499,46.911578,7.520485,46.984937] //Bern area
});
let hoveredStateId = null;
const popup = new maptilersdk.Popup({closeOnClick: false});
map.on('ready', async () => {
map.addLayer({
"id": "parcel",
"source": "cadastre",
"source-layer": "parcel",
"type": "fill",
"layout": {},
"paint": {
"fill-color": "#ffffff",
"fill-opacity": [
'case',
['boolean', ['feature-state', 'hover'], false],
0.5,
0
]
}
}, "Parcel border");
map.on('click', 'Building', (e) => {
const features = map.queryRenderedFeatures(e.point, {
layers: ['Building', 'parcel']
});
if (features.length !== 0) {
const description = createPopupContent(features);
popup.setLngLat(e.lngLat).setHTML(description).addTo(map);
}
});
map.on('mousemove', 'Building', function (e) {
map.getCanvas().style.cursor = 'pointer';
});
map.on('mouseleave', 'Building', function () {
map.getCanvas().style.cursor = '';
});
map.on('mousemove', 'Building', function (e) {
if (e.features.length > 0) {
const features = map.queryRenderedFeatures(e.point, {
layers: ['parcel']
});
if (hoveredStateId) {
map.setFeatureState(
{ source: 'cadastre', sourceLayer: 'parcel', id: hoveredStateId },
{ hover: false }
);
}
if (features) {
hoveredStateId = features[0].id;
map.setFeatureState(
{ source: 'cadastre', sourceLayer: 'parcel', id: hoveredStateId },
{ hover: true }
);
}
}
});
map.on('mouseleave', 'Building', function () {
if (hoveredStateId) {
map.setFeatureState(
{ source: 'cadastre', sourceLayer: 'parcel', id: hoveredStateId },
{ hover: false }
);
}
hoveredStateId = null;
});
});
}
loadMap();
function createPopupContent(features) {
const data = features.reduce((agg, feat) => {
if (feat.layer.id == "parcel") {
agg.parcel = feat.properties.id;
agg.parcel_number = feat.properties.number;
agg.zone = feat.properties.zone;
} else if (feat.layer.id == "Building") {
agg.building = feat.properties.id;
}
return agg;
}, {});
return `<div><strong>Parcel number</strong>: ${data.parcel_number}</div>
<div><strong>Building</strong>: ${data.building}</div>
<div><a href="https://www.oereb2.apps.be.ch/extract/pdf/?EGRID=${data.parcel}">${data.parcel}</a></div>
`;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="robots" content="noindex">
<title>Interact with cadastral map information effectively | NPM example</title>
<link rel="stylesheet" href="./style.css">
</head>
<body>
<div id="map"></div>
<script type="module" src="./main.js"></script>
</body>
</html>
body {margin: 0; padding: 0;}
#map {position: absolute; top: 0; bottom: 0; width: 100%;}
Related examples
Get features under the mouse pointer
ExamplesShow properties of hovered map elements with queryRenderedFeatures.