I'm working on an app using GeoServer and OpenLayers 2.13.1. I have several WMS layers and I need to export whatever in my openlayers map div as an image. After researching, I found this blog: http://blogs.edina.ac.uk/category/openlayers-html5-canvas/ which is working fine (exporting my layers as an image).
However, my wms layer also has dynamic sld functionality (using SLD_BODY). The problem shows up when I use attribute-based sld: it wasn't drawn on the canvas. It only works when I use non-attribute-based sld.
Did I miss something here?
This is how I call the wms layer:
wms = new OpenLayers.Layer.WMS(layer_name,
WMSServiceURL, {
layers: "bappeko:"+map_name,
styles: null,
transparent: true,
format: "image/jpeg"
},{
ratio: 1,
singleTile: true,
tileOptions: {maxGetUrlLength: 2048},
buffer: 0,
projection: new OpenLayers.Projection("EPSG:32749")
}
);
map.addLayer(wms);
This is JS function I used to export:
function exportMap() {
var mapcanvasDiv = null ;
var mapDiv = document.getElementById("mapdiv") ;
if (mapcanvasDiv === null) {
var canvasElement = document.createElement("canvas");
canvasElement.id = "mapcvs";
mapcanvasDiv = document.getElementById("mapcanvas");
mapcanvasDiv.appendChild(canvasElement) ;
canvasElement.width = mapDiv.clientWidth ;
canvasElement.height = mapDiv.clientHeight ;
}
var mapCanvas = document.getElementById("mapcvs");
var mapContainer = document.getElementById("OpenLayers_Map_2_OpenLayers_Container");
if (mapCanvas !== null) {
var ctx = mapCanvas.getContext("2d");
ctx.clearRect(0, 0, mapCanvas.width, mapCanvas.height);
var olLayersDiv = document.getElementsByClassName("olLayerDiv");
var olLayers = map.layers;
for (var i=0; i<olLayersDiv.length; i++){
//ONLY EXPORT VISIBLE LAYERS
if (olLayers[i].visibility == true) {
var layertiles = olLayersDiv[i].getElementsByClassName("olTileImage");
for(var j=0; j<layertiles.length; j++) {
var tileImg = layertiles[j];
var offsetLeft = tileImg.offsetLeft;
var offsetTop = tileImg.offsetTop;
var left = Number(mapContainer.style.left.slice(0, mapContainer.style.left.indexOf("p")));
var top = Number(mapContainer.style.top.slice(0, mapContainer.style.top.indexOf("p")));
ctx.drawImage(tileImg, 0, 0);
}
}
}
var dataUrl = mapCanvas.toDataURL();
window.open(dataUrl, "toDataURL() image", "width=600, height=360");
}
This is how I set my dynamic SLD (the SLD is created dynamically by PHP script via Ajax) in JS:
l = map.getLayersByName(layer_name)[0];
l.mergeNewParams({sld_body: sld, styles: null});
I guess I've found the culprit: It seems that my PHP-created SLD is way too long even when I've set tileOptions: {maxGetUrlLength: 2048}
because I use many <ogc:Filter>
for my Attribute-Based SLD.
Here's what I've tried: I put my SLD in a text file and load it using SLD: some_url/text.sld
param, instead of putting it straight to SLD_BODY like I did before. But another error happens, the map won't load (pink image) and I'm getting this error Resource interpreted as Image but transferred with MIME type application/vnd.ogc.se_xml: http://localhost/geoserver/wms?...
Seems like the WMS request doesn't return an image but XML.
Best Answer
Here's what I did, and it finally works.
First, I created a sld file and saved it to the some folder in PHP:
Then the file url is passed to JS using AJAX and set it to the layer using
SLD
param:the
file:///
will works on localhost. When online, you need to save it to a folder (e.g.sld/
) and call it fromhttp_your_domain/sld/your_sld_file
.So this way, I don't need to send my complete sld (which can be very-very long when we use many filters). I just need to send the url of sld file created which is much shorter.