Search code examples
javascriptselectionopenlayers-3web-feature-service

Polygon selection option in Openlayers 3


I am currently working on a polygon selection tool in Openlayers 3 and am developing on the code posted here.

The above example displays the searchable layer (in this case a WFS) from when the application loads, but as my WFS layer contains 80,000+ features that I need to search against, I am trying to adapt this so that the WFS layer is only displayed once the user completes their search polygon to reduce the loading time, and features only within the bounding box of the drawn polygon are shown.

The JSTS library is then used to do a spatial intersect between the user's drawn polygon and the WFS features added to the map.

The below code works ok as it correctly displays the WFS features in the drawn polygon extent, but it isn't returning the feature's attribute(s) in the console.

I am trying to work out if this is because the layer fully isn't loaded before we try to return the feature's attributes? Do we need to include something to wait until the layer is loaded before carrying out the forEachFeatureInExtent method?

var myDrawSource = new ol.source.Vector({wrapX: false});

var myDrawVector = new ol.layer.Vector({
  source: myDrawSource,
  style: new ol.style.Style({
    fill: new ol.style.Fill({
      color: 'rgba(255, 255, 255, 0.5)'
    }),
    stroke: new ol.style.Stroke({
      color: '#ffcc33',
      width: 2
    }),
    image: new ol.style.Circle({
      radius: 7,
      fill: new ol.style.Fill({
        color: '#ffcc33'
      })
    })
  })
});

var mySelectionsSource = new ol.source.Vector({wrapX: false});

var mySelectionsVector = new ol.layer.Vector({
  source: mySelectionsSource,
  style: new ol.style.Style({
    fill: new ol.style.Fill({
      color: 'rgba(255, 0, 0, 0.5)'
    }),
    stroke: new ol.style.Stroke({
      color: 'rgba(255, 0, 0, 1)',
      width: 2
    }),
    image: new ol.style.Circle({
      radius: 7,
      fill: new ol.style.Fill({
        color: '#ffcc33'
      })
    })
  })
});

var map = new ol.Map({
  layers: [raster,myDrawVector,mySelectionsVector],
  target: 'map',
  view: new ol.View({
    projection: bng,
        resolutions: resolutions,
        center: [501776, 167214],
        zoom: 5
  })
});

var  draw = new ol.interaction.Draw({
      source: myDrawSource,
      type: "Polygon",
    });

map.addInteraction(draw);

draw.on('drawend',function(e){
myDrawSource.clear();
mySelectionsSource.clear();
var waterAreasVecSource = new ol.source.Vector({
        format: new ol.format.GeoJSON(),
        url: function() {
          var featuresExtent = e.feature.getGeometry().getExtent();
          return '../../geoserver/wfs?service=WFS&' +
              'version=1.1.0&request=GetFeature&typename=waterfeature&' +
              'outputFormat=application/json&srsname=EPSG:27700&' +
              'bbox=' + featuresExtent.join(',') + ',EPSG:27700';
        },
        strategy: ol.loadingstrategy.tile(ol.tilegrid.createXYZ({
          maxZoom: 13
        }))
      });

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

map.addLayer(waterAreasVector);
var extent = e.feature.getGeometry().getExtent();
var geomA = e.feature.getGeometry();
waterAreasVecSource.forEachFeatureInExtent(extent,function(aa){
console.log("forEachFeatureInExtent",aa.get('name'));
if (polyIntersectsPoly(geomA,aa.getGeometry()) === true){
mySelectionsSource.addFeature(aa);
}
});
});


/**
* check whether the supplied polygons have any spatial interaction
* @{ol.geometry.Polygon} polygeomA 
* @{ol.geometry.Polygon} polygeomB 
* @returns {Boolean} true||false
*/
function polyIntersectsPoly(polygeomA, polygeomB) {
 var geomA = new jsts.io.GeoJSONReader().read(new ol.format.GeoJSON().writeFeatureObject(
        new ol.Feature({
            geometry: polygeomA
       })
   )
   ).geometry;
var geomB = new jsts.io.GeoJSONReader().read(new ol.format.GeoJSON().writeFeatureObject(
        new ol.Feature({
            geometry: polygeomB
        })
    )
    ).geometry;
return geomA.intersects(geomB);
};

