maposmatic-dev
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Maposmatic-dev] [PATCH] Improve the bounding box selection in 'Create n


From: Gaël Utard
Subject: [Maposmatic-dev] [PATCH] Improve the bounding box selection in 'Create new map' form.
Date: Wed, 4 Aug 2010 17:08:12 +0200

Do not hide the bounding box drawn just after the mouse up event.
Do not zoom out when the form is displayed again because the
validation failed.
Do not validate the form if no bounding box was drawn.

Signed-off-by: Gaël Utard <address@hidden>
---
 www/locale/fr/LC_MESSAGES/django.po |   31 +++++----
 www/maposmatic/forms.py             |   14 +++--
 www/maposmatic/widgets.py           |   57 ++++++++----------
 www/media/osm_map.js                |  114 +++++++++++++++++++++++------------
 www/templates/maposmatic/new.html   |    2 +-
 5 files changed, 129 insertions(+), 89 deletions(-)

diff --git a/www/locale/fr/LC_MESSAGES/django.po 
b/www/locale/fr/LC_MESSAGES/django.po
index 4d0d38a..e240d76 100644
--- a/www/locale/fr/LC_MESSAGES/django.po
+++ b/www/locale/fr/LC_MESSAGES/django.po
@@ -20,14 +20,14 @@ msgid ""
 msgstr ""
 "Project-Id-Version: mapOSMatic 0.1\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2010-07-07 15:36+0200\n"
+"POT-Creation-Date: 2010-08-04 15:56+0200\n"
 "PO-Revision-Date: 2009-12-26 20:47+0100\n"
 "Last-Translator: Thomas Petazzoni <address@hidden>\n"
 "Language-Team: FR <address@hidden>\n"
-"Language: \n"
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
+"Language: \n"
 
 #: settings.py:199
 msgid "No localization"
@@ -70,7 +70,7 @@ msgstr "Titre de la carte obligatoire"
 msgid "Required"
 msgstr "Obligatoire"
 
-#: maposmatic/forms.py:129
+#: maposmatic/forms.py:137
 msgid "Bounding Box too large"
 msgstr "Zone géographique trop grande"
 
@@ -183,8 +183,8 @@ msgid ""
 "href=\"http://www.openstreetmap.org\";>OpenStreetMap</a> and free\n"
 "software contributor of Rennes area, France. From his idea, a group of\n"
 "crazy <a\n"
-"href=\"http://en.wikipedia.org/wiki/Hacker_%28programmer_subculture";
-"%29\">hackers</a>\n"
+"href=\"http://en.wikipedia.org/wiki/Hacker_%28programmer_subculture%29";
+"\">hackers</a>\n"
 "met together during a one-week <em>Hackfest</em> in August 2009 and\n"
 "brought the idea of Gilles Lamiral to life by writing the code and\n"
 "named the project <strong>MapOSMatic</strong>. The group of crazy\n"
@@ -515,13 +515,11 @@ msgid "MapOSMatic maps feed"
 msgstr ""
 
 #: templates/maposmatic/all_maps.html:51
-#, python-format
-msgid "No map starts with %(current_letter)s in our database!"
+msgid "Our database does not contain any rendered maps for the moment."
 msgstr ""
-"Aucune carte ne commence par %(current_letter)s dans notre base de données !"
 
 #: templates/maposmatic/all_maps.html:53
-msgid "Our database does not contain any rendered maps for the moment."
+msgid "No map matches your query."
 msgstr ""
 
 #: templates/maposmatic/base.html:57
@@ -811,16 +809,16 @@ msgid ""
 "Latitude and longitude of the top left and bottom right corners of the area "
 "to render."
 msgstr ""
+"Latitude et longitude des coins supérieur gauche et inférieur droit de la "
+"zone à rendre."
 
 #: templates/maposmatic/new.html:98
 msgid ""
