Project

General

Profile

Feature #1790

Map: make intersecting polygons selectable

Added by Alexander Watzinger 3 months ago. Updated about 2 months ago.

Status:
Closed
Priority:
Normal
Category:
Maps
Target version:
Start date:
2022-08-19
Estimated time:

Description

Additional feature to select map polygons in case they overlap.

History

#1

Updated by Alexander Watzinger 3 months ago

Stefan Eichert: you already have something like this implemented in THANADOS. Can you give us any pointers?

#2

Updated by Stefan Eichert 3 months ago

//**select overlapping polygons on click**//
///////////////////////////////////////////////
function polygonSelect() {
    //define layergroup for selected polygons
    selectedpolys = new L.LayerGroup();
    selectedpolys.addTo(map);

    //layergroup for highlighting on popup hover
    hoverPolys = new L.LayerGroup();
    hoverPolys.addTo(map);

//define invisible marker
    invisIcon = L.icon({
        iconUrl: '/static/images/icons/burial.png',
        iconSize: [1, 1] // size of the icon
    });

//function to get coordinates of clicked position and loop through polygons for matches
    map.on('click', function (e) {
        //set invisible marker and remove invisible marker and popupconent if exists
        if (typeof (newMarker) !== 'undefined') {
            map.removeLayer(newMarker);
        }
        popupContent = '';
        newMarker = new L.marker(e.latlng, {icon: invisIcon}); //global to have it for further use

        //clear previous polygons
        selectedpolys.clearLayers();
        selectedIDs = [];

        //loop through polygons and set matches
        var polys = L.geoJSON(mypolyjson, {
            onEachFeature: function (feature, layer) {
                isMarkerInsidePolygon(newMarker, layer)
            }
        });

        //set popup content to matching polygons for invisible marker
        if (selectedIDs.length !== 0) {
            newMarker.addTo(map);
            newMarker.bindPopup(popupContent).openPopup();
            if (typeof (oldcollapsediv) !== 'undefined') {
                $('#collapseg' + oldcollapsediv).collapse('hide');
                var down = ($('#btn' + oldcollapsediv).hasClass("fa-chevron-down"));
                if (down)
                    $('#btn' + oldcollapsediv).removeClass('fa-chevron-down').addClass('fa-chevron-right');
            }
        }
    });
}

//check if marker is inside polygon and return values
function isMarkerInsidePolygon(checkmarker, poly) {
    if (poly.feature.geometry.type === "Polygon") {
        var inside = false;
        var x = checkmarker.getLatLng().lat, y = checkmarker.getLatLng().lng; //uses the global
        for (var ii = 0; ii < poly.getLatLngs().length; ii++) {
            var polyPoints = poly.getLatLngs()[ii];
            for (var i = 0, j = polyPoints.length - 1; i < polyPoints.length; j = i++) {
                var xi = polyPoints[i].lat, yi = polyPoints[i].lng;
                var xj = polyPoints[j].lat, yj = polyPoints[j].lng;
                var intersect = ((yi > y) != (yj > y))
                    && (x < (xj - xi) * (y - yi) / (yj - yi) + xi);
                if (intersect)
                    inside = !inside;
            }
        }
        if (inside) {
            var mypopupLine =
                JSON.parse('{"id":"' + poly.feature.id + '"' +
                    ', "name":"' + poly.feature.properties.name + '"' +
                    ', "type":"' + poly.feature.properties.maintype.name + '"}');
            selectedIDs.push(mypopupLine);
            var popupLine =
                '<a id="' + poly.feature.id + '"' +
                ' onclick="modalset(this.id)" ' +
                ' onmouseout="hoverPolys.clearLayers()"' +
                ' onmouseover="HoverId = this.id; hoverPoly()"' +
                ' href="#"><p><b>' + poly.feature.properties.name + ' </b>' +
                '(' + poly.feature.properties.maintype.name + ')</p></a>';
            popupContent += popupLine;
            var selectedpoly = L.polygon(polyPoints, SelectionStyle);
            selectedpolys.addLayer(selectedpoly);
        }
        return inside;
    }
}

//add the respective polygon if hovered over popup link
function hoverPoly() {
    hoverPolys.clearLayers();
    hoverGraves = L.geoJSON(mypolyjson, {
        filter: hoverFilter,
        style: HoverStyle
    });
    hoverPolys.addLayer(hoverGraves);
}

//filter to check whether it is the matching polygon
function hoverFilter(feature) {
    if (feature.id == HoverId) {
        return true
    }
}
#3

Updated by Andreas Olschnögger about 2 months ago

  • Status changed from Assigned to In Progress
  • Assignee changed from Andreas Olschnögger to Alexander Watzinger

Now when clicking on overlapping polygons a pop up will open that lists all of these polygons.
For these changes an update of the frontend libraries is necessary.
@ Alexander Watzinger please update the translation for the pop up text that is located in static/js/map/map.js on line 388
Changes are currently on the feature_map_intersecting_polygons branch.

#4

Updated by Andreas Olschnögger about 2 months ago

  • Target version changed from A 7.10.0 to 7.7.0
#5

Updated by Alexander Watzinger about 2 months ago

  • Assignee changed from Alexander Watzinger to Andreas Olschnögger

Do I understand correctly? This feature is finished and I can merge it to develop but have to add in the upgrade notes that the frontend libraries have to be updated, e.g. like

    $ cd openatlas/static
    $ pip3 install -e ./
    $ ~/.local/bin/calmjs npm --install openatlas

About the translations, I do this shortly before the release for everything at once. Only thing you have to do in this (JavaScript) case is to add it to the array at the top of templates/map.html with the typical _('') writing style so that it can be picked up automatically by the translation program. I did this for you in this case, see: https://github.com/craws/OpenAtlas/commit/526c55006a03ff92e66f0e4d92319f8d69ccc0dc

That said, if you are saying it is ready to release please add a note and assign this issue back to me, thank you.

#6

Updated by Andreas Olschnögger about 2 months ago

  • Assignee changed from Andreas Olschnögger to Alexander Watzinger

Do I understand correctly? This feature is finished and I can merge it to develop but have to add in the upgrade notes that the frontend libraries have to be updated, e.g. like...

Yes exactly. It might be also good to note that you have to delete the openatlas/static/package.js file before running the calmjs command, otherwise you will get an error that states that this file already exits und the updates cannot be made. (This file will be created automatically)

About the translations, I do this shortly before the release for everything at once. Only thing you have to do in this (JavaScript) case is to add it to the array at the top of templates/map.html with the typical _('') writing style so that it can be picked up automatically by the translation program. I did this for you in this case, see: https://github.com/craws/OpenAtlas/commit/526c55006a03ff92e66f0e4d92319f8d69ccc0dc

Thanks i will do so the next time

#7

Updated by Alexander Watzinger about 2 months ago

  • Description updated (diff)
  • Status changed from In Progress to Closed
  • Assignee changed from Alexander Watzinger to Andreas Olschnögger

Is already in develop, update install notes updated, feature branch removed online and translations will be finished before release.
Thanks again for another great user interface improvement!

Also available in: Atom PDF