Search code examples
javascriptjqueryloopsopenlayersopenlayers-3

OpenLayers 3 - deleting features


So, I want to delete selected features using code below:

var vector = new ol.layer.Vector({
    source: new ol.source.Vector()
});

var map = new ol.Map({
    layers: [
        new ol.layer.Tile({
            source: new ol.source.OSM()
        }),
        vector
    ],
    target: 'map',
    view: new ol.View({
        center: [-11000000, 4600000],
        zoom: 4
    })
});

map.on('pointermove', function(e) {
    if (e.dragging) return;
    var
        pixel = map.getEventPixel(e.originalEvent),
        hit = map.hasFeatureAtPixel(pixel);
    map.getTargetElement().style.cursor = hit ? 'pointer' : '';
});
document.getElementById('js-remove').addEventListener('click', function() {
    vector.getSource().removeFeature(selectedFeature);
    overlay.setPosition(undefined);
    interaction.getFeatures().clear();
});
var remove_b = document.getElementById('js-overlay');
var overlay = new ol.Overlay({
    element: remove_b
});
map.addOverlay(overlay);
document.getElementById('js-overlay').style.display = 'block';
var selectedFeature;
var button = $('#pan').button('toggle');
var interaction;
var features;
$('div.btn-group button').on('click', function(event) {
    var id = event.target.id;
    var features;
    button.button('toggle');
    button = $('#' + id).button('toggle');
    map.removeInteraction(interaction);

    switch (id) {
        case "point":
            interaction = new ol.interaction.Draw({
                type: 'Point',
                source: vector.getSource()
            });
            map.addInteraction(interaction);
            break;
        case "line":
            interaction = new ol.interaction.Draw({
                type: 'LineString',
                source: vector.getSource()
            });

            map.addInteraction(interaction);
            break;
        case "polygon":
            interaction = new ol.interaction.Draw({
                type: 'Polygon',
                source: vector.getSource()
            });
            map.addInteraction(interaction);
            break;
        case "modify":

            interaction = new ol.interaction.Modify({
                features: new ol.Collection(vector.getSource().getFeatures())
            });
            map.addInteraction(interaction);

            break;
        case "delete":
            interaction = new ol.interaction.Select({
                condition: ol.events.condition.click,
                layers: [vector]
            });
            map.addInteraction(interaction);

            interaction.on('select', function(event) {
                selectedFeature = event.selected[0];
                (selectedFeature) ? overlay.setPosition(selectedFeature.getGeometry().getExtent()): overlay.setPosition(undefined);

            });
            break;

        default:
            break;
    }
    var snap = new ol.interaction.Snap({
        source: vector.getSource()
    });
    map.addInteraction(snap);
});
.ol-attribution > ul {
    font-size: 1.6rem;
}

.overlay {
    display: none;
    position: absolute;
    background: rgba(255,255,255,0.9);
    box-shadow: 0 0 10px 0 rgba(0,0,0,0.25);
    padding: 15px;
    border-radius: 10px;
    border: 1px solid #ccc;
    width: 180px;
    top: -76px;
    left: -90px;
}

.overlay:after {
    top: 100%;
    border: 10px solid transparent;
    content: "";
    height: 0;
    width: 0;
    position: absolute;
    border-top-color: rgba(255,255,255,0.9);
}

.overlay button + button {
    float: right;
}
<!DOCTYPE html>
<html lang="en">

<head>
    <!-- Required meta tags -->
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <!-- Bootstrap CSS -->
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/css/bootstrap.min.css" integrity="sha384-/Y6pD6FV/Vv2HJnA6t+vslU6fwYXjCFtcEpHbNJ0lyAFsXTsjBbfaDjzALeQsN6M" crossorigin="anonymous">
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/openlayers/4.6.5/ol.css" type="text/css">
</head>

