Sunday, 15 May 2016

OpenLayers 3 WMS Styling Using SLD_BODY and POST request



I'm using OpenLayers 3 and GeoServer to create a spatial web application in which I want to enable users to choose a colour ramp (using Colorbrewer) and a number of breaks for styling an attribute in their analysis layer (i.e. to style a choropleth). I have been able to get this working by dynamically generating an SLD XML string and passing it in as the value to the SLD_BODY parameter in the TileWMS source, but only with 3 breaks/classes. When I select 4 or more classes nothing is returned and I believe the issue is that the SLD becomes too long for the OpenLayers TileWMS GET request. I have read a variety of posts that explain you can do a POST request in OpenLayers 2 to get around this issue, but I haven't found anything on how to do this using OpenLayers 3. Only a response in this post hints at a solution, but it's not enough for me to work out an answer. The following is how I'm currently defining the layer and adding the SLD. Does anyone know how to get around character limit with the OpenLayers 3 GET request by using POST instead?


window.layer = new ol.layer.Tile({
source: new ol.source.TileWMS({
url: 'http://' + window.location.hostname + ':8080/geoserver/wms',
params: {LAYERS: geoserverLayer, STYLES: undefined, SLD_BODY: sld, CQL_FILER: geoserverFilter, TILED: true},
serverType: 'geoserver'
})
});

Answer



I am not sure whether my answer is going to give you the final solution. But give it a try and let us know if something good comes up. So do the following:





  1. add tileLoadFunction to your source. Like so:


    window.layer = new ol.layer.Tile({
    source: new ol.source.TileWMS({
    url: 'http://' + window.location.hostname + ':8080/geoserver/wms',
    params: {LAYERS: geoserverLayer, STYLES: undefined, SLD_BODY: sld, CQL_FILER: geoserverFilter, TILED: true},
    serverType: 'geoserver',
    tileLoadFunction: function(image, src) {
    imagePostFunction(image, src);

    }
    })
    });


  2. create your custom imagePostFunction like so:


    function imagePostFunction(image, src) {
    var img = image.getImage();
    if (typeof window.btoa === 'function') {
    var xhr = new XMLHttpRequest();

    xhr.open('POST', src, true);
    xhr.responseType = 'arraybuffer';
    xhr.onload = function(e) {
    if (this.status === 200) {
    console.log("this.response",this.response);
    var uInt8Array = new Uint8Array(this.response);
    var i = uInt8Array.length;
    var binaryString = new Array(i);
    while (i--) {
    binaryString[i] = String.fromCharCode(uInt8Array[i]);

    }
    var data = binaryString.join('');
    var type = xhr.getResponseHeader('content-type');
    if (type.indexOf('image') === 0) {
    img.src = 'data:' + type + ';base64,' + window.btoa(data);
    }
    }
    };
    xhr.send();
    } else {

    img.src = src;
    }
    }

    It should force ol3 to execute a POST request but I am not sure if parameters are going to be passed to the POST body of the request and thus solve the long url problem.




Also consider the following post , might helps. In any way please let us know if it works.


UPDATE HERE FOR imagePostFunction


function imagePostFunction(image, src) {

var img = image.getImage();
if (typeof window.btoa === 'function') {
var xhr = new XMLHttpRequest();
console.log("src",src);
**//GET ALL THE PARAMETERS OUT OF THE SOURCE URL**
var dataEntries = src.split("&");
var url;
var params = "";
for (var i = 0 ; i< dataEntries.length ; i++){
console.log("dataEntries[i]",dataEntries[i]);

if (i===0){
url = dataEntries[i];
}
else{
params = params + "&"+dataEntries[i];
}
}
console.log("params",params);
xhr.open('POST', url, true);


xhr.responseType = 'arraybuffer';
xhr.onload = function(e) {
if (this.status === 200) {
console.log("this.response",this.response);
var uInt8Array = new Uint8Array(this.response);
var i = uInt8Array.length;
var binaryString = new Array(i);
while (i--) {
binaryString[i] = String.fromCharCode(uInt8Array[i]);
}

var data = binaryString.join('');
var type = xhr.getResponseHeader('content-type');
if (type.indexOf('image') === 0) {
img.src = 'data:' + type + ';base64,' + window.btoa(data);
}
}
};
//SET THE PROPER HEADERS AND FINALLY SEND THE PARAMETERS
xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
xhr.setRequestHeader("Content-length", params.length);

xhr.setRequestHeader("Connection", "close");
xhr.send(params);
} else {
img.src = src;
}
}

No comments:

Post a Comment

arcpy - Changing output name when exporting data driven pages to JPG?

Is there a way to save the output JPG, changing the output file name to the page name, instead of page number? I mean changing the script fo...