diff options
author | Étienne Loks <etienne.loks@iggdrasil.net> | 2019-02-04 19:06:55 +0100 |
---|---|---|
committer | Étienne Loks <etienne.loks@iggdrasil.net> | 2019-04-24 19:38:56 +0200 |
commit | 96f9289714320dc42368d2a5647979017a771c35 (patch) | |
tree | 2293abaeaae428986477c12c6686b26d0b66af76 /ishtar_common/static/js | |
parent | 8c41c66665fe34195cd3329aebfaaa20de0e1ab5 (diff) | |
download | Ishtar-96f9289714320dc42368d2a5647979017a771c35.tar.bz2 Ishtar-96f9289714320dc42368d2a5647979017a771c35.zip |
Map JS: display popup - manage click on cluster - hover
Diffstat (limited to 'ishtar_common/static/js')
-rw-r--r-- | ishtar_common/static/js/ishtar-map.js | 237 | ||||
-rw-r--r-- | ishtar_common/static/js/ishtar.js | 1 |
2 files changed, 222 insertions, 16 deletions
diff --git a/ishtar_common/static/js/ishtar-map.js b/ishtar_common/static/js/ishtar-map.js index 3cce09fcb..1d84adb49 100644 --- a/ishtar_common/static/js/ishtar-map.js +++ b/ishtar_common/static/js/ishtar-map.js @@ -1,13 +1,16 @@ -/* layers */ - +/* default variables */ var default_pointer = "/media/images/default-pointer.png"; var marker_cluster = "/media/images/marker-cluster.png"; var view_projection = 'EPSG:3857'; +var animation_duration = 250; var map_default_center = 'SRID=4326;POINT (2.4397 46.5528)'; var map_default_zoom = '7'; +var min_auto_zoom_on_cluster = 13; + +/* base layers */ var source_osm = function(options){ return new ol.layer.Tile({ @@ -15,7 +18,6 @@ var source_osm = function(options){ }); }; - var default_map_layers = { 'osm': source_osm }; @@ -83,10 +85,11 @@ var enable_clustering = function(){ function cluster_get_style (feature, resolution){ feature.set('key', 'cluster'); - var features = feature.get('features'); + var cluster_features = feature.get('features'); - var size = features.length; + var size = cluster_features.length; feature.set('size', size); + var style = _styleCache[size]; // no cluster for lonely marker @@ -100,7 +103,7 @@ var enable_clustering = function(){ radius: radius, stroke: new ol.style.Stroke({ color:"rgba("+color+",0.5)", - width:15 + width: 15 }), fill: new ol.style.Fill({ color:"rgba("+color+",1)" @@ -122,8 +125,8 @@ var enable_clustering = function(){ } if (size > 1){ // marker himself disappear - for (idx in features){ - var feat = features[idx]; + for (idx in cluster_features){ + var feat = cluster_features[idx]; if (!_remindUpdated[feat.getProperties()['id']]){ if (!_remindOldStyle[feat.getProperties()['id']]){ _remindOldStyle[feat.getProperties()['id']] = feat.getStyle(); @@ -134,7 +137,7 @@ var enable_clustering = function(){ } } else { // or re-appear - var feat = features[0]; + var feat = cluster_features[0]; if (!_remindUpdated[feat.getProperties()['id']] && _remindOldStyle[feat.getProperties()['id']]){ feat.setStyle(_remindOldStyle[feat.getProperties()['id']]); @@ -167,6 +170,200 @@ var reinit_clustering = function(){ _currentRemind = -1; }; +/* manage clicks */ + +var current_feature; +var animate_in_progress = false; + +var animate_end = function(){animate_in_progress = false}; + +var wait_animation_end = function(callback, retry){ + if (!retry) retry = 1; + setTimeout(function(){ + retry += 1 + if (retry < 5 && animate_in_progress){ + wait_animation_end(callback) + } else { + callback(); + } + }, 100); +}; + +var manage_click_on_map = function(e) { + var feature = map.forEachFeatureAtPixel( + e.pixel, + function(feature, layer) { + return feature; + } + ); + click_on_feature(feature); +}; + +var click_on_feature = function(feature){ + + if (typeof feature == 'undefined'){ + current_feature = null; + return; + } + if (current_feature == feature){ + return + } + current_feature = feature; + if (!feature) return; + $(popup_item).hide(); + + var timeout = 200; + setTimeout(function(){ + // zoom on aggregated + var key = feature.get('key'); + if (key && key.length > 6 && key.substring(0, 7) == 'cluster'){ + feature = click_on_cluster(feature); + } else { + feature = click_on_pointer(feature); + } + }, timeout); +}; + +var click_on_cluster = function(feature, zoom_level, duration, nb_zoom, + current_nb_items){ + if (!duration){ + // zoom animation must be slower + duration = animation_duration * 2; + } + if (!nb_zoom) nb_zoom = 0; + + var props = feature.getProperties(); + if (!'features' in props) return feature; + if (!current_nb_items){ + current_nb_items = props['features'].length; + } else if(current_nb_items != props['features'].length) { + // stop zooming there less item in the cluster + return feature; + } + + var v = map.getView(); + if (!zoom_level) zoom_level = v.getZoom() + 1; + + // center + var new_center = feature.getGeometry().getCoordinates() + // max zoom reached + if (zoom_level >= min_auto_zoom_on_cluster){ + animate_in_progress = true; + v.animate({center: new_center, duration: duration}, animate_end); + return display_cluster_detail(feature); + } + + // zoom + animate_in_progress = true; + v.animate({center: new_center, zoom: zoom_level, duration: duration}, + animate_end); + + nb_zoom += 1; + // something wrong stop zoom! + if (nb_zoom > v.getMaxZoom()) return feature; + + // wait for the animation to finish before rezoom + return setTimeout( + function(){ + // our cluster must be at the center (if it exists after zoom) + var pixel = map.getPixelFromCoordinate(v.getCenter()); + var new_feature; + map.forEachFeatureAtPixel( + pixel, function(feat, layer){ + if (layer == cluster_layer){ + new_feature = feat; + return true + } + } + ); + if (new_feature){ + if (zoom_level < min_auto_zoom_on_cluster){ + return display_cluster_detail( + new_feature, zoom_level + 1, duration, nb_zoom, + current_nb_items); + } + return click_on_cluster( + new_feature, zoom_level + 1, duration, nb_zoom, + current_nb_items); + } + // no more cluster feature here or min auto zoom reach: stop zooming + return feature; + }, duration + 200); +}; + +var click_on_pointer = function(feature){ + console.log("click_on_pointer"); + var features = new Array(); + features.push(feature) + display_items(features, -14, -54); +}; + +/* display info */ + +var display_cluster_detail = function(cluster){ + console.log("display_cluster_detail"); + display_items(cluster.getProperties()['features'], -14, -21); +}; + +var display_items = function(features, offset_x, offset_y){ + wait_animation_end(function() {_display_items(features, offset_x, offset_y)}); +}; + +var _display_items = function(features, offset_x, offset_y){ + console.log("display_items"); + var feature = features[0]; + var geom = feature.getGeometry(); + var popup_content = "<ul>"; + features.forEach(function(feat){ + var properties = feat.getProperties(); + popup_content += "<li>" + properties['link'] + " " + properties['name'] + "</li>" + console.log(properties); + }); + popup_content += "</ul>"; + $(popup_item).html(popup_content); + popup.setPosition([0, 0]); // out of the map + $(popup_item).show(function(){ + + offset_x -= $(popup_item).width() / 2; + console.log(offset_x); + popup.setOffset([offset_x, offset_y]); + popup.setPosition(geom.getCoordinates()); + }); +}; + +/* hover */ + +var manage_hover = function(e) { + var pixel = map.getEventPixel(e.originalEvent); + var feature = map.forEachFeatureAtPixel( + e.pixel, + function(feature, layer) { + return feature; + } + ); + var hit = map.hasFeatureAtPixel(pixel); + var target = map.getTarget(); + target = typeof target === "string" ? + document.getElementById(target) : target; + target.style.cursor = hit ? 'pointer' : ''; +}; + +/* popup */ + +var popup; +var popup_item; + +var init_popup = function(){ + popup_item = document.getElementById("ishtar-map-popup-" + map_id); + var popup_options = { + element: popup_item, + positioning: 'bottom-left', + stopEvent: false + } + popup = new ol.Overlay(popup_options); + map.addOverlay(popup); +}; + /* display map */ var vector_source; @@ -174,6 +371,7 @@ var vector_layer; var center; var point_features; var map; +var map_id; var map_view; var map_layers; var proj_options = { @@ -182,7 +380,7 @@ var proj_options = { var geojson_format = new ol.format.GeoJSON(proj_options); var wkt_format = new ol.format.WKT(proj_options); -var initialize_map = function(map_id, layers){ +var initialize_map = function(layers){ center = wkt_format.readGeometry(map_default_center).getCoordinates(); /* @@ -213,18 +411,21 @@ var initialize_map = function(map_id, layers){ } -var redraw_map = function(map_id, layers){ +var redraw_map = function(layers){ map.setTarget(null); map = null; - initialize_map(map_id, layers); + initialize_map(layers); + reinit_clustering(); + current_feature = null; }; -var display_map = function(map_id, points, layers){ +var display_map = function(current_map_id, points, layers){ + map_id = current_map_id; if (map){ - redraw_map(map_id, layers); + redraw_map(layers); } else { - initialize_map(map_id, layers); + initialize_map(layers); } point_features = geojson_format.readFeatures(points); vector_source.clear(); @@ -240,5 +441,9 @@ var display_map = function(map_id, points, layers){ enable_clustering(); cluster_source.getSource().addFeatures(point_features); -} + init_popup(); + + map.on('click', manage_click_on_map); + map.on('pointermove', manage_hover); +} diff --git a/ishtar_common/static/js/ishtar.js b/ishtar_common/static/js/ishtar.js index 96f1a4cc9..929629397 100644 --- a/ishtar_common/static/js/ishtar.js +++ b/ishtar_common/static/js/ishtar.js @@ -1241,6 +1241,7 @@ var render_map = function(data_table, table_name, nb_select, map_id){ //var html = render_paginate_select(table_name, 'map', nb_select); var html = ""; html += "<div class='ishtar-table-map' id='" + map_id + "'></div>"; + html += "<div class='ishtar-map-popup' id='ishtar-map-popup-" + map_id + "'></div>"; return {"points": data_table, "html": html}; }; |