diff --git a/combo/apps/maps/migrations/0005_auto_20180212_1742.py b/combo/apps/maps/migrations/0005_auto_20180212_1742.py new file mode 100644 index 00000000..8970ebdc --- /dev/null +++ b/combo/apps/maps/migrations/0005_auto_20180212_1742.py @@ -0,0 +1,19 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('maps', '0004_map_initial_state'), + ] + + operations = [ + migrations.AddField( + model_name='map', + name='group_markers', + field=models.BooleanField(default=False, verbose_name='Group markers in clusters'), + ), + ] diff --git a/combo/apps/maps/models.py b/combo/apps/maps/models.py index eb5bcf63..37023416 100644 --- a/combo/apps/maps/models.py +++ b/combo/apps/maps/models.py @@ -200,6 +200,7 @@ class Map(CellBase): choices=ZOOM_LEVELS, default='0') max_zoom = models.CharField(_('Maximal zoom level'), max_length=2, choices=ZOOM_LEVELS, default=19) + group_markers = models.BooleanField(_('Group markers in clusters'), default=False) layers = models.ManyToManyField(MapLayer, verbose_name=_('Layers'), blank=True) template_name = 'maps/map_cell.html' @@ -208,7 +209,7 @@ class Map(CellBase): verbose_name = _('Map') class Media: - js = ('xstatic/leaflet.js', 'js/combo.map.js') + js = ('xstatic/leaflet.js', 'js/combo.map.js', 'xstatic/leaflet.markercluster.js') css = {'all': ('xstatic/leaflet.css', 'css/combo.map.css')} def get_default_position(self): @@ -216,7 +217,7 @@ class Map(CellBase): def get_default_form_class(self): fields = ('title', 'initial_state', 'initial_zoom', 'min_zoom', - 'max_zoom', 'layers') + 'max_zoom', 'group_markers', 'layers') widgets = {'layers': forms.widgets.CheckboxSelectMultiple} return forms.models.modelform_factory(self.__class__, fields=fields, widgets=widgets) @@ -245,4 +246,5 @@ class Map(CellBase): ctx['tile_urltemplate'] = settings.COMBO_MAP_TILE_URLTEMPLATE ctx['map_attribution'] = settings.COMBO_MAP_ATTRIBUTION ctx['max_bounds'] = settings.COMBO_MAP_MAX_BOUNDS + ctx['group_markers'] = self.group_markers return ctx diff --git a/combo/apps/maps/static/css/combo.map.scss b/combo/apps/maps/static/css/combo.map.scss index 9c9ad860..8e841862 100644 --- a/combo/apps/maps/static/css/combo.map.scss +++ b/combo/apps/maps/static/css/combo.map.scss @@ -44,7 +44,7 @@ div.combo-cell-map.leaflet-container { /* leaflet styles */ -div.leaflet-marker-icon { +div.leaflet-marker-icon.leaflet-div-icon { border: none; background: transparent; } @@ -135,3 +135,52 @@ ul#id_icon { } } } + + +/* leaflet markercluster styles */ + +.leaflet-cluster-anim .leaflet-marker-icon, .leaflet-cluster-anim .leaflet-marker-shadow { + transition: transform 0.3s ease-out, opacity 0.3s ease-in; +} + +.leaflet-cluster-spider-leg { + /* stroke-dashoffset (duration and function) should match with leaflet-marker-icon transform in order to track it exactly */ + transition: stroke-dashoffset 0.3s ease-out, stroke-opacity 0.3s ease-in; +} + +.marker-cluster { + background-clip: padding-box; + border-radius: 30px; + div { + display: block; + background: #fff; + border-radius: 30px; + font-weight: bold; + height: 50px; + width: 50px; + text-align: center; + margin-left: 5px; + margin-top: 5px; + } + span { + line-height: 50px; + } + &-small { + background: #b5e28c; + div { + font-size: 200%; + } + } + &-medium { + background: #f1d357; + div { + font-size: 200%; + } + } + &-large { + background: #fd9c73; + div { + font-size: 150%; + } + } +} diff --git a/combo/apps/maps/static/js/combo.map.js b/combo/apps/maps/static/js/combo.map.js index 915b8134..31744c56 100644 --- a/combo/apps/maps/static/js/combo.map.js +++ b/combo/apps/maps/static/js/combo.map.js @@ -29,7 +29,30 @@ $(function() { }); if (map.geo_json) map.geo_json.remove(); map.geo_json = geo_json; - geo_json.addTo(map); + if ($map_widget.data('group-markers')) { + var markers = L.markerClusterGroup({showCoverageOnHover: false, + zoomToBoundsOnClick: true, + removeOutsideVisibleBounds: true, + iconCreateFunction: function (cluster) { + var icon_size = 60; + var childCount = cluster.getChildCount(); + var icon_html = '