TransWikia.com

How to deal with overlapping polygons from GeoJSON in OpenLayers 4

Geographic Information Systems Asked on September 28, 2021

I have a series of GeoJSON files (generated by QGIS) loaded on to a map in OpenLayers 4 as different layers. Each file contains multiple polygons. When mouse-clicking each polygon a pop-up window appears with info on the polygon.
Layers (each layer corresponding to a single GeoJSON file) are loaded as:

//adding layers
map.addLayer(ocean_map);
map.addLayer(layer_mediterranean_aoi);
map.addLayer(layer_mediterranean_cimma); 
map.addLayer(layer_mediterranean_imma);

While the function to trigger the pop-up is written in this way:

     var info = document.getElementById('info');
     var target = document.getElementById('map');
     function displayFeatureInfo(pixel) {
            info.style.left = '30%';
            info.style.top = '20%';
            info.style.height = 300 + 'px';
            var feature = map.forEachFeatureAtPixel(pixel, function(feature, layer) {
        return feature;
      });
      if (feature) {
        var geometry = feature.getGeometry();
        var coord = geometry.getCoordinates();
        var text = '<button class="close-button" id="close-button">X</button><div><table><tbody>';
        //if (feature.get('AOI')) {text += '<tr><td> <h2> ' + feature.get('AOI') + '</h2></td></tr>';} else {text += '';}
        text += '<tr><td style="background-color: rgba(140, 177, 222, 0.5);"> <h2> ' + feature.get('Title') + '</h2></td></tr>';
        text += '<tr><td><strong>Summary: </strong>' + feature.get('Summary') + '</h2></td></tr>';
        text += '<tr><td style="background-color: rgba(140, 177, 222, 0.5);"><strong>Region:</strong> ' + feature.get('Region') + '</td></tr>';
        if (feature.get('AOI')) {text += '';} else {
        text += '<tr><td> <strong>Criteria:</strong> ' + feature.get('Criteria') + '</td></tr>';
        }
        if (feature.get('AOI')) {text += '';} else {  
        text += '<tr><td style="background-color: rgba(140, 177, 222, 0.5);"> <strong>Species:</strong> ' + feature.get('Species') + '</td></tr>';
        }
        if (feature.get('Status')) {text += '<tr><td> <strong>Status:</strong> ' + feature.get('Status') + '</td></tr>';} else {text += '';}
        if (feature.get('URL')) {text += '<tr><td> <a href=" ' + feature.get('URL') + '"> MORE INFO </a></td></tr>';} else {text += '<tr><td> </td></tr>';}
        text += '</tbody></table></div>';
        info.style.display = 'none';
        info.innerHTML = text;
        info.style.display = 'block';
        target.style.cursor = "pointer";

        //handles the closing "x" button to shut down the popup
        var closer = document.getElementById('close-button');
        closer.addEventListener('click', function () {
              info.style.display = 'none';
  
        });

      } else {
        info.style.display = 'none';
        target.style.cursor = "";
      }
    }

  //handles the opening of the popup
  map.on('click', function(evt) {
      if (evt.dragging) {
        //it doesn't show the info if I just drag the map
        info.style.display = 'none';
        return;
      }
      var pixel = map.getEventPixel(evt.originalEvent);
      displayFeatureInfo(pixel);
  });

Few of these polygons may overlap, and obviously the one that is in the background (if smaller) is not selectable. How can I fix the problem?
At the moment I figure out that one way is to prepare the geojson files with the polygons ordered in a way that the smaller areas appear after the bigger ones where they overlap, so that when the layer is loaded on the map the smaller polygons are loaded last (therefore on top).
I was wondering if there is a better way to solve the problem on OpenLayers side.

One Answer

If can't control the polygon source and polygon overlaping is a must you have to deal with, then for visual representation you have done it well by ordering the polygons by area from bigger to smaller. At this point, IMHO you can do two things:

  • Use a semi-transparent fill. So when two polygons (or more) overlap, the overlapping area will have more opacity and is visually evident the overlap. If you don't do this, visually there is no difference between an operlapping polygon and a polygon filling a hole of another bigger.

Polygon semitransparency overlap

  • Show a feature choose menu on click. When you use the 'getFeaturesAtPixel' method it will return all the polygons that intersects the clicked point. In case that you get more than one polygon you can show a menu listing the IDs (or names, etc... a field that is relevant to the user on your data) of the polygons so the user can choose wich polygon info display. This menu should highlight the polygon on the map when hovering with the mouse the option, so visually the user will see wich ID belongs to wich polygon.

Choose menu and feature highlight

EDIT: Now I see your code... You can get all the polygons at pixel like this:

var features = [];
map.forEachFeatureAtPixel(pixel, function(feature, layer) {
    features.push(feature);
});

if (features.length == 1) {
    // Show the popup
}
else if (features.length > 1) {
    // Show the choose menu
}

Correct answer by César Argul García on September 28, 2021

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP