Geocoding Openstreetmap gives different responses depending on zoom-level

Viewed 30

I am trying to figure out why when hoovering on a village when zoom level is low show's the town of Västerås instead of Irsta, but when I zoom in it shows the village of Irsta.

You guys can try it yourselves in this example.

I would like to be able to locate Irsta when you can see the label of Irsta, it shouldn't be the bigger city of Västerås in that case.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    
    <title>Query Nominatem</title>
    
    <link rel="shortcut icon" type="image/x-icon" href="docs/images/favicon.ico" />

    <link rel="stylesheet" href="https://unpkg.com/leaflet@1.8.0/dist/leaflet.css" integrity="sha512-hoalWLoI8r4UszCkZ5kL8vayOGVae1oxXe/2A4AO6J9+580uKHDO3JdHb7NzwwzK5xr/Fs0W40kiNHxM9vyTtQ==" crossorigin=""/>
    <script src="https://unpkg.com/leaflet@1.8.0/dist/leaflet.js" integrity="sha512-BB3hKbKWOc9Ez/TAwyWxNXeoV9c1v6FIeYiBieIWkpLjauysF18NzgR1MBNBXf8/KABdlkX68nAhlwcDFLGPCQ==" crossorigin=""></script>

    <style>
   html, body, #map {
      height:100%;
      width:100%;
      padding:0px;
      margin:0px;
   } 
    </style>

    
</head>
<body>

<div id="map"></div>
<script>

    const map = L.map('map').setView([48.210033, 16.363449], 10);

    const tiles = L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', {
        maxZoom: 19,
        attribution: '&copy; <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>'
    }).addTo(map);


  let timeOut;
  let popUp;
  let queryState = false;

  function mousemove(e) {
    clearTimeout(timeOut)
    if (!queryState) {
      timeOut = setTimeout(() => {
        queryState = true;
        if (popUp) {
          popUp.remove()
        }
        popPup = L.popup()
          .setLatLng(e.latlng)
          .setContent("Loading data....")
          .openOn(map);
        queryNominatem(e)
      }, 1000);
    }
  }

  function queryNominatem(e) {
    fetch(`https://nominatim.openstreetmap.org/reverse.php?lat=${e.latlng.lat}&lon=${e.latlng.lng}&zoom=${map.getZoom()}&format=json`).then(
      (x) => {
        return x.json()
      }
    ).then(
      (data) => {
        popUp = L.popup()
          .setLatLng(e.latlng)
          .setContent(data.display_name)
          .openOn(map);
        queryState = false;
      }
    ).catch(
      (err) => {
        console.log(err);       
        popUp = L.popup()
          .setLatLng(e.latlng)
          .setContent("Error Loading data ... ")
          .openOn(map);

        setTimeout(() => {
          popUp.remove();
          queryState = false;
        }, 1000);
      }
    );    
  }

  map.on("mousemove", mousemove);
</script>
</body>
</html>

Zoom-in picture of village Irsta Zoom-in picture of village Irsta

Normal zooom of village Irsta Normal zooom of village Irsta

1 Answers

This is happening as you are using a dynamic zoom level in your reverse Nominatim request. If the zoom level is lower than 14, Nominatim will try to get the next city, (or if it way lower, even the country, etc., see https://nominatim.org/release-docs/develop/api/Reverse/#result-limitation )

So you'll have to define a min-value in your zoom while doing the reverse call, e.g. q&d:

reverseZoom=Math.max(14,map.getZoom());
fetch(`https://nominatim.openstreetmap.org/reverse.php?lat=${e.latlng.lat}&lon=${e.latlng.lng}&zoom=${reverseZoom}&format=json`)

Now the reverse call will always try to get a village, but - and this may be a problem - also a suburb instead of a city (but this would have happened with your original code as well if you zoom in). So I would recommend to use addressdetails=1 in your request and parse the addressdetails response for city/village/town to return that value instead of the display name value.

Related