-"You can use <tt>Shift+drag</tt> to zoom on a specific area of the map. If "
-"you only want to render part of what the slippy map shows, you can use "
-"<tt>Control+drag</tt> to draw the limits of the area to render."
+"You can use <tt>Shift+drag</tt> to zoom on a specific area of the map. You "
+"can use <tt>Control+drag</tt> to draw the limits of the area to render."
 msgstr ""
 "Vous pouvez utiliser <tt>Shift+cliquer-déplacer</tt> pour zoomer sur une "
-"zone spécifique de la carte. Si vous ne souhaitez le rendu que d'une partie "
-"de ce qu'affiche la mini-carte, vous pouvez utiliser <tt>Contrôle+cliquer-"
+"zone spécifique de la carte. Vous pouvez utiliser <tt>Contrôle+cliquer-"
 "déplacer</tt> pour tracer les limites de la zone à rendre."
 
 #: templates/maposmatic/new.html:103
@@ -851,6 +849,11 @@ msgstr "Précédent"
 msgid "Next"
 msgstr "Suivant"
 
+#~ msgid "No map starts with %(current_letter)s in our database!"
+#~ msgstr ""
+#~ "Aucune carte ne commence par %(current_letter)s dans notre base de "
+#~ "données !"
+
 #~ msgid "Page"
 #~ msgstr "Page"
 
diff --git a/www/maposmatic/forms.py b/www/maposmatic/forms.py
index 621fe14..88543fe 100644
--- a/www/maposmatic/forms.py
+++ b/www/maposmatic/forms.py
@@ -111,9 +111,17 @@ class MapRenderingJobForm(forms.ModelForm):
                 val = cleaned_data.get(f)
                 if val is None:
                     msg = _(u"Required")
-                    self._errors[f] = forms.util.ErrorList([msg])
+                    self._errors['bbox'] = forms.util.ErrorList([msg])
                     del cleaned_data[f]
 
+            # Make sure that bbox and admin modes are exclusive
+            cleaned_data["administrative_city"] = ''
+            cleaned_data["administrative_osmid"] = None
+
+            # Don't try to instanciate a bounding box with empty coordinates
+            if self._errors:
+                return cleaned_data
+                
             lat_upper_left = cleaned_data.get("lat_upper_left")
             lon_upper_left = cleaned_data.get("lon_upper_left")
             lat_bottom_right = cleaned_data.get("lat_bottom_right")
@@ -129,10 +137,6 @@ class MapRenderingJobForm(forms.ModelForm):
                 msg = _(u"Bounding Box too large")
                 self._errors['bbox'] = forms.util.ErrorList([msg])
 
-            # Make sure that bbox and admin modes are exclusive
-            cleaned_data["administrative_city"] = ''
-            cleaned_data["administrative_osmid"] = None
-
         return cleaned_data
 
 class MapRecreateForm(forms.Form):
diff --git a/www/maposmatic/widgets.py b/www/maposmatic/widgets.py
index 8c502f0..265d6d8 100644
--- a/www/maposmatic/widgets.py
+++ b/www/maposmatic/widgets.py
@@ -41,30 +41,20 @@ class AreaWidget(forms.TextInput):
 
     def render(self, name, value, attrs=None):
         """
-        Render a map
+        Render the bbox selection widget.
         """
-        upper_left_lat, upper_left_lon = 0, 0
-        lower_right_lat, lower_right_lon = 0, 0
-
+        # Initially the widget shows no bounding box and shows an area that
+        # contains the France
         if value:
