3

I have a map, the very bottom (behind) layer contains united states (polygons for each state); and the very top layer contains my study locations (points layer).

The layers are displaying correctly, but when I hover over one of my study location points, the information is given as "Montana", which is the information for my "behind" united states layer and not for my "top" study locations layer. (Please see photo 1)

I changed the order of my layers (put the field locations behind the US polygons). I can't see my field locations, because they are hidden behind the polygons, BUT now when I hover over my study site locations (even though I can't see them) the information for my study site appears.

It seems that even though the map is displaying layers in the correct order, the information for popup-on-hover is accessed in reverse order. This is true for qgis2web preview within the QGIS desktop and once I extract the files and look at my Index.html in a web browser.

I added a duplicate of my study sites layer, behind the united states layer (but this is an ugly fix and the "Study Sites copy" layer shows up in the layer switcher, which will confuse the user) (Please see photo 2)

Can someone help me understand the connection between the order of layers which I think is determined in the layers.js:

var layersList = [lyr_USA1,lyr_MajorUSCities2,lyr_MT3,lyr_MTRoads4,lyr_MTCities5,lyr_StudySites6];   

--> The USA layer already has 1 attached to it?

and the qgis2web.js code

map.forEachFeatureAtPixel(pixel, function(feature, layer)

How can I order layers in a different way (one layersList to display the layers and reverse layersList to extract hover popup information)?

popups are displayed fro the wrong (behind) layer

My ugly fix to the problem

2
  • 1
    Looks like you've found a bug. Until it's fixed, in QGIS, for your background states layer, can you try setting every field's edit widget to Hidden? That might prevent any popup for that layer. If so, that could mean you get the correct info on hover. Commented Apr 26, 2017 at 18:22
  • Thanks Tom Chadwin, your suggestion helped with my issue and the popups are now displaying for my field sites, without interference from the USA states polygons. I will look into the code more carefully and hopefully figure out how to hard code a solution.
    – Olak
    Commented Apr 26, 2017 at 20:26

2 Answers 2

4

After debugging for a number of hours (being out of practice and all), I found a simple solution:

The issue is that map.forEachFeatureAtPixel loop reads features in the following order: top-most to bottom-most. Since the bottom-most feature is read last, it overwrites the popupText table with its information.

My solution was to add a counter and only populating the popupText if counter = 1 (only get information from the first read feature, which is the top-most feature).

(alternative solution is to declare the popupText = '<table>' outside of the map.forEachFeatureAtPixel loop, in which case the table will get populated with information from multiple features)

var counter = 1;

map.forEachFeatureAtPixel(pixel, function(feature, layer) {  // goes through features that are present as that pixel coordinate
    currentFeature = feature; 
    currentFeatureKeys = currentFeature.getKeys(); //currentFeatureKeys is an array with field names
    var doPopup = false;      

    //this loop checks if current feature contains at least one field that is not set to 'hidden'
    for (k in layer.get('fieldImages')) { 
        if (layer.get('fieldImages')[k] != "Hidden") {  
            doPopup = true;
        }
    } 

    if (counter == 1){
        if (doPopup) {
            popupText = '<table>';
            for (var i=0; i<currentFeatureKeys.length; i++) {
                if (currentFeatureKeys[i] != 'geometry') { 
                    popupField = '';
                    if (layer.get('fieldLabels')[currentFeatureKeys[i]] == "inline label") {  //checks if label-type is a header or an inline (displayed on top or beside the value)
                        popupField += '<th>' + layer.get('fieldAliases')[currentFeatureKeys[i]] + ':</th><td>'; // 
                    } else {
                        popupField += '<td colspan="2">';
                    }
                    if (layer.get('fieldLabels')[currentFeatureKeys[i]] == "header label") {
                        popupField += '<strong>' + layer.get('fieldAliases')[currentFeatureKeys[i]] + ':</strong><br />'; //
                    }
                    if (layer.get('fieldImages')[currentFeatureKeys[i]] != "Photo") { // checks if the actual value is a string or a link to a photo
                        popupField += (currentFeature.get(currentFeatureKeys[i]) != null ? Autolinker.link(String(currentFeature.get(currentFeatureKeys[i]))) + '</td>' : '');  // currentFeature.get(currentFeatureKeys[i])) this is the actual value at that pixel for that field
                    } else {
                        popupField += (currentFeature.get(currentFeatureKeys[i]) != null ? '<img src="images/' + currentFeature.get(currentFeatureKeys[i]).replace(/[\\\/:]/g, '_').trim()  + '" /></td>' : '');
                    }
                    popupText = popupText + '<tr>' + popupField + '</tr>'; //popupField gets appended to the popupText table
                }
            }
            popupText = popupText + '</table>';
        }
    }
    counter++;

});
4
  • I thought all features under the popup were added to the popup. Is that not the case? Commented Apr 27, 2017 at 18:53
  • 1
    No this is not. The 'map.forEachFeatureAtPixel' is a loop that fetches 'features' one-by-one starting at the top-most. The popupText gets populated for the first feature, but then it gets erased for the next feature, because it's a local variable ( popupField = '', so it gets replaced with an empty string and then repopulated with values from the second feature). Keeping the code the same, but declaring the popupField = '' before the map.forEachFeatureAtPixel will result in information from all features populating this same popup.
    – Olak
    Commented Apr 27, 2017 at 21:36
  • From my initial read through the code, you are completely right. popupText should be initialized outside the forEachFeatureAtPixel, as should doPopup, though the latter is possibly redundant. I'll investigate properly when not just using a phone. Or do submit a pull request for qgis2web if you want - I'd be very grateful. Thanks for all the work! Commented Apr 27, 2017 at 23:20
  • Ok Tom, I will try to do a pull request on GitHub and keep you posted. I'm glad that I could contribute to this great project even in a small way!
    – Olak
    Commented Apr 27, 2017 at 23:58
2

Looks like you've found a bug in qgis2web. Until it's fixed, in QGIS, for your background states layer, try setting every field's edit widget to Hidden. That should prevent any popup for that layer, which should mean you get the correct info on hover.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.