Merge pull request #382 from ahocevar/wps
WPS example and improvements. r=@marcjansen,@bartvde
This commit is contained in:
BIN
examples/data/tazdem.tiff
Normal file
BIN
examples/data/tazdem.tiff
Normal file
Binary file not shown.
@@ -20,7 +20,7 @@ allowedHosts = ['www.openlayers.org', 'openlayers.org',
|
||||
'prototype.openmnnd.org', 'geo.openplans.org',
|
||||
'sigma.openplans.org', 'demo.opengeo.org',
|
||||
'www.openstreetmap.org', 'sample.azavea.com',
|
||||
'v2.suite.opengeo.org', 'v-swe.uni-muenster.de:8080',
|
||||
'v2.suite.opengeo.org', 'v-swe.uni-muenster.de:8080',
|
||||
'vmap0.tiles.osgeo.org', 'www.openrouteservice.org',
|
||||
'maps.wien.gv.at']
|
||||
|
||||
|
||||
87
examples/wps.html
Normal file
87
examples/wps.html
Normal file
@@ -0,0 +1,87 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">
|
||||
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||
<title>OpenLayers WPS Builder Example</title>
|
||||
<link rel="stylesheet" href="../theme/default/style.css" type="text/css">
|
||||
<link rel="stylesheet" href="style.css" type="text/css">
|
||||
<style type="text/css">
|
||||
.olControlEditingToolbar .olControlModifyFeatureItemInactive {
|
||||
background-image: url(../theme/default/img/draw_point_off.png);
|
||||
}
|
||||
.olControlEditingToolbar .olControlModifyFeatureItemActive {
|
||||
background-image: url(../theme/default/img/draw_point_on.png);
|
||||
}
|
||||
textarea {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 3em;
|
||||
}
|
||||
label {
|
||||
display: block;
|
||||
}
|
||||
.notsupported {
|
||||
color: red;
|
||||
}
|
||||
button {
|
||||
display: block;
|
||||
margin-top: 10px;
|
||||
}
|
||||
#docs {
|
||||
top: 6em;
|
||||
left: 550px;
|
||||
position: absolute;
|
||||
margin-right: 10px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1 id="title">WPS Builder Example</h1>
|
||||
|
||||
<div id="tags">
|
||||
wps, process, advanced
|
||||
</div>
|
||||
|
||||
<div id="shortdesc">Using WPS formats to interact with WPS</div>
|
||||
|
||||
<div id="docs">
|
||||
<p>This example shows WPS in action by using the WPSCapabilities,
|
||||
WPSDescribeProcess and WPSExecute formats. See
|
||||
<a target="_blank" href="wps.js">wps.js</a> for the
|
||||
source code.</p>
|
||||
<ol>
|
||||
<li>Select a process from the list below the map. The list is
|
||||
populated with the result of a WPS GetCapabilities request, parsed
|
||||
using <code>OpenLayers.Format.WPSCapabilities::read</code>.</li>
|
||||
<li>Fill out the Input form. Hover over fields to get a description.
|
||||
Required fields are marked with a "*".
|
||||
To use a geometry from the map as input, select the geometry on the
|
||||
map (using the pen symbol on the left of the toolbar) and just
|
||||
click the field. The form is generated from the object returned by
|
||||
<code>OpenLayers.Format.WPSDescribeProcess::read</code></li>
|
||||
<li>Click "Execute" and examine the result in the result text area.
|
||||
If the result can be parsed as features, it will be displayed on
|
||||
the map as well. The process data is sent to the server with the
|
||||
serialized XML from <code>OpenLayers.Format.WPSExecute::write</code>,
|
||||
which can use a modified
|
||||
<code>OpenLayers.Format.WPSDescribeProcess</code> result object as
|
||||
input.</li>
|
||||
</ol>
|
||||
</div>
|
||||
|
||||
<div id="example" style="width:520px">
|
||||
<div id="map" class="smallmap"></div>
|
||||
|
||||
<div>
|
||||
<select id="processes"><option>Select a process</option></select>
|
||||
<p id="abstract"></p>
|
||||
<div id="input"></div>
|
||||
<div id="output"></div>
|
||||
</div>
|
||||
</div>
|
||||
<script src="../lib/OpenLayers.js"></script>
|
||||
<script src="wps.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
355
examples/wps.js
Normal file
355
examples/wps.js
Normal file
@@ -0,0 +1,355 @@
|
||||
OpenLayers.ProxyHost = "proxy.cgi?url=";
|
||||
|
||||
var wps = "http://demo.opengeo.org/geoserver/wps",
|
||||
capabilities, // the capabilities, read by Format.WPSCapabilities::read
|
||||
process; // the process description from Format.WPSDescribeProcess::read
|
||||
|
||||
// get some capabilities
|
||||
getCapabilities();
|
||||
|
||||
// create the UI
|
||||
var layer = new OpenLayers.Layer.Vector("Scratchpad", {
|
||||
isBaseLayer: true
|
||||
});
|
||||
var toolbar = new OpenLayers.Control.EditingToolbar(layer);
|
||||
toolbar.addControls([new OpenLayers.Control.ModifyFeature(layer, {
|
||||
title: "Select feature"
|
||||
})]);
|
||||
var map = new OpenLayers.Map('map', {
|
||||
controls: [
|
||||
toolbar,
|
||||
new OpenLayers.Control.ZoomPanel(),
|
||||
new OpenLayers.Control.PanPanel()
|
||||
],
|
||||
layers: [
|
||||
new OpenLayers.Layer.WMS(
|
||||
"OSM", "http://maps.opengeo.org/geowebcache/service/wms",
|
||||
{layers: "openstreetmap", format: "image/png"}
|
||||
), layer
|
||||
]
|
||||
});
|
||||
map.zoomToMaxExtent();
|
||||
|
||||
// add behavior to html elements
|
||||
document.getElementById("processes").onchange = describeProcess;
|
||||
|
||||
// using OpenLayers.Format.WPSCapabilities to read the capabilities
|
||||
function getCapabilities() {
|
||||
OpenLayers.Request.GET({
|
||||
url: wps,
|
||||
params: {
|
||||
"SERVICE": "WPS",
|
||||
"REQUEST": "GetCapabilities"
|
||||
},
|
||||
success: function(response){
|
||||
capabilities = new OpenLayers.Format.WPSCapabilities().read(
|
||||
response.responseText
|
||||
);
|
||||
var dropdown = document.getElementById("processes");
|
||||
var offerings = capabilities.processOfferings, option;
|
||||
// populate the dropdown
|
||||
for (var p in offerings) {
|
||||
option = document.createElement("option");
|
||||
option.innerHTML = offerings[p].identifier;
|
||||
option.value = p;
|
||||
dropdown.appendChild(option);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// using OpenLayers.Format.WPSDescribeProcess to get information about a
|
||||
// process
|
||||
function describeProcess() {
|
||||
var selection = this.options[this.selectedIndex].value;
|
||||
OpenLayers.Request.GET({
|
||||
url: wps,
|
||||
params: {
|
||||
"SERVICE": "WPS",
|
||||
"REQUEST": "DescribeProcess",
|
||||
"VERSION": capabilities.version,
|
||||
"IDENTIFIER": selection
|
||||
},
|
||||
success: function(response) {
|
||||
process = new OpenLayers.Format.WPSDescribeProcess().read(
|
||||
response.responseText
|
||||
).processDescriptions[selection];
|
||||
buildForm();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// dynamically create a form from the process description
|
||||
function buildForm() {
|
||||
document.getElementById("abstract").innerHTML = process["abstract"];
|
||||
document.getElementById("input").innerHTML = "<h3>Input:</h3>";
|
||||
document.getElementById("output").innerHTML = "";
|
||||
|
||||
var inputs = process.dataInputs, supported = true,
|
||||
sld = "text/xml; subtype=sld/1.0.0",
|
||||
input;
|
||||
for (var i=0,ii=inputs.length; i<ii; ++i) {
|
||||
input = inputs[i];
|
||||
if (input.complexData) {
|
||||
var formats = input.complexData.supported.formats;
|
||||
if (formats["application/wkt"]) {
|
||||
addWKTInput(input);
|
||||
} else if (formats["text/xml; subtype=wfs-collection/1.0"]) {
|
||||
addWFSCollectionInput(input);
|
||||
} else if (formats["image/tiff"]) {
|
||||
addRasterInput(input);
|
||||
} else if (formats[sld]) {
|
||||
addXMLInput(input, sld);
|
||||
} else {
|
||||
supported = false;
|
||||
}
|
||||
} else if (input.boundingBoxData) {
|
||||
addBoundingBoxInput(input);
|
||||
} else if (input.literalData) {
|
||||
addLiteralInput(input);
|
||||
} else {
|
||||
supported = false;
|
||||
}
|
||||
if (input.minOccurs > 0) {
|
||||
document.getElementById("input").appendChild(document.createTextNode("* "));
|
||||
}
|
||||
}
|
||||
|
||||
if (supported) {
|
||||
var executeButton = document.createElement("button");
|
||||
executeButton.innerHTML = "Execute";
|
||||
document.getElementById("input").appendChild(executeButton);
|
||||
executeButton.onclick = execute;
|
||||
} else {
|
||||
document.getElementById("input").innerHTML = '<span class="notsupported">' +
|
||||
"Sorry, the WPS builder does not support the selected process." +
|
||||
"</span>";
|
||||
}
|
||||
}
|
||||
|
||||
// helper function to dynamically create a textarea for geometry (WKT) data
|
||||
// input
|
||||
function addWKTInput(input, previousSibling) {
|
||||
var name = input.identifier;
|
||||
var container = document.getElementById("input");
|
||||
var label = document.createElement("label");
|
||||
label["for"] = name;
|
||||
label.title = input["abstract"];
|
||||
label.innerHTML = name + " (select feature, then click field):";
|
||||
previousSibling && previousSibling.nextSibling ?
|
||||
container.insertBefore(label, previousSibling.nextSibling) :
|
||||
container.appendChild(label);
|
||||
var field = document.createElement("textarea");
|
||||
field.onclick = function () {
|
||||
if (layer.selectedFeatures.length) {
|
||||
this.innerHTML = new OpenLayers.Format.WKT().write(
|
||||
layer.selectedFeatures[0]
|
||||
);
|
||||
}
|
||||
createCopy(input, this, addWKTInput);
|
||||
};
|
||||
field.onblur = function() {
|
||||
input.data = field.value ? {
|
||||
complexData: {
|
||||
mimeType: "application/wkt",
|
||||
value: this.value
|
||||
}
|
||||
} : undefined;
|
||||
};
|
||||
field.title = input["abstract"];
|
||||
field.id = name;
|
||||
previousSibling && previousSibling.nextSibling ?
|
||||
container.insertBefore(field, previousSibling.nextSibling.nextSibling) :
|
||||
container.appendChild(field);
|
||||
}
|
||||
|
||||
// helper function for xml input
|
||||
function addXMLInput(input, type) {
|
||||
var name = input.identifier;
|
||||
var field = document.createElement("input");
|
||||
field.title = input["abstract"];
|
||||
field.value = name + " (" + type + ")";
|
||||
field.onblur = function() {
|
||||
input.data = field.value ? {
|
||||
complexData: {
|
||||
mimeType: type,
|
||||
value: this.value
|
||||
}
|
||||
} : undefined;
|
||||
};
|
||||
document.getElementById("input").appendChild(field);
|
||||
}
|
||||
|
||||
// helper function to dynamically create a WFS collection reference input
|
||||
function addWFSCollectionInput(input) {
|
||||
var name = input.identifier;
|
||||
var field = document.createElement("input");
|
||||
field.title = input["abstract"];
|
||||
field.value = name + " (layer on demo server)";
|
||||
addValueHandlers(field, function() {
|
||||
input.reference = field.value ? {
|
||||
mimeType: "text/xml; subtype=wfs-collection/1.0",
|
||||
href: "http://geoserver/wfs",
|
||||
method: "POST",
|
||||
body: {
|
||||
wfs: {
|
||||
version: "1.0.0",
|
||||
outputFormat: "GML2",
|
||||
featureType: field.value
|
||||
}
|
||||
}
|
||||
} : undefined;
|
||||
});
|
||||
document.getElementById("input").appendChild(field);
|
||||
}
|
||||
|
||||
// helper function to dynamically create a raster (GeoTIFF) url input
|
||||
function addRasterInput(input) {
|
||||
var name = input.identifier;
|
||||
var field = document.createElement("input");
|
||||
field.title = input["abstract"];
|
||||
var url = window.location.href.split("?")[0];
|
||||
field.value = url.substr(0, url.lastIndexOf("/")+1) + "data/tazdem.tiff";
|
||||
document.getElementById("input").appendChild(field);
|
||||
(field.onblur = function() {
|
||||
input.reference = {
|
||||
mimeType: "image/tiff",
|
||||
href: field.value,
|
||||
method: "GET"
|
||||
};
|
||||
})();
|
||||
}
|
||||
|
||||
// helper function to dynamically create a bounding box input
|
||||
function addBoundingBoxInput(input) {
|
||||
var name = input.identifier;
|
||||
var field = document.createElement("input");
|
||||
field.title = input["abstract"];
|
||||
field.value = "left,bottom,right,top (EPSG:4326)";
|
||||
document.getElementById("input").appendChild(field);
|
||||
addValueHandlers(field, function() {
|
||||
input.boundingBoxData = {
|
||||
projection: "EPSG:4326",
|
||||
bounds: OpenLayers.Bounds.fromString(field.value)
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
// helper function to create a literal input textfield or dropdown
|
||||
function addLiteralInput(input, previousSibling) {
|
||||
var name = input.identifier;
|
||||
var container = document.getElementById("input");
|
||||
var anyValue = input.literalData.anyValue;
|
||||
// anyValue means textfield, otherwise we create a dropdown
|
||||
var field = document.createElement(anyValue ? "input" : "select");
|
||||
field.id = name;
|
||||
field.title = input["abstract"];
|
||||
previousSibling && previousSibling.nextSibling ?
|
||||
container.insertBefore(field, previousSibling.nextSibling) :
|
||||
container.appendChild(field);
|
||||
if (anyValue) {
|
||||
var dataType = input.literalData.dataType;
|
||||
field.value = name + (dataType ? " (" + dataType + ")" : "");
|
||||
addValueHandlers(field, function() {
|
||||
input.data = field.value ? {
|
||||
literalData: {
|
||||
value: field.value
|
||||
}
|
||||
} : undefined;
|
||||
createCopy(input, field, addLiteralInput);
|
||||
});
|
||||
} else {
|
||||
var option;
|
||||
option = document.createElement("option");
|
||||
option.innerHTML = name;
|
||||
field.appendChild(option);
|
||||
for (var v in input.literalData.allowedValues) {
|
||||
option = document.createElement("option");
|
||||
option.value = v;
|
||||
option.innerHTML = v;
|
||||
field.appendChild(option);
|
||||
}
|
||||
field.onchange = function() {
|
||||
createCopy(input, field, addLiteralInput);
|
||||
input.data = this.selectedIndex ? {
|
||||
literalData: {
|
||||
value: this.options[this.selectedIndex].value
|
||||
}
|
||||
} : undefined;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// if maxOccurs is > 1, this will add a copy of the field
|
||||
function createCopy(input, field, fn) {
|
||||
if (input.maxOccurs && input.maxOccurs > 1 && !field.userSelected) {
|
||||
// add another copy of the field - we don't check maxOccurs
|
||||
field.userSelected = true;
|
||||
var newInput = OpenLayers.Util.extend({}, input);
|
||||
// we recognize copies by the occurrence property
|
||||
newInput.occurrence = (input.occurrence || 0) + 1;
|
||||
process.dataInputs.push(newInput);
|
||||
fn(newInput, field);
|
||||
}
|
||||
}
|
||||
|
||||
// helper function for adding events to form fields
|
||||
function addValueHandlers(field, onblur) {
|
||||
field.onclick = function() {
|
||||
if (!this.initialValue) {
|
||||
this.initialValue = this.value;
|
||||
this.value = "";
|
||||
}
|
||||
};
|
||||
field.onblur = function() {
|
||||
if (!this.value) {
|
||||
this.value = this.initialValue;
|
||||
delete this.initialValue;
|
||||
}
|
||||
onblur.apply(this, arguments);
|
||||
};
|
||||
}
|
||||
|
||||
// execute the process
|
||||
function execute() {
|
||||
var output = process.processOutputs[0];
|
||||
var input;
|
||||
// remove occurrences that the user has not filled out
|
||||
for (var i=process.dataInputs.length-1; i>=0; --i) {
|
||||
input = process.dataInputs[i];
|
||||
if ((input.minOccurs === 0 || input.occurrence) && !input.data && !input.reference) {
|
||||
OpenLayers.Util.removeItem(process.dataInputs, input);
|
||||
}
|
||||
}
|
||||
process.responseForm = {
|
||||
rawDataOutput: {
|
||||
identifier: output.identifier
|
||||
}
|
||||
};
|
||||
if (output.complexOutput && output.complexOutput.supported.formats["application/wkt"]) {
|
||||
process.responseForm.rawDataOutput.mimeType = "application/wkt";
|
||||
}
|
||||
OpenLayers.Request.POST({
|
||||
url: wps,
|
||||
data: new OpenLayers.Format.WPSExecute().write(process),
|
||||
success: showOutput
|
||||
});
|
||||
}
|
||||
|
||||
// add the process's output to the page
|
||||
function showOutput(response) {
|
||||
var result = document.getElementById("output");
|
||||
result.innerHTML = "<h3>Output:</h3>";
|
||||
var features;
|
||||
var contentType = response.getResponseHeader("Content-Type");
|
||||
if (contentType == "application/wkt") {
|
||||
features = new OpenLayers.Format.WKT().read(response.responseText);
|
||||
} else if (contentType == "text/xml; subtype=wfs-collection/1.0") {
|
||||
features = new OpenLayers.Format.WFST.v1_0_0().read(response.responseText);
|
||||
}
|
||||
if (features && (features instanceof OpenLayers.Feature.Vector || features.length)) {
|
||||
layer.addFeatures(features);
|
||||
result.innerHTML += "The result should also be visible on the map.";
|
||||
}
|
||||
result.innerHTML += "<textarea>" + response.responseText + "</textarea>";
|
||||
}
|
||||
@@ -270,8 +270,8 @@ OpenLayers.Format.OWSCommon.v1 = OpenLayers.Class(OpenLayers.Format.XML, {
|
||||
*/
|
||||
writers: {
|
||||
"ows": {
|
||||
"BoundingBox": function(options) {
|
||||
var node = this.createElementNSPlus("ows:BoundingBox", {
|
||||
"BoundingBox": function(options, nodeName) {
|
||||
var node = this.createElementNSPlus(nodeName || "ows:BoundingBox", {
|
||||
attributes: {
|
||||
crs: options.projection
|
||||
}
|
||||
|
||||
@@ -82,7 +82,7 @@ OpenLayers.Format.WFST.v1_0_0 = OpenLayers.Class(
|
||||
// Not the superclass, only the mixin classes inherit from
|
||||
// Format.GML.v2. We need this because we don't want to get readNode
|
||||
// from the superclass's superclass, which is OpenLayers.Format.XML.
|
||||
return OpenLayers.Format.GML.v2.prototype.readNode.apply(this, [node, obj]);
|
||||
return OpenLayers.Format.GML.v2.prototype.readNode.apply(this, arguments);
|
||||
},
|
||||
|
||||
/**
|
||||
|
||||
@@ -81,7 +81,7 @@ OpenLayers.Format.WFST.v1_1_0 = OpenLayers.Class(
|
||||
// Not the superclass, only the mixin classes inherit from
|
||||
// Format.GML.v3. We need this because we don't want to get readNode
|
||||
// from the superclass's superclass, which is OpenLayers.Format.XML.
|
||||
return OpenLayers.Format.GML.v3.prototype.readNode.apply(this, [node, obj]);
|
||||
return OpenLayers.Format.GML.v3.prototype.readNode.apply(this, arguments);
|
||||
},
|
||||
|
||||
/**
|
||||
|
||||
@@ -175,6 +175,9 @@ OpenLayers.Format.WPSExecute = OpenLayers.Class(OpenLayers.Format.XML, {
|
||||
if (input.reference) {
|
||||
this.writeNode("wps:Reference", input.reference, node);
|
||||
}
|
||||
if (input.boundingBoxData) {
|
||||
this.writeNode("wps:BoundingBoxData", input.boundingBoxData, node);
|
||||
}
|
||||
return node;
|
||||
},
|
||||
"Data": function(data) {
|
||||
@@ -228,6 +231,9 @@ OpenLayers.Format.WPSExecute = OpenLayers.Class(OpenLayers.Format.XML, {
|
||||
}
|
||||
return node;
|
||||
},
|
||||
"BoundingBoxData": function(node, obj) {
|
||||
this.writers['ows']['BoundingBox'].apply(this, [node, obj, "wps:BoundingBoxData"]);
|
||||
},
|
||||
"Body": function(body) {
|
||||
var node = this.createElementNSPlus("wps:Body", {});
|
||||
if (body.wcs) {
|
||||
|
||||
Reference in New Issue
Block a user