diff options
-rw-r--r-- | chimere/admin.py | 12 | ||||
-rw-r--r-- | chimere/fixtures/initial_data.json | 2 | ||||
-rw-r--r-- | chimere/migrations/0004_auto_20161117_1911.py | 56 | ||||
-rw-r--r-- | chimere/models.py | 41 | ||||
-rw-r--r-- | chimere/static/chimere/js/jquery.chimere.js | 111 | ||||
-rw-r--r-- | chimere/templates/chimere/blocks/map.html | 32 | ||||
-rw-r--r-- | chimere/templatetags/chimere_tags.py | 8 |
7 files changed, 228 insertions, 34 deletions
diff --git a/chimere/admin.py b/chimere/admin.py index fda0dd7..41ca53a 100644 --- a/chimere/admin.py +++ b/chimere/admin.py @@ -48,8 +48,8 @@ from chimere import models from chimere.models import Category, Icon, SubCategory, Marker, \ PropertyModel, News, Route, Area, ColorTheme, Color, \ MultimediaFile, PictureFile, Importer, Layer, AreaLayers,\ - PropertyModelChoice, Page, get_areas_for_user, \ - ImporterKeyCategories, SubCategoryUserLimit + PropertyModelChoice, Page, get_areas_for_user, Overlay, \ + ImporterKeyCategories, SubCategoryUserLimit, AreaOverlays from chimere.utils import ShapefileManager, KMLManager, CSVManager @@ -443,13 +443,18 @@ class LayerInline(admin.TabularInline): extra = 1 +class OverlayInline(admin.TabularInline): + model = AreaOverlays + extra = 1 + + class AreaAdmin(admin.ModelAdmin): """ Specialized the area field. """ form = AreaAdminForm exclude = ['upper_left_corner', 'lower_right_corner'] - inlines = [LayerInline] + inlines = [LayerInline, OverlayInline] list_display = ['name', 'order', 'available', 'default'] @@ -600,3 +605,4 @@ if not settings.CHIMERE_HIDE_PROPERTYMODEL: admin.site.register(Area, AreaAdmin) admin.site.register(ColorTheme, ColorThemeAdmin) admin.site.register(Layer) +admin.site.register(Overlay) diff --git a/chimere/fixtures/initial_data.json b/chimere/fixtures/initial_data.json index 592e589..1c2fade 100644 --- a/chimere/fixtures/initial_data.json +++ b/chimere/fixtures/initial_data.json @@ -194,7 +194,7 @@ "pk": 1, "model": "chimere.layer", "fields": { - "layer_code": "new ol.layer.Tile({\r\n source: new ol.source.OSM(),\r\n baselayer: true,\r\n name: 'OSM - Mapnik'\r\n})", + "layer_code": "new ol.layer.Tile({\r\n source: new ol.source.OSM(),\r\n baselayer: true,\r\n title: 'OSM - Mapnik'\r\n})", "name": "OSM - Mapnik" } } diff --git a/chimere/migrations/0004_auto_20161117_1911.py b/chimere/migrations/0004_auto_20161117_1911.py new file mode 100644 index 0000000..100b2d6 --- /dev/null +++ b/chimere/migrations/0004_auto_20161117_1911.py @@ -0,0 +1,56 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import migrations, models +import chimere.widgets + + +class Migration(migrations.Migration): + + dependencies = [ + ('chimere', '0003_convert_tiny_urls'), + ] + + operations = [ + migrations.CreateModel( + name='AreaOverlays', + fields=[ + ('id', models.AutoField(primary_key=True, verbose_name='ID', auto_created=True, serialize=False)), + ('order', models.IntegerField(verbose_name='Order')), + ('area', models.ForeignKey(to='chimere.Area')), + ], + options={ + 'verbose_name': 'Area - Overlay', + 'ordering': ('order',), + 'verbose_name_plural': 'Areas - Overlays', + }, + ), + migrations.CreateModel( + name='Overlay', + fields=[ + ('id', models.AutoField(primary_key=True, verbose_name='ID', auto_created=True, serialize=False)), + ('name', models.CharField(verbose_name='Name', max_length=150)), + ('overlay_type', models.CharField(verbose_name='Importer type', max_length=4, choices=[('JSON', 'GeoJSON')])), + ('overlay_file', models.FileField(verbose_name='File', upload_to='')), + ('style', models.TextField(null=True, help_text='Javascript definition. Cf. to openlayers3 documentation.', blank=True, verbose_name='Style definition')), + ], + options={ + 'verbose_name': 'Overlay file', + 'verbose_name_plural': 'Overlay files', + }, + ), + migrations.AlterModelOptions( + name='arealayers', + options={'verbose_name': 'Area - Layer', 'ordering': ('order',), 'verbose_name_plural': 'Areas - Layers'}, + ), + migrations.AddField( + model_name='areaoverlays', + name='overlay', + field=models.ForeignKey(to='chimere.Overlay'), + ), + migrations.AddField( + model_name='area', + name='overlays', + field=chimere.widgets.SelectMultipleField(through='chimere.AreaOverlays', blank=True, related_name='overlays', to='chimere.Overlay'), + ), + ] diff --git a/chimere/models.py b/chimere/models.py index f21e45a..2d5c991 100644 --- a/chimere/models.py +++ b/chimere/models.py @@ -528,6 +528,30 @@ class ImporterKeyCategories(models.Model): class Meta: verbose_name = _("Importer - Key categories") +OVERLAY_CHOICES = ( + ('JSON', 'GeoJSON'), +) + + +class Overlay(models.Model): + ''' + Static overlay on the map + ''' + name = models.CharField(_("Name"), max_length=150) + overlay_type = models.CharField(_("Importer type"), max_length=4, + choices=OVERLAY_CHOICES) + overlay_file = models.FileField(_("File")) + style = models.TextField(_("Style definition"), blank=True, null=True, + help_text=_("Javascript definition. Cf. to " + "openlayers3 documentation.")) + + def __str__(self): + return self.name or "" + + class Meta: + verbose_name = _("Overlay file") + verbose_name_plural = _("Overlay files") + class GeographicItem(models.Model): categories = SelectMultipleField(SubCategory) @@ -1797,6 +1821,8 @@ class Area(models.Model, SimpleArea): _("Default area"), help_text=_("Only one area is set by default")) layers = SelectMultipleField(Layer, related_name='areas', through='AreaLayers', blank=True) + overlays = SelectMultipleField(Overlay, related_name='overlays', + through='AreaOverlays', blank=True) default_subcategories = SelectMultipleField( SubCategory, blank=True, verbose_name=_("Sub-categories checked by default")) @@ -1979,8 +2005,19 @@ class AreaLayers(models.Model): class Meta: ordering = ('order',) - verbose_name = _("Layers") - verbose_name_plural = _("Layers") + verbose_name = _("Area - Layer") + verbose_name_plural = _("Areas - Layers") + + +class AreaOverlays(models.Model): + area = models.ForeignKey(Area) + overlay = models.ForeignKey(Overlay) + order = models.IntegerField(_("Order")) + + class Meta: + ordering = ('order',) + verbose_name = _("Area - Overlay") + verbose_name_plural = _("Areas - Overlays") class PropertyModel(models.Model): diff --git a/chimere/static/chimere/js/jquery.chimere.js b/chimere/static/chimere/js/jquery.chimere.js index 6dbe811..f586e7f 100644 --- a/chimere/static/chimere/js/jquery.chimere.js +++ b/chimere/static/chimere/js/jquery.chimere.js @@ -43,7 +43,82 @@ if (typeof language != 'undefined'){ } } -// Create a simple layer switcher +var default_image = new ol.style.Circle({ + radius: 5, + fill: null, + stroke: new ol.style.Stroke({ color: 'red', width: 1 }) +}); + +var default_styles = { + 'Point': new ol.style.Style({ + image: default_image + }), + 'LineString': new ol.style.Style({ + stroke: new ol.style.Stroke({ + color: 'green', + width: 1 + }) + }), + 'MultiLineString': new ol.style.Style({ + stroke: new ol.style.Stroke({ + color: 'green', + width: 1 + }) + }), + 'MultiPoint': new ol.style.Style({ + image: default_image + }), + 'MultiPolygon': new ol.style.Style({ + stroke: new ol.style.Stroke({ + color: 'yellow', + width: 1 + }), + fill: new ol.style.Fill({ + color: 'rgba(255, 255, 0, 0.1)' + }) + }), + 'Polygon': new ol.style.Style({ + stroke: new ol.style.Stroke({ + color: 'blue', + lineDash: [4], + width: 3 + }), + fill: new ol.style.Fill({ + color: 'rgba(0, 0, 255, 0.1)' + }) + }), + 'GeometryCollection': new ol.style.Style({ + stroke: new ol.style.Stroke({ + color: 'magenta', + width: 2 + }), + fill: new ol.style.Fill({ + color: 'magenta' + }), + image: new ol.style.Circle({ + radius: 10, + fill: null, + stroke: new ol.style.Stroke({ + color: 'magenta' + }) + }) + }), + 'Circle': new ol.style.Style({ + stroke: new ol.style.Stroke({ + color: 'red', + width: 2 + }), + fill: new ol.style.Fill({ + color: 'rgba(255,0,0,0.2)' + }) + }) +}; + +var defaultStyleFunction = function (feature) { + return default_styles[feature.getGeometry().getType()]; +}; + + var default_map_lbl = ''; @@ -1935,7 +2010,39 @@ function transformCoordToLonLat(coord) { settings.editionSource.clear(); }, // add json layer - addJSON: function(json_url){ + addJSON: function(json_url, title, projection, style){ + if (typeof projection == 'undefined' || !projection) + projection = EPSG_DISPLAY_PROJECTION; + if (projection.substring(0, 5) != "EPSG:") + projection = "EPSG:" + projection; + + if (typeof style == 'undefined' || !style) + style = defaultStyleFunction; + + var vector = new ol.layer.Vector({ + title: title, + source: new ol.source.Vector(), + style: style + }); + + settings.map.addLayer(vector); + var format = new ol.format.GeoJSON(); + + if (json_url.substring(0, 4) != "http") + json_url = window.location.origin + json_url; + $.ajax({url: json_url, + dataType: "json", + success: function (data) { + vector.getSource().addFeatures( + format.readFeatures( + data, { + featureProjection: EPSG_PROJECTION, + dataProjection: projection} + ) + ); + } + }); + // TODO ol3 : json /* var jsonStyle = new OpenLayers.Style({ diff --git a/chimere/templates/chimere/blocks/map.html b/chimere/templates/chimere/blocks/map.html index 85a4350..fd0cae4 100644 --- a/chimere/templates/chimere/blocks/map.html +++ b/chimere/templates/chimere/blocks/map.html @@ -3,7 +3,7 @@ <div class="modal-dialog"> <div class="modal-content"> <div class="modal-header"> - <button type="button" class="close" data-dismiss="modal" aria-label="{% trans "Close" %}"><span aria-hidden="true">×</span></button> + <button type="button" class="close" data-dismiss="modal" aria-label="{% trans 'Close' %}"><span aria-hidden="true">×</span></button> <h4 class="modal-title" id="category_description-label"></h4> </div> <div class="modal-body" id="category_description-content"> @@ -86,32 +86,14 @@ $("#{{map_id}}").show(); $('#main-map').chimere('update_permalink'); }; + {% for overlay in json_overlays %} + $('#main-map').chimere('addJSON', '{{overlay.overlay_file.url}}', + "{{overlay.name}}"{% if overlay.style %}, + "EPSG:4326", + {{overlay.style|safe}}{% endif %}); + {% endfor %} {{extra_map_def|safe}} - // init layer selection - /* $(function() { - {% for layer_name, js, def in map_layers %} - $('#layer_list').append("<li><input type='radio' value='{{forloop.counter0}}' name='layer_type' id='layer_{{forloop.counter}}'{% if def %} checked='checked'{% endif %}><label for='layer_{{forloop.counter}}'>{{layer_name}}</li>");{% endfor %} - {% for subcat in subcat_layer %} - {% if not subcat.category %} - $('#layer_list').append("<li class='head layer_category'>{{subcat.name}}</li>");{% else %} - $('#layer_list').append("<li><input type='checkbox' name='layer_cat' value='category_{{subcat.pk}}' id='layer_cat_{{subcat.pk}}'{% if subcat.pk in checked_categories %} checked='checked'{% endif %}><label for='layer_cat_{{subcat.pk}}'>{{subcat.name}}</li>");{%endif%}{% endfor %} - $('#layer_selection h4').click(function(){ - $('#layer_list').toggle(); - }); - $('#layer_list input[name=layer_type]').change(function(){ - $('#{{map_id}}').chimere('changeMapLayer', $(this).val()); - }); - $('#layer_list input[name=layer_cat]').change(function(){ - // the prop has to be called twice not to mess up with the triggered - // click - $('#'+$(this).val()).prop("checked", this.checked); - $('#'+$(this).val()).trigger('click'); - $('#'+$(this).val()).prop("checked", this.checked); - }); - highlight_selected_categories(); - }); - */ </script> <div id='marker_hover'><div id='marker_hover_content'></div></div> <div class="modal fade" id="cluster_list" tabindex="-1" role="dialog" aria-labelledby="cluster-label" aria-hidden="true"> diff --git a/chimere/templatetags/chimere_tags.py b/chimere/templatetags/chimere_tags.py index c1e71b2..c5cd555 100644 --- a/chimere/templatetags/chimere_tags.py +++ b/chimere/templatetags/chimere_tags.py @@ -14,7 +14,8 @@ from django.template import defaultfilters from django.utils.translation import ugettext as _ from django.template.loader import render_to_string -from chimere.models import Marker, Area, News, SubCategory, MultimediaType +from chimere.models import Marker, Area, News, SubCategory, MultimediaType, \ + AreaOverlays from chimere.version import get_version from chimere.widgets import get_map_layers @@ -250,6 +251,11 @@ def map(context, map_id='map'): pass subcat_layer = SubCategory.objects.filter(as_layer=True, available=True) if area: + context_data['json_overlays'] = [ + area_overlay.overlay for area_overlay in + AreaOverlays.objects.filter( + area=area, overlay__overlay_type='JSON').all() + ] if area.subcategories.count(): subcat_layer = subcat_layer.filter(areas__pk=area.pk) context_data['area_id'] = area_name |