source: trunk/docs/workshop/2010/building_wps_client_using_ol.txt @ 256

Last change on this file since 256 was 256, checked in by djay, 13 years ago

Add the workshop 2010 material as Restructured text. Some issues with table of content and pdf production due to number of sub title level used in the workshop material.

File size: 13.0 KB
Line 
1.. _building_wps_client_using_ol:
2
3Building a WPS client using OpenLayers
4###############################
5
6.. contents:: Table of Contents
7    :depth: 5
8    :backlinks: top
9
10The next step of our workshop is to connect to the OGR Services we have created from an OpenLayers map. This will allow to apply single or multiple geometries processes on user-selected polygons and to display the new generated geometries.
11
12Creating a simple map showing the dataset as WMS
13******************************************************
14
15OpenLayers is also included in OSGeoLive default distribution, so it is convenient to use it for our needs. Please open ``/var/www/zoo-ogr.html`` using your favorite text editor and paste the following HTML snippet:
16
17.. code-block:: guess
18
19    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"><html xmlns="http://www.w3.org/1999/xhtml" xml:lang="EN" lang="EN">
20     <head>
21      <meta content="text/html; charset=UTF-8" http-equiv="content-type"/>
22      <title>ZOO WPS Client example</title>
23      <style>
24      #map{width:700px;height:600px;}
25      </style>
26      <link rel="stylesheet" href="/openlayers/theme/default/style.css" type="text/css" />
27      <script type="text/javascript" src="/openlayers/lib/OpenLayers.js"></script>
28     </head>
29     <body onload="init()">
30      <div id="map"></div>
31     </body>
32    </html>
33
34The following JavaScript code must then be added in a ``<script></script>`` section within the ``<head>`` one. This will setup a map showing the japanese regions data as WMS.
35
36.. code-block:: guess
37
38    var map, layer, select, hover, multi, control;
39   
40    var typename="regions";
41    var main_url="http://localhost/cgi-bin/mapserv?map=/var/www/wfs.map";
42   
43    function init(){
44      map = new OpenLayers.Map('map', {
45        controls: [
46          new OpenLayers.Control.PanZoom(),
47          new OpenLayers.Control.Permalink(),
48          new OpenLayers.Control.Navigation()
49        ]
50      });
51      layer = new OpenLayers.Layer.WMS(typename,main_url, {
52            layers: 'regions',
53            transparent: 'true',
54            format: 'image/png'
55          },
56          {
57            isBaseLayer: true,
58            visibility: true,
59            buffer: 0,
60            singleTile: true
61          }
62    );
63      map.addLayers([layer]);
64      map.setCenter(new OpenLayers.LonLat(138,33.5),5);
65    }
66
67Once done, please save your HTML file as ``zoo-ogr.html`` in your workshop directory, then copy it in ``/var/www`` and visualize it with your favorite Web browser using this link :  ``http://localhost/zoo-ogr.html``. You should obtain a map centered on the Japan with the WMS layer activated.
68
69.. image:: ./images/OL-JP-1.png
70   :width: 356px
71   :height: 280px
72   :align: center
73
74Fetching the data layer as WFS and adding selection controls
75****************************************************************
76
77Before accessing the displayed data via WFS, you first have to create new vector layers dedicated to host the several interactions we are going to create. Please add the following lines within the ``init()`` function, and do not forget to add the newly created layer in the map.addLayers method:
78
79.. code-block:: guess
80
81    select = new OpenLayers.Layer.Vector("Selection", {
82      styleMap: new OpenLayers.Style(OpenLayers.Feature.Vector.style["select"])
83    });
84         
85    hover = new OpenLayers.Layer.Vector("Hover");
86    multi = new OpenLayers.Layer.Vector("Multi", { styleMap:
87      new OpenLayers.Style({
88        fillColor:"red",
89        fillOpacity:0.4,
90        strokeColor:"red",
91        strokeOpacity:1,
92        strokeWidth:2
93      })
94    });
95   
96    map.addLayers([layer, select, hover, multi]);
97
98Then, you can now access the data by creating new controls to select polygons, as the following. Please note that ``OpenLayers.Protocol.WFS.fromWMSLayer`` is used to access geometries and that several state of selection are declared and append to the control variable.
99
100.. code-block:: guess
101
102    var protocol = OpenLayers.Protocol.WFS.fromWMSLayer(layer, {
103            featurePrefix: 'ms',
104            geometryName: 'msGeometry',
105            featureType: typename
106    });
107   
108    control = new OpenLayers.Control.GetFeature({
109            protocol: protocol,
110            box: false,
111            hover: false,
112            multipleKey: "shiftKey",
113            toggleKey: "ctrlKey"
114    });
115    control.events.register("featureselected", this, function(e) {
116                    select.addFeatures([e.feature]);
117    });
118    control.events.register("featureunselected", this, function(e) {
119                    select.removeFeatures([e.feature]);
120    });
121    map.addControl(control);
122    control.activate();
123
124Please save your HTML file again. You should now be able to select a polygon only by clicking on it. The selected polygon should appear in blue color.
125
126.. image:: ./images/OL-JP-2.png
127   :width: 356px
128   :height: 280px
129   :align: center
130
131Calling the single geometry services from JavaScript
132*******************************************************
133
134Now that everything is setup, we can go on and call our OGR ZOO services with JavaScript. Please add the following lines after the ``init()`` function, which will call the single geometry processes. You can notice that we use a specific ``parseMapServerId`` function which let us remove the unecessary white space returned as fid value.
135
136.. code-block:: guess
137
138    function parseMapServerId(){
139      var sf=arguments[0].split(".");
140      return sf[0]+"."+sf[1].replace(/ /g,'');
141    }
142   
143    function simpleProcessing(aProcess) {
144      if (select.features.length == 0)
145        return alert("No feature selected!");
146      if(multi.features.length>=1)
147        multi.removeFeatures(multi.features);
148      var url = '/cgi-bin/zoo_loader.cgi?request=Execute&service=WPS&version=1.0.0&';
149      if (aProcess == 'Buffer') {
150        var dist = document.getElementById('bufferDist')?document.getElementById('bufferDist').value:'1';
151        if (isNaN(dist)) return alert("Distance is not a Number!");
152        url+='Identifier=Buffer&DataInputs=BufferDistance='+dist+'@datatype=interger;InputPolygon=Reference@xlink:href=';
153      } else
154        url += 'Identifier='+aProcess+'&DataInputs=InputPolygon=Reference@xlink:href=';
155      var xlink = control.protocol.url +"&SERVICE=WFS&REQUEST=GetFeature&VERSION=1.0.0";
156      xlink += '&typename='+control.protocol.featurePrefix;
157      xlink += ':'+control.protocol.featureType;
158      xlink += '&SRS='+control.protocol.srsName;
159      xlink += '&FeatureID='+parseMapServerId(select.features[0].fid);
160      url += encodeURIComponent(xlink);
161      url += '&RawDataOutput=Result@mimeType=application/json';
162     
163      var request = new OpenLayers.Request.XMLHttpRequest();
164      request.open('GET',url,true);
165      request.onreadystatechange = function() {
166        if(request.readyState == OpenLayers.Request.XMLHttpRequest.DONE) {
167          var GeoJSON = new OpenLayers.Format.GeoJSON();
168          var features = GeoJSON.read(request.responseText);
169          hover.removeFeatures(hover.features);
170          hover.addFeatures(features);
171        }
172      }
173      request.send();
174    }
175
176
177Then, some specific buttons must be added in the HTML, in order to be able to call the different processes we just declared. You can add them on top of the map by writing the following lines before the ``<div id="map"></div>``.
178
179.. code-block:: guess
180
181    <div style="float: right;padding-left: 5px;">
182     <h3>Single geometry processing</h3>
183     <ul>
184       <li>
185        <input type="button" onclick="simpleProcessing(this.value);" value="Buffer" />
186        <input id="bufferDist" value="1" />
187       </li>
188       <li>
189        <input type="button" onclick="simpleProcessing(this.value);" value="ConvexHull" />
190       </li>
191       <li>
192        <input type="button" onclick="simpleProcessing(this.value);" value="Boundary" />
193       </li>
194       <li>
195        <input type="button" onclick="simpleProcessing(this.value);" value="Centroid" />
196       </li>
197     </ul>
198    </div>
199
200Save your HTML file again. You should now be able to select a polygon and to launch a Buffer, ConvexHull, Boundary or Centroid on it by clicking one of the button. The result of the process should appear as GeoJSON layer on the map, in orange color.
201
202.. image:: ./images/OL-JP-3.png
203   :width: 536px
204   :height: 270px
205   :align: center
206
207Calling the multiples geometries processes from JavaScript
208**************************************************************
209
210Using the same technique, you can now write a function dedicated to the multiple geometries processes. Please add the following lines after the ``simpleProcessing()`` function, we will guide you during the exercise in section 5 on how to create such a function.
211
212.. code-block:: guess
213
214    function multiProcessing(aProcess) {
215      if (select.features.length == 0 || hover.features.length == 0)
216        return alert("No feature created!");
217      var url = '/cgi-bin/zoo_loader.cgi';
218      var xlink = control.protocol.url +"&SERVICE=WFS&REQUEST=GetFeature&VERSION=1.0.0";
219      xlink += '&typename='+control.protocol.featurePrefix;
220      xlink += ':'+control.protocol.featureType;
221      xlink += '&SRS='+control.protocol.srsName;
222      xlink += '&FeatureID='+parseMapServerId(select.features[0].fid);
223      var GeoJSON = new OpenLayers.Format.GeoJSON();
224      try {
225        var params = '<wps:Execute service="WPS" version="1.0.0" xmlns:wps="http://www.opengis.net/wps/1.0.0" xmlns:ows="http://www.opengis.net/ows/1.1" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.opengis.net/wps/1.0.0/../wpsExecute_request.xsd">';
226        params += '<ows:Identifier>'+aProcess+'</ows:Identifier>';
227        params += '<wps:DataInputs>';
228        params += '<wps:Input>';
229        params += '<ows:Identifier>InputEntity1</ows:Identifier>';
230        params += '<wps:Reference xlink:href="'+xlink.replace(/&/gi,'&amp;')+'"/>';
231        params += '</wps:Input>';
232        params += '<wps:Input>';
233        params += '<ows:Identifier>InputEntity2</ows:Identifier>';
234        params += '<wps:Data>';
235        params += '<wps:ComplexData mimeType="application/json"> '+GeoJSON.write(hover.features[0].geometry)+' </wps:ComplexData>';
236        params += '</wps:Data>';
237        params += '</wps:Input>';
238        params += '</wps:DataInputs>';
239        params += '<wps:ResponseForm>';
240        params += '<wps:RawDataOutput>';
241        params += '<ows:Identifier>Result</ows:Identifier>';
242        params += '</wps:RawDataOutput>';
243        params += '</wps:ResponseForm>';
244        params += '</wps:Execute>';
245      } catch(e) {
246        alert(e);
247        return false;
248      }
249      var request = new OpenLayers.Request.XMLHttpRequest();
250      request.open('POST',url,true);
251      request.setRequestHeader('Content-Type','text/xml');
252      request.onreadystatechange = function() {
253        if(request.readyState == OpenLayers.Request.XMLHttpRequest.DONE) {
254          var GeoJSON = new OpenLayers.Format.GeoJSON();
255          var features = GeoJSON.read(request.responseText);
256          multi.removeFeatures(multi.features);
257          multi.addFeatures(features);
258        }
259      }
260      request.send(params);
261    }
262
263Note that this time we didn't use the GET method to request the ZOO Kernel but a XML POST. We did that because if you use the GET method you will get error due to the HTTP GET method limitation based on the length of your request. Using JSON string representing the geometry will make your request longer.
264
265Once you get the functions to call your multiple geometries processes, you' must add some buttons to fire the request call. Here is the HTML code to add to your current ``zoo-ogr.html`` file :
266
267.. code-block:: guess
268
269    <h3>Multiple geometries processing</h3>
270    <ul>
271      <li>
272        <input type="button" onclick="multiProcessing(this.value);" value="Union"/>
273      </li>
274      <li>
275        <input type="button" onclick="multiProcessing(this.value);" value="Difference"/>
276      </li>
277      <li>
278        <input type="button" onclick="multiProcessing(this.value);" value="SymDifference"/>
279      </li>
280      <li>
281        <input type="button" onclick="multiProcessing(this.value);" value="Intersection"/>
282      </li>
283    </ul>
284
285Please reload the page. You should then be able to run your multiple geometries services and you should get results displayed in red as shown by the following screenshots :
286
287
288.. image:: ./images/OL-JP-4.png
289   :width: 406px
290   :height: 140px
291.. image:: ./images/OL-JP-5.png
292   :width: 406px
293   :height: 140px
294.. image:: ./images/OL-JP-6.png
295   :width: 406px
296   :height: 140px
297.. image:: ./images/OL-JP-7.png
298   :width: 406px
299   :height: 140px
300   
301It seems that something is missing in your Services Provider to get the same results … The multiple geometries Services ! This is what we are going to do together in the next section.
Note: See TracBrowser for help on using the repository browser.

Search

Context Navigation

ZOO Sponsors

http://www.zoo-project.org/trac/chrome/site/img/geolabs-logo.pnghttp://www.zoo-project.org/trac/chrome/site/img/neogeo-logo.png http://www.zoo-project.org/trac/chrome/site/img/apptech-logo.png http://www.zoo-project.org/trac/chrome/site/img/3liz-logo.png http://www.zoo-project.org/trac/chrome/site/img/gateway-logo.png

Become a sponsor !

Knowledge partners

http://www.zoo-project.org/trac/chrome/site/img/ocu-logo.png http://www.zoo-project.org/trac/chrome/site/img/gucas-logo.png http://www.zoo-project.org/trac/chrome/site/img/polimi-logo.png http://www.zoo-project.org/trac/chrome/site/img/fem-logo.png http://www.zoo-project.org/trac/chrome/site/img/supsi-logo.png http://www.zoo-project.org/trac/chrome/site/img/cumtb-logo.png

Become a knowledge partner

Related links

http://zoo-project.org/img/ogclogo.png http://zoo-project.org/img/osgeologo.png