Solution

  • There are several mistakes within the provided fiddle. Adding one more layer each time drawend event is fired is defenanlty wrong. Instead add a vactor layer on start up and then add / remove features on it. here is a working code. and fiddle Check the console to see the logging of feature attributes.

    var raster = new ol.layer.Tile({
      source: new ol.source.OSM({})
    });
    
    var myDrawSource = new ol.source.Vector({wrapX: false});
    
    var myDrawVector = new ol.layer.Vector({
      source: myDrawSource,
      style: new ol.style.Style({
        fill: new ol.style.Fill({
          color: 'rgba(255, 255, 255, 0.5)'
        }),
        stroke: new ol.style.Stroke({
          color: '#ffcc33',
          width: 2
        }),
        image: new ol.style.Circle({
          radius: 7,
          fill: new ol.style.Fill({
            color: '#ffcc33'
          })
        })
      })
    });
    
    var mySelectionsSource = new ol.source.Vector({wrapX: false});
    
    var mySelectionsVector = new ol.layer.Vector({
      source: mySelectionsSource,
      style: new ol.style.Style({
        fill: new ol.style.Fill({
          color: 'rgba(255, 0, 0, 0.5)'
        }),
        stroke: new ol.style.Stroke({
          color: 'rgba(255, 0, 0, 1)',
          width: 2
        }),
        image: new ol.style.Circle({
          radius: 7,
          fill: new ol.style.Fill({
            color: '#ffcc33'
          })
        })
      })
    });
    
    var map = new ol.Map({
      layers: [raster, myDrawVector,mySelectionsVector],
      target: 'map',
      view: new ol.View({
        center: [-8908887.277395891, 5381918.072437216],
        maxZoom: 19,
        zoom: 12
      })
    });
    
    
    var  draw = new ol.interaction.Draw({
          source: myDrawSource,
          type: "Polygon",
        });
    
    map.addInteraction(draw);
    
    //just clear featutes and add back those falling within drawn polygon
    //you need an ajax request and new ol.format.WFS to parse the feats 
    draw.on('drawend',function(e){
    var extent = e.feature.getGeometry().getExtent();
    var geomA = e.feature.getGeometry();
    
    myDrawSource.clear();
    mySelectionsSource.clear();
    $.ajax('http://demo.opengeo.org/geoserver/wfs', {
                type: 'GET',
                data: {
                    service: 'WFS',
                    version: '1.1.0',
                    request: 'GetFeature',
                    typename: 'water_areas',
                    srsname: 'EPSG:3857',
                    bbox: extent.join(',') + ',EPSG:3857'
                }
            }).done(function(resp){
            var formatWFS = new ol.format.WFS();
            var featuresInExtent = formatWFS.readFeatures(resp);
            var featuresOnDrawPoly = new Array();
            for (var i=0;i<featuresInExtent.length;i++){       
            var geomB = featuresInExtent[i].getGeometry();
              if (polyIntersectsPoly(geomA,geomB)===true){
              featuresOnDrawPoly.push(featuresInExtent[i])
              }
            }
            mySelectionsSource.addFeatures(featuresOnDrawPoly);
            //here you may iterate and get the attributes of those falling within the draw polygon
            for (var z=0;z<featuresOnDrawPoly.length;z++){
            console.log("feature landuse is ======", featuresOnDrawPoly[z].get('landuse'));
            }
            }).fail(function () {
            alert("fail loading layer!!!")
            });
    
    })
    
    
    
    
    
    /**
    * check whether the supplied polygons have any spatial interaction
    * @{ol.geometry.Polygon} polygeomA 
    * @{ol.geometry.Polygon} polygeomB 
    * @returns {Boolean} true||false
    */
    function polyIntersectsPoly(polygeomA, polygeomB) {
     var geomA = new jsts.io.GeoJSONReader().read(new ol.format.GeoJSON().writeFeatureObject(
            new ol.Feature({
                geometry: polygeomA
           })
       )
       ).geometry;
    var geomB = new jsts.io.GeoJSONReader().read(new ol.format.GeoJSON().writeFeatureObject(
            new ol.Feature({
                geometry: polygeomB
            })
        )
        ).geometry;
    return geomA.intersects(geomB);
    };