Bienvenue sur PostGIS.fr

Bienvenue sur PostGIS.fr , le site de la communauté des utilisateurs francophones de PostGIS.

PostGIS ajoute le support d'objets géographique à la base de données PostgreSQL. En effet, PostGIS "spatialise" le serverur PostgreSQL, ce qui permet de l'utiliser comme une base de données SIG.

Maintenu à jour, en fonction de nos disponibilités et des diverses sorties des outils que nous testons, nous vous proposons l'ensemble de nos travaux publiés en langue française.

source: trunk/workshop-routing-foss4g/docs/chapters/geoext_client.rst @ 77

Revision 76, 16.2 KB checked in by djay, 13 years ago (diff)

Ajout du répertoire web

RevLine 
[63]1==============================================================================================================
[74]2Client en GeoExt
[63]3==============================================================================================================
4
[74]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.
[63]6
[74]7Commençons avec un exemple simple d'utilisation de GeoExt et ajoutons-y les fonctionalités de routage :
[63]8
9.. literalinclude:: ../../web/routing-0.html
10        :language: html
11
[74]12Dans 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).
[63]13
[74]14Cette 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.
[63]16
[74]17Pour 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.
[63]20
[74]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.
[63]22
23-------------------------------------------------------------------------------------------------------------
[74]24Outil de sélection de la méthode de routage
[63]25-------------------------------------------------------------------------------------------------------------
26
[74]27Pour 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.
[63]29
[74]30Comme 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) :
[63]31
32 .. code-block:: html
33
34   <body>
35     <div id="gxmap"></div>
36     <div id="method"></div>
37   </body>
38
[74]39Créons ensuite le combo :
[63]40 .. code-block:: js
41
42   var method = new Ext.form.ComboBox({
43       renderTo: "method",
44       triggerAction: "all",
45       editable: false,
46       forceSelection: true,
47       store: [
48           ["SPD", "Shortest Path Dijkstra"],
49           ["SPA", "Shortest Path A*"],
50           ["SPS", "Shortest Path Shooting*"]
51       ]
52   });
53
[74]54Dans 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.
[63]55
[74]56L'option ``renderTo`` défini où la liste déroulante doit être affichée , nous utilisons ici notre élément div.
[63]57
[74]58Et pour finir, une valeur par défaut est définie :
[63]59 .. code-block:: js
60
61    method.setValue("SPD");
62
[74]63Cette partie utilise le composant ExtJS : ni code OpenLayers ni GeoExt.
[63]64
65-------------------------------------------------------------------------------------------------------------
[74]66Sélectionner un point de départ et d'arrivée
[63]67-------------------------------------------------------------------------------------------------------------
68
[74]69Nous 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.
[63]70
[74]71Dans 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>`_.
[63]73
[74]74Pour faire ceci nous aurons besoin d'un outil permettant de dessiner des points (nous utiliserons le control
[63]75`OpenLayers.Control.DrawFeatures
[74]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.
[63]78
[74]79Ces 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).
[63]81
[74]82Comme 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 :
[63]83
84 .. code-block:: js
85
[74]86    // Création de la couche où le chemin sera affiché
[63]87    var route_layer = new OpenLayers.Layer.Vector("route", {
88        styleMap: new OpenLayers.StyleMap(new OpenLayers.Style({
89            strokeColor: "#ff9933",
90            strokeWidth: 3
91        }))
92    });
93
[74]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).
[63]96
[74]97La seconde couche est simplement initialiser comme suit :
[63]98
99 .. code-block:: js
100
[74]101    // Création de la couche ou seront affiché les points de départ et d'arrivée
[63]102    var points_layer = new OpenLayers.Layer.Vector("points");
103
[74]104Les deux couches sont ajoutée à l'objet OpenLayers.Map avec :
[63]105
106 .. code-block:: js
107
[74]108    // Ajouter la cocuhe à la carte
[63]109    map.addLayers([points_layer, route_layer]);
110
[74]111Regardons 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
112OpenLayers.Control.DrawFeatures. Ce control (nommé DrawPoints) est enregistré dans un fichier javascript à part (``web/DrawPoints.js``):
[63]113
114.. literalinclude:: ../../web/DrawPoints.js
115        :language: js
116
[74]117Dans 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).
[63]118
[74]119Le 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()``.
[63]120
[74]121Notre control est ensuite créé avec :
[63]122
123 .. code-block:: js
124
[74]125    // Création du control pour dessiner les points (voir le fichier DrawPoints.js)
[63]126    var draw_points = new DrawPoints(points_layer);
127
[74]128``points_layer`` est la couche vecteur créée précédemment.
[63]129
[74]130Et maintenant pour le control DragFeature :
[63]131
132 .. code-block:: js
133
[74]134    // Création du control pour déplacer les points
[63]135    var drag_points = new OpenLayers.Control.DragFeature(points_layer, {
136        autoActivate: true
137    });
138
[74]139Encore une fois, la couche ``points_layer``est de type vecteur, ``autoActivate: true`` dit à OpenLayers que nous voulons que ce control soit automatiquement activé.
[63]140
141 .. code-block:: js
142
[74]143    // Ajouter le control à la carte
[63]144    map.addControls([draw_points, drag_points]);
145
[74]146Ajouter le control à la carte.
[63]147
148-------------------------------------------------------------------------------------------------------------
[74]149Envoyer et recevoire des données du service web
[63]150-------------------------------------------------------------------------------------------------------------
151
[74]152Le cheminement de base pour obtenir un chemin depuis le service web est le suivant :
[63]153
[74]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
[63]159
[74]160La 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/>`_.
[63]162
[74]163(La deuxiÚme étape *appeler le service web* est étudié au chapitre suivant.)
[63]164
[74]165Le 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 :
[63]166
167 .. code-block:: js
168
169    var store = new GeoExt.data.FeatureStore({
170        layer: route_layer,
171        fields: [
172            {name: "length"}
173        ],
174        proxy: new GeoExt.data.ProtocolProxy({
175            protocol: new OpenLayers.Protocol.HTTP({
176                url: './php/pgrouting.php',
177                format: new OpenLayers.Format.GeoJSON({
178                    internalProjection: epsg_900913,
179                    externalProjection: epsg_4326
180                })
181            })
182        })
183    });
184
[74]185Un Store est simplement un conteneur qui stocke des informations : nous pouvons y ajouter des éléments et les récupérer.
[63]186
[74]187Expliquons les options :
[63]188
[74]189``layer``: le paramÚtre est une couche vecteur : en spécifiant une couche, le
190FeatureStore 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.
[63]191
[74]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.
[63]193
[74]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).
[63]195
[74]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.
[63]197
[74]198Nous 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.
[63]199
200-------------------------------------------------------------------------------------------------------------
[74]201Déclancher l'appel au service web
[63]202-------------------------------------------------------------------------------------------------------------
203
[74]204Nous 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é
[63]208
[74]209Notre 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) :
[63]210
211 .. code-block:: js
212
213    draw_layer.events.on({
214        featureadded: function() {
215            pgrouting(store, draw_layer, method.getValue());
216        }
217    });
218
[74]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.
[63]220
[74]221Aucune é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é :
[63]222
223 .. code-block:: js
224
225    drag_points.onComplete = function() {
226        pgrouting(store, draw_layer, method.getValue());
227    };
228
[74]229Pour 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) :
[63]230
231 .. code-block:: js
232
233    var method = new Ext.form.ComboBox({
234        renderTo: "method",
235        triggerAction: "all",
236        editable: false,
237        forceSelection: true,
238        store: [
239            ["SPD", "Shortest Path Dijkstra"],
240            ["SPA", "Shortest Path A*"],
241            ["SPS", "Shortest Path Shooting*"]
242        ],
243        listeners: {
244            select: function() {
245                pgrouting(store, draw_layer, method.getValue());
246            }
247    });
248
[74]249Il est maintenant temps de présenter la fonction pgrouting :
[63]250
251 .. code-block:: js
252
253   // global projection objects (uses the proj4js lib)
254   var epsg_4326 = new OpenLayers.Projection("EPSG:4326"),
255       epsg_900913 = new OpenLayers.Projection("EPSG:900913");
256
257   function pgrouting(store, layer, method) {
258         if (layer.features.length == 2) {
259             // erase the previous route
260             store.removeAll();
261
262             // transform the two geometries from EPSG:900913 to EPSG:4326
263             var startpoint = layer.features[0].geometry.clone();
264             startpoint.transform(epsg_900913, epsg_4326);
265             var finalpoint = layer.features[1].geometry.clone();
266             finalpoint.transform(epsg_900913, epsg_4326);
267
268             // load to route
269             store.load({
270                 params: {
271                     startpoint: startpoint.x + " " + startpoint.y,
272                     finalpoint: finalpoint.x + " " + finalpoint.y,
273                     method: method
274                 }
275             });
276        }
277    }
278
[74]279La fonction pgrouting appÚle me service web à travers l'argument store.
[63]280
[74]281Au 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.
[63]282
[74]283Pour finir, ``store.load()`` est appelée avec un argument ``params`` (ils sont passés via un appÚle HTTP utilisant la méthode GET).
[63]284
285-------------------------------------------------------------------------------------------------------------
[74]286Que faire maintenant ?
[63]287-------------------------------------------------------------------------------------------------------------
288
[74]289Possibles 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
[63]294
295-------------------------------------------------------------------------------------------------------------
[74]296Code source complet
[63]297-------------------------------------------------------------------------------------------------------------
298
299.. literalinclude:: ../../web/routing-final.html
300        :language: html
301
Note: See TracBrowser for help on using the repository browser.