summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorÉtienne Loks <etienne.loks@iggdrasil.net>2019-02-04 16:20:47 +0100
committerÉtienne Loks <etienne.loks@iggdrasil.net>2019-04-24 19:38:56 +0200
commit8c41c66665fe34195cd3329aebfaaa20de0e1ab5 (patch)
tree0d5fd1b1e9fccbf3b58e23c108bffd834997f849
parentdf8ac2b90a6e819e9199b168213c250e437eded9 (diff)
downloadIshtar-8c41c66665fe34195cd3329aebfaaa20de0e1ab5.tar.bz2
Ishtar-8c41c66665fe34195cd3329aebfaaa20de0e1ab5.zip
Map JS: display clusters
-rw-r--r--ishtar_common/static/js/ishtar-map.js125
-rw-r--r--ishtar_common/static/media/images/marker-cluster.pngbin0 -> 1211 bytes
-rw-r--r--ishtar_common/views_item.py21
3 files changed, 136 insertions, 10 deletions
diff --git a/ishtar_common/static/js/ishtar-map.js b/ishtar_common/static/js/ishtar-map.js
index 402284da3..3cce09fcb 100644
--- a/ishtar_common/static/js/ishtar-map.js
+++ b/ishtar_common/static/js/ishtar-map.js
@@ -2,6 +2,7 @@
var default_pointer = "/media/images/default-pointer.png";
+var marker_cluster = "/media/images/marker-cluster.png";
var view_projection = 'EPSG:3857';
@@ -40,8 +41,6 @@ var get_markers = function(points){
/* styles */
var get_style = function(feature){
- properties = feature.getProperties();
- console.log(properties);
return new ol.style.Style({
image: new ol.style.Icon({
anchor: [17, 50],
@@ -53,10 +52,127 @@ var get_style = function(feature){
});
};
+/* clustering */
+
+var invisible_style_icon;
+var _styleCache;
+var _remindOldStyle;
+var _remindUpdated;
+var _currentRemind;
+var _revision = 1;
+var cluster_source;
+var cluster_layer;
+
+var enable_clustering = function(){
+
+ if (!invisible_style_icon){
+ invisible_style_icon = new ol.style.Style({
+ image: new ol.style.Icon({
+ //still need something even if it's invisible
+ src : static_path + marker_cluster,
+ opacity : 0
+ })
+ });
+ }
+
+ // Style clusters and hide items inside clusters
+ _styleCache = {};
+ _remindOldStyle = {};
+ _remindUpdated = {};
+ _currentRemind = -1;
+
+ function cluster_get_style (feature, resolution){
+ feature.set('key', 'cluster');
+ var features = feature.get('features');
+
+ var size = features.length;
+ feature.set('size', size);
+ var style = _styleCache[size];
+
+ // no cluster for lonely marker
+ if (!style && size > 1){
+ var color = size > 25 ? "192,0,0" : size > 8 ? "255,128,0" : "0,128,0";
+ var radius = Math.max(8, Math.min(size * 0.75, 20));
+ var lbl = size.toString();
+ style = _styleCache[size] = [
+ new ol.style.Style({
+ image: new ol.style.Circle({
+ radius: radius,
+ stroke: new ol.style.Stroke({
+ color:"rgba("+color+",0.5)",
+ width:15
+ }),
+ fill: new ol.style.Fill({
+ color:"rgba("+color+",1)"
+ })
+ }),
+ text: new ol.style.Text({
+ text: lbl,
+ fill: new ol.style.Fill({
+ color: '#fff'
+ })
+ })
+ })
+ ];
+ }
+ // don't reapply the style when no modif have been opered
+ if (_currentRemind != _revision){
+ _remindUpdated = [];
+ _currentRemind = _revision;
+ }
+ if (size > 1){
+ // marker himself disappear
+ for (idx in features){
+ var feat = features[idx];
+ if (!_remindUpdated[feat.getProperties()['id']]){
+ if (!_remindOldStyle[feat.getProperties()['id']]){
+ _remindOldStyle[feat.getProperties()['id']] = feat.getStyle();
+ }
+ feat.setStyle(invisible_style_icon);
+ _remindUpdated[feat.getProperties()['id']] = 1;
+ }
+ }
+ } else {
+ // or re-appear
+ var feat = features[0];
+ if (!_remindUpdated[feat.getProperties()['id']] &&
+ _remindOldStyle[feat.getProperties()['id']]){
+ feat.setStyle(_remindOldStyle[feat.getProperties()['id']]);
+ _remindUpdated[feat.getProperties()['id']] = 1;
+ }
+ }
+ return style;
+ }
+
+ // Cluster Source
+ cluster_source = new ol.source.Cluster({
+ distance: 40,
+ source: new ol.source.Vector()
+ });
+ // Animated cluster layer
+ cluster_layer = new ol.layer.Vector({
+ name: 'Cluster',
+ source: cluster_source,
+ // Cluster style
+ style: cluster_get_style
+ });
+ map.addLayer(cluster_layer);
+};
+
+var reinit_clustering = function(){
+ cluster_source.getSource().clear();
+ _styleCache = {};
+ _remindOldStyle = {};
+ _remindUpdated = {};
+ _currentRemind = -1;
+};
+
+
/* display map */
var vector_source;
var vector_layer;
var center;
+var point_features;
var map;
var map_view;
var map_layers;
@@ -110,8 +226,9 @@ var display_map = function(map_id, points, layers){
} else {
initialize_map(map_id, layers);
}
+ point_features = geojson_format.readFeatures(points);
vector_source.clear();
- vector_source.addFeatures(geojson_format.readFeatures(points));
+ vector_source.addFeatures(point_features);
map.updateSize();
if (points.features.length){
@@ -121,5 +238,7 @@ var display_map = function(map_id, points, layers){
}
}
+ enable_clustering();
+ cluster_source.getSource().addFeatures(point_features);
}
diff --git a/ishtar_common/static/media/images/marker-cluster.png b/ishtar_common/static/media/images/marker-cluster.png
new file mode 100644
index 000000000..73b41464c
--- /dev/null
+++ b/ishtar_common/static/media/images/marker-cluster.png
Binary files differ
diff --git a/ishtar_common/views_item.py b/ishtar_common/views_item.py
index f019fbcb3..72381ed8b 100644
--- a/ishtar_common/views_item.py
+++ b/ishtar_common/views_item.py
@@ -1006,16 +1006,20 @@ def _format_geojson(rows):
if not rows:
return data
geo_attr, name_attr = None, None
- for attr in rows[0]:
- if attr.endswith('point_2d'):
- geo_attr = attr
- if attr in ['name', 'cached_label']:
- name_attr = attr
+ full, idx = len(rows), 0
+ while not geo_attr and idx < full:
+ row = rows[idx]
+ for attr in row:
+ if attr.endswith('point_2d'):
+ geo_attr = attr
+ if attr in ['name', 'cached_label']:
+ name_attr = attr
+ idx += 1
if not geo_attr or not name_attr:
return data
for row in rows:
feat = {'name': row[name_attr], 'id': row['id']}
- if not row[geo_attr]:
+ if not row.get(geo_attr, None):
data['no-geo'].append(feat)
continue
feature = {'type': 'Feature'}
@@ -1206,6 +1210,9 @@ def get_item(model, func_name, default_name, extra_request_keys=None,
except (ValueError, TypeError):
row_nb = DEFAULT_ROW_NUMBER
+ if data_type == 'jso # no limit for mapn-map': # no limit for map
+ row_nb = None
+
dct_request_items = {}
# filter requested fields
@@ -1610,7 +1617,7 @@ def get_item(model, func_name, default_name, extra_request_keys=None,
try:
lnk_template = link_template
lnk = lnk_template % reverse('show-' + default_name,
- args=[data[0], ''])
+ args=[data[0], ''])
except NoReverseMatch:
logger.warning(
'**WARN "show-' + default_name + '" args ('