maps: add option to clusterize markers (#21048)
This commit is contained in:
parent
4ae2ac1ad5
commit
ce7386ffd6
|
@ -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'),
|
||||
),
|
||||
]
|
|
@ -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
|
||||
|
|
|
@ -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%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,7 +29,30 @@ $(function() {
|
|||
});
|
||||
if (map.geo_json) map.geo_json.remove();
|
||||
map.geo_json = geo_json;
|
||||
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 = '<div><span>' + childCount + '</span></div>';
|
||||
var c = ' marker-cluster-';
|
||||
if (childCount < 10) {
|
||||
c += 'small';
|
||||
} else if (childCount < 100) {
|
||||
c += 'medium';
|
||||
} else {
|
||||
c += 'large';
|
||||
}
|
||||
return new L.DivIcon({html: icon_html, className: 'marker-cluster' + c, iconSize: new L.Point(icon_size, icon_size)});
|
||||
}});
|
||||
markers.addLayer(geo_json);
|
||||
map.addLayer(markers);
|
||||
map.clustered_markers = markers;
|
||||
} else {
|
||||
geo_json.addTo(map);
|
||||
}
|
||||
if (callback) {
|
||||
callback(geo_json);
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
data-max-zoom="{{ max_zoom }}" data-init-lat="{{ init_lat }}"
|
||||
data-init-lng="{{ init_lng }}" data-geojson-url="{{ geojson_url }}"
|
||||
data-tile-urltemplate="{{ tile_urltemplate}}" data-map-attribution="{{ map_attribution}}"
|
||||
{% if group_markers %}data-group-markers="1"{% endif %}
|
||||
{% if max_bounds.corner1.lat %}
|
||||
data-max-bounds-lat1="{{ max_bounds.corner1.lat }}"
|
||||
data-max-bounds-lng1="{{ max_bounds.corner1.lng }}"
|
||||
|
|
|
@ -82,6 +82,7 @@ INSTALLED_APPS = (
|
|||
'xstatic.pkg.leaflet',
|
||||
'xstatic.pkg.opensans',
|
||||
'xstatic.pkg.roboto_fontface',
|
||||
'xstatic.pkg.leaflet_markercluster',
|
||||
)
|
||||
|
||||
INSTALLED_APPS = plugins.register_plugins_apps(INSTALLED_APPS)
|
||||
|
|
|
@ -17,6 +17,7 @@ Depends: ${misc:Depends}, ${python:Depends},
|
|||
python-xstatic-chartnew-js,
|
||||
python-xstatic-josefinsans,
|
||||
python-xstatic-leaflet,
|
||||
python-xstatic-leaflet-markercluster,
|
||||
python-xstatic-opensans,
|
||||
python-xstatic-roboto-fontface,
|
||||
python-eopayment (>= 1.9),
|
||||
|
|
1
setup.py
1
setup.py
|
@ -142,6 +142,7 @@ setup(
|
|||
'requests',
|
||||
'XStatic-ChartNew.js',
|
||||
'XStatic-Leaflet',
|
||||
'XStatic-Leaflet-MarkerCluster',
|
||||
'XStatic_JosefinSans',
|
||||
'XStatic_OpenSans',
|
||||
'XStatic_roboto-fontface',
|
||||
|
|
|
@ -94,12 +94,18 @@ def test_cell_rendering(layer):
|
|||
assert 'data-init-lat="48.83369263315934"' in rendered
|
||||
assert 'data-init-lng="2.3233688436448574"' in rendered
|
||||
assert 'data-geojson-url="/ajax/mapcell/geojson/1/"' in rendered
|
||||
assert 'data-group-markers="1"' not in rendered
|
||||
resp = client.get('/test_map_cell/')
|
||||
assert 'xstatic/leaflet.js' in resp.content
|
||||
assert 'js/combo.map.js' in resp.content
|
||||
assert 'xstatic/leaflet.css' in resp.content
|
||||
assert 'css/combo.map.css' in resp.content
|
||||
|
||||
cell.group_markers = True
|
||||
cell.save()
|
||||
rendered = cell.render(context)
|
||||
assert 'data-group-markers="1"' in rendered
|
||||
|
||||
|
||||
def test_get_geojson_on_non_public_page(layer):
|
||||
page = Page(title='xxx', slug='new', template_name='standard',
|
||||
|
|
Loading…
Reference in New Issue