-            if len(value) == 2:
-                upper_left = value[0]
-                lower_right = value[1]
-                if hasattr(upper_left, 'x') and hasattr(upper_left, 'y'):
-                    upper_left_lon = str(upper_left.x)
-                    upper_left_lat = str(upper_left.y)
-                elif len(upper_left) == 2:
-                    upper_left_lon = upper_left[1]
-                    upper_left_lat = upper_left[0]
-                if hasattr(lower_right, 'x') and hasattr(lower_right, 'y'):
-                    lower_right_lon = str(lower_right.x)
-                    lower_right_lat = str(lower_right.y)
-                elif len(lower_right) == 2:
-                    lower_right_lon = lower_right[1]
-                    lower_right_lat = lower_right[0]
+            upper_left_lat, upper_left_lon, \
+                lower_right_lat, lower_right_lon = value[0]
+            area_upper_left_lat, area_upper_left_lon, \
+                area_lower_right_lat, area_lower_right_lon = value[1]
         else:
             upper_left_lat, upper_left_lon, \
-                lower_right_lat, lower_right_lon = settings.BASE_BOUNDING_BOX
+                lower_right_lat, lower_right_lon = '', '', '', ''
+            area_upper_left_lat, area_upper_left_lon, \
+                area_lower_right_lat, area_lower_right_lon = 
settings.BASE_BOUNDING_BOX
 
         tpl = u"""<div id="map"></div>
         <div id="map_bb">
@@ -81,8 +71,20 @@ class AreaWidget(forms.TextInput):
             <input type="text" name="lon_bottom_right" id="lon_bottom_right"
                    onchange="updateMap();" value="%(br_lon)s"
                    title="%(br_lon_help)s" />
+            <input type="hidden" name="area_lat_upper_left"
+                   id="area_lat_upper_left" value="%(area_tl_lat)s">
+            <input type="hidden" name="area_lon_upper_left"
+                   id="area_lon_upper_left" value="%(area_tl_lon)s">
+            <input type="hidden" name="area_lat_bottom_right"
+                   id="area_lat_bottom_right" value="%(area_br_lat)s">
+            <input type="hidden" name="area_lon_bottom_right"
+                   id="area_lon_bottom_right" value="%(area_br_lon)s">
         </div>""" % {'tl_lat': upper_left_lat, 'tl_lon': upper_left_lon,
                      'br_lat': lower_right_lat, 'br_lon': lower_right_lon,
+                     'area_tl_lat': area_upper_left_lat,
+                     'area_tl_lon': area_upper_left_lon,
+                     'area_br_lat': area_lower_right_lat,
+                     'area_br_lon': area_lower_right_lon,
                      'tl_lat_help': _("Latitude of the top left corner"),
                      'tl_lon_help': _("Longitude of the top left corner"),
                      'br_lat_help': _("Latitude of the bottom right corner"),
@@ -94,17 +96,10 @@ class AreaWidget(forms.TextInput):
         """
         Return the appropriate values
         """
-        values = []
-        for keys in (('lat_upper_left', 'lon_upper_left',),
-                     ('lat_bottom_right', 'lon_bottom_right')):
-            value = []
-            for key in keys:
-                val = data.get(key, None)
-                if not val:
-                    return []
-                value.append(val)
-            values.append(value)
-        return values
+        return ((data['lat_upper_left'], data['lon_upper_left'],
+                 data['lat_bottom_right'], data['lon_bottom_right']),
+                (data['area_lat_upper_left'], data['area_lon_upper_left'],
+                 data['area_lat_bottom_right'], data['area_lon_bottom_right']))
 
 class AreaField(forms.MultiValueField):
     '''
diff --git a/www/media/osm_map.js b/www/media/osm_map.js
index f785a17..f3f6bc1 100644
--- a/www/media/osm_map.js
+++ b/www/media/osm_map.js
@@ -31,48 +31,74 @@ var map = null;
 var update_lock = 0;
 var epsg_display_projection = new OpenLayers.Projection('EPSG:4326');
 var epsg_projection = new OpenLayers.Projection('EPSG:900913');
+var bbox_style = {fill: true, fillColor: "#FFFFFF", fillOpacity: 0.5,
+    stroke: true, strokeOpacity: 0.8, strokeColor: "#FF0000", strokeWidth: 2};
 
 function getUpperLeftLat() { return document.getElementById('lat_upper_left'); 
}
 function getUpperLeftLon() { return document.getElementById('lon_upper_left'); 
}
 function getBottomRightLat() { return 
document.getElementById('lat_bottom_right'); }
 function getBottomRightLon() { return 
document.getElementById('lon_bottom_right'); }
+function getAreaUpperLeftLat() { return 
document.getElementById('area_lat_upper_left'); }
+function getAreaUpperLeftLon() { return 
document.getElementById('area_lon_upper_left'); }
+function getAreaBottomRightLat() { return 
document.getElementById('area_lat_bottom_right'); }
+function getAreaBottomRightLon() { return 
document.getElementById('area_lon_bottom_right'); }
 
-function updateFormWithLonLats(topleft, bottomright)
+/* Update form fields on bbox drawing. */
+function updateFormBbox(bounds)
 {
-    topleft = topleft.transform(epsg_projection, epsg_display_projection);
-    bottomright = bottomright.transform(epsg_projection, 
epsg_display_projection);
+    bounds = bounds.transform(epsg_projection, epsg_display_projection);
 
-    getUpperLeftLat().value = topleft.lat.toFixed(4);
-    getUpperLeftLon().value = topleft.lon.toFixed(4);
-    getBottomRightLat().value = bottomright.lat.toFixed(4);
-    getBottomRightLon().value = bottomright.lon.toFixed(4);
-}
-
-/** Map Zoom/Move events callback: update form fields on zoom action. */
-function updateForm()
-{
-    if (update_lock)
-      return;
-
-    var bounds = map.getExtent();
-    updateFormWithLonLats(new OpenLayers.LonLat(bounds.left, bounds.top),
-                          new OpenLayers.LonLat(bounds.right, bounds.bottom));
+    getUpperLeftLat().value = bounds.top.toFixed(4);
+    getUpperLeftLon().value = bounds.left.toFixed(4);
+    getBottomRightLat().value = bounds.bottom.toFixed(4);
+    getBottomRightLon().value = bounds.right.toFixed(4);
 }
 
 /* Update the map on form field modification. */
-function updateMap()
+function updateMap(vectorLayer)
 {
-    var bounds = new OpenLayers.Bounds(getUpperLeftLon().value,
-                                       getUpperLeftLat().value,
-                                       getBottomRightLon().value,
-                                       getBottomRightLat().value);
+    if (getUpperLeftLon().value!="" && getUpperLeftLat().value!="" &&
+        getBottomRightLon().value!="" && getBottomRightLat().value!="")
+    {
+        var bbox_bounds = new OpenLayers.Bounds(
+            getUpperLeftLon().value, getUpperLeftLat().value,
+            getBottomRightLon().value, getBottomRightLat().value);
+        bbox_bounds.transform(epsg_display_projection, epsg_projection);
+        var feature = new OpenLayers.Feature.Vector(
+            bbox_bounds.toGeometry(), {}, bbox_style);
+        vectorLayer.addFeatures(feature);
+        closest = true
+    }
+    else
+    {
+        closest = false
+    }
+
+    var bounds = new OpenLayers.Bounds(getAreaUpperLeftLon().value,
+                                       getAreaUpperLeftLat().value,
+                                       getAreaBottomRightLon().value,
+                                       getAreaBottomRightLat().value);
     bounds.transform(epsg_display_projection, epsg_projection);
 
     update_lock = 1;
-    map.zoomToExtent(bounds);
+    map.zoomToExtent(bounds, closest);
     update_lock = 0;
 }
 
+/** Map Zoom/Move events callback: update form fields on zoom action. */
+function updateFormArea()
+{
+    if (update_lock)
+      return;
+
+    var bounds = map.getExtent();
+    bounds = bounds.transform(epsg_projection, epsg_display_projection);
+    getAreaUpperLeftLat().value = bounds.top.toFixed(4);
+    getAreaUpperLeftLon().value = bounds.left.toFixed(4);
+    getAreaBottomRightLat().value = bounds.bottom.toFixed(4);
+    getAreaBottomRightLon().value = bounds.right.toFixed(4);
+}
+
 /* Main initialisation function. Must be called before the map is manipulated. 
*/
 function mapInit()
 {
@@ -90,25 +116,37 @@ function mapInit()
     layerTilesMapnik = new OpenLayers.Layer.OSM.Mapnik("Mapnik");
     map.addLayer(layerTilesMapnik);
 
+    var vectorLayer = new OpenLayers.Layer.Vector("Overlay");
+    map.addLayer(vectorLayer);
+
     var selectControl = new OpenLayers.Control();
     OpenLayers.Util.extend(selectControl, {
-      draw: function() {
-        this.box = new OpenLayers.Handler.Box(selectControl,
-          {'done': this.notice}, {keyMask: OpenLayers.Handler.MOD_CTRL});
-        this.box.activate();
-      },
-
-      notice: function(bounds) {
-        updateFormWithLonLats(
-          map.getLonLatFromPixel(new OpenLayers.Pixel(bounds.left, 
bounds.top)),
-          map.getLonLatFromPixel(new OpenLayers.Pixel(bounds.right, 
bounds.bottom)));
-      }
+        draw: function() {
+            this.box = new OpenLayers.Handler.Box(selectControl,
+                {'done': this.notice}, {keyMask: OpenLayers.Handler.MOD_CTRL});
+            this.box.activate();
+        },
+
+        notice: function(pxbounds) {
+            ltpixel = map.getLonLatFromPixel(
+                new OpenLayers.Pixel(pxbounds.left, pxbounds.top));
+            rbpixel = map.getLonLatFromPixel(
+                new OpenLayers.Pixel(pxbounds.right, pxbounds.bottom));
+            bounds = new OpenLayers.Bounds();
+            bounds.extend(ltpixel);
+            bounds.extend(rbpixel);
+            var feature = new OpenLayers.Feature.Vector(
+                bounds.toGeometry(), {}, bbox_style);
+            vectorLayer.destroyFeatures()
+            vectorLayer.addFeatures(feature);
+            updateFormBbox(bounds);
+        }
     });
     map.addControl(selectControl);
 
-    map.events.register('zoomend', map, updateForm);
-    map.events.register('moveend', map, updateForm);
-    updateMap();
+    map.events.register('zoomend', map, updateFormArea);
+    map.events.register('moveend', map, updateFormArea);
+    updateMap(vectorLayer);
 }
 
 function setFormActivation(active) {
diff --git a/www/templates/maposmatic/new.html 
b/www/templates/maposmatic/new.html
index a179c84..a883598 100644
--- a/www/templates/maposmatic/new.html
+++ b/www/templates/maposmatic/new.html
@@ -95,7 +95,7 @@ map.{% endblocktrans %}
       {{ form.bbox }}
       {{ form.bbox.errors }}
       <p class="bbox_select_help">{% blocktrans %}Latitude and longitude of 
the top left and bottom right corners of the area to render.{% endblocktrans 
%}</p>
-      <p class="bbox_select_help">{% blocktrans %}You can use 
<tt>Shift+drag</tt> to zoom on a specific area of the map. If you only want to 
render part of what the slippy map shows, you can use <tt>Control+drag</tt> to 
draw the limits of the area to render.{% endblocktrans %}</p>
+      <p class="bbox_select_help">{% blocktrans %}You can use 
<tt>Shift+drag</tt> to zoom on a specific area of the map. You can use 
<tt>Control+drag</tt> to draw the limits of the area to render.{% endblocktrans 
%}</p>
     </td></tr>
 
     <tr><td class="submit">
-- 
1.7.0.4




reply via email to

[Prev in Thread] Current Thread [Next in Thread]