<body>
    <div class="container">
        <nav class="navbar navbar-expand-sm navbar-light bg-light">
            <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarTogglerDemo01" aria-controls="navbarTogglerDemo01" aria-expanded="false" aria-label="Toggle navigation">
                    <span class="navbar-toggler-icon"></span>
                </button>
            <div class="collapse navbar-collapse" id="navbarTogglerDemo01">
                <a class="navbar-brand" href="#">Test</a>
            </div>
        </nav>
        <div id="map" class="map"></div>
        <br>
        <div id="js-overlay">
            <button id="js-remove">Remove</button>
        </div>
        <div class="btn-group btn-group-sm" role="group" aria-label="Draw">
            <button id="pan" type="button" class="btn btn-primary">Pan</button>
            <button id="point" type="button" class="btn btn-success">Point</button>
            <button id="line" type="button" class="btn btn-success">Line</button>
            <button id="polygon" type="button" class="btn btn-success">Polygon</button>
            <button id="modify" type="button" class="btn btn-primary">Modify</button>
            <button id="delete" type="button" class="btn btn-danger">Delete</button>
        </div>

    </div>

    <!-- Optional JavaScript -->
    <!-- jQuery first, then Popper.js, then Bootstrap JS -->
    <script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.11.0/umd/popper.min.js" integrity="sha384-b/U6ypiBEHpOf/4+1nzFpr53nxSS+GLCkfwBdFNTxtclqqenISfwAzpKaMNFNmj4" crossorigin="anonymous"></script>
    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/js/bootstrap.min.js" integrity="sha384-h0AbiXch4ZDo7tp9hKZ4TsHbi047NrKGLO3SEJAg45jXxnGIfYzk4Si90RDIqNm1" crossorigin="anonymous"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/openlayers/4.6.5/ol.js" type="text/javascript"></script>
    <script src="select.js" type="text/javascript"></script>
</body>

</html>

UPDATE_3

So, let's say that I've managed to delete drew features but with some changes in code and with new but I believe manageable error. In delete case I added Select interaction along with delete features. (I've updated code snippet)

So, in delete case I added this block of code:

        interaction = new ol.interaction.Select({
            condition: ol.events.condition.click,
            layers: [vector]
        });
        map.addInteraction(interaction);

        interaction.on('select', function(event) {
            selectedFeature = event.selected[0];
            console.log(selectedFeature.getGeometry().getExtent());
            (selectedFeature) ? overlay.setPosition(selectedFeature.getGeometry().getExtent()): overlay.setPosition(undefined);
        });

        document.getElementById('js-remove').addEventListener('click', function() {
            vector.getSource().removeFeature(selectedFeature);
            overlay.setPosition(undefined);
            interaction.getFeatures().clear();
        });

This successfully deletes drew vectors but produces this error:

Uncaught TypeError: Cannot read property 'forEach' of undefined

This error takes place every time after I successfully delete vector and when I want to add new vector and then delete again that same vector it produces error above. I believe that the problem lies in that last block

document.getElementById('js-remove').addEventListener('click', function() {
    vector.getSource().removeFeature(selectedFeature);
    overlay.setPosition(undefined);
    interaction.getFeatures().clear();
});

Does any one know what may be the problem or how to solve it? I did try for loop instead that last block but without any success. It's worth mention it that when I use code below it simple selects vectors but does not delete it.

   var buttons = document.getElementById('js-remove');
      for (var i = 0; i < buttons.length; i++) {
                 var self = buttons[i];
                 console.log (self);
                self.addEventListener('click', function(event) {
                    vector.getSource().removeFeature(selectedFeature);
                    overlay.setPosition(undefined);
                    interaction.getFeatures().clear();
                });
            }

Solution

  • So, after "stabbing in the dark" I finally figured out (by dumb luck). I just cut this block of code from delete case and put it near top of the code.

    document.getElementById('js-remove').addEventListener('click', function() {
        vector.getSource().removeFeature(selectedFeature);
        overlay.setPosition(undefined);
        interaction.getFeatures().clear();
    });
    

    I've updated question snippet with properly working example, enjoy. I hope it helps someone :)