/* 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 cluster_threshold_1 = 8; var cluster_threshold_2 = 25; var base_color_R = 111; var base_color_V = 66; var base_color_B = 193; var base_color_rvb; var map_default_center = 'SRID=4326;POINT (2.4397 46.5528)'; var map_default_zoom = '7'; var min_auto_zoom_on_cluster = 13; /* custom control */ var track_me_msg = "Geolocalize me"; var geoloc_activated_msg = "Geolocation activated"; var geoloc_disabled_msg = "Geolocation disabled"; var geolocation = {}; var geoloc_feature = {}; var geoloc_activated = {}; var fetching_msg = "Fetching data..."; var base_maps_msg = "Base maps"; var _map_submit_search = function(query_vars, name, source, extra){ if (!extra) extra = "default"; var modal_base_text = $('.modal-progress .modal-header').html(); $('.modal-progress .modal-header').html(fetching_msg); $('.modal-progress').modal('show'); var data = search_get_query_data(query_vars, name); var nb_select = jQuery("#id_" + name + "-length_map").val(); if (!nb_select) nb_select = 10; var url = source + "json-map?length=" + nb_select + "&submited=1&" + data; var use_map_limit = false; if(data.indexOf("no_limit=true") == -1){ url += "&limit=" + current_map_limit; use_map_limit = true; } $.getJSON(url, function(data) { var timestamp = Math.floor(Date.now() / 1000); var map_id = "map-" + extra + "-" + timestamp; $('.modal-progress .modal-header').html("{% trans 'Render map...' %}"); var html = render_map(map_id, use_map_limit); $("#tab-content-map-" + name + " #map-" + name + "-" + extra).html(html); $("#id_" + name + "-length_map").change(map_submit_search); if ($('.modal-progress').length > 0){ $('.modal-progress').modal('hide'); $('.modal-progress .modal-header').html(modal_base_text); } register_map(map_id, data); }); return false; }; var geoloc_activated_message = function(map_id){ setTimeout(function(){ navigator.geolocation.watchPosition(function(position) { if(!geoloc_activated[map_id]){ if (display_info) display_info(geoloc_activated_msg); geoloc_activated[map_id] = true; } }, function (error) { if (error.code == error.PERMISSION_DENIED) if (display_info) display_info(geoloc_disabled_msg); }); }, 200); }; var set_geoloc_source = function(map_id){ geolocation[map_id] = new ol.Geolocation({ projection: view_projection }); geolocation[map_id].setTracking(true); geoloc_feature[map_id] = new ol.Feature(); geoloc_feature[map_id].setStyle(new ol.style.Style({ image: new ol.style.Circle({ radius: 6, fill: new ol.style.Fill({color: '#3399CC'}), stroke: new ol.style.Stroke({color: '#fff', width: 2}) }) })); var accuracy_feature = new ol.Feature(); geolocation[map_id].on('change:accuracyGeometry', function() { accuracy_feature.setGeometry(geolocation[map_id].getAccuracyGeometry()); }); geolocation[map_id].on('change:position', function() { var coordinates = geolocation[map_id].getPosition(); geoloc_feature[map_id].setGeometry( coordinates ? new ol.geom.Point(coordinates) : null); var v = map[map_id].getView(); v.animate({center: coordinates, duration: animation_duration * 2}); }); new ol.layer.Vector({ map: map[map_id], source: new ol.source.Vector({ features: [geoloc_feature[map_id], accuracy_feature] }) }); geoloc_activated_message(map_id); }; var TrackPositionControl = (function (Control) { function TrackPositionControl(opt_options) { var options = opt_options || {}; this.map_id = options['map_id']; var button = document.createElement('button'); button.type = "button"; button.innerHTML = ''; button.title = track_me_msg; var element = document.createElement('div'); element.className = 'track-position ol-unselectable ol-control'; element.appendChild(button); Control.call(this, { element: element, target: options.target }); button.addEventListener( 'click', this.handleTrackPosition.bind(this), false ); } if ( Control ) TrackPositionControl.__proto__ = Control; TrackPositionControl.prototype = Object.create( Control && Control.prototype ); TrackPositionControl.prototype.constructor = TrackPositionControl; TrackPositionControl.prototype.handleTrackPosition = function handleTrackPosition () { if (!geolocation[this.map_id]){ set_geoloc_source(this.map_id); } else { if (!geoloc_activated[this.map_id]) return; if (geolocation[this.map_id].getTracking()){ geolocation[this.map_id].setTracking(false); if (display_info) display_info(geoloc_disabled_msg); } else { geolocation[this.map_id].setTracking(true); if (display_info) display_info(geoloc_activated_msg); } } return false; }; return TrackPositionControl; }(ol.control.Control)); /* base layers */ var source_osm = function(options){ options["source"] = new ol.source.OSM(); return new ol.layer.Tile(options); }; var ign_resolutions = [ 156543.03392804103, 78271.5169640205, 39135.75848201024, 19567.879241005125, 9783.939620502562, 4891.969810251281, 2445.9849051256406, 1222.9924525628203, 611.4962262814101, 305.74811314070485, 152.87405657035254, 76.43702828517625, 38.218514142588134, 19.109257071294063, 9.554628535647034, 4.777314267823517, 2.3886571339117584, 1.1943285669558792, 0.5971642834779396, 0.29858214173896974, 0.14929107086948493, 0.07464553543474241 ] ; var ign_key = "essentiels"; var source_ign = function(options){ options["source"] = new ol.source.WMTS({ url: "https://wxs.ign.fr/" + ign_key + "/geoportail/wmts", layer: "ORTHOIMAGERY.ORTHOPHOTOS", matrixSet: "PM", format: "image/jpeg", style: "normal", tileGrid : new ol.tilegrid.WMTS({ origin: [-20037508,20037508], // topLeftCorner resolutions: ign_resolutions, // résolutions matrixIds: ["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15","16","17","18","19"] // ids des TileMatrix }) }); return new ol.layer.Tile(options); } var default_map_layers = { 'osm': source_osm, 'ign': source_ign }; var get_layers = function(layers){ if (!layers){ layers = [ { 'type': 'ign', 'options': {'title': "IGN aérien (France)", 'visible': false, "type": 'base'} }, { 'type': 'osm', 'options': {'title': "OpenStreetMap", 'visible': true, "type": 'base'} } ]; } var ol_layers = []; for (idx in layers){ var layer_attr = layers[idx]; ol_layers.push( default_map_layers[layer_attr['type']](layer_attr['options']) ); } return ol_layers; }; /* styles */ var get_icon_style = function(feature){ return new ol.style.Style({ image: new ol.style.Icon({ anchor: [17, 50], anchorXUnits: 'pixels', anchorYUnits: 'pixels', size: [35, 50], src: static_path + default_pointer }) }); }; var get_vector_style = function(feature){ return new ol.style.Style({ stroke: new ol.style.Stroke({ color: 'rgba(' + base_color_rvb + ', 1)', width: 2 }), fill: new ol.style.Fill({ color: 'rgba(' + base_color_rvb + ', 0.2)' }) }); }; var cluster_get_style = function(feature, resolution){ feature.set('key', 'cluster'); var cluster_features = feature.get('features'); var size = cluster_features.length; feature.set('size', size); var style = _styleCache[size]; if (!style && size == 1){ style = _styleCache[size] = [get_icon_style()]; } else if (!style && size > 1){ var color = size > cluster_threshold_2 ? "192,0,0" : size > cluster_threshold_1 ? "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' }) }) }) ]; } return style; } /* clustering */ var _styleCache; var cluster_source = {}; var cluster_layer = {}; var enable_clustering = function(map_id){ // cache for styles _styleCache = {}; // cluster Source cluster_source[map_id] = new ol.source.Cluster({ distance: 40, source: new ol.source.Vector() }); // animated cluster layer cluster_layer[map_id] = new ol.layer.Vector({ name: 'Cluster', source: cluster_source[map_id], // cluster style style: cluster_get_style }); map[map_id].addLayer(cluster_layer[map_id]); }; var reinit_clustering = function(map_id){ if (map_id in cluster_source) { cluster_source[map_id].getSource().clear(); } _styleCache = {}; }; /* 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(map_id){ return function(e) { var feature = map[map_id].forEachFeatureAtPixel( e.pixel, function(feature, layer) { return feature; } ); click_on_feature(map_id, feature, e); }; }; var current_event; var click_on_feature = function(map_id, feature, e){ // console.log("click_on_feature"); current_event = e; if (!$(e.target).is($(popup_item[map_id])) && !$.contains($(popup_item[map_id])[0], e.target) ) { $(popup_item[map_id]).hide(); $('#ishtar-map-window-' + map_id).hide(); } if (typeof feature == 'undefined'){ current_feature = null; return; } current_feature = feature; if (!feature) return; var timeout = 10; setTimeout(function(){ // zoom on aggregated var key = feature.get('key'); if (feature.get('name') || feature.get('key')){ feature = click_on_cluster(map_id, feature); } }, timeout); }; var auto_zoom = false; var click_on_cluster = function(map_id, feature, zoom_level, duration, nb_zoom, current_nb_items){ // console.log("click_on_cluster"); 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 (!auto_zoom || props['features'].length == 1){ return display_cluster_detail(map_id, 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[map_id].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(map_id, 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[map_id].getPixelFromCoordinate(v.getCenter()); var new_feature; map.forEachFeatureAtPixel( pixel, function(feat, layer){ if (layer == cluster_layer[map_id]){ new_feature = feat; return true } } ); if (new_feature){ if (zoom_level < min_auto_zoom_on_cluster){ return display_cluster_detail(map_id, new_feature); } return click_on_cluster( map_id, 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); }; /* display info */ var display_cluster_detail = function(map_id, cluster){ // console.log("display_cluster_detail"); var features = cluster.getProperties()['features'] var offset_x = 0; var offset_y = -21; if (!features){ features = [cluster]; offset_y = -7; } else if (features.length == 1){ offset_y = -54; } display_items(map_id, features, offset_x, offset_y); }; var display_items = function(map_id, features, offset_x, offset_y){ wait_animation_end(function() {_display_items(map_id, features, offset_x, offset_y)}); }; var open_map_window = function(map_id){ return function(){ $('#ishtar-map-window-' + map_id).show(); }; }; var complete_list_label = "complete list..."; var _display_items = function(map_id, features, offset_x, offset_y){ // console.log("display_items"); var feature = features[0]; var geom = feature.getGeometry(); var ul_class = "map-list-" + map_id; var popup_content = ""; $("#ishtar-map-window-" + map_id + " .modal-body").html(window_content); $(popup_item[map_id]).html(popup_content); $("." + ul_class + " .map-list-detail").click(open_map_window(map_id)); if (geom.getType() == "Point"){ popup[map_id].setPosition(geom.getCoordinates()); } else { popup[map_id].setPosition(current_event.coordinate); } popup[map_id].setOffset([offset_x, offset_y]); $(popup_item[map_id]).css({opacity: 0}); $(popup_item[map_id]).show(0, function(){ setTimeout(function(){ popup[map_id].setOffset([offset_x, offset_y]); $(popup_item[map_id]).css({opacity: 1}); }, 200); }); }; /* hover */ var manage_hover = function(map_id){ return function(e) { var pixel = map[map_id].getEventPixel(e.originalEvent); var feature = map[map_id].forEachFeatureAtPixel( e.pixel, function(feature, layer) { return feature; } ); var hit = map[map_id].hasFeatureAtPixel(pixel); var target = map[map_id].getTarget(); target = typeof target === "string" ? document.getElementById(target) : target; target.style.cursor = hit ? 'pointer' : ''; } }; /* popup */ var popup = {}; var popup_item = {}; var init_popup = function(map_id){ popup_item[map_id] = document.getElementById("ishtar-map-popup-" + map_id); var popup_options = { element: popup_item[map_id], positioning: 'bottom-center' } popup[map_id] = new ol.Overlay(popup_options); map[map_id].addOverlay(popup[map_id]); }; /* display map */ var center; var point_features = {}; var map = {}; var map_view = {}; var map_layers = {}; var proj_options = { dataProjection:'EPSG:4326', featureProjection: view_projection } var geojson_format = new ol.format.GeoJSON(proj_options); var wkt_format = new ol.format.WKT(proj_options); var link_template = {}; var vector_source = {}; var vector_layer = {}; var vector_features = {}; /* for test */ let geo_items_features = null; let current_test = false; var initialize_test_map = function (slug_pk) { const id = "http-geo-items-ready-" + slug_pk; geo_items_features = {}; current_test = true; if ($("#"+id).length === 0) { $("#display-geo-items-for-" + slug_pk).after('
Ready!
'); } $("#"+id).hide(); } var initialize_base_map = function(map_id, layers){ center = wkt_format.readGeometry(map_default_center).getCoordinates(); map_layers[map_id] = [ new ol.layer.Group({ title: base_maps_msg, visible: true, layers: get_layers(layers) }) ]; map_view[map_id] = new ol.View({ projection: view_projection, center: ol.proj.fromLonLat([center[0], center[1]]), zoom: map_default_zoom }); var map_controls = ol.control.defaults().extend([ new ol.control.OverviewMap({ layers: map_layers[map_id] }), new ol.control.FullScreen(), new ol.control.ScaleLine() ]); if (location.protocol == 'https:'){ map_controls.push( new TrackPositionControl({map_id: map_id}) ); } map[map_id] = new ol.Map({ controls: map_controls, target: map_id, layers: map_layers[map_id], view: map_view[map_id] }); var layer_switcher = new ol.control.LayerSwitcher({ tipLabel: 'Légende', groupSelectStyle: 'children' }); map[map_id].addControl(layer_switcher); } var redraw_map = function(map_id, layers){ if (!map || !map[map_id]) return; map[map_id].setTarget(null); map[map_id] = null; initialize_base_map(map_id, layers); reinit_clustering(map_id); current_feature = null; }; var display_map = function(map_id, points, lines_and_polys, layers){ base_color_rvb = base_color_R + ', ' + base_color_V + ', ' + base_color_B; if (points){ link_template[map_id] = points['link_template']; } else if (lines_and_polys) { link_template[map_id] = lines_and_polys['link_template']; } if (map[map_id]){ redraw_map(map_id, layers); } else { initialize_base_map(map_id, layers); } display_points(map_id, points); init_popup(map_id); map[map_id].on('click', manage_click_on_map(map_id)); map[map_id].on('pointermove', manage_hover(map_id)); if (current_test) { geo_items_features[map_id] = []; // for test } }; var display_points = function(map_id, points, first_init){ if (!points) return; point_features[map_id] = geojson_format.readFeatures(points); console.log(708); if (!cluster_source[map_id]){ enable_clustering(map_id); } else { cluster_source[map_id].getSource().clear(); cluster_source[map_id].getSource().refresh(); } cluster_source[map_id].getSource().addFeatures(point_features[map_id]); if (first_init && points.features && points.features.length){ map_view[map_id].fit(cluster_source[map_id].getSource().getExtent()); if (map_view[map_id].getZoom() > 14){ map_view[map_id].setZoom(14); } } }; var display_lines_and_polys = function(map_id, lines_and_polys, first_init){ if (!lines_and_polys) return; vector_features[map_id] = geojson_format.readFeatures(lines_and_polys); if (!vector_source[map_id]){ vector_source[map_id] = new ol.source.Vector(); } else { vector_source[map_id].clear(); vector_source[map_id].refresh(); } vector_source[map_id].addFeatures(vector_features[map_id]); vector_layer[map_id] = new ol.layer.Vector({ source: vector_source[map_id], style: get_vector_style }); console.log(738); map[map_id].addLayer(vector_layer[map_id]); if (first_init && lines_and_polys.features && lines_and_polys.features.length){ map_view[map_id].fit(vector_source[map_id].getExtent()); } }; var display_geo_items = function(map_id, base_url, slug, pk, disp_cr, disp_bf, get_poly) { let url = base_url; if (slug === "operation") { url += "?operation_pk="; } else { url += "?context_record_pk="; } url += pk; httpRequest = new XMLHttpRequest(); if (!httpRequest) { return; } httpRequest.onreadystatechange = function() { if (httpRequest.readyState === XMLHttpRequest.DONE) { if (httpRequest.status === 200) { const geo_items = to_geo_items(JSON.parse(httpRequest.responseText), slug, disp_cr, disp_bf) if (current_test) { geo_items_features[map_id] = []; } let bfs = null; let crs = null; if (get_poly) { bfs = display_associated_polys(map_id, geo_items['base-finds'], 'basefind'); crs = display_associated_polys(map_id, geo_items['context-records'], 'contextrecord'); } else { bfs = display_associated_points(map_id, geo_items['base-finds'], 'basefind'); crs = display_associated_points(map_id, geo_items['context-records'], 'contextrecord'); } if (current_test) { geo_items_features[map_id].push(bfs) geo_items_features[map_id].push(crs) $("#http-geo-items-ready-"+slug+"-"+pk).show(); } } else { return; } } }; httpRequest.open('GET', url, true); httpRequest.send(); }; var to_geo_items = function (obj, slug, disp_cr, disp_bf) { const objects = {'context-records': {'features': [], 'type': 'FeatureCollection'}, 'base-finds': {'features': [], 'type': 'FeatureCollection'}}; if (slug === "operation") { const crs = obj['properties']['context-records']; for (const cr of crs['features']) { if (disp_bf) { for (const bf of cr['properties']['base-finds']['features']) { objects['base-finds']['features'].push(bf) } } delete cr['properties']; if (disp_cr) { objects['context-records']['features'].push(cr) } } } else { for (const bf of obj['properties']['base-finds']['features']) { objects['base-finds']['features'].push(bf) } } return objects; } var display_associated_polys = function (map_id, polys, slug) { const _vector_features = geojson_format.readFeatures(polys); const _vector_source = new ol.source.Vector(); _vector_source.addFeatures(_vector_features); let style = get_associated_base_find_style; if (slug === 'contextrecord') { style = get_associated_context_record_style; } const _vector_layer = new ol.layer.Vector({ source: _vector_source, style: style }); map[map_id].addLayer(_vector_layer); return _vector_features } var get_associated_base_find_style = function (feature) { return new ol.style.Style({ stroke: new ol.style.Stroke({ color: 'rgba(0, 0, 0, 1)', width: 2 }), fill: new ol.style.Fill({ color: 'rgba(O, O, O, 0.2)' }) }); }; var get_associated_context_record_style = function (feature) { return new ol.style.Style({ stroke: new ol.style.Stroke({ color: 'rgba(255, 255, 255, 1)', width: 2 }), fill: new ol.style.Fill({ color: 'rgba(255, 255, 255, 0.2)' }), radius: 10 }); }; var display_associated_points = function (map_id, points, slug) { const _point_features = geojson_format.readFeatures(points); const _cluster_source = new ol.source.Cluster({ distance: 40, source: new ol.source.Vector() }); _cluster_source.getSource().addFeatures(_point_features); // TODO: create own style const style = cluster_get_style; const _cluster_layer = new ol.layer.Vector({ name: 'Cluster', source: _cluster_source, style: style }); map[map_id].addLayer(_cluster_layer); return _point_features; } var get_features_by_id = function (id) { let base_features = null if (vector_features[id] == null) { base_features = geojson_format.writeFeaturesObject(point_features[id], {decimals: 5}); } else { base_features = geojson_format.writeFeaturesObject(vector_features[id], {decimals: 5}); } const geo_items_feats = []; if (geo_items_features && id in geo_items_features) { for (const features of geo_items_features[id]) { geo_items_feats.push(geojson_format.writeFeaturesObject(features, {decimals: 5})); } } return [base_features, geo_items_feats]; } var base_features_type = function (id) { if (vector_features[id] == null) { if (point_features[id] == null) { return 'both null'; } else { return 'Point'; } } if (point_features[id] == null) { return 'MultiPolygon'; } else { return 'Point and MultiPolygon' } }