Display popup with multiple layers - openlayers - javascript

I am using geoserver and openlayers to display popup by clicking I have displayed popup with one layer. But I couldn't display popup when I have multiple layers.
map = new ol.Map({
target: 'map',
layers: [
new ol.layer.Group({
layers: [
new ol.layer.Group({
layers: [
new ol.layer.Tile({
source: new ol.source.Stamen({
layer: 'baselayer'
})
}),
new ol.layer.Image({
title:'Sometitle',
source: new ol.source.ImageWMS(
{
ratio:1,
url:"http://localhost:wp/wms",
params:{
'LAYERS':'layer:layername',
}
})
}),
new ol.layer.Image({
title:'sometitle2',
source: new ol.source.ImageWMS(
{
ratio:1,
url:"http://localhost:wp/wms",
params:{
'LAYERS':'layer:layername',
}
})
}),
Then using the popup codes,
//Scripts for popup
var popup = new ol.Overlay.Popup();
map.addOverlay(popup);
//Displaying popup on click
map.on('singleclick', function(evt) {
console.log("In singleClick");
//Check for visible layers
var data = [];
layer = map.getSource(); //
var url = layer.getGetFeatureInfoUrl(
evt.coordinate, viewResolution, view.getProjection(),
reqwest({
url: url,
type: 'json',
}).then(function (data) {
if (data.features.length == 0) {
popup.hide(); //If user clicks outside
return;
}
for (var i = 0; i < data.features.length; i++)
{
console.log("In for");
var feature = data.features[i]; //Read features of JSON array
var props = feature.properties; //Read properties of feature array
var data1 = [];
var data2 = [];
Finally after all codes for popup(That worked for me to display popup for single layer) I used this line to render my popup.
popup.show(evt.coordinate,popup);

If you find it easier to have separate layers, e.g. in the GIS StackExchange question you only display bedrock geology:
source: new ol.source.ImageWMS({
url: 'http://ogc.bgs.ac.uk/cgi-bin/BGS_Bedrock_and_Superficial_Geology/wms',
params: {
'FORMAT': 'image/png',
'LAYERS': 'GBR_BGS_625k_BLS',
'TRANSPARENT': 'TRUE'
},
attributions: bgsAttrib,
}),
in an info request you can specify other layers to query, so you could get bedrock and superficial geology in one popup:
source.getGetFeatureInfoUrl( evt.coordinate,
view.getResolution,
view.getProjection(),
{ 'QUERY_LAYERS': 'GBR_BGS_625k_BLS,GBR_BGS_625k_SLS',
'INFO_FORMAT': 'text/html',
'FEATURE_COUNT': '10'} );

Related

.getFeatures() method for ol.source.Vector instance working in console, but not in script

I'm trying to return the attributes of a vector source in OpenLayers (v.4) using the .getFeatures function some indexing, and the .get('key') method, like so: gdeltVectorSource.getFeatures()[15].get('count'). When I enter this into the developer console in Chrome, the result is as expected and it works just fine. However, when added to the script referenced in the html document, it returns: Uncaught TypeError: Cannot read property 'get' of undefined at pen.js:46. It seems to fail to return an array of features from .getFeatures(). Can someone help me understand why this occurs? I'd like to return attributes of a vector source in order to use the values ('count' in this example) in styling, etc. Is there something about how javascript compiles and runs code that I'm missing?
Here's a link to a codepen that illustrates what I'm talking about. The points don't display (I don't know why, but it's irrelevant), but the source loads just fine. Also note, you'll have to open the chrome console to see error message.
Thank you for stopping to read my question!
The $.ajax call is asynchronous. You need to process/use the features in the callback function when/where they exist:
current code:
$.ajax({
type: 'GET',
url: gdeltURL,
dataType: "json",
success: function(data) {
// console.log(typeof JSON.stringify(data))
// 'canot read property 'readFeatures' of undefined
var geojsonFormat = new ol.format.GeoJSON();
// console.log(typeof geojsonFormat)
var features = geojsonFormat.readFeatures(data, {
});
gdeltVectorSource.addFeatures(features);
}
});
// snip...
console.log(gdeltVectorSource.getFeatures()[15].get('count'))
should be:
$.ajax({
type: 'GET',
url: gdeltURL,
dataType: "json",
success: function(data) {
// console.log(typeof JSON.stringify(data))
// 'canot read property 'readFeatures' of undefined
var geojsonFormat = new ol.format.GeoJSON();
// console.log(typeof geojsonFormat)
var features = geojsonFormat.readFeatures(data, {
});
gdeltVectorSource.addFeatures(features);
console.log(gdeltVectorSource.getFeatures()[15].get('count'))
}
});
proof of concept fiddle
code snippet:
var osm = new ol.layer.Tile({
source: new ol.source.OSM()
});
function styleFn(f) {
var retSytle;
f.set('styledwithcolor', "red");
retSytle = new ol.style.Style({
image: new ol.style.Circle({
radius: 6,
stroke: new ol.style.Stroke({
color: 'white',
width: 2
}),
fill: new ol.style.Fill({
color: "red"
})
})
});
return [retSytle];
}
var gdeltVectorSource = new ol.source.Vector({
// format: new ol.format.GeoJSON()
})
var gdeltLayer = new ol.layer.Vector({
source: gdeltVectorSource,
visible: true,
style: styleFn
});
var gdeltURL = "https://api.gdeltproject.org/api/v2/geo/geo?query=theme:WB_1791_AIR_POLLUTION&format=GeoJSON"
$.ajax({
type: 'GET',
url: gdeltURL,
dataType: "json",
success: function(data) {
// console.log(typeof JSON.stringify(data))
// 'canot read property 'readFeatures' of undefined
var geojsonFormat = new ol.format.GeoJSON();
// console.log(typeof geojsonFormat)
var features = geojsonFormat.readFeatures(data, {
featureProjection: 'EPSG:3857'
});
gdeltVectorSource.addFeatures(features);
console.log(gdeltVectorSource.getFeatures()[15].get('count'))
}
});
var map = new ol.Map({
layers: [osm, gdeltLayer],
target: 'map',
controls: ol.control.defaults({
attributionOptions: {
collapsible: false
}
}),
view: new ol.View({
center: [-11000000, 4600000],
zoom: 4
})
});
html,
body,
#map {
height: 100%;
width: 100%;
padding: 0px;
margin: 0px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/openlayers/4.6.5/ol-debug.js"></script>
<div id="map" class="map"></div>
The features are loaded in the ajax call, which returns after the remaining code (creating the map and trying to display the count value) has executed.
Getting the desired feature attribute works fine. You can try putting the call within the ajax function.
To solve your issue, either don't use ajax or ensure the features are loaded before accessing them.

ol3Cesium map not loading, giving error ''olcs is not defined"

I am unable to load ol3cesium map in Ionic 2.
My index.html (code within body tag):
<ion-app></ion-app>
<script src="http://openlayers.org/en/v3.16.0/build/ol.js"
<script src="../ol3-cesium-v1.17/ol3cesium.js"></script>
<script src="../ol3-cesium-v1.17/Cesium/Cesium.js"></script>
My home.ts:
Inside constructor, below code is added --
var view = new ol.View({
projection: 'EPSG:4326',
center: [-100, 35],
zoom: 3
});
var layer = new ol.layer.Tile({
source: new ol.source.TileWMS({
url: 'http://demo.boundlessgeo.com/geoserver/wms',
params: {
'LAYERS': 'ne:NE1_HR_LC_SR_W_DR'
}
})
});
var overlay = new ol.layer.Tile({
opacity: 0.7,
extent: [-124.74, 24.96, -66.96, 49.38],
source: new ol.source.TileWMS(/** #type {olx.source.TileWMSOptions} */({
url: 'http://demo.boundlessgeo.com/geoserver/wms',
params: { 'LAYERS': 'topp:states', 'TILED': true },
serverType: 'geoserver',
crossOrigin: 'anonymous'
}))
});
var ol2d = new ol.Map({
layers: [layer, overlay],
target: 'map2d',
view: view
});
var ol3d = new olcs.OLCesium({ map: ol2d });
var scene = ol3d.getCesiumScene();
var terrainProvider = new Cesium.CesiumTerrainProvider({
url: '//assets.agi.com/stk-terrain/world'
});
ol3d.getCesiumScene().scene.terrainProvider = terrainProvider;
ol3d.setEnabled(true);
});
'map2d' is my div id in home.html.
I don't know why it is saying 'olcs is not defined' when running the project by ionic serve --lab. How can I resolve this JavaScript issue?
i solved it.
Actually i had to put cesium.js and ol3cesium inside www folder.

OpenLayers 3: Forcing a vector layer to reload GeoJSON source

I'm trying to force a vector layer in OpenLayers 3 to periodically reload its data from a GeoJSON source. The GeoJSON source changes from time to time.
After many different attempts using different methods, I think this is the closest I've managed to get so far:
$(document).ready(function(){
map.once("postcompose", function(){
//start refreshing each 3 seconds
window.setInterval(function(){
var source = testLayer.getSource();
var params = source.getParams();
params.t = new Date().getMilliseconds();
source.updateParams(params);
}, 3000);
});
});
However this is giving me the following (every 3 seconds of course):
Uncaught TypeError: source.getParams is not a function
Here's all of the other code I'm using to load and display the GeoJSON file. The other layers in the map are loaded in the same way:
var testSource = new ol.source.Vector({
url: '/js/geojson/testfile.geojson',
format: new ol.format.GeoJSON()
});
...
window.testLayer = new ol.layer.Vector({
source: testSource,
style: function(feature, resolution) {
var style = new ol.style.Style({
fill: new ol.style.Fill({color: '#ffffff'}),
stroke: new ol.style.Stroke({color: 'black', width: 1}),
text: new ol.style.Text({
font: '12px Verdana',
text: feature.get('testvalue'),
fill: new ol.style.Fill({
color: 'rgba(255, 255, 255, 0.1)'
}),
stroke: new ol.style.Stroke({
color: 'rgba(0, 0, 0, 1)',
width: 1
})
})
});
return style
}
});
...
var olMapDiv = document.getElementById('olmap');
var map = new ol.Map({
layers: [paddocksLayer,zonesLayer,structuresLayer,roadsLayer,testLayer],
interactions: ol.interaction.defaults({
altShiftDragRotate: false,
dragPan: false,
rotate: false
}).extend([new ol.interaction.DragPan({kinetic: null})]),
target: olMapDiv,
view: view
});
view.setZoom(1);
view.setCenter([0,0]);
I read somewhere else that getParams simply doesn't work on vector layers, so this error wasn't entirely unexpected.
Is there an alternative method which will reload (not just re-render) a vector layer?
Thanks in advance. I must also apologise in advance as I'll need really specific guidance with this - I'm very new to JS and OpenLayers.
Gareth
(fiddle)
You can achieve this with a custom AJAX loader (when you pass url to ol.source.Vector this is AJAX as well). Then you can reload your JSON file as you will.
You can use any AJAX library you want but this is as simple as:
var utils = {
refreshGeoJson: function(url, source) {
this.getJson(url).when({
ready: function(response) {
var format = new ol.format.GeoJSON();
var features = format.readFeatures(response, {
featureProjection: 'EPSG:3857'
});
source.addFeatures(features);
source.refresh();
}
});
},
getJson: function(url) {
var xhr = new XMLHttpRequest(),
when = {},
onload = function() {
if (xhr.status === 200) {
when.ready.call(undefined, JSON.parse(xhr.response));
}
},
onerror = function() {
console.info('Cannot XHR ' + JSON.stringify(url));
};
xhr.open('GET', url, true);
xhr.setRequestHeader('Accept','application/json');
xhr.onload = onload;
xhr.onerror = onerror;
xhr.send(null);
return {
when: function(obj) { when.ready = obj.ready; }
};
}
};

Changing Source url of a XYZ layer and redrawing the layer/map?

I wanna change the url of my ol3 map source. I've tryed using things such as map.set or map.getlayers().set or whatever but I can't seem to find a way to access my source object. Here's the code:
function init() {
var map = new ol.Map({
target: 'map',
layers: [
new ol.layer.Tile({
source: new ol.source.XYZ({
projection: 'PIXELS',
tileGrid: mapTileGrid,
url: loc
})
})
],
view: new ol.View({
projection: ol.proj.get('PIXELS'),
extent: mapExtent,
maxResolution: mapTileGrid.getResolution(0)
})
});
map.getView().fit(mapExtent, map.getSize());
console.log(map.get("layergroup").get("layers").get("url"));
map.get("layergroup").get("layers").set("url",loc);
}
What's a way to change the url property and reload the layer ?
I also tried using the setSource function as in the following answer : here
but it seems to not work (can't setSource of undefined).
try the following
function init() {
var map = new ol.Map({
target: 'map',
layers: [
new ol.layer.Tile({
source: new ol.source.XYZ({
projection: 'PIXELS',
tileGrid: mapTileGrid,
url: loc
})
})
],
view: new ol.View({
projection: ol.proj.get('PIXELS'),
extent: mapExtent,
maxResolution: mapTileGrid.getResolution(0)
})
});
map.getView().fit(mapExtent, map.getSize());
//get alll the layers exist on your map
var layers = map.getLayers();
//lets assume you want to set the url for the first layer found
layers[0].getSource().setUrl(loc);
}

OpenLayers-3 - What is the correct usage of source.clear()

I have a ol 3.10.1 map where the goal is to redraw the features of a layer dynamically. On the road to get there, I'm using the source.clear() function. The strange thing is that the source.clear() actually clear the features from the layer at the current zoom level, but while zooming in or out the features are still there. Am I using the source.clear() function the correct way? Please find bellow the code snippet which I'm using for testing purposes.
var image = new ol.style.Circle({
radius: 5,
fill: null,
stroke: new ol.style.Stroke({color: 'red', width: 1})
});
var styles = {
'Point': [new ol.style.Style({
image: image
})]};
var styleFunction = function(feature, resolution) {
return styles[feature.getGeometry().getType()];
};
var CITYClusterSource = new ol.source.Cluster({
source: new ol.source.Vector({
url: 'world_cities.json',
format: new ol.format.GeoJSON(),
projection: 'EPSG:3857'
}),
})
var CITYClusterLayer = new ol.layer.Vector({
source: CITYClusterSource,
style: styleFunction
});
setTimeout(function () { CITYClusterSource.clear(); }, 5000);
var map = new ol.Map({
target: 'map',
renderer: 'canvas',
layers: [
new ol.layer.Tile({
source: new ol.source.OSM(),
}),
CITYClusterLayer
],
view: new ol.View({
center: ol.proj.transform([15.0, 45.0], 'EPSG:4326', 'EPSG:3857'),
zoom:3
})
});
I'm using the setTimout() function to have the features visible for some seconds, before they are supposed to be cleared.
Please advice.
UPDATE: http://jsfiddle.net/jonataswalker/ayewaz87/
I forgot, OL will load your features again and again, for each resolution. So if you want to remove once and for all, use a custom loader, see fiddle.
Your source is asynchronously loaded, so set a timeout when it's ready:
CITYClusterSource.once('change', function(evt){
if (CITYClusterSource.getState() === 'ready') {
// now the source is fully loaded
setTimeout(function () { CITYClusterSource.clear(); }, 5000);
}
});
Note the once method, you can use on instead of it.

Categories