diff options
author | Étienne Loks <etienne.loks@peacefrogs.net> | 2013-04-03 16:30:13 +0200 |
---|---|---|
committer | Étienne Loks <etienne.loks@peacefrogs.net> | 2013-04-03 16:30:13 +0200 |
commit | e3dd113da11a69f2107e6ac7fc5998626a23a2cc (patch) | |
tree | 3da0560ae689b607f4e34d3bc57387af1f41f643 | |
parent | a204849cb48d8acdaebeac484235c3a91fba00e6 (diff) | |
download | Chimère-e3dd113da11a69f2107e6ac7fc5998626a23a2cc.tar.bz2 Chimère-e3dd113da11a69f2107e6ac7fc5998626a23a2cc.zip |
First work on Leaflet script
* manage markers from a GeoJson source with custom icon
-rw-r--r-- | chimere/settings.sample.py | 11 | ||||
-rw-r--r-- | chimere/static/chimere/js/jquery.chimere-leaflet.js | 371 | ||||
-rw-r--r-- | chimere/static/chimere/js/jquery.chimere-ol.js | 67 | ||||
-rw-r--r-- | chimere/templates/chimere/blocks/head_chimere.html | 7 | ||||
-rw-r--r-- | chimere/templates/chimere/blocks/map.html | 3 | ||||
-rw-r--r-- | chimere/templatetags/chimere_tags.py | 4 |
6 files changed, 429 insertions, 34 deletions
diff --git a/chimere/settings.sample.py b/chimere/settings.sample.py index 2e5ad40..391c6e5 100644 --- a/chimere/settings.sample.py +++ b/chimere/settings.sample.py @@ -290,7 +290,8 @@ if 'MAP_JS_URLS' not in globals(): STATIC_URL + "openlayers/OpenLayers.js", STATIC_URL + "openlayers/SimplePanZoom.js", "http://www.openstreetmap.org/openlayers/OpenStreetMap.js", - STATIC_URL + "chimere/js/jquery.chimere-ol.js"], + STATIC_URL + "chimere/js/jquery.chimere-ol.js" + ], 'leaflet':[ STATIC_URL + "leaflet/leaflet.js", STATIC_URL + "chimere/js/jquery.chimere-leaflet.js" @@ -299,11 +300,13 @@ if 'MAP_JS_URLS' not in globals(): if 'MAP_CSS_URLS' not in globals(): global MAP_CSS_URLS + # key: [(url, condition)] MAP_CSS_URLS = { - 'openlayers':["http://www.openlayers.org/api/theme/default/style.css"], + 'openlayers':[("http://www.openlayers.org/api/theme/default/style.css", + None)], 'leaflet':[ - STATIC_URL + "leaflet/leaflet.css", - STATIC_URL + "leaflet/leaflet.ie.css" + (STATIC_URL + "leaflet/leaflet.css", None), + (STATIC_URL + "leaflet/leaflet.ie.css", 'lte IE 8') ] } diff --git a/chimere/static/chimere/js/jquery.chimere-leaflet.js b/chimere/static/chimere/js/jquery.chimere-leaflet.js index 75a0fc3..569f9f5 100644 --- a/chimere/static/chimere/js/jquery.chimere-leaflet.js +++ b/chimere/static/chimere/js/jquery.chimere-leaflet.js @@ -106,9 +106,380 @@ See the file COPYING for details. * Plugin init function */ init: function ( options ) { + settings = $.extend({}, defaults); + if ( options ) $.extend(settings, options); + var map_element = $(this).attr('id'); + + settings.map = map = L.map(map_element); + for (idx in settings.map_layers){ + map.addLayer(settings.map_layers[idx]); + } + if(settings.zoom && settings.lat && settings.lon){ + map.setView([settings.lat, settings.lon], settings.zoom); + } else { + map.fitWorld(); + } + settings.icons = new Object(); + settings.layerMarkers = L.geoJson(null, { + onEachFeature: function (feature, layer) { + layer.bindPopup(feature.properties.name); + }, + pointToLayer: function (feature, latlng) { + if (feature.properties.weigthed){ + var geojsonMarkerOptions = { + radius: 8, + fillColor: "#ff7800", + color: "#000", + weight: 1, + opacity: 1, + fillOpacity: 0.8 + }; + return L.circleMarker(latlng, geojsonMarkerOptions); + } + var icon_path = MEDIA_URL + feature.properties.icon_path; + if (!settings.icons.hasOwnProperty(icon_path)){ + var icon_offset = null; + if (feature.properties.icon_offset){ + icon_offset = feature.properties.icon_offset; + } else { + icon_offset = [feature.properties.icon_width/2, + feature.properties.icon_height]; + } + var popup_anchor = null; + if (feature.properties.popup_anchor){ + popup_anchor = feature.properties.popup_anchor; + } else { + popup_anchor = [0, + -feature.properties.icon_height]; + } + settings.icons[icon_path] = L.icon({ + iconUrl: icon_path, + iconSize: [feature.properties.icon_width, + feature.properties.icon_height], + iconAnchor: icon_offset, + popupAnchor: popup_anchor + }); + } + return L.marker(latlng, {icon: settings.icons[icon_path]}); + } + }).addTo(map); + settings.layerVectors = L.geoJson().addTo(map); + + methods.loadCategories(); + methods.loadGeoObjects(); + }, + hidePopup: function (evt) { + settings.map.closePopup(); + return true; + }, + /* + * Update the categories div in ajax + */ + loadCategories: function () { + var current_extent = settings.map.getBounds(); + current_extent = current_extent.toBBoxString(); + current_extent = current_extent.split(',').join('_'); + current_extent = current_extent.replace(/\./g, 'D'); + current_extent = current_extent.replace(/-/g, 'M'); + var uri = extra_url + if (settings.area_id) uri += settings.area_id + "/"; + uri += "getAvailableCategories/"; + var params = {"current_extent": current_extent} + if (settings.display_submited) params["status"] = "A_S"; + $.ajax({url: uri, + data: params, + cache: false, + success: function (data) { + $('#categories').empty(); + $('#categories').html(data); + _init_categories(); + _reCheckCategories(); + if (settings.current_category) { + // TODO : add a force mode + // (in case the category is yet visible in HTML...) + methods.toggle_category(); + } + } + }); + var _toggle_subcategories = function (category_element) { + // Check subcategories only if unchecked + var val = category_element.is(":checked") ? true : false; + category_element.parent().find("li input").attr("checked", val); + } + var _toggle_categories = function (subcategory_element) { + var parent = subcategory_element.closest('ul'); + var parent_label = parent.parent().find("> span"); + 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){ + master_check.attr('checked', 'checked'); + } 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 () { + /* + * Add event listener in categories DOM elements + */ + $('#categories #ul_categories > li > input').bind("click", + function (e) { + methods.hidePopup(e); + _toggle_subcategories($(this)); + methods.loadGeoObjects(); + //settings.permalink.updateLink(); + }); + $('.subcategories li input').bind("click", function (e) { + var c_name = $(this).attr('name'); + c_name = c_name.substr(c_name.lastIndexOf("_")+1); + if($(this).is(':checked')){ + methods.subcategory_detail(c_name); + } + var par = $(this).parent(); + if ($(this).attr('checked')){ + par.addClass('selected'); + } else { + par.removeClass('selected'); + } + methods.hidePopup(e); + methods.loadGeoObjects(); + _toggle_categories($(this)); + //settings.permalink.updateLink(); + if ($('#layer_cat_'+c_name).length){ + $('#layer_cat_'+c_name).prop("checked", + this.checked); + } + }); + $('#display_submited_check').bind("click", function () { + methods.loadGeoObjects(); + //settings.permalink.updateLink(); + }); + // Zoom to category + $(".zoom_to_category").bind("click", function (e) { + var id = this.id.substr(this.id.lastIndexOf("_")+1); + helpers.zoom_to_category(id); + }); + $(".zoom_to_subcategory").bind("click", function (e) { + var id = this.id.substr(this.id.lastIndexOf("_")+1); + helpers.zoom_to_subcategories([id]); + }); + $(".toggle_category").parent().bind("click", function (e) { + var item = $(this).children('.toggle_category'); + var id = item.attr('id').substr(item.attr('id').lastIndexOf("_")+1); + methods.toggle_category(id); + }); + } + var _reCheckCategories = function (){ + /* recheck categories on init or when a redraw occurs */ + if (!settings.checked_categories){ + return; + } + $('#frm_categories .subcategories input:checkbox').each(function(index){ + cat_id = $(this).attr('id').split('_').pop(); + if (settings.checked_categories.indexOf(parseInt(cat_id)) != -1) { + $(this).attr("checked", "checked"); + _toggle_categories($(this)); + methods.toggle_category(); + } else { + $(this).attr("checked", false); + } + }); + if (settings.display_submited == true){ + $('#display_submited_check').attr("checked", "checked"); + } + } + }, + /* + * Load markers and route from DB + */ + loadGeoObjects: function () { + if ($('#waiting').length){ + $('#waiting').show(); + } + helpers.retrieve_checked_categories(); + var ids = settings.checked_categories.join('_'); + if (!ids) ids = '0'; + var uri = extra_url + "getGeoObjects/" + ids; + if (settings.display_submited) uri += "/A_S"; + $.ajax({url: uri, + dataType: "json", + success: function (data) { + settings.layerMarkers.clearLayers(); + settings.layerVectors.clearLayers(); + settings.layerMarkers.addData(data); + /* + for (var i = 0; i < data.features.length; i++) { + var feature = data.features[i]; + if (feature.geometry.type == 'Point'){ + methods.addMarker(feature); + } else if (feature.geometry.type == 'LineString') { + methods.addRoute(feature); + } else if (feature.geometry.type == 'MultiLineString') { + methods.addMultiLine(feature); + } + }*/ + }, + error: function (data, textStatus, errorThrown) { + settings.layerMarkers.clearLayers(); + settings.layerVectors.clearLayers(); + }, + complete: function () { + if($('#waiting').length){$('#waiting').hide();} + } + }); + }, + subcategory_detail: function(category_id){ + var uri = extra_url + "getCategory/" + category_id; + + $.ajax({url: uri, + dataType: "json", + success: function (data) { + if (!data.description){return} + $('#category_description').html(data.description); + $("#category_description").dialog("option", "title", + data.name); + $('#category_description').dialog('open'); + }, + error: function (data) { + // fail silently + } + }); + }, + toggle_category: function (id) { + // TODO make this id DOM element customisable + // Check if element is currently visible or not + var was_visible = $("#maincategory_" + id).is(":visible"); + // Close all categories + var category_plus = STATIC_URL + "chimere/img/plus.png"; + var category_minus = STATIC_URL + "chimere/img/minus.png"; + if (settings.category_accordion){ + $("#categories ul.subcategories").hide(); + $("#categories img.toggle_category").attr("src", category_plus); + $("#categories .main_category").addClass("toggle_plus"); + $("#categories .main_category").removeClass("toggle_minus"); + } + // Put a minus image + if (!was_visible) + { + // Show the subcategories + $("#maincategory_" + id).toggle(); + $("#maincategory_" + id).parent().addClass("toggle_minus"); + $("#maincategory_" + id).parent().removeClass("toggle_plus"); + // Put a plus image + $("#maincategory_img_" + id).attr("src", category_minus); + settings.current_category = id; + } + if (!settings.category_accordion && was_visible) + { + $("#maincategory_" + id).toggle(); + $("#maincategory_" + id).parent().addClass("toggle_plus"); + $("#maincategory_" + id).parent().removeClass("toggle_minus"); + // Put a minus image + $("#maincategory_img_" + id).attr("src", category_plus); + } + }, + zoom: function (options) { + if ($.hasattr("category", options)) { + helpers.zoom_to_category(options["category"]); + } else if ($.hasattr("subcategories", options)) { + helpers.zoom_to_subcategories(options["subcategories"]); + } else if ($.hasattr("area", options)) { + helpers.zoom_to_area(options["area"]); + } } // end of init }; // End of public methods var helpers = { + getSubcategories: function (category_id) { + if(settings.get_subcategories_fx) { + return settings.get_subcategories_fx(category_id, settings); + } + else { + var ul = document.getElementById('maincategory_'+category_id); + var subcats = new Array(); + for (i in ul.children){ + var li = ul.children[i]; + if (li.id){ + subcats.push(li.id.split('_').pop()); + } + } + return subcats; + } + }, + retrieve_checked_categories: function () { + /* + * Retrieve checked_categories, and store it in settings + */ + var initialized = false; + $('#frm_categories .subcategories input:checkbox').each( + function(index){ + if (!initialized){ + initialized = true; + settings.checked_categories = []; + settings.display_submited = false; + } + if ($(this).attr('checked') == 'checked' || $(this).attr('checked') == true){ + cat_id = $(this).attr('id').split('_').pop(); + settings.checked_categories.push(parseInt(cat_id)); + } + }); + if(initialized && ($('#display_submited_check').attr("checked") == "checked" || $('#display_submited_check').attr("checked") == true)){ + settings.display_submited = true; + } + }, + zoom_to: function (bounds) { + settings.map.fitBounds(bounds); + }, + zoom_to_subcategories: function (ids) { + // TODO add markers and check the subcategory, if not yet checked/displayed + var ids = ids.join('_'); + if (!ids) ids = '0'; + var uri = extra_url + "getGeoObjects/" + ids; + if (settings.display_submited) uri += "/A_S"; + $.ajax({url: uri, + dataType: "json", + success: function (data) { + // Create a generic bounds + var lon, lat, feature; + var points = new Array(); + for (var i = 0; i < data.features.length; i++) { + feature = data.features[i]; + if (feature.geometry.type == 'Point') { + lat = feature.geometry.coordinates[1]; + lon = feature.geometry.coordinates[0]; + points.push(settings.map.latLngToLayerPoint([lat, lon])); + } else if (feature.geometry.type == 'LineString') { + // TODO + } + } + var bound = L.Bounds(points); + helpers.zoom_to(bounds); + } + }); + }, + zoom_to_category: function (id) { + helpers.zoom_to_subcategories(helpers.getSubcategories(id)); + }, + zoom_to_area: function (coords) { + /* zoom to an area */ + helpers.zoom_to([[coords[1], coords[0]], + [coords[3], coords[2]]]); + if (settings.dynamic_categories) { + methods.loadCategories(); + } + } }; // End of helpers $.fn.chimere = function (thing) { diff --git a/chimere/static/chimere/js/jquery.chimere-ol.js b/chimere/static/chimere/js/jquery.chimere-ol.js index 2e2d238..6660b2e 100644 --- a/chimere/static/chimere/js/jquery.chimere-ol.js +++ b/chimere/static/chimere/js/jquery.chimere-ol.js @@ -17,20 +17,22 @@ See the file COPYING for details. */ /* Add OpenLayers MapQuest layer management */ -OpenLayers.Layer.MapQuestOSM = OpenLayers.Class(OpenLayers.Layer.XYZ, { - name: "MapQuestOSM", - sphericalMercator: true, - url: ' http://otile1.mqcdn.com/tiles/1.0.0/osm/${z}/${x}/${y}.png', - clone: function(obj) { - if (obj == null) { - obj = new OpenLayers.Layer.OSM( - this.name, this.url, this.getOptions()); - } - obj = OpenLayers.Layer.XYZ.prototype.clone.apply(this, [obj]); - return obj; - }, - CLASS_NAME: "OpenLayers.Layer.MapQuestOSM" -}); +if (typeof(OpenLayers) != 'undefined'){ + OpenLayers.Layer.MapQuestOSM = OpenLayers.Class(OpenLayers.Layer.XYZ, { + name: "MapQuestOSM", + sphericalMercator: true, + url: ' http://otile1.mqcdn.com/tiles/1.0.0/osm/${z}/${x}/${y}.png', + clone: function(obj) { + if (obj == null) { + obj = new OpenLayers.Layer.OSM( + this.name, this.url, this.getOptions()); + } + obj = OpenLayers.Layer.XYZ.prototype.clone.apply(this, [obj]); + return obj; + }, + CLASS_NAME: "OpenLayers.Layer.MapQuestOSM" + }); +}; /* * Little hasattr helper @@ -82,16 +84,13 @@ OpenLayers.Layer.MapQuestOSM = OpenLayers.Class(OpenLayers.Layer.XYZ, { hide_popup_fx: null, // if leave to false every click on the map hide the pop-up explicit_popup_hide: false, - controls:[new OpenLayers.Control.Navigation(), - new OpenLayers.Control.PanPanel(), - new OpenLayers.Control.ZoomPanel(), - new OpenLayers.Control.ScaleLine()], - popupClass: OpenLayers.Popup.FramedCloud, + controls: null, + popupClass: null, popupContentFull: false, // if true the detail is inside the popup category_accordion: true, // category opening behave like an accordion maxResolution: 156543.0399, units: 'm', - projection: new OpenLayers.Projection('EPSG:4326'), + projection: null, theme: null, enable_clustering: false, routing: false, // enable routing management @@ -104,13 +103,10 @@ OpenLayers.Layer.MapQuestOSM = OpenLayers.Class(OpenLayers.Layer.XYZ, { current_category: null, // To store the current category clicked in list current_route_feature: null, // To store the current route find by routing itinerary_step_number:0, // current step number - icon_offset: new OpenLayers.Pixel(0, 0), + icon_offset: null, edition: false, // edition mode edition_type_is_route: false, // route or POI edition - default_icon: new OpenLayers.Icon( - 'http://www.openlayers.org/dev/img/marker-green.png', - new OpenLayers.Size(21, 25), - new OpenLayers.Pixel(-(21/2), -25)), + default_icon: null, cluster_icon: null, marker_hover_id:'marker_hover', marker_hover_content_id:'marker_hover_content', @@ -129,6 +125,27 @@ OpenLayers.Layer.MapQuestOSM = OpenLayers.Class(OpenLayers.Layer.XYZ, { */ init: function ( options ) { /* Manage parameters */ + if (defaults.controls == null){ + defaults.controls = [new OpenLayers.Control.Navigation(), + new OpenLayers.Control.PanPanel(), + new OpenLayers.Control.ZoomPanel(), + new OpenLayers.Control.ScaleLine()]; + } + if (defaults.popupClass == null){ + defaults.popupClass = OpenLayers.Popup.FramedCloud; + } + if (defaults.projection == null){ + defaults.projection = new OpenLayers.Projection('EPSG:4326'); + } + if (defaults.icon_offset == null){ + defaults.icon_offset = new OpenLayers.Pixel(0, 0); + } + if (defaults.default_icon == null){ + defaults.default_icon = new OpenLayers.Icon( + 'http://www.openlayers.org/dev/img/marker-green.png', + new OpenLayers.Size(21, 25), + new OpenLayers.Pixel(-(21/2), -25)); + } // not staticaly in default because of STATIC_URL init if (defaults.cluster_icon == null && typeof STATIC_URL != 'undefined'){ defaults.cluster_icon = new OpenLayers.Icon( diff --git a/chimere/templates/chimere/blocks/head_chimere.html b/chimere/templates/chimere/blocks/head_chimere.html index 099a044..dea92ec 100644 --- a/chimere/templates/chimere/blocks/head_chimere.html +++ b/chimere/templates/chimere/blocks/head_chimere.html @@ -1,5 +1,5 @@ -{% for css_url in MAP_CSS_URLS %} -<link rel="stylesheet" href="{{ css_url }}" />{% endfor %} +{% for css_url, condition in MAP_CSS_URLS %} +{% if condition %}<!--[if {{condition}}]>{%endif%}<link rel="stylesheet" href="{{ css_url }}" />{% if condition %}<![endif]-->{%endif%}{% endfor %} {% for js_url in MAP_JS_URLS %} <script src="{{ js_url }}" type="text/javascript"></script>{% endfor %} {% if routing %}<script src="{{ STATIC_URL }}chimere/js/routing-widget.js" type="text/javascript"></script>{% endif %} @@ -13,11 +13,12 @@ <script src="{{ STATIC_URL }}chimere/js/base.js" type="text/javascript"></script> <script type="text/javascript"> var DEFAULT_ZOOM = {{ DEFAULT_ZOOM }}; + {% ifequal CHIMERE_VIEW_RENDERER 'openlayers' %} var EPSG_DISPLAY_PROJECTION = epsg_display_projection = new OpenLayers.Projection('EPSG:{{ EPSG_DISPLAY_PROJECTION }}'); OpenLayers.ImgPath = '{{ STATIC_URL }}chimere/img/'; var EPSG_PROJECTION = epsg_projection = new OpenLayers.Projection('EPSG:{{ EPSG_PROJECTION }}'); var CENTER_LONLAT = centerLonLat = new OpenLayers.LonLat{{ DEFAULT_CENTER }}.transform(epsg_display_projection, epsg_projection); - /*var map_layer = {{ MAP_LAYER|safe }};*/ + {% endifequal %} var restricted_extent; {% if area_name %} var area_name = '{{ area_name }}';{% endif %} diff --git a/chimere/templates/chimere/blocks/map.html b/chimere/templates/chimere/blocks/map.html index e00ff8b..6d4508d 100644 --- a/chimere/templates/chimere/blocks/map.html +++ b/chimere/templates/chimere/blocks/map.html @@ -36,8 +36,9 @@ {% if p_routing_end_lon %}chimere_init_options["routing_end_lon"] = {{ p_routing_end_lon }};{% endif %} {% if p_routing_end_lat %}chimere_init_options["routing_end_lat"] = {{ p_routing_end_lat }};{% endif %} {% if p_routing_steps %}chimere_init_options["routing_steps_lonlat"] = [{{ p_routing_steps }}];{% endif %} + {% ifequal map_renderer 'openlayers' %} chimere_init_options["icon_offset"] = new OpenLayers.Pixel({{icon_offset_x}}, - {{icon_offset_y}}); + {{icon_offset_y}});{% endifequal %} chimere_init_options["dynamic_categories"] = {{ dynamic_categories }}; {% if p_display_submited %}chimere_init_options["display_submited"] = {{ p_display_submited }};{% endif %} chimere_init_options["checked_categories"] = [{% for cc in checked_categories %}{% if forloop.counter0 > 0 %}, {% endif %}{{cc}}{% endfor %}]; diff --git a/chimere/templatetags/chimere_tags.py b/chimere/templatetags/chimere_tags.py index f086251..90252a1 100644 --- a/chimere/templatetags/chimere_tags.py +++ b/chimere/templatetags/chimere_tags.py @@ -143,6 +143,7 @@ def head_chimere(context, view=True): "DEFAULT_CENTER": settings.CHIMERE_DEFAULT_CENTER, "DEFAULT_ZOOM": settings.CHIMERE_DEFAULT_ZOOM, "MAP_LAYER": settings.CHIMERE_DEFAULT_MAP_LAYER, + "CHIMERE_VIEW_RENDERER": settings.CHIMERE_VIEW_RENDERER, "MAP_CSS_URLS": settings.MAP_CSS_URLS[map_renderer], "MAP_JS_URLS": settings.MAP_JS_URLS[map_renderer], 'routing': settings.CHIMERE_ENABLE_ROUTING \ @@ -183,7 +184,8 @@ def routing(context): @register.inclusion_tag('chimere/blocks/map.html', takes_context=True) def map(context, map_id='map'): context_data = {'map_id':map_id, - "STATIC_URL": settings.STATIC_URL} + "STATIC_URL": settings.STATIC_URL, + "map_renderer":settings.CHIMERE_VIEW_RENDERER} context_data['icon_offset_x'] = settings.CHIMERE_ICON_OFFSET_X context_data['icon_offset_y'] = settings.CHIMERE_ICON_OFFSET_Y context_data['icon_width'] = settings.CHIMERE_ICON_WIDTH |