diff options
| -rw-r--r-- | ishtar_common/static/js/ishtar-map.js | 125 | ||||
| -rw-r--r-- | ishtar_common/static/media/images/marker-cluster.png | bin | 0 -> 1211 bytes | |||
| -rw-r--r-- | ishtar_common/views_item.py | 21 | 
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.pngBinary files differ new file mode 100644 index 000000000..73b41464c --- /dev/null +++ b/ishtar_common/static/media/images/marker-cluster.png 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 (' | 
