Changeset 74 for trunk/workshop-routing-foss4g/chapters
- Timestamp:
- 02/04/2012 01:02:15 (13 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/workshop-routing-foss4g/chapters/geoext_client.rst
r63 r74 1 1 ============================================================================================================== 2 GeoExt Browser Client2 Client en GeoExt 3 3 ============================================================================================================== 4 4 5 `GeoExt <http://www.geoext.org/>`_ is a *JavaScript Toolkit for Rich Web Mapping Applications*. GeoExt 6 brings together the geospatial know how of `OpenLayers <http://www.openlayers.org>`_ with 7 the user interface savvy of `Ext JS <http://www.sencha.com>`_ to help you build powerful desktop 8 style GIS apps on the web with JavaScript. 9 10 Let's start with a simple GeoExt example and extend it with routing functionality then: 5 `GeoExt <http://www.geoext.org/>`_ est une librairie JavaScript pour le développement d'applications internet avancées. GeoExt rassemble les capacités d'`OpenLayers <http://www.openlayers.org>`_ avec l'interface utilsiateur savvy de `Ext JS <http://www.sencha.com>`_ pour aider au développement d'applications similaires à des applications bureautiques. 6 7 Commençons avec un exemple simple d'utilisation de GeoExt et ajoutons-y les fonctionalités de routage : 11 8 12 9 .. literalinclude:: ../../web/routing-0.html 13 10 :language: html 14 11 15 In the header we include all the javascript and css needed for the application, 16 we also define a function to be run when the page is loaded (Ext.onReady). 17 18 This function creates a `GeoExt.MapPanel 19 <http://www.geoext.org/lib/GeoExt/widgets/MapPanel.html>`_ with an 20 OpenStreetMap layer centered to Denver. In this code, no OpenLayers.Map is 21 explicitly created; the GeoExt.MapPanel do this under the hood: it takes the map options, the 22 center and the zoom and create a map instance accordingly. 23 24 To allow our users to get directions, we need to provide: 25 * a way to select the routing algorithm (Shortest path Dijkstra, A* or Shooting*), 26 * a way to select the start and final destination. 27 28 .. note:: This chapter only show code snippets, the full source code of the 29 page can be found in ``pgrouting-workshop/web/routing-final.html`` that should 30 be on your desktop. The full listing can also be found at the end of this chapter. 31 32 ------------------------------------------------------------------------------------------------------------- 33 Routing method selection 34 ------------------------------------------------------------------------------------------------------------- 35 36 To select the routing method, we will use an `Ext.form.ComboBox 37 <http://www.sencha.com/deploy/dev/docs/?class=Ext.form.ComboBox>`_: it 38 behaves just like a normal html select but we can more easily control it. 39 40 Just like the GeoExt.MapPanel, we need an html element to place our control, 41 let's create a new div in the body (with 'method' as id): 12 Dans l'entête nous chargeons l'ensemble des fichiers javascript et css requis pour l'application. Nous définissons aussi une fonction qui sera exécutée à la fin du chargement de la page (Ext.onReady). 13 14 Cette fonction cée une instance de`GeoExt.MapPanel 15 <http://www.geoext.org/lib/GeoExt/widgets/MapPanel.html>`_ avec une couche de fond OpenStreetMap centrée sur Denver. Dans ce code, aucun objet OpenLayers.Map est explicitemet créé; le GeoExt.MapPanel le fait de façon camouflé : il récupÚre les options de la carte, le centre, le seuil de zoom et crée une instance de maniÚre appropriée. 16 17 Pour permettre à nos utilisateurs de trouver leur direction, nous devons fournir : 18 * un moyen de sélectionner un algorithme de routage (Dijkstra, A* ou Shooting*), 19 * un moyen de sélectionner la position de départ et d'arrivée. 20 21 .. note:: Ce chapitre présente uniquement des extraits de codes, le code source complet de la page peut être récupérée depuis ``pgrouting-workshop/web/routing-final.html`` qui devrait être sur votre bureau. Le fichier complet se trouve à la fin de ce chapitre. 22 23 ------------------------------------------------------------------------------------------------------------- 24 Outil de sélection de la méthode de routage 25 ------------------------------------------------------------------------------------------------------------- 26 27 Pour sélectionner une méthode de routage, nous utiliserons un `Ext.form.ComboBox 28 <http://www.sencha.com/deploy/dev/docs/?class=Ext.form.ComboBox>`_: il se comporte simplement comme un select html mais est plus simple à controler. 29 30 Comme pour le GeoExt.MapPanel, nous avons besoin d'un éléments html pour placer notre control, créons un div dans le body (ayant 'method' comme identifiant) : 42 31 43 32 .. code-block:: html … … 48 37 </body> 49 38 50 Then we create the combo itself:39 Créons ensuite le combo : 51 40 .. code-block:: js 52 41 … … 63 52 }); 64 53 65 In the ``store`` option, we set all the possible values for the routing method; 66 the format is an array of options where an option is in the form ``[key, name]``. 67 The ``key`` will be send to the server (the php script in our case) and the 68 ``value`` displayed in the combo. 69 70 The ``renderTo`` specify where the combo must be rendered, we use our new div here. 71 72 And finally, a default value is selected: 54 Dans l'option ``store``, nous avons défini toutes les valeurs pour les méthodes de routages; les formats sont dans un tableau d'options ou une option est de la forme ``[clef,valeur]``. La ``clef`` sera envoyée au serveur (the script php dans note cas) et la ``valeur`` affichée dans la liste déroulante. 55 56 L'option ``renderTo`` défini où la liste déroulante doit être affichée , nous utilisons ici notre élément div. 57 58 Et pour finir, une valeur par défaut est définie : 73 59 .. code-block:: js 74 60 75 61 method.setValue("SPD"); 76 62 77 This part only uses ExtJS component: no OpenLayers or GeoExt code here. 78 79 ------------------------------------------------------------------------------------------------------------- 80 Select the start and final destination 81 ------------------------------------------------------------------------------------------------------------- 82 83 We want to allow the users to draw and move the start and final destination 84 points. This is more or less the behavior of google maps and others: the user 85 selects the points via a search box (address search) or by clicking the 86 map. The system query the server and display the route on the map. The user 87 can later move the start or final point and the route is updated. 88 89 In this workshop, we will only implement the input via the map (draw points and 90 drag-and-drop) but it's possible to implement the search box feature by using a 91 web service like `GeoNames <http://www.geonames.org/>`_ or any other `geocoding 92 <http://en.wikipedia.org/wiki/Geocoding>`_ service. 93 94 To do this we will need a tool to draw points (we will use the 63 Cette partie utilise le composant ExtJS : ni code OpenLayers ni GeoExt. 64 65 ------------------------------------------------------------------------------------------------------------- 66 Sélectionner un point de départ et d'arrivée 67 ------------------------------------------------------------------------------------------------------------- 68 69 Nous souhaitons permettre à nos utilisateurs de déssiner et déplacer un point de départ et d'arrivée. C'est plus ou moins le comportement des applications comme google map et les autres : l'utilsateur choisi un point de départ à l'aide d'un moteur de recherche ou en cliquant sur la carte. L'applicationinterroge ensuite le serveur afin d'afficher le chemin sur la carte. L'utilisateur peut ensuite modifier son opint de départ et d'arrivée afin que le chemin soit mis à jour automatiquement. 70 71 Dans ces travaux pratiques, nous implémenterons seulement la saisie de point sur la carte (dessiner des points et les déplacer) mais il est parfaitement possible d'implémenter un moteur de recherche en utilisant un service web dédié tel que `GeoNames <http://www.geonames.org/>`_ ou tout autre service de `geocodage 72 <http://fr.wikipedia.org/wiki/Geocodage>`_. 73 74 Pour faire ceci nous aurons besoin d'un outil permettant de dessiner des points (nous utiliserons le control 95 75 `OpenLayers.Control.DrawFeatures 96 <http://openlayers.org/dev/examples/draw-feature.html>`_ control) and a tool to 97 move points (`OpenLayers.Control.DragFeatures 98 <http://openlayers.org/dev/examples/drag-feature.html>`_ will be perfect for 99 this job). As their name suggests these controls comes from OpenLayers. 100 101 These two controls will need a place to draw and manipulate the points; we 102 will also need an `OpenLayers.Layer.Vector 103 <http://dev.openlayers.org/releases/OpenLayers-2.10/doc/apidocs/files/OpenLayers/Layer/Vector-js.html>`_ 104 layer. In OpenLayers, a vector layer in a place where features (a geometry and 105 attributes) can be drawn programmatically (in contrast, the OSM layer is a 106 raster layer). 107 108 Because vector layers are cheap, we will use a second one to draw the route 109 returned by the web service. The layers initialization is: 110 111 .. code-block:: js 112 113 // create the layer where the route will be drawn 76 <http://openlayers.org/dev/examples/draw-feature.html>`_) et un outil pour déplacer les points (`OpenLayers.Control.DragFeatures 77 <http://openlayers.org/dev/examples/drag-feature.html>`_ sera parfait pour ce travail). Comme leur noms le suppose ces controls sont disponibles dans OpenLayers. 78 79 Ces deux controls auront besoin d'un emplacement pour afficher et manipuler les points; nous aurons besoin d'une couche `OpenLayers.Layer.Vector 80 <http://dev.openlayers.org/releases/OpenLayers-2.10/doc/apidocs/files/OpenLayers/Layer/Vector-js.html>`_. Dans OpenLayers, une couche vecteur est un endroit où des élements (une geométrie et des attributs) peuvent être afffichée (contrairement à la couche OSM qui est une couche raster). 81 82 Comme les couches vecteurs sont légÚres, nous en utiliserons une seconde pour afficher la route retourner par le service web. L'initialisation de la couche se fait de la maniÚre suivante : 83 84 .. code-block:: js 85 86 // Création de la couche où le chemin sera affiché 114 87 var route_layer = new OpenLayers.Layer.Vector("route", { 115 88 styleMap: new OpenLayers.StyleMap(new OpenLayers.Style({ … … 119 92 }); 120 93 121 ``"route"`` is the layer name, any string can be used. 122 ``styleMap`` gives the layer a bit of visual style with a custom stroke color and 123 width (in pixel). 124 125 The second layer initialization is simply: 126 127 .. code-block:: js 128 129 // create the layer where the start and final points will be drawn 94 ``"route"`` est le nom de la couche, n'importe qu'elle chaîne de caractÚres peut être utilisée. 95 ``styleMap`` fournis à la couche un mimum de style avec une couleur de contour particuliÚre et un largeur (en pixel). 96 97 La seconde couche est simplement initialiser comme suit : 98 99 .. code-block:: js 100 101 // Création de la couche ou seront affiché les points de départ et d'arrivée 130 102 var points_layer = new OpenLayers.Layer.Vector("points"); 131 103 132 The two layers are added to the OpenLayers.Map object with:133 134 .. code-block:: js 135 136 // add the layers to the map104 Les deux couches sont ajoutée à l'objet OpenLayers.Map avec : 105 106 .. code-block:: js 107 108 // Ajouter la cocuhe à la carte 137 109 map.addLayers([points_layer, route_layer]); 138 110 139 Let's look at the control to draw the points: because this component has 140 special behavior it's more easy to create a new class based on the standard 141 OpenLayers.Control.DrawFeatures control. This new control (named DrawPoints) is 142 saved in a separated javascript file (``web/DrawPoints.js``): 111 Regardons le control pour afficher les points : puisque ce composant à un comportement particulier il est plus simple de créer une nouvelle classe basée sur le control standard 112 OpenLayers.Control.DrawFeatures. Ce control (nommé DrawPoints) est enregistré dans un fichier javascript à part (``web/DrawPoints.js``): 143 113 144 114 .. literalinclude:: ../../web/DrawPoints.js 145 115 :language: js 146 116 147 In the ``initialize`` function (that's the class constructor) we set that 148 this control can only draw points (handler variable is OpenLayers.Handler.Point). 149 150 The special behavior is implemented in the ``drawFeature`` function: because we 151 only need the start and final points the control deactivates itself when two 152 points are drawn by counting how many features has the vector 153 layer. Control deactivation is ``this.deactivate()``. 154 155 Our control is then created with: 156 157 .. code-block:: js 158 159 // create the control to draw the points (see the DrawPoints.js file) 117 Dans la fonction ``initialize`` (qui est le constructeur de la classe) nous spécifions que ce control peut seulement dessiner des point (la variable handler est OpenLayers.Handler.Point). 118 119 Le comportement spécifique est implémenté dans la fonction ``drawFeature`` : puisque nous avons seulement besoin des points de départ et d'arrivée, le control se desactive automatiquemnt lorsque deux points ont été saisie. La désactivation se fait via ``this.deactivate()``. 120 121 Notre control est ensuite créé avec : 122 123 .. code-block:: js 124 125 // Création du control pour dessiner les points (voir le fichier DrawPoints.js) 160 126 var draw_points = new DrawPoints(points_layer); 161 127 162 ``points_layer`` is the vector layer created earlier.163 164 And now for the DragFeature control:165 166 .. code-block:: js 167 168 // create the control to move the points128 ``points_layer`` est la couche vecteur créée précédemment. 129 130 Et maintenant pour le control DragFeature : 131 132 .. code-block:: js 133 134 // Création du control pour déplacer les points 169 135 var drag_points = new OpenLayers.Control.DragFeature(points_layer, { 170 136 autoActivate: true 171 137 }); 172 138 173 Again, ``points_layer`` is the vector layer, ``autoActivate: true`` tells 174 OpenLayers that we want this control to be automatically activated. 175 176 .. code-block:: js 177 178 // add the controls to the map 139 Encore une fois, la couche ``points_layer``est de type vecteur, ``autoActivate: true`` dit à OpenLayers que nous voulons que ce control soit automatiquement activé. 140 141 .. code-block:: js 142 143 // Ajouter le control à la carte 179 144 map.addControls([draw_points, drag_points]); 180 145 181 Adds the controls to the map. 182 183 ------------------------------------------------------------------------------------------------------------- 184 Call and receive data from web service 185 ------------------------------------------------------------------------------------------------------------- 186 187 The basic workflow to get a route from the web server is: 188 189 #. transform our points coordinates from EPSG:900913 to EPSG:4326 190 #. call the web service with the correct arguments (method name and two points coordinates) 191 #. parse the web service response: transform GeoJSON to OpenLayers.Feature.Vector 192 #. transform all the coordinates from EPSG:4326 to EPSG:900913 193 #. add this result to a vector layer 194 195 The first item is something new: our map uses the EPSG:900913 projection 196 (because we use an OSM layer) but the web service expects coordinates in 197 EPSG:4326: we have to re-project the data before sending them. This is not a 198 big deal: we will simply use the `Proj4js <http://trac.osgeo.org/proj4js/>`_ 199 javascript library. 200 201 (The second item *call the web service* is covered in the next chapter.) 202 203 The routing web service in pgrouting.php returns a `GeoJSON 204 <http://geojson.org/>`_ FeatureCollection object. A FeatureCollection is simply 205 an array of features: one feature for each route segment. This is very convenient because 206 OpenLayers and GeoExt have all what we need to handle this format. To make our 207 live even easier, we are going to use the GeoExt.data.FeatureStore: 146 Ajouter le control à la carte. 147 148 ------------------------------------------------------------------------------------------------------------- 149 Envoyer et recevoire des données du service web 150 ------------------------------------------------------------------------------------------------------------- 151 152 Le cheminement de base pour obtenir un chemin depuis le service web est le suivant : 153 154 #. transformer nos points en coordonnées de EPSG:900913 en EPSG:4326 155 #. appeler le service web avec les arguments correctes (nom de la méthode et deux points) 156 #. lire le résultat retourné par le service web : transformer le GeoJSON en OpenLayers.Feature.Vector 157 #. transformer toutes les coordonnées de EPSG:4326 à EPSG:900913 158 #. ajouter le résultat à la couche vecteur 159 160 La premiÚre étape est quelque chose de nouveau : notre carte utilise le systÚme de projection EPSG:900913 161 (parce que nous utilisons une couche OSM) mais le service web attends des coordonnées en EPSG:4326 : nous devons re-projeter les données avant de les envoyer. Ce n'est pas bien difficile : nous aurons simplement besoin de la ` librairie javascript Proj4js <http://trac.osgeo.org/proj4js/>`_. 162 163 (La deuxiÚme étape *appeler le service web* est étudié au chapitre suivant.) 164 165 Le service web de routage dans pgrouting.php renvoit un objet FeatureCollection au format `GeoJSON <http://geojson.org/>`_. Un objet FeatureCollection est simplement un tableau d'élément : un éléments pour chaque tronçon de route. Ceci est trÚs pratique carOpenLayers et GeoExt ont tout ce dont nous avons besoin pour gérer ce format. Pour nous rendre la tâche encore plus simple, nous utiliserons le GeoExt.data.FeatureStore suivant : 208 166 209 167 .. code-block:: js … … 225 183 }); 226 184 227 A store is simply a container to store informations: we can push data into and 228 get it back. 229 230 Let's explain all the options: 231 232 ``layer``: the argument is a vector layer: by specifying a layer, the 233 FeatureStore will automatically draw the data received into this 234 layer. This is exactly what we need for the last item (*add this result to a 235 vector layer*) in the list above. 236 237 ``fields``: lists all the attributes returned along with the geometry: pgrouting.php 238 returns the segment length so we set it here. Note that this information is not 239 used in this workshop. 240 241 ``proxy``: the proxy item specify where the data should be taken: in our case 242 from a HTTP server. The proxy type is GeoExt.data.ProtocolProxy: this class 243 connects the ExtJS world (the store) and the OpenLayers world (the protocol 244 object). 245 246 ``protocol``: this OpenLayers component is able to make HTTP requests to an ``url`` 247 (our php script) and to parse the response (``format`` option). By adding the 248 ``internalProjection`` and ``externalProjection`` option, the coordinates 249 re-projection in made by the format. 250 251 We now have all what we need to handle the data returned by the web service: the next 252 chapter will explain how and when to call the service. 253 254 ------------------------------------------------------------------------------------------------------------- 255 Trigger the web service call 256 ------------------------------------------------------------------------------------------------------------- 257 258 We need to call the web service when: 259 * the two points are drawn 260 * one of the point is moved 261 * the routing method has changed 262 263 Our vector layer generates an event (called ``featureadded``) when a 264 new feature is added, we can listen to this event and call to pgrouting 265 function (this function will be presented shortly): 185 Un Store est simplement un conteneur qui stocke des informations : nous pouvons y ajouter des éléments et les récupérer. 186 187 Expliquons les options : 188 189 ``layer``: le paramÚtre est une couche vecteur : en spécifiant une couche, le 190 FeatureStore affichera automatiquement les données qu'elle contient. C'est exactement ce dont nous avons besoin pour la derniÚre étape (*ajouter le résultat à la couche vecteur*) dans la liste ci-dessus. 191 192 ``fields``: liste tout les attributs renvoyés avec la géométrie : pgrouting.php renvoit la longueurdu segment donc nous le spécifions ici. Notez que cette information n'est pas utilisée dans ces travaux pratiques. 193 194 ``proxy``: le paramÚtre proxy specifie où nous devons récupérer les données : dans notre cas depuis le serveur HTTP. Le type de proxy est GeoExt.data.ProtocolProxy : cette classe connecte le monde ExtJS (le Store) et le monde OpenLayers (l'objet protocol). 195 196 ``protocol``: ce composant OpenLayers est capable d'exécuter des requêtes à un``url`` (notre script php) et de lire la réponse (option ``format``). En ajoutant les options ``internalProjection`` et ``externalProjection``, les coordonnées sont reprojetées par l'objet format. 197 198 Nous avons maintenant tout ce qu'il nous faut pour gérer les données renvoyées par le service web : le prochain chapitre expliquera comment et quand l'appeler. 199 200 ------------------------------------------------------------------------------------------------------------- 201 Déclancher l'appel au service web 202 ------------------------------------------------------------------------------------------------------------- 203 204 Nous devons appeler le service web lorsque : 205 * les deux points sont dessinés 206 * un point à été déplacé 207 * la méthode à utiliser a changé 208 209 Notre couche vecteur génÚre une événement (appelé ``featureadded``) lorsqu'un nouvel élément est ajouté, nous pouvons utiliser cet événement pour appeler la fonction pgrouting (cette fonction sera présenté dans peu de temps) : 266 210 267 211 .. code-block:: js … … 273 217 }); 274 218 275 .. note:: Before we continue some words about events: an event in OpenLayers 276 (the same apply for ExtJS and other frameworks), is a system to allow a 277 function to be called when *something* happened. For instance when a layer is 278 added to the map or when the mouse is over a feature. Multiple functions can 279 be connected to the same event. 280 281 No event is generated when a point is moved, hopefully we can give a 282 function to the DragFeature control to be called we the point is moved: 219 .. note:: Avant de continuer quelque mots sur les événements : un événement dans OpenLayers (la même chose s'applique pour ExtJS et les autres frameworks), est un systÚme qui permet à une fonction d'être appelée lorsque *quelquechose* se passe. Par exemple lorsqu'une couche est ajoutée à la carte ou quand la souris se trouve au dessus d'un objet de la carte. Plusieurs fonctions peuvent être liées à un même événement. 220 221 Aucune événemenet n'est généré lorsqu'un point est déplacé, heureusement nous pouvons définir une fonction à notre control DragFeature à appeler lorsqu'un point est déplacé : 283 222 284 223 .. code-block:: js … … 288 227 }; 289 228 290 For the *method* combo, we can add a listeners options to the constructor with 291 a `select` argument (that's the event triggered when the user changes the value): 229 Pour la liste déroulante *method*, nous pouvons ajouter une option `select` au contructeur (c'est l'événement déclencher lorsqu'un utilisateur change sa sélection) : 292 230 293 231 .. code-block:: js … … 309 247 }); 310 248 311 312 It's now time to present the pgrouting function: 249 Il est maintenant temps de présenter la fonction pgrouting : 313 250 314 251 .. code-block:: js … … 340 277 } 341 278 342 The pgrouting function calls the web service through the store argument. 343 344 At first, the function checks if two points are passed in 345 argument. Then, ``store.removeAll()`` is called to erase a previous result 346 from the layer (remember that the store and the vector layer are binded). 347 The two points coordinates are then projected using OpenLayers.Projection 348 instances. 349 350 Finally, ``store.load()`` is called with a ``params`` representing the 351 pgrouting.php arguments (they are passed to the HTTP GET call). 352 353 ------------------------------------------------------------------------------------------------------------- 354 What's next ? 355 ------------------------------------------------------------------------------------------------------------- 356 357 Possible enhancements: 358 * use a geocoding service to get start/final point 359 * way point support 360 * nice icons for the start and final points 361 * driving directions (road map): we already have the segment length 362 363 ------------------------------------------------------------------------------------------------------------- 364 Full source code 279 La fonction pgrouting appÚle me service web à travers l'argument store. 280 281 Au début, la fonction vérifie si deux points sont présent dans les paramÚtres. Ensuite, `select` est appelée pour éffacer le résultat précédent de la couche (souvenez-vous que le Store et la couche vecteur sont lié). Les deux points sont projetés en utilisant une instance de OpenLayers.Projection. 282 283 Pour finir, ``store.load()`` est appelée avec un argument ``params`` (ils sont passés via un appÚle HTTP utilisant la méthode GET). 284 285 ------------------------------------------------------------------------------------------------------------- 286 Que faire maintenant ? 287 ------------------------------------------------------------------------------------------------------------- 288 289 Possibles améliorations : 290 * Utiliser un service de géocodage pour récupérer le point de départ / d'arrivée 291 * Support de plusieurs points 292 * De jolies icÃŽnes pour le point de départ et celui d'arrivée 293 * Direction du parcour (carte de voyage) : nous avons déjà la distance 294 295 ------------------------------------------------------------------------------------------------------------- 296 Code source complet 365 297 ------------------------------------------------------------------------------------------------------------- 366 298
Note: See TracChangeset
for help on using the changeset viewer.