summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--chimere/forms.py18
-rw-r--r--chimere/locale/fr/LC_MESSAGES/django.po146
-rw-r--r--chimere/route.py93
-rw-r--r--chimere/static/chimere/css/styles.css129
-rw-r--r--chimere/static/chimere/img/flag-finish.pngbin0 -> 1652 bytes
-rw-r--r--chimere/static/chimere/img/flag-start.pngbin0 -> 1165 bytes
-rw-r--r--chimere/static/chimere/img/flag-step.pngbin0 -> 1256 bytes
-rw-r--r--chimere/static/chimere/img/images_licences14
-rw-r--r--chimere/static/chimere/js/jquery.chimere.js292
-rw-r--r--chimere/static/chimere/js/nominatim-widget.js41
-rw-r--r--chimere/templates/base.html36
-rw-r--r--chimere/templates/chimere/blocks/categories.html56
-rw-r--r--chimere/templates/chimere/blocks/map_menu.html14
-rw-r--r--chimere/templates/chimere/blocks/map_params.html1
-rw-r--r--chimere/templates/chimere/blocks/routing.html56
-rw-r--r--chimere/templates/chimere/main_map.html2
-rw-r--r--chimere/templatetags/chimere_tags.py13
-rw-r--r--chimere/urls.py11
-rw-r--r--chimere/views.py29
-rw-r--r--chimere/widgets.py53
-rw-r--r--example_project/settings.py25
21 files changed, 900 insertions, 129 deletions
diff --git a/chimere/forms.py b/chimere/forms.py
index d3c55ce..20171df 100644
--- a/chimere/forms.py
+++ b/chimere/forms.py
@@ -35,7 +35,7 @@ from chimere.models import Marker, Route, PropertyModel, Property, Area,\
News, Category, SubCategory, RouteFile, MultimediaFile, MultimediaType, \
PictureFile, Importer
from chimere.widgets import AreaField, PointField, TextareaWidget, \
- DatePickerWidget
+ DatePickerWidget, ButtonSelectWidget, NominatimWidget
from datetime import timedelta, datetime, tzinfo
@@ -452,3 +452,19 @@ class AreaForm(AreaAdminForm):
class Meta:
model = Area
+class RoutingForm(forms.Form):
+ transport = forms.ChoiceField(label='', widget=ButtonSelectWidget,
+ choices=settings.CHIMERE_ROUTING_TRANSPORT,
+ initial=settings.CHIMERE_ROUTING_TRANSPORT[0][0])
+ start = forms.CharField(label=_(u"Start"), widget=NominatimWidget)
+ end = forms.CharField(label=_(u"Finish"), widget=NominatimWidget)
+ speed = forms.ChoiceField(label=_(u"Speed"), choices=[], required=False)
+
+ def __init__(self, *args, **kwargs):
+ super(RoutingForm, self).__init__(*args, **kwargs)
+ if not settings.CHIMERE_ROUTING_SPEEDS:
+ self.fields.pop('speed')
+ for transport in settings.CHIMERE_ROUTING_SPEEDS:
+ for speed, lbl in settings.CHIMERE_ROUTING_SPEEDS[transport]:
+ self.fields['speed'].widget.choices.append(
+ ("%s_%d" % (transport, speed), lbl))
diff --git a/chimere/locale/fr/LC_MESSAGES/django.po b/chimere/locale/fr/LC_MESSAGES/django.po
index 4462ff1..b986cf5 100644
--- a/chimere/locale/fr/LC_MESSAGES/django.po
+++ b/chimere/locale/fr/LC_MESSAGES/django.po
@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: 0.2\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2012-08-20 21:17+0200\n"
+"POT-Creation-Date: 2012-08-22 14:54+0200\n"
"PO-Revision-Date: 2010-03-20 20:00+0100\n"
"Last-Translator: Étienne Loks <etienne.loks@peacefrogs.net>\n"
"MIME-Version: 1.0\n"
@@ -134,6 +134,18 @@ msgstr "Nom"
msgid "Area"
msgstr "Zone"
+#: forms.py:461
+msgid "Start"
+msgstr "Départ"
+
+#: forms.py:462
+msgid "Finish"
+msgstr "Arrivée :"
+
+#: forms.py:463
+msgid "Speed"
+msgstr "Vitesse"
+
#: models.py:50 models.py:124 models.py:151 models.py:244 models.py:453
#: models.py:822 models.py:903
msgid "Available"
@@ -630,19 +642,19 @@ msgstr ""
msgid "Bad param"
msgstr "Mauvais paramètre"
-#: views.py:229
+#: views.py:236
msgid "There are missing field(s) and/or errors in the submited form."
msgstr "Il y a des champs manquants ou des erreurs dans ce formulaire."
-#: views.py:312
+#: views.py:319
msgid "Bad file. Please check it with an external software."
msgstr "Fichier incohérent. Merci de le vérifier avec un logiciel externe."
-#: views.py:434
+#: views.py:441
msgid "Comments/request on the map"
msgstr "Commentaires/requètes sur la carte"
-#: views.py:437
+#: views.py:444
msgid ""
"Thank you for your contribution. It will be taken into account. If you have "
"left your email you may be contacted soon for more details."
@@ -651,48 +663,48 @@ msgstr ""
"laissé votre courriel vous serez peut-être contacté bientôt pour plus de "
"détails."
-#: views.py:441
+#: views.py:448
msgid "Temporary error. Renew your message later."
msgstr "Erreur temporaire. Réenvoyez votre message plus tard."
-#: views.py:572
+#: views.py:579
msgid "No category available in this area."
msgstr "Pas de catégorie disponible sur cette zone."
-#: views.py:679
+#: views.py:708
msgid "Incorrect choice in the list"
msgstr "Choix incorrect dans la liste"
-#: widgets.py:187
+#: widgets.py:240
msgid "Latitude"
msgstr "Latitude"
-#: widgets.py:187
+#: widgets.py:240
msgid "Longitude"
msgstr "Longitude"
-#: widgets.py:212
+#: widgets.py:265
msgid "Invalid point"
msgstr "Point invalide"
-#: widgets.py:262
+#: widgets.py:315
msgid "Creation mode"
msgstr "Mode création"
-#: widgets.py:263
+#: widgets.py:316
msgid "To start drawing the route click on the toggle button: \"Draw\"."
msgstr ""
"Pour commencer le dessin cliquez sur le bouton&nbsp;: «&nbsp;Tracer&nbsp;»."
-#: widgets.py:265
+#: widgets.py:318
msgid "Then click on the map to begin the drawing."
msgstr "Puis cliquez sur la carte pour commencer le dessin."
-#: widgets.py:266
+#: widgets.py:319
msgid "You can add points by clicking again."
msgstr "Vous pouvez ajouter des points en cliquant de nouveau."
-#: widgets.py:267
+#: widgets.py:320
msgid ""
"To finish the drawing double click. When the drawing is finished you can "
"edit it."
@@ -700,7 +712,7 @@ msgstr ""
"Pour finir le tracé double-cliquez. Quand le tracé est fini vous pouvez "
"toujours l'éditer."
-#: widgets.py:269
+#: widgets.py:322
msgid ""
"While creating to undo a drawing click again on the toggle button \"Stop "
"drawing\"."
@@ -708,17 +720,17 @@ msgstr ""
"En mode création vous pouvez annuler un tracé en appuyant sur le bouton "
"«&nbsp;Arrêter le tracé&nbsp;»."
-#: widgets.py:274
+#: widgets.py:327
msgid "Modification mode"
msgstr "Mode modification"
-#: widgets.py:275
+#: widgets.py:328
msgid "To move a point click on it and drag it to the desired position."
msgstr ""
"Pour bouger un point, cliquez dessus, maintenez le click pour le déposer à "
"la position désirée."
-#: widgets.py:276
+#: widgets.py:329
msgid ""
"To delete a point move the mouse cursor over it and press the \"d\" or \"Del"
"\" key."
@@ -726,7 +738,7 @@ msgstr ""
"Pour supprimer un point, mettez le curseur de la souris sur celui-ci et "
"appuyez sur le touche «&nbsp;d&nbsp;» ou «&nbsp;Suppr&nbsp;»."
-#: widgets.py:278
+#: widgets.py:331
msgid ""
"To add a point click in the middle of a segment and drag the new point to "
"the desired position"
@@ -735,33 +747,33 @@ msgstr ""
"maintenez le bouton appuyé et déplacez le nouveau point à la position "
"désirée."
-#: widgets.py:285
+#: widgets.py:338
msgid "Give a name and set category before uploading a file."
msgstr ""
"Renseignez le nom et choisissez au moins une catégorie avant de déposer un "
"fichier."
-#: widgets.py:288
+#: widgets.py:341
msgid "Upload a route file (GPX or KML)"
msgstr "Déposer un trajet (fichier GPX ou KML)"
-#: widgets.py:289
+#: widgets.py:342
msgid "or"
msgstr "ou"
-#: widgets.py:294
+#: widgets.py:347
msgid "Start \"hand\" drawing"
msgstr "Commencer le tracé manuellement"
-#: widgets.py:317
+#: widgets.py:370
msgid "Move on the map"
msgstr "Se déplacer"
-#: widgets.py:317
+#: widgets.py:370
msgid "Draw"
msgstr "Tracer"
-#: widgets.py:442
+#: widgets.py:495
msgid "Select..."
msgstr "Sélectionner..."
@@ -913,6 +925,38 @@ msgstr "Ce site utilise Chimère"
msgid "Map"
msgstr "Carte"
+#: templates/chimere/blocks/map_menu.html:5
+msgctxt "routing"
+msgid "From"
+msgstr "En partir"
+
+#: templates/chimere/blocks/map_menu.html:6
+msgctxt "routing"
+msgid "Add a step"
+msgstr "Ajout d'une étape"
+
+#: templates/chimere/blocks/map_menu.html:7
+msgctxt "routing"
+msgid "To"
+msgstr "Y aller"
+
+#: templates/chimere/blocks/map_menu.html:8
+msgctxt "routing"
+msgid "Clear the itinerary"
+msgstr "Effacer l'itinéraire"
+
+#: templates/chimere/blocks/map_menu.html:10
+msgid "Zoom in"
+msgstr "Zoomer en avant"
+
+#: templates/chimere/blocks/map_menu.html:11
+msgid "Zoom out"
+msgstr "Zoomer en arrière"
+
+#: templates/chimere/blocks/map_menu.html:12
+msgid "Center the map here"
+msgstr "Centrer la carte ici"
+
#: templates/chimere/blocks/map_params.html:6
msgid "Permalink"
msgstr "Lien permanent"
@@ -923,6 +967,27 @@ msgstr ""
"Utilisez un navigateur internet plus récent ou installez le greffon non "
"libre Flash."
+#: templates/chimere/blocks/routing.html:4
+#: templates/chimere/blocks/routing.html:40
+msgid "Itinerary"
+msgstr "Itinéraire"
+
+#: templates/chimere/blocks/routing.html:19
+msgid "Modify"
+msgstr "Modifier"
+
+#: templates/chimere/blocks/routing.html:22
+msgid "New search"
+msgstr "Nouvelle recherche"
+
+#: templates/chimere/blocks/routing.html:27
+msgid "Start:"
+msgstr "Départ :"
+
+#: templates/chimere/blocks/routing.html:31
+msgid "Finish:"
+msgstr "Arrivée :"
+
#: templates/chimere/blocks/submited.html:3
msgid ""
"Your new proposition/modification has been submited. A moderator will treat "
@@ -987,26 +1052,5 @@ msgstr "Choisir une zone pré-définie"
msgid "Or select the area by zooming and panning this map"
msgstr "Ou sélectionner une zone en zoomant et en se déplaçant sur cette carte"
-#~ msgid "Submit a modification"
-#~ msgstr "Proposer une modification"
-
-#~ msgid "Add/modify a site"
-#~ msgstr "Ajouter ou modifier un site"
-
-#~ msgid "Categorys"
-#~ msgstr "Catégories"
-
-#~ msgid "Theme"
-#~ msgstr "Thème"
-
-#~ msgid "Subtheme"
-#~ msgstr "Sous-thème"
-
-#~ msgid "Subthemes"
-#~ msgstr "Sous-thèmes"
-
-#~ msgid "Themes"
-#~ msgstr "Thèmes"
-
-#~ msgid "Site name"
-#~ msgstr "Nom du site"
+#~ msgid "End"
+#~ msgstr "Fin"
diff --git a/chimere/route.py b/chimere/route.py
new file mode 100644
index 0000000..bc08a39
--- /dev/null
+++ b/chimere/route.py
@@ -0,0 +1,93 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# Copyright (C) 2012 Étienne Loks <etienne.loks_AT_peacefrogsDOTnet>
+#
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+# See the file COPYING for details.
+
+"""
+Routing management
+"""
+
+import os, re, shutil, tempfile
+from BeautifulSoup import BeautifulSoup
+from subprocess import Popen, PIPE
+from django.contrib.gis.gdal import DataSource
+
+from django.conf import settings
+
+class Router:
+ def route(self, lon1, lat1, lon2, lat2, transport='foot'):
+ '''
+ Get a list of geojson polylines
+ '''
+ return []
+
+class RoutinoRouter(Router):
+ re_desc = [re.compile("<tr class='n'>"), re.compile("<tr class='s'>"),
+ re.compile("<tr class='t'>")]
+ def route(self, lon1, lat1, lon2, lat2, steps=[], transport='foot'):
+ '''
+ Get a list of geojson polylines and route description
+ '''
+ language = settings.LANGUAGE_CODE.split('-')[0]
+ args = [settings.CHIMERE_ROUTING_ENGINE['PATH'],
+ "--dir=%s" % settings.CHIMERE_ROUTING_ENGINE['DB_PATH'],
+ "--transport=%s" % transport,
+ "--language=%s" % language,
+ "--shortest",
+ "--output-html",
+ "--output-gpx-track",
+ "--lat1=%0.15f" % lat1,
+ "--lon1=%0.15f" % lon1,
+ ]
+ lonlat_index = 1
+ for lon, lat in steps:
+ lonlat_index += 1
+ args += ["--lat%d=%0.15f" % (lonlat_index, lat),
+ "--lon%d=%0.15f" % (lonlat_index, lon)]
+ lonlat_index += 1
+ args += ["--lat%d=%0.15f" % (lonlat_index, lat2),
+ "--lon%d=%0.15f" % (lonlat_index, lon2)]
+ tmp_dir = tempfile.mkdtemp(prefix='chimere_') + os.sep
+ p = Popen(args, stdout=PIPE, cwd=tmp_dir)
+ p.communicate()
+ ds = DataSource(tmp_dir + 'shortest-track.gpx')
+ if not ds:
+ return [], None
+ layer = ds[0]
+ trk_layer = None
+ for layer in ds:
+ if layer.name == 'tracks':
+ trk_layer = layer
+ break
+ multilines = trk_layer.get_geoms()
+ res = []
+ for multiline in multilines:
+ res += [geom.geojson for geom in multiline]
+ desc = []
+ # only keeping interessant lines of the desc
+ for line in open(tmp_dir + 'shortest.html').readlines():
+ if [True for r in self.re_desc if r.match(line)]:
+ desc.append(BeautifulSoup(line).prettify())
+ desc = ['<table>'] + desc[1:-2] + [desc[-1], '</table>']
+ desc = BeautifulSoup('\n'.join(desc)).prettify()
+ shutil.rmtree(tmp_dir)
+ return res, desc
+router = None
+if settings.CHIMERE_ROUTING_ENGINE['ENGINE'] == 'routino':
+ router = RoutinoRouter()
+
diff --git a/chimere/static/chimere/css/styles.css b/chimere/static/chimere/css/styles.css
index f8ed3fe..188cc3b 100644
--- a/chimere/static/chimere/css/styles.css
+++ b/chimere/static/chimere/css/styles.css
@@ -15,7 +15,8 @@ a, a:link, a:visited, legend,
h2, h3, th, .action li, .action li a,
.action li li a, #no-js-message,
-#footer a, #footer a:link, #footer a:visited, .ui-widget-header{
+#footer a, #footer a:link, #footer a:visited, .ui-widget-header,
+#chimere_itinerary td.l{
color:#fff;
}
@@ -29,7 +30,10 @@ h2, h3, th, .action li, .action li a,
body, h2, h3, th,
.ui-widget-header,
-.action li.selected, #no-js-message{
+.action li.selected, #no-js-message,
+#content .olControlLayerSwitcher .layersDiv,
+#content .olControlLayerSwitcher span,
+#chimere_itinerary td.l{
background-color:#449506;
}
@@ -38,7 +42,7 @@ body, h2, h3, th,
}
fieldset, .action li, #content,
-#map-footer, #panel, #areas,
+#map-footer, #panel, #chimere_itinerary_panel, #areas,
#welcome, #detail, .detail_footer a,
#content .olControlLayerSwitcher .layersDiv,
#content .olControlLayerSwitcher span,
@@ -63,7 +67,7 @@ div.warning,
#content,
.action li.selected,
#content .olControlLayerSwitcher .layersDiv,
-#panel, #map-footer,
+#panel, #map-footer, #chimere_itinerary_panel,
#utils-div{
border:1px solid #327e04;
}
@@ -79,7 +83,7 @@ div.warning,
opacity:0.9;
}
-#panel, #areas, #detail, #category_detail{
+#panel, #areas, #detail, #category_detail, #chimere_itinerary_panel{
opacity:0.8;
}
@@ -409,12 +413,111 @@ ul#share li{
top:50px;
right:18px;
width:300px;
- bottom:44px;
+ max-height:300px;
overflow:auto;
padding:0.5em;
padding-top:0;
}
+#chimere_itinerary_panel,
+#chimere_itinerary{
+ display:none;
+}
+
+#chimere_itinerary_panel label{
+ color:#000;
+}
+
+#chimere_itinerary_panel p
+{
+ margin:0.5em;
+}
+
+.itinerary_label{
+ font-size:0.9em;
+ padding-top:0.5em;
+ font-style:italic;
+}
+
+.itinerary_label.label{
+ font-style:normal;
+ font-weight:bold;
+}
+
+
+#chimere_itinerary_content{
+ overflow:auto;
+ height:190px;
+ margin-top:10px;
+}
+
+#chimere_itinerary_content table
+{
+ border-collapse:collapse;
+}
+
+#chimere_itinerary_content table td{
+ border:1px solid #333;
+}
+
+#chimere_itinerary_content td.l{
+ padding:5px;
+ width:60px;
+}
+
+#chimere_itinerary_content td.r{
+ font-size:0.8em;
+ padding:0.8em;
+}
+
+#chimere_itinerary_content span.j{
+ font-style:italic;
+}
+
+#chimere_itinerary_content span.t,
+#chimere_itinerary_content span.b
+{
+ text-transform: lowercase;
+}
+
+#chimere_map_menu{
+ z-index:4;
+ display:none;
+ position:absolute;
+ padding:0.5em;
+ background-color:#fff;
+ border:1px solid #bbb;
+ -webkit-border-radius: 0 8px 8px 8px;
+ -moz-border-radius: 0 8px 8px 8px;
+ border-radius: 0 8px 8px 8px;
+}
+
+#map_menu_clear{
+ display:none;
+}
+
+#map_menu_zoomin{
+ border-top:1px solid #999;
+}
+
+#chimere_map_menu ul, #chimere_map_menu li{
+ padding:0.2em;
+ margin:0;
+ list-style:none;
+}
+
+#chimere_map_menu li:hover{
+ cursor:pointer;
+ background-color:#ccc;
+}
+
+.nominatim-label{
+ display:block;
+ font-size:0.9em;
+ font-weight:bold;
+ height:2.8em;
+}
+
.simple #panel{
top:5px;
}
@@ -533,26 +636,18 @@ p.warning{
}
-#welcome_button,
+a#welcome_button,
+a#routing_button,
#permalink{
display: block;
- text-align:center;
margin:0.3em;
padding:0.2em;
-}
-
-a#welcome_button,
-#permalink{
+ width:100%;
font-size:14px;
text-align:center;
text-decoration:none;
}
-#welcome_button,
-#permalink{
- width:100%;
-}
-
/* forms */
table.inline-table{
diff --git a/chimere/static/chimere/img/flag-finish.png b/chimere/static/chimere/img/flag-finish.png
new file mode 100644
index 0000000..04bfa1d
--- /dev/null
+++ b/chimere/static/chimere/img/flag-finish.png
Binary files differ
diff --git a/chimere/static/chimere/img/flag-start.png b/chimere/static/chimere/img/flag-start.png
new file mode 100644
index 0000000..c93f2a3
--- /dev/null
+++ b/chimere/static/chimere/img/flag-start.png
Binary files differ
diff --git a/chimere/static/chimere/img/flag-step.png b/chimere/static/chimere/img/flag-step.png
new file mode 100644
index 0000000..5556c94
--- /dev/null
+++ b/chimere/static/chimere/img/flag-step.png
Binary files differ
diff --git a/chimere/static/chimere/img/images_licences b/chimere/static/chimere/img/images_licences
index 0e732fc..cbc9307 100644
--- a/chimere/static/chimere/img/images_licences
+++ b/chimere/static/chimere/img/images_licences
@@ -1,5 +1,5 @@
-* Upload image credit
+* Upload image credit (upload.png)
* Farm-Fresh layer gps.png in Farm-Fresh Web Icons
Author: FatCow Web Hosting
@@ -16,7 +16,7 @@ Author: The Tango! Desktop Project
Licence: Public domain
Url: http://commons.wikimedia.org/wiki/File:Internet-web-browser.svg
-* Drawing image credit
+* Drawing image credit (drawing.png)
* Icons from the Tango! project set.
Author: The Tango! Desktop Project
@@ -24,9 +24,17 @@ Licence: Public domain
Url: http://commons.wikimedia.org/wiki/File:Edit-find-replace.svg
Url 2: http://commons.wikimedia.org/wiki/File:Internet-web-browser.svg
-* Quaver image credit
+* Quaver image credit (8thNote.png)
* An 8th-note.
Author: Sbrools
Licence: Public domain
Url: https://commons.wikimedia.org/wiki/File:8thNote.svg
+
+* Flags image credit (flag-start.png, flag-step.png, flag-finish.png)
+
+Author: FatCow Web Hosting
+Licence: Creative Commons Attribution 3.0 United States license
+Url: https://upload.wikimedia.org/wikipedia/commons/c/cb/Farm-Fresh_flag_1.png
+ https://upload.wikimedia.org/wikipedia/commons/8/81/Farm-Fresh_flag_blue.png
+ https://upload.wikimedia.org/wikipedia/commons/6/64/Farm-Fresh_flag_finish.png
diff --git a/chimere/static/chimere/js/jquery.chimere.js b/chimere/static/chimere/js/jquery.chimere.js
index fbb3ecd..c1d028c 100644
--- a/chimere/static/chimere/js/jquery.chimere.js
+++ b/chimere/static/chimere/js/jquery.chimere.js
@@ -77,10 +77,15 @@ OpenLayers.Layer.MapQuestOSM = OpenLayers.Class(OpenLayers.Layer.XYZ, {
controls:[new OpenLayers.Control.Navigation(),
new OpenLayers.Control.SimplePanZoom(),
new OpenLayers.Control.ScaleLine()],
+ category_accordion: true, // category opening behave like an accordion
maxResolution: 156543.0399,
units: 'm',
projection: new OpenLayers.Projection('EPSG:4326'),
theme:null,
+ routing: false, // enable routing management
+ routing_panel_open: function(){
+ $('#chimere_itinerary_panel').dialog('open');
+ },
current_feature: null, // To store the active POI
current_control: null, // To store the current control
current_popup: null, // To store the current POI popup displayed
@@ -119,6 +124,8 @@ OpenLayers.Layer.MapQuestOSM = OpenLayers.Class(OpenLayers.Layer.XYZ, {
map_options['restrictedExtent'] = settings.restricted_extent;
}
+ settings.current_position = null;
+
/* Create map object */
settings.map = map = new OpenLayers.Map(map_element, map_options);
@@ -168,6 +175,40 @@ OpenLayers.Layer.MapQuestOSM = OpenLayers.Class(OpenLayers.Layer.XYZ, {
}
settings.map.setBaseLayer(
settings.map_layers[settings.selected_map_layer]);
+
+ /* manage the context menu */
+ $('#map_menu_zoomin').bind("click", methods.zoomIn);
+ $('#map_menu_zoomout').bind("click", methods.zoomOut);
+ $('#map_menu_center').bind("click", methods.mapCenter);
+ /* manage the routing */
+ if (settings.routing){
+ settings.routing_start = null;
+ settings.routing_steps = new Array();
+ settings.routing_end = null;
+ settings.icon_start = new OpenLayers.Icon(
+ STATIC_URL + "chimere/img/flag-start.png",
+ new OpenLayers.Size(32, 32),
+ new OpenLayers.Pixel(0, -32));
+ settings.icon_step = new OpenLayers.Icon(
+ STATIC_URL + "chimere/img/flag-step.png",
+ new OpenLayers.Size(32, 32),
+ new OpenLayers.Pixel(0, -32));
+ settings.icon_end = new OpenLayers.Icon(
+ STATIC_URL + "chimere/img/flag-finish.png",
+ new OpenLayers.Size(32, 32),
+ new OpenLayers.Pixel(0, -32));
+ $('#map_menu_from').bind("click", methods.routingFrom);
+ $('#map_menu_step').bind("click", methods.routingAddStep);
+ $('#map_menu_to').bind("click", methods.routingTo);
+ $('#map_menu_clear').bind("click", methods.routingClear);
+ settings.layerRoute = new OpenLayers.Layer.Vector("Route Layer");
+ settings.map.addLayer(settings.layerRoute);
+ settings.layerRoute.setOpacity(0.8);
+ settings.layerRouteMarker = new OpenLayers.Layer.Markers(
+ 'Route markers');
+ settings.map.addLayer(settings.layerRouteMarker);
+ settings.layerRouteMarker.setOpacity(0.8);
+ }
/* Vectors layer */
settings.layerVectors = new OpenLayers.Layer.Vector("Vector Layer");
settings.map.addLayer(settings.layerVectors);
@@ -211,7 +252,7 @@ OpenLayers.Layer.MapQuestOSM = OpenLayers.Class(OpenLayers.Layer.XYZ, {
methods.loadGeoObjects();
// Hide popUp when clicking on map
settings.map.events.register('click', settings.map,
- methods.hidePopup);
+ methods.displayMapMenu);
} else {
if (!settings.edition_type_is_route){
map.events.register('click', settings.map,
@@ -225,6 +266,43 @@ OpenLayers.Layer.MapQuestOSM = OpenLayers.Class(OpenLayers.Layer.XYZ, {
}
}, // end of init
+ // zoom in from the map menu
+ zoomIn: function(){
+ methods.mapCenter();
+ settings.map.zoomIn();
+ },
+
+ // zoom out from the map menu
+ zoomOut: function(){
+ methods.mapCenter();
+ settings.map.zoomOut();
+ },
+
+ // center from the map menu
+ mapCenter: function(){
+ $('#chimere_map_menu').hide();
+ settings.map.setCenter(settings.current_position);
+ },
+
+ /*
+ * Display menu on the map
+ */
+ displayMapMenu: function(e) {
+ if (methods.hidePopup()) return;
+ if ($('#chimere_map_menu').is(":visible")){
+ $('#chimere_map_menu').hide();
+ } else{
+ settings.current_position =
+ settings.map.getLonLatFromViewPortPx(e.xy);
+ var offsetX = e.pageX;
+ var offsetY = e.pageY;
+ $('#chimere_map_menu').show('fast');
+ $('#chimere_map_menu').css('display', 'block');
+ $('#chimere_map_menu').css('top', offsetY);
+ $('#chimere_map_menu').css('left', offsetX);
+ }
+ },
+
/*
* Load markers and route from DB
*/
@@ -289,7 +367,13 @@ OpenLayers.Layer.MapQuestOSM = OpenLayers.Class(OpenLayers.Layer.XYZ, {
category_element.parent().find("li input").attr("checked", val);
}
var _toggle_categories = function (subcategory_element) {
- var parent = subcategory_element.parent().parent().parent();
+ var parent = subcategory_element.closest('ul');
+ var parent_label = parent.parent().find("> span > label");
+ if (parent.find('input[type=checkbox]:checked').length){
+ parent_label.addClass('category-selected');
+ } else {
+ parent_label.removeClass('category-selected');
+ }
var master_check = parent.find("> input");
if (parent.find('.subcategories input[type=checkbox]').length ==
parent.find('.subcategories input[type=checkbox]:checked').length){
@@ -297,6 +381,14 @@ OpenLayers.Layer.MapQuestOSM = OpenLayers.Class(OpenLayers.Layer.XYZ, {
} else {
master_check.removeAttr('checked');
}
+
+ if($('#action-categories').length){
+ if ($('#categories input[type=checkbox]:checked').length){
+ $('#action-categories').addClass('category-selected');
+ } else {
+ $('#action-categories').removeClass('category-selected');
+ }
+ }
return master_check;
};
var _init_categories = function () {
@@ -383,12 +475,12 @@ OpenLayers.Layer.MapQuestOSM = OpenLayers.Class(OpenLayers.Layer.XYZ, {
}
else
{
+ $('#chimere_map_menu').hide();
// Default popup
if (feature.popup && feature.popup.visible()) {
if (settings.current_popup == feature.popup) {
feature.popup.hide();
if (!settings.simple){
- $('#panel').removeClass('panel-minified');
$('#detail').hide();
}
} else {
@@ -448,6 +540,164 @@ OpenLayers.Layer.MapQuestOSM = OpenLayers.Class(OpenLayers.Layer.XYZ, {
settings.current_feature.geometry = linestring;
settings.layerVectors.addFeatures([settings.current_feature]);
},
+ routingInputChange: function(){
+ $('#map_menu_clear').show();
+ if ($('#nominatim_start_lon').val()){
+ settings.routing_start = new OpenLayers.Marker(
+ new OpenLayers.LonLat($('#nominatim_start_lon').val(),
+ $('#nominatim_start_lat').val()
+ ).transform(EPSG_DISPLAY_PROJECTION,
+ settings.map.getProjectionObject()),
+ settings.icon_start);
+ settings.layerRouteMarker.addMarker(settings.routing_start);
+ }
+ if ($('#nominatim_end_lon').val()){
+ settings.routing_end = new OpenLayers.Marker(
+ new OpenLayers.LonLat($('#nominatim_end_lon').val(),
+ $('#nominatim_end_lat').val()
+ ).transform(EPSG_DISPLAY_PROJECTION,
+ settings.map.getProjectionObject()),
+ settings.icon_end);
+ settings.layerRouteMarker.addMarker(settings.routing_end);
+ }
+ if (settings.routing_end && settings.routing_start) methods.route();
+ },
+
+ // set the start point for routing
+ routingFrom: function(){
+ $('#chimere_map_menu').hide();
+ settings.routing_panel_open();
+ $('#map_menu_clear').show();
+ settings.routing_start = new OpenLayers.Marker(
+ settings.current_position.clone(),
+ settings.icon_start);
+ settings.layerRouteMarker.addMarker(settings.routing_start);
+ if (nominatim_url){
+ helpers.updateNominatimName(settings.current_position.clone()
+ .transform(settings.map.getProjectionObject(),
+ EPSG_DISPLAY_PROJECTION),
+ 'start_label');
+ }
+ if (settings.routing_end) methods.route();
+ },
+ // add a step point for routing
+ routingAddStep: function(){
+ $('#chimere_map_menu').hide();
+ settings.routing_panel_open();
+ $('#map_menu_clear').show();
+ settings.routing_steps.push(new OpenLayers.Marker(
+ settings.current_position.clone(),
+ settings.icon_step.clone()));
+ settings.layerRouteMarker.addMarker(
+ settings.routing_steps[settings.routing_steps.length-1]);
+ if (settings.routing_end && settings.routing_start) methods.route();
+ },
+
+ // set the finish point for routing
+ routingTo: function(){
+ $('#chimere_map_menu').hide();
+ settings.routing_panel_open();
+ $('#map_menu_clear').show();
+ settings.routing_end = new OpenLayers.Marker(
+ settings.current_position.clone(),
+ settings.icon_end);
+ settings.layerRouteMarker.addMarker(settings.routing_end);
+ if (nominatim_url){
+ helpers.updateNominatimName(settings.current_position.clone()
+ .transform(settings.map.getProjectionObject(),
+ EPSG_DISPLAY_PROJECTION),
+ 'end_label');
+ }
+ if (settings.routing_start) methods.route();
+ },
+
+ // clear the current itinerary
+ routingClear: function(){
+ $('#nominatim_start_lon').val('');
+ $('#nominatim_start_lat').val('');
+ $('#nominatim_start_label').html('');
+ $('#chimere_start_label').html('');
+ $('#nominatim_end_lon').val('');
+ $('#nominatim_end_lat').val('');
+ $('#nominatim_end_label').html('');
+ $('#chimere_end_label').html('');
+ $('.nominatim-widget').val('');
+ $('#chimere_map_menu').hide();
+ $('#map_menu_clear').hide();
+ $('#chimere_itinerary').hide();
+ $('#chimere_itinerary_form').show();
+ settings.layerRoute.removeAllFeatures();
+ settings.layerRouteMarker.clearMarkers();
+ settings.routing_start = null;
+ settings.routing_end = null;
+ settings.routing_steps = new Array();
+ },
+
+ // display a route
+ route: function(){
+ if (!settings.routing_start || !settings.routing_end){
+ return;
+ }
+ var steps = [settings.routing_start.lonlat.clone()]
+ for (var i = 0; i < settings.routing_steps.length; i++) {
+ steps.push(settings.routing_steps[i].lonlat.clone());
+ }
+ steps.push(settings.routing_end.lonlat.clone());
+ // create the appropriate URL
+ var uri = extra_url + "route/"
+ var transport = $('input:radio[name=transport]:checked').val();
+ uri += transport + "/"
+ for (var i = 0; i < steps.length; i++) {
+ var step = steps[i].transform(
+ settings.map.getProjectionObject(),
+ EPSG_DISPLAY_PROJECTION);
+ if (i > 0){
+ uri += '_';
+ }
+ uri += step.lon + '_' + step.lat;
+ }
+ $.ajax({url: uri,
+ dataType: "json",
+ success: function (data) {
+ settings.layerRoute.removeAllFeatures();
+ for (var i = 0; i < data.features.length; i++) {
+ methods.putRoute(data.features[i]);
+ }
+ settings.map.zoomToExtent(
+ settings.layerRoute.getDataExtent());
+ settings.map.zoomOut();
+ $('#chimere_itinerary_content').html(
+ data.properties.description);
+ $('#chimere_itinerary').show();
+ $('#chimere_itinerary_form').hide();
+ settings.routing_panel_open();
+ },
+ error: function (data) {
+ settings.layerRoute.removeAllFeatures();
+ }
+ });
+
+ },
+ /*
+ Put a route on the map
+ */
+ putRoute: function(polyline) {
+ var point_array = new Array();
+ for (i=0; i<polyline.coordinates.length; i++){
+ var point = new OpenLayers.Geometry.Point(polyline.coordinates[i][0],
+ polyline.coordinates[i][1]);
+ point_array.push(point);
+ }
+ var linestring = new OpenLayers.Geometry.LineString(point_array);
+ linestring.transform(EPSG_DISPLAY_PROJECTION, settings.map.getProjectionObject());
+ current_route = new OpenLayers.Feature.Vector();
+ var style = OpenLayers.Util.extend({},
+ OpenLayers.Feature.Vector.style['default']);
+ style.strokeWidth = 3;
+ current_route.style = style;
+ current_route.geometry = linestring;
+ settings.layerRoute.addFeatures([current_route]);
+ },
display_feature_detail: function (pk) {
/*
* update current detail panel with an AJAX request
@@ -466,7 +716,6 @@ OpenLayers.Layer.MapQuestOSM = OpenLayers.Class(OpenLayers.Layer.XYZ, {
}
else {
if (!settings.simple) {
- $('#panel').addClass('panel-minified');
$('#detail').html(data).show();
}
else {
@@ -508,9 +757,11 @@ OpenLayers.Layer.MapQuestOSM = OpenLayers.Class(OpenLayers.Layer.XYZ, {
// Check if element is currently visible or not
var was_visible = $("#maincategory_" + id).is(":visible");
// Close all categories
- $("#categories ul.subcategories").hide();
+ if (settings.category_accordion){
+ $("#categories ul.subcategories").hide();
+ $("#categories img.toggle_category").attr("src", STATIC_URL + "chimere/img/plus.png");
+ }
// Put a minus image
- $("#categories img.toggle_category").attr("src", STATIC_URL + "chimere/img/plus.png");
if (!was_visible)
{
// Show the subcategories
@@ -519,6 +770,12 @@ OpenLayers.Layer.MapQuestOSM = OpenLayers.Class(OpenLayers.Layer.XYZ, {
$("#maincategory_img_" + id).attr("src", STATIC_URL + "chimere/img/minus.png");
settings.current_category = id;
}
+ if (!settings.category_accordion && was_visible)
+ {
+ $("#maincategory_" + id).toggle();
+ // Put a minus image
+ $("#maincategory_img_" + id).attr("src", STATIC_URL + "chimere/img/plus.png");
+ }
},
zoomToCurrentExtent: function(){
/* zoom to current extent */
@@ -629,13 +886,16 @@ OpenLayers.Layer.MapQuestOSM = OpenLayers.Class(OpenLayers.Layer.XYZ, {
else { // Default behaviour
if (settings.current_popup)
{
- settings.current_popup.hide();
if (!settings.simple){
- $('#panel').removeClass('panel-minified');
$('#detail').hide();
}
+ if (settings.current_popup.visible()){
+ settings.current_popup.hide();
+ return true;
+ }
}
}
+ return false;
},
saveExtent: function(){
var extent_key = 'MAP_EXTENT';
@@ -770,8 +1030,22 @@ OpenLayers.Layer.MapQuestOSM = OpenLayers.Class(OpenLayers.Layer.XYZ, {
if (vertices){
jQuery('#id_point').val(vertices);
}
+ },
+ updateNominatimName:function(lonlat, response_id){
+ $.ajax({
+ url: nominatim_url.substring(0, nominatim_url.length-6) + 'reverse',
+ data: {
+ format: "json",
+ lat:lonlat.lat,
+ lon:lonlat.lon
+ },
+ success: function (data) {
+ vals = $.parseJSON(data);
+ $('#nominatim_'+response_id).html(vals.display_name);
+ $('#chimere_'+response_id).html(vals.display_name);
+ }
+ });
}
-
}; // End of helpers
$.fn.chimere = function (thing) {
diff --git a/chimere/static/chimere/js/nominatim-widget.js b/chimere/static/chimere/js/nominatim-widget.js
new file mode 100644
index 0000000..fea654d
--- /dev/null
+++ b/chimere/static/chimere/js/nominatim-widget.js
@@ -0,0 +1,41 @@
+
+$(function(){
+ $(".nominatim-widget").autocomplete({
+ source: function (request, response) {
+ $.ajax({
+ url: nominatim_url,
+ data: {
+ format: "json",
+ q: request.term,
+ },
+ success: function ( data ) {
+ response ( $.map( $.parseJSON(data), function( item ) {
+ return {
+ label: item.display_name,
+ value: item.display_name,
+ lat: item.lat,
+ lon: item.lon
+ }}));
+
+ }
+ })
+ },
+ minLength: 6,
+ delay: 1000,
+ select: function ( event, ui ) {
+ $('#'+$(this).attr('id')+'_lat').val(ui.item.lat);
+ $('#'+$(this).attr('id')+'_lon').val(ui.item.lon);
+ $('#'+$(this).attr('id')+'_label').html(ui.item.label);
+ $('#chimere_'+$(this).attr('id').substring(10)+'_label').html(ui.item.label);
+ $('#'+$(this).attr('id')).val('');
+ jQuery("#map").chimere("routingInputChange");
+ return false;
+ },
+ open: function() {
+ $( this ).removeClass( "ui-corner-all" ).addClass( "ui-corner-top" );
+ },
+ close: function() {
+ $( this ).removeClass( "ui-corner-top" ).addClass( "ui-corner-all" );
+ }
+ });
+});
diff --git a/chimere/templates/base.html b/chimere/templates/base.html
index 2a50fc3..149cc71 100644
--- a/chimere/templates/base.html
+++ b/chimere/templates/base.html
@@ -7,25 +7,25 @@
{% endblock %}
</head>
<body {% block body_id %}{% endblock %} {% block body_class %}{% endblock %}>
- {% block extrabody %}
+{% block extrabody %}
+{% endblock %}
+{% block body %}
+<div id="header">
+ {% block header %}
{% endblock %}
- {% block body %}
- <div id="header">
- {% block header %}
- {% endblock %}
- </div>
- <div id="sidebar">
- {% block sidebar %}
- {% endblock %}
- </div>
- <div id="content">
- {% block content %}
- {% endblock %}
- </div>
- <div id="footer">
- {% block footer %}
- {% endblock %}
- </div>
+</div>
+<div id="sidebar">
+ {% block sidebar %}
{% endblock %}
+</div>
+<div id="content">
+ {% block content %}
+ {% endblock %}
+</div>
+<div id="footer">
+ {% block footer %}
+ {% endblock %}
+</div>
+{% endblock %}
</body>
</html>
diff --git a/chimere/templates/chimere/blocks/categories.html b/chimere/templates/chimere/blocks/categories.html
index 5ba89fc..9c5ffd6 100644
--- a/chimere/templates/chimere/blocks/categories.html
+++ b/chimere/templates/chimere/blocks/categories.html
@@ -1,29 +1,29 @@
{% load i18n %}
-<ul id='ul_categories'>
- {% for category, lst_sub_categories in sub_categories %}
- <li>
- <img class="control_image toggle_category" id="maincategory_img_{{category.id}}" alt="control" src="{{ STATIC_URL }}chimere/img/{% if category.selected %}minus.png{% else %}plus.png{% endif %}" />
- <input type="checkbox" id='checkall_{{category.id}}'>
- {% trans category.name %}
- <img id="zoom_to_category_{{category.id}}" class="zoom_image zoom_to_category" alt='{% trans "Zoom to" %} {{category.name}}' src='{{ STATIC_URL }}chimere/img/zoom.png' />
- <ul class='subcategories' id='maincategory_{{category.id}}'{% if not category.selected %} style='display:None'{% endif %}>
- {% for sub_category in lst_sub_categories %}
- <li id='li_sub_{{sub_category.id}}'>
- <input type='checkbox' name='category_{{sub_category.id}}' id='category_{{sub_category.id}}'{% if sub_category.selected %} checked='checked'{% endif %}/>
- <label for='category_{{sub_category.id}}'>
- <img alt='{{ sub_category.name }}' src='{{ MEDIA_URL }}{{sub_category.icon.image}}'/>
- {% trans sub_category.name %}
- </label>
- <img id="zoom_to_subcategory_{{sub_category.id}}" class="zoom_image zoom_to_subcategory" alt='{% trans "Zoom to" %} {{sub_category.name}}' src='{{ STATIC_URL }}chimere/img/zoom.png' />
- </li>
- {% endfor %}
- {% if category.description %}
- <li><a href="#" onclick="$('#map').chimere('category_detail', {{category.id}});">{% trans "Tell me more..." %}</a></li>
- {% endif %}
- </ul>
- </li>
- {% endfor %}
- <li id='display_submited'>
- <input type='checkbox' name='display_submited' id='display_submited_check'/> {% trans "Display markers and routes waiting for validation"%}
- </li>
-</ul>
+ <ul id='ul_categories'>
+ {% for category, lst_sub_categories in sub_categories %}
+ <li>
+ <img class="control_image toggle_category" id="maincategory_img_{{category.id}}" alt="control" src="{{ STATIC_URL }}chimere/img/{% if category.selected %}minus.png{% else %}plus.png{% endif %}" />
+ <input type="checkbox" id='checkall_{{category.id}}'>
+ {% trans category.name %}
+ <img id="zoom_to_category_{{category.id}}" class="zoom_image zoom_to_category" alt='{% trans "Zoom to" %} {{category.name}}' src='{{ STATIC_URL }}chimere/img/zoom.png' />
+ <ul class='subcategories' id='maincategory_{{category.id}}'{% if not category.selected %} style='display:None'{% endif %}>
+ {% for sub_category in lst_sub_categories %}
+ <li id='li_sub_{{sub_category.id}}'>
+ <input type='checkbox' name='category_{{sub_category.id}}' id='category_{{sub_category.id}}'{% if sub_category.selected %} checked='checked'{% endif %}/>
+ <label for='category_{{sub_category.id}}'>
+ <img alt='{{ sub_category.name }}' src='{{ MEDIA_URL }}{{sub_category.icon.image}}'/>
+ {% trans sub_category.name %}
+ </label>
+ <img id="zoom_to_subcategory_{{sub_category.id}}" class="zoom_image zoom_to_subcategory" alt='{% trans "Zoom to" %} {{sub_category.name}}' src='{{ STATIC_URL }}chimere/img/zoom.png' />
+ </li>
+ {% endfor %}
+ {% if category.description %}
+ <li><a href="#" onclick="$('#map').chimere('category_detail', {{category.id}});">{% trans "Tell me more..." %}</a></li>
+ {% endif %}
+ </ul>
+ </li>
+ {% endfor %}
+ <li id='display_submited'>
+ <input type='checkbox' name='display_submited' id='display_submited_check'/> {% trans "Display markers and routes waiting for validation"%}
+ </li>
+ </ul>
diff --git a/chimere/templates/chimere/blocks/map_menu.html b/chimere/templates/chimere/blocks/map_menu.html
new file mode 100644
index 0000000..38fb4a8
--- /dev/null
+++ b/chimere/templates/chimere/blocks/map_menu.html
@@ -0,0 +1,14 @@
+{% load i18n %}
+<div id='chimere_map_menu'>
+ <ul>
+ {% if routing %}
+ <li id='map_menu_from' class='routing_item'>{% trans "From" context "routing" %}</li>
+ <li id='map_menu_step' class='routing_item'>{% trans "Add a step" context "routing" %}</li>
+ <li id='map_menu_to' class='routing_item'>{% trans "To" context "routing" %}</li>
+ <li id='map_menu_clear' class='routing_item'>{% trans "Clear the itinerary" context "routing" %}</li>
+ {% endif%}
+ <li id='map_menu_zoomin'>{% trans "Zoom in" %}</li>
+ <li id='map_menu_zoomout'>{% trans "Zoom out" %}</li>
+ <li id='map_menu_center'>{% trans "Center the map here" %}</li>
+ </ul>
+</div>
diff --git a/chimere/templates/chimere/blocks/map_params.html b/chimere/templates/chimere/blocks/map_params.html
index 57ced90..27762a3 100644
--- a/chimere/templates/chimere/blocks/map_params.html
+++ b/chimere/templates/chimere/blocks/map_params.html
@@ -7,6 +7,7 @@
chimere_init_options["map_layers"] = [{{map_layers|safe|escape}}];
chimere_init_options['permalink_label'] = '{%trans "Permalink"%}';
chimere_init_options['permalink_element'] = document.getElementById('permalink');
+ chimere_init_options['routing'] = {{routing}};
{% if dynamic_categories %}chimere_init_options['dynamic_categories'] = true;{% endif %}
{% if default_area %}
chimere_init_options["default_area"] = new Array({{default_area.upper_left_corner.x}}, {{default_area.upper_left_corner.y}}, {{default_area.lower_right_corner.x}}, {{default_area.lower_right_corner.y}});
diff --git a/chimere/templates/chimere/blocks/routing.html b/chimere/templates/chimere/blocks/routing.html
new file mode 100644
index 0000000..4948a1c
--- /dev/null
+++ b/chimere/templates/chimere/blocks/routing.html
@@ -0,0 +1,56 @@
+{% load i18n %}
+{% if routing %}
+{{itinerary_form.media}}
+<a href='#' id='routing_button' class='ui-widget ui-button ui-state-default ui-corner-all'>{% trans "Itinerary"%}</a>
+<div id='chimere_itinerary_panel'>
+ <div id='chimere_itinerary_form'>
+ {% for hidden in itinerary_form.hidden_fields %}
+ {{ hidden }}
+ {% endfor %}
+ {% for field in itinerary_form.visible_fields %}
+ {% if field.label %}<p><label for='{{field.auto_id}}'>{{ field.label }}</label></p>{%endif%}
+ <p>{{field}}</p>
+ {% endfor %}
+ </div>
+ <div id='chimere_itinerary'>
+ <div id='chimere_itinerary_action'>
+ <ul class='action'>
+ <li class='ui-widget ui-button ui-state-default ui-corner-all'>
+ <a href='#' id='chimere_itinerary_modify'>{% trans "Modify" %}</a>
+ </li>
+ <li class='ui-widget ui-button ui-state-default ui-corner-all'>
+ <a href='#' id='chimere_itinerary_new'>{% trans "New search" %}</a>
+ </li>
+ </ul>
+ </div>
+ <div class='itinerary_label'>
+ <span class='label'>{% trans "Start:"%}</span> <span id='chimere_start_label'></span></div>
+ <div id='chimere_itinerary_content'>
+ </div>
+ <div class='itinerary_label'>
+ <span class='label'>{% trans "Finish:"%}</span> <span id='chimere_end_label'></span>
+ </div>
+ </div>
+</div>
+<script language='javascript' type='text/javascript'>
+$(document).ready(function() {
+ $('#chimere_itinerary_panel').dialog({
+ autoOpen: false,
+ position: [50, 50],
+ title: "{% trans "Itinerary" %}",
+ height: 360,
+ resizable: false
+ });
+ $('#routing_button').click(function(){
+ $('#chimere_itinerary_panel').dialog('open');
+ });
+ $('#chimere_itinerary_modify').click(function(){
+ $('#chimere_itinerary').hide();
+ $('#chimere_itinerary_form').show();
+ });
+ $('#chimere_itinerary_new').click(function(){
+ $('#map').chimere('routingClear');
+ });
+});
+</script>
+{% endif%}
diff --git a/chimere/templates/chimere/main_map.html b/chimere/templates/chimere/main_map.html
index 5a49e46..4a53b3f 100644
--- a/chimere/templates/chimere/main_map.html
+++ b/chimere/templates/chimere/main_map.html
@@ -22,6 +22,7 @@
{% if areas_visible %}
{% display_areas %}
{% endif %}
+ {% routing %}
{% display_news news_visible %}
<div id='permalink' class='ui-widget ui-button ui-state-default ui-corner-all'></div>
</div>
@@ -34,6 +35,7 @@
<script type="text/javascript">
$("#main-map").show();
</script>
+ {% map_menu %}
{% map_params %}
{% endblock %}
{% block footer %}
diff --git a/chimere/templatetags/chimere_tags.py b/chimere/templatetags/chimere_tags.py
index 46fb422..132af09 100644
--- a/chimere/templatetags/chimere_tags.py
+++ b/chimere/templatetags/chimere_tags.py
@@ -111,6 +111,17 @@ def head_chimere(context):
}
return context_data
+@register.inclusion_tag('chimere/blocks/map_menu.html', takes_context=True)
+def map_menu(context):
+ context_data = {'routing':settings.CHIMERE_ENABLE_ROUTING}
+ return context_data
+
+@register.inclusion_tag('chimere/blocks/routing.html', takes_context=True)
+def routing(context):
+ context_data = {'routing':settings.CHIMERE_ENABLE_ROUTING,
+ 'itinerary_form':context['itinerary_form']}
+ return context_data
+
@register.inclusion_tag('chimere/blocks/map_params.html', takes_context=True)
def map_params(context):
context_data = {}
@@ -118,6 +129,8 @@ def map_params(context):
context_data['icon_offset_y'] = settings.CHIMERE_ICON_OFFSET_Y
context_data['icon_width'] = settings.CHIMERE_ICON_WIDTH
context_data['icon_height'] = settings.CHIMERE_ICON_HEIGHT
+ context_data['routing'] = 'true' if settings.CHIMERE_ENABLE_ROUTING \
+ else 'none'
area_name = context['area_name'] if 'area_name' in context else 'area_name'
map_layers, default_area = get_map_layers(area_name)
context_data['map_layers'] = ", ".join(map_layers)
diff --git a/chimere/urls.py b/chimere/urls.py
index a232382..81263a0 100644
--- a/chimere/urls.py
+++ b/chimere/urls.py
@@ -51,6 +51,17 @@ if settings.CHIMERE_FEEDS:
LatestPOIsByZoneID(), name='feeds-areaid'),
)
+if settings.CHIMERE_ENABLE_ROUTING:
+ urlpatterns += patterns('chimere.views',
+ url(r'^(?P<area_name>[a-zA-Z0-9_-]*/)?route/'\
+ r'(?P<transport>(%s))/'
+ r'(?P<lon1>[-]?[0-9]+[.]?[0-9]*)_(?P<lat1>[-]?[0-9]+[.]?[0-9]*)_'\
+ r'(?P<lonlat_steps>([-]?[0-9]+[.]?[0-9]*_[-]?[0-9]+[.]?[0-9]*_)*)'\
+ r'(?P<lon2>[-]?[0-9]+[.]?[0-9]*)_(?P<lat2>[-]?[0-9]+[.]?[0-9]*)$' %
+ ('|'.join([key for key, lbl in settings.CHIMERE_ROUTING_TRANSPORT])),
+ 'route', name="route"),
+ )
+
urlpatterns += patterns('chimere.views',
url(r'^charte/?$', 'charte', name="charte"),
url(r'^(?P<area_name>[a-zA-Z0-9_-]+/)?contact/?$', 'contactus', name="contact"),
diff --git a/chimere/views.py b/chimere/views.py
index f10b7fa..c71b4eb 100644
--- a/chimere/views.py
+++ b/chimere/views.py
@@ -26,6 +26,7 @@ Views of the project
import datetime
from itertools import groupby
+import simplejson
from django.conf import settings
from django.core import serializers
@@ -47,7 +48,9 @@ from chimere.widgets import getMapJS, PointChooserWidget, \
RouteChooserWidget, AreaWidget
from chimere.forms import MarkerForm, RouteForm, ContactForm, FileForm, \
FullFileForm, MultimediaFileFormSet, PictureFileFormSet, notifySubmission,\
- notifyStaff, AreaForm
+ notifyStaff, AreaForm, RoutingForm
+
+from chimere.route import router
def get_base_uri(request):
base_uri = 'http://'
@@ -120,6 +123,8 @@ def index(request, area_name=None, default_area=None, simple=False):
if request.GET and 'lat' in request.GET \
and 'lon' in request.GET:
zoomout = None
+ if settings.CHIMERE_ENABLE_ROUTING:
+ response_dct['itinerary_form'] = RoutingForm()
response_dct.update({
'actions':actions, 'action_selected':('view',),
'error_message':'',
@@ -635,6 +640,28 @@ def redirectFromTinyURN(request, area_name='', tiny_urn=''):
return redir
return HttpResponseRedirect(response_dct['extra_url'] + parameters)
+def route(request, area_name, lon1, lat1, lonlat_steps, lon2, lat2,
+ transport='foot'):
+ '''
+ Get the JSON for a route
+ '''
+ try:
+ lon1, lat1 = float(lon1), float(lat1)
+ lon2, lat2 = float(lon2), float(lat2)
+ steps = [float(lonlat) for lonlat in lonlat_steps.split('_') if lonlat]
+ # regroup by 2
+ steps = [(steps[i*2], steps[i*2+1]) for i in range(len(steps)/2)]
+ except ValueError:
+ return HttpResponse('no results')
+ jsons, desc = router.route(lon1, lat1, lon2, lat2, steps=steps,
+ transport=transport)
+ if not jsons:
+ return HttpResponse('no results')
+ jsonencoder = simplejson.JSONEncoder()
+ data = '{"properties":{"description":%s}, "type": "FeatureCollection",'\
+ '"features":[%s]}' % (jsonencoder.encode(desc), ",".join(jsons))
+ return HttpResponse(data)
+
def rss(request, area_name=''):
'''
Redirect to RSS subscription page
diff --git a/chimere/widgets.py b/chimere/widgets.py
index 8e2b8ad..b520fcd 100644
--- a/chimere/widgets.py
+++ b/chimere/widgets.py
@@ -26,6 +26,9 @@ from django.core.exceptions import ObjectDoesNotExist
from django.conf import settings
from django.contrib.gis.db import models
from django.contrib.gis.geos import fromstr
+from django.utils.html import conditional_escape
+from django.forms.widgets import RadioInput, RadioFieldRenderer
+from django.utils.encoding import force_unicode
from django.utils.safestring import mark_safe
from django.utils.translation import ugettext as _
@@ -100,6 +103,41 @@ class ChosenSelectWidget(forms.Select):
u"</script>\n" % kwargs['attrs']['id']
return mark_safe(rendered)
+"""
+JQuery UI button select widget.
+"""
+class ButtonRadioInput(RadioInput):
+ def render(self, name=None, value=None, attrs=None, choices=()):
+ name = name or self.name
+ value = value or self.value
+ attrs = attrs or self.attrs
+ if 'id' in self.attrs:
+ label_for = ' for="%s_%s"' % (self.attrs['id'], self.index)
+ else:
+ label_for = ''
+ choice_label = conditional_escape(force_unicode(self.choice_label))
+ return mark_safe(u'%s <label%s>%s</label>' % (self.tag(), label_for,
+ choice_label))
+class ButtonRadioFieldRenderer(RadioFieldRenderer):
+ def __iter__(self):
+ for i, choice in enumerate(self.choices):
+ yield ButtonRadioInput(self.name, self.value, self.attrs.copy(),
+ choice, i)
+ def render(self):
+ return mark_safe(u'\n'.join([force_unicode(w) for w in self]))
+class ButtonSelectWidget(forms.RadioSelect):
+ def __init__(self, *args, **kwargs):
+ self.renderer = ButtonRadioFieldRenderer
+ super(ButtonSelectWidget, self).__init__(*args, **kwargs)
+
+ def render(self, *args, **kwargs):
+ rendered = "<div id='%s'>\n" % kwargs['attrs']['id']
+ rendered += super(ButtonSelectWidget, self).render(*args, **kwargs)
+ rendered += u"\n<script type='text/javascript'>\n"\
+ u" $('#%s').buttonset();\n"\
+ u"</script>\n</div>\n" % kwargs['attrs']['id']
+ return mark_safe(rendered)
+
class TextareaWidget(forms.Textarea):
"""
Manage the edition of a text using TinyMCE
@@ -121,6 +159,21 @@ class DatePickerWidget(forms.TextInput):
u"</script>\n" % kwargs['attrs']['id']
return mark_safe(rendered)
+class NominatimWidget(forms.TextInput):
+ class Media:
+ js = ["%schimere/js/nominatim-widget.js" % settings.STATIC_URL]
+ def render(self, name, value, attrs=None, area_name=''):
+ tpl = u"""
+<input type='hidden' name='nominatim_%(id)s_lat' id='nominatim_%(id)s_lat'/>
+<input type='hidden' name='nominatim_%(id)s_lon' id='nominatim_%(id)s_lon'/>
+<input type='text' class='nominatim-widget' name='nominatim_%(id)s' id='nominatim_%(id)s'/>
+<label class='nominatim-label' id='nominatim_%(id)s_label'>&nbsp;</label>
+<script type='text/javascript'>
+var nominatim_url = "%(nominatim_url)s";
+</script>
+""" % {'id':name, 'nominatim_url':settings.NOMINATIM_URL}
+ return mark_safe(tpl)
+
class PointChooserWidget(forms.TextInput):
"""
Manage the edition of point on a map
diff --git a/example_project/settings.py b/example_project/settings.py
index dec2827..e78751d 100644
--- a/example_project/settings.py
+++ b/example_project/settings.py
@@ -5,6 +5,7 @@
# overload all theses settings in your local_settings.py file
import os
+_ = lambda s: s
DEBUG = False
TEMPLATE_DEBUG = DEBUG
@@ -72,11 +73,33 @@ CHIMERE_OSM_PASSWORD = 'test'
# encoding for shapefile import
CHIMERE_SHAPEFILE_ENCODING = 'ISO-8859-1'
+# enable routing in Chimère
+CHIMERE_ENABLE_ROUTING = False
+
+CHIMERE_ROUTING_TRANSPORT = (('foot', _(u"Foot")),
+ ('bicycle', _(u"Bicycle")),
+ ('motorcar', _(u"Motorcar")),
+ )
+
+CHIMERE_ROUTING_SPEEDS = {'foot':((3, _(u"You are walking slowly")),
+ (6, _(u"You are walking pretty quickly")),),
+ 'bicycle':((16, _(u"You are riding pretty slowly")),
+ (22, _(u"You are riding pretty quickly")),)
+ }
+
+# available routing engine: 'routino'
+CHIMERE_ROUTING_ENGINE = {
+ 'ENGINE': 'routino',
+ 'PATH': '/usr/local/src/web/bin/router',
+ 'DB_PATH': '/var/local/routino/',
+}
+
+NOMINATIM_URL = 'http://nominatim.openstreetmap.org/search'
+
# thumbnail
CHIMERE_THUMBS_SCALE_HEIGHT=250
CHIMERE_THUMBS_SCALE_WIDTH=None
-
ADMINS = (
# ('Your Name', 'your_email@domain.com'),
)