0

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);
};
Community
  • 1
  • 1
Chris
  • 647
  • 1
  • 8
  • 32
  • Are you sure you get back feature attributes when loading your wfs layer?. I have used `console.log("forEachFeatureInExtent",aa.get('landuse'));` within the fiddle you provide and it works fine. check it here http://jsfiddle.net/p_tsagkis/p8qhowy9/7/ – pavlos Mar 09 '16 at 22:38
  • What I am trying to do is dynamically add the layer and set the extent to the current map view when initiating the draw interaction - yes your fiddle does work but this loads the layer from start up. I cannot seem to get it working when adding the layer when activating the draw option. – Chris Mar 14 '16 at 12:33
  • I have updated the fiddle to try and ideally get what I need where the layer is loaded on the completion of the draw, with the water areas layer loaded only to the bounding extent of the drawn feature, but you will notice the features do not output to the console - do I need a further step? Fiddle is here http://jsfiddle.net/p8qhowy9/14/ – Chris Mar 17 '16 at 13:26
  • I just added an answer which should solve your problem. – pavlos Mar 17 '16 at 14:25

1 Answers1

2

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);
};
pavlos
  • 3,001
  • 18
  • 23
  • Oops, I just tried it within my own set up though and it has given me an error of "ol.js:51 Uncaught TypeError: Cannot read property 'f' of undefined" - if you know what 'f' might refer to then great but I will probably need to resolve this as your example works perfectly! I am using the proj4 library as my data is in a different SRID and checking the error line I do notice something about meter units so not sure if it could be a problem with this? – Chris Mar 18 '16 at 10:26
  • use the ol-debug.js file instead of ol.js so you can get the proper error – pavlos Mar 18 '16 at 11:42
  • Ah good idea - returns an error of Cannot read property 'getAxisOrientation' of undefined. I was thinking I might need to specify my srs or projection in the readFeatures request, but this should recognise my projection as the application is set with it? – Chris Mar 18 '16 at 12:20
  • It has to do with the projection you use. Better make a new question and create a fiddle so we can see the error and help you. – pavlos Mar 18 '16 at 12:52
  • I am unable to get it into jsfiddle because of problems with cross origin :( I will post a new question with a link to it though. – Chris Mar 18 '16 at 14:40