After reading a very good tutorial on how to edit WFS with OpenLayers, I've tried replicating it but with my own WFS layer from Geoserver. Need some Javascript help finding what's wrong with it.
I managed to load the WFS and my basemap successfully and managed to get the buttons to show up. The buttons appear correctly like in the working example from that page but, for some reason the geometry data isn't being saved. Every time a user draws something, a new id is created on the table but its associated geometry column is left empty
The bit for posting is:
var formatWFS = new ol.format.WFS();
var formatGML = new ol.format.GML({
featureNS: 'http://geoserver.org/bftchamber',
featureType: 'bft',
srsName: 'EPSG:27700'
});
var transactWFS = function(p,f) {
switch(p) {
case 'insert':
node = formatWFS.writeTransaction([f],null,null,formatGML);
break;
case 'update':
node = formatWFS.writeTransaction(null,[f],null,formatGML);
break;
case 'delete':
node = formatWFS.writeTransaction(null,null,[f],formatGML);
break;
}
s = new XMLSerializer();
str = s.serializeToString(node);
$.ajax('http://localhost:8080/geoserver/wfs',{
type: 'POST',
dataType: 'xml',
processData: false,
contentType: 'text/xml',
data: str
}).done();
}
Fiddle with the whole code (apologies if it looks messy, most of it comes from the working example 2 )
https://jsfiddle.net/Luffydude/ex06jr1e/6/
The app looks like this:
Also even though my WFS appears correctly along the river Thames when I load it in QGIS, in my app it appears somewhere else in the ocean even though I specified EPSG 27700 (though this is just a minor annoyance at the moment).
My main problem now is how to make the edit buttons save user edits to the WFS layer?
I haven't really looked at OpenLayers in anger for a while and I kind of let slip updating my working examples. I just put together a new JSFiddle with simple WFS-T insert for polygons.
I use Geoserver 2.8 in production (2.9 in dev and testing).
Database backend is PostGIS 2.1 in production (2.2 dev).
The fiddle uses OpenLayers 3.16.
A few notes to my setup. I tend to have all geometries in EPSG:3857 and I do not specify the SRS in PostGIS. Haters gonna hate but I simply set my geometry column to geometry. This way I can get lines, points and polygons in the same table. I cannot see the mixed geometry in QGIS but this is a simple test setup. It's important that the geometry field is called geometry. It's probably possible but I could not make this work with the field being called the_geom or geom. In that case a record is inserted but the geometry field is empty as described in the post. I believe this is the problem.
CREATE TABLE wfs_geom
(
id bigint NOT NULL,
geometry geometry,
CONSTRAINT wfs_geom_pkey PRIMARY KEY (id)
)
WITH (
OIDS=FALSE
);
ALTER TABLE wfs_geom
OWNER TO geoserver;
Here is the code bit from the jsfiddle.
var formatWFS = new ol.format.WFS();
var formatGML = new ol.format.GML({
featureNS: 'https://geolytix.net/wfs',
featureType: 'wfs_geom',
srsName: 'EPSG:3857'
});
var s = new XMLSerializer();
var sourceWFS = new ol.source.Vector({
loader: function (extent) {
$.ajax('https://maps.geolytix.net/geoserver/geolytix.wfs/wfs', {
type: 'GET',
data: {
service: 'WFS',
version: '1.1.0',
request: 'GetFeature',
typename: 'wfs_geom',
srsname: 'EPSG:3857',
bbox: extent.join(',') + ',EPSG:3857'
}
}).done(function (response) {
sourceWFS.addFeatures(formatWFS.readFeatures(response));
});
},
strategy: ol.loadingstrategy.bbox,
projection: 'EPSG:3857'
});
var layerWFS = new ol.layer.Vector({
source: sourceWFS
});
var map = new ol.Map({
target: 'map',
layers: [
new ol.layer.Tile({
source: new ol.source.OSM({
url: 'https://cartodb-basemaps-{a-d}.global.ssl.fastly.net/light_nolabels/{z}/{x}/{y}.png',
opaque: false,
attributions: []
})
}),
layerWFS
],
view: new ol.View({
center: ol.proj.fromLonLat([-0.1, 51.50]),
zoom: 13
})
});
var interaction = new ol.interaction.Draw({
type: 'Polygon',
source: layerWFS.getSource()
});
map.addInteraction(interaction);
interaction.on('drawend', function (e) {
$.ajax('https://maps.geolytix.net/geoserver/geolytix.wfs/wfs', {
type: 'POST',
dataType: 'xml',
contentType: 'text/xml',
data: s.serializeToString(formatWFS.writeTransaction([e.feature], null, null, formatGML))
}).done();
});
Related
I've got problem with wms heatmap layer in cesium. I know how to handle it in openlayers (single tile) and in leaflet (non tiled plugin) but I don't know how to handle it on 3d globe.
Here is my example code
const imageryLayers = this.viewer.imageryLayers;
imageryLayers.addImageryProvider(
new Cesium.WebMapServiceImageryProvider({
url: "http://localhost:8084/geoserver/test/wms/",
layers: "points2",
parameters: {
service: 'WMS',
version: '1.3.0',
transparent: true,
format: "image/png",
},
})
);
You have to specify GeoServer workspace name in the layers parameter.
And need to specify srs in the "parameters"
Here's the sample code.
const geoServerUrl = "http://localhost:8090/geoserver"
const layerName = "tiger:poly_landmarks";
const parameters = {
version: '1.1.1',
format: 'image/png',
srs: 'EPSG:4326',
transparent: true,
"exceptions": 'application/vnd.ogc.se_inimage',
};
const webMapServiceImageryProviderOptions = {
url: geoServerUrl + "/tiger/wms",
layers: layerName,
parameters: parameters,
};
const imageryLayer = new Cesium.ImageryLayer(new Cesium.WebMapServiceImageryProvider(webMapServiceImageryProviderOptions));
viewer.imageryLayers.add(imageryLayer);
I started working on a Vector Layer to render SQL Spatial Data in OpenLayers. When rendering this example (see Json) everything works perfectly fine. See code below:
//creates source to get json data from
let vSource = new VectorSource({
url: '/assets/germany.json',
format: new GeoJSON()
});
//set focus of the camera on this source
vSource.on('addfeature', () => {
this.map.getView().fit(vSource.getExtent());
console.log(this.map.getView().getCenter());
});
//add source to layer and afterwards load it into map
let vLayer = new VectorLayer({
source: vSource,
visible: true
});
//layer styling
vLayer.setStyle(new Style({
stroke: new Stroke({
color: '#FF5733',
width: 8
})
}));
this.map.addLayer(vLayer);
Map instantiation looks as following:
this.map = new Map({
view: new View({
center: [10, 10],
zoom: 3,
}),
layers: [],
target: 'ol-map'
});
But when i want to render this json file I am facing a blank map. Focus wont get set and not even errors appear. I am assuming its all about the boundaries?
How can Polygon coordinates get rendered which are our outside default boundaries, if there is such thing as "default"?
For example:
[12058.4521484375, 5345.98388671875],
[11408.95703125, 5345.98388671875]
Reading through the API I can deduce that the option extent may be key to solving this issue?
Best regards
A newbie at OpenLayers
Openlayers default projection is EPSG:3857. I think your geojson and center of map is EPSG:4326.
this.map = new Map({
view: new View({
projection: 'EPSG:4326',
center: [10, 10],
zoom: 3,
}),
layers: [],
target: 'ol-map'
});
let vSource = new VectorSource({
url: '/assets/germany.json',
format: new GeoJSON({ featureProjection: 'EPSG:3857' })
});
I have being playing around with MapBox and I am having some issues with getting the GeoLocation API to send data back to the map and update the it.
This is what I got right now:
mapboxgl.accessToken = 'TOKEN-HERE';
var map = new mapboxgl.Map({
container: 'map', // container id
style: 'mapbox://styles/mapbox/streets-v9',
center: [-0.968539, 54.562917],
zoom: 9
});
map.on('style.load', function() {
map.addSource("myMap", {
"type": "geojson",
"data": "https://api.mapbox.com/geocoding/v5/mapbox.places/UK_ADDRESS_HERE.json?country=gb&types=address&autocomplete=true&access_token=TOEKN"
});
map.addLayer({
'id': 'test1',
'type': 'line',
'source': 'myMap',
'interactive': true
});
});
The answer may lie with how you are encoding UK_ADDRESS_HERE.
https://api.mapbox.com/geocoding/v5/mapbox.places/UK_ADDRESS_HERE.json
The request format for the Mapbox Geocding API requires that since the {query} parameter can contain any value, it should be URL-encoded.
That means that a simple geocode request like 10 Downing Street, Westminster must be encoded using encodeURIComponent to 10%20Downing%20Street%2C%20Westminster.
Try this and verify that your request is proper.
curl https://api.tiles.mapbox.com/geocoding/v5/mapbox.places/10%20Downing%20Street%2C%20London.json?access_token=${MAPBOX_ACCESS_TOKEN}
My intention is to load GeoJSON data and display it on the map. Coordinates of the features specified in GeoJSON are normal lon/lat. For some reason openlayers is rendering them using the projection used by the map and without converting them.
// Underlying sat layer.
var world = new ol.layer.Tile({
source: new ol.source.MapQuest({layer: 'sat'})
});
// GeoJSON data.
var geojsonObject = {
'type': 'FeatureCollection',
'features': [
{
'type': 'Feature',
'geometry': {
'coordinates': [ 50.07539747, 19.76809501 ],
'type': 'Point'
},
}
]
};
var vectorSource = new ol.source.Vector({
features: (new ol.format.GeoJSON()).readFeatures(geojsonObject)
});
var vectorLayer = new ol.layer.Vector({
source: vectorSource
});
// Map.
map = new ol.Map({
target: 'map',
layers: [world, vectorLayer],
view: new ol.View({
center: ol.proj.transform([37.41, 8.82], 'EPSG:4326', 'EPSG:3857'),
zoom: 2
})
});
The point is being rendered in the middle of the map. By placing multiple points I determined that they are in fact moved relative to each other but by a small amount which leads me to believe the for some reason the map uses a different coordinate system for them.
What I tried:
Setting crs in GeoJSON, providing defaultDataProjection option to format. I use openlayers v3.8.2 and all solutions I found online are very outdated (and as far as I can see the API used to be way better, maybe I should just switch to an old version).
Just use a featureProjection to read features like:
var vectorSource = new ol.source.Vector({
features: new ol.format.GeoJSON().readFeatures(geojsonObject,{
featureProjection: 'EPSG:3857'
})
});
UPDATE:
When reading features from url is even easier, OL makes the conversion internally for you:
var geojson_layer = new ol.layer.Vector({
source: new ol.source.Vector({
url: 'file.geojson',
format: new ol.format.GeoJSON()
})
});
Demo - http://plnkr.co/edit/GvdVNE?p=preview
I want to implement this example http://api.geoext.org/1.1/examples/feature-grid.html made of geoext and openlayers, that feature grid is populated of a geojson file
In my development I have a geojson file with utm format, this is a single feature of my file (the coordinates are utm)
{"geometry": {"type": "Point", "coordinates": [7535169.36, 402844.172]}, "type": "Feature", "properties": {"NOMBRE": "LA VICTORIA", "CODIGO": "1702"}, "id": "1702"}
I tried to show the points in my code, but I can't see anything, this is my code
// create feature store, binding it to the vector layer
store = new GeoExt.data.FeatureStore({
layer: vecCiudades,
fields: [
{ name: 'NOMBRE' },
{ name: 'CODIGO' }
],
proxy: new GeoExt.data.ProtocolProxy({
protocol: new OpenLayers.Protocol.HTTP({
url: "data/summits.json",
format: new OpenLayers.Format.GeoJSON({
ignoreExtraDims: true,
internalProjection: new OpenLayers.Projection("EPSG:900913"),
externalProjection: new OpenLayers.Projection("EPSG:4326")
})
})
}),
autoLoad: true
});
as you can see, I tried to specify the internal and external projection of the feature store, my implementation looks like the example of the link mentioned above, but when I select a city the map is located to a wrong place (the place is shown near south pole, but it has to be near south america)
Thanks in advance
For what reason FeatureStore..? Just define layer as following:
var vecCiudades = new OpenLayers.Layer.Vector('MyLayer', {
strategies:[new OpenLayers.Strategy.BBOX()],
isBaseLayer:false,
projection:new OpenLayers.Projection("EPSG:900913"),
styleMap:new OpenLayers.StyleMap(null),
transitionEffect:'resize',
protocol:new OpenLayers.Protocol.HTTP({
url: "data/summits.json",
format:new OpenLayers.Format.GeoJSON({
ignoreExtraDims:true
}),
readWithPOST:false,
updateWithPOST:false,
srsInBBOX:true
})
});
Also register following event on map:
map.events.register("moveend", this, function (e) {
vecCiudades.refresh({force:true});
});
That will reread GeoJSON anytime moved or zoomed map and request will contain bounding box of visible area so you can only send features that going to be visible not all of them.