/* eslint-disable no-undef */ var startpos = [51.05, -1.38]; // Start location - somewhere in UK :-) var startzoom = 10; var ws; var map; var allData = {}; var markers = {}; var polygons = {}; var layers = {}; var overlays = {}; var basemaps = {}; var marks = []; var buttons = {}; var marksIndex = 0; var menuOpen = false; var clusterAt = 0; var maxage = 600; // default max age of icons on map in seconds - cleared after 10 mins var baselayername = "OSM grey"; // Default base layer OSM but uniform grey var ibmfoot = " © IBM 2015,2019" var inIframe = false; var showUserMenu = true; var showLayerMenu = true; var showMouseCoords = false; var allowFileDrop = false; var minimap; var sidebyside; var layercontrol; var drawingColour = "#910000"; var iconSz = { "Team/Crew": 24, "Squad": 24, "Section": 24, "Platoon/detachment": 26, "Company/battery/troop": 28, "Battalion/squadron": 30, "Regiment/group": 32, "Brigade": 34, "Division": 36, "Corps/MEF": 36, "Army": 40, "Army Group/front": 40, "Region/Theater": 44, "Command": 44 }; // Polyfill assign for IE11 for now if (typeof Object.assign !== 'function') { // Must be writable: true, enumerable: false, configurable: true Object.defineProperty(Object, "assign", { value: function assign(target, varArgs) { // .length of function is 2 'use strict'; if (target === null || target === undefined) { throw new TypeError('Cannot convert undefined or null to object'); } var to = Object(target); for (var index = 1; index < arguments.length; index++) { var nextSource = arguments[index]; if (nextSource !== null && nextSource !== undefined) { for (var nextKey in nextSource) { // Avoid bugs when hasOwnProperty is shadowed if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) { to[nextKey] = nextSource[nextKey]; } } } } return to; }, writable: true, configurable: true }); } // Create the socket var connect = function() { ws = new SockJS(location.pathname.split("index")[0] + 'socket'); ws.onopen = function() { console.log("CONNECTED"); if (!inIframe) { document.getElementById("footer").innerHTML = ""+ibmfoot+""; } ws.send(JSON.stringify({action:"connected",parameters:Object.fromEntries((new URL(location)).searchParams)})); onoffline(); }; ws.onclose = function() { console.log("DISCONNECTED"); if (!inIframe) { document.getElementById("footer").innerHTML = ""+ibmfoot+""; } setTimeout(function() { connect(); }, 2500); }; ws.onmessage = function(e) { try { var data = JSON.parse(e.data); handleData(data); } catch (e) { console.log("BAD DATA"); return; } // console.log("DATA",typeof data,data); }; } console.log("CONNECT TO",location.pathname + 'socket'); var handleData = function(data) { if (Array.isArray(data)) { //console.log("ARRAY"); // map.closePopup(); // var bnds= L.latLngBounds([0,0]); for (var prop in data) { if (data[prop].command) { doCommand(data[prop].command); delete data[prop].command; } if (data[prop].hasOwnProperty("name")) { setMarker(data[prop]); // bnds.extend(markers[data[prop].name].getLatLng()); } else { console.log("SKIP A",data[prop]); } } // map.fitBounds(bnds.pad(0.25)); } else { if (typeof data === "string" && data.indexOf(" { var content = event.target.result; var data; if (content.indexOf("base64") !== -1) { if (content.indexOf("image") === -1) { data = atob(content.split("base64,")[1]); if (data.indexOf('Reset Heatmap', function() { console.log("Reset heatmap"); heat.setLatLngs([]); }, "Clears the current heatmap", "bottomright"); } var helpMenu = '' helpMenu += ''; helpMenu += ''; helpMenu += ''; helpMenu += ''; helpMenu += ''; helpMenu += ''; if (!inIframe) { helpMenu += '
 
Set Max Age s
Cluster at zoom <
Auto Pan Map
Lock Map
Heatmap all layers
Help
'; } else { helpMenu += '' } document.getElementById('menu').innerHTML = helpMenu; // Add graticule var showGrid = false; var Lgrid = L.latlngGraticule({ font: "Verdana", fontColor: "#666", zoomInterval: [ {start:1, end:2, interval:40}, {start:3, end:3, interval:20}, {start:4, end:4, interval:10}, {start:5, end:7, interval:5}, {start:8, end:20, interval:1} ] }); var panit = false; function doPanit(v) { if (v !== undefined) { panit = v; } console.log("Panit set :",panit); } var heatAll = false; function doHeatAll(v) { if (v !== undefined) { heatall = v; } console.log("Heatall set :",heatAll); } var lockit = false; var mb = new L.LatLngBounds([[-120,-360],[120,360]]); function doLock(v) { if (v !== undefined) { lockit = v; } if (lockit === false) { mb = new L.LatLngBounds([[-120,-360],[120,360]]); map.dragging.enable(); } else { mb = map.getBounds(); map.dragging.disable(); window.localStorage.setItem("lastpos",JSON.stringify(map.getCenter())); window.localStorage.setItem("lastzoom", map.getZoom()); window.localStorage.setItem("lastlayer", baselayername); //window.localStorage.setItem("clusterat", clusterAt); window.localStorage.setItem("maxage", maxage); console.log("Saved :",JSON.stringify(map.getCenter()),map.getZoom(),baselayername); } map.setMaxBounds(mb); //console.log("Map bounds lock :",lockit); } // Remove old markers function doTidyUp(l) { var d = parseInt(Date.now()/1000); for (var m in markers) { if ((l && (l == markers[m].lay)) || typeof markers[m].ts != "undefined") { if ((l && (l == markers[m].lay)) || (markers[m].hasOwnProperty("ts") && (Number(markers[m].ts) < d) && (markers[m].lay !== "_drawing"))) { //console.log("STALE :",m); if (typeof polygons[m+"_"] != "undefined") { layers[polygons[m+"_"].lay].removeLayer(polygons[m+"_"]); delete polygons[m+"_"]; } if (typeof polygons[m] != "undefined") { layers[markers[m].lay].removeLayer(polygons[m]); delete polygons[m]; } layers[markers[m].lay].removeLayer(markers[m]); delete markers[m]; } } } if (l) { if (layers[l]) { map.removeLayer(layers[l]); layercontrol.removeLayer(layers[l]); delete layers[l]; } if (overlays[l]) { map.removeLayer(overlays[l]); layercontrol.removeLayer(overlays[l]); delete overlays[l]; } } } // Call tidyup every {maxage} seconds - default 10 mins var stale = null; function setMaxAge() { maxage = document.getElementById('maxage').value; if (stale) { clearInterval(stale); } //if (maxage > 0) { stale = setInterval( function() { doTidyUp() }, 20000); // check every 20 secs //} //every minute //console.log("Stale time set :",maxage+"s"); } setMaxAge(); // move the daylight / nighttime boundary (if enabled) every minute function moveTerminator() { // if terminator line plotted move it every minute if (layers["_daynight"].getLayers().length > 0) { layers["_daynight"].clearLayers(); layers["_daynight"].addLayer(L.terminator()); } } setInterval( function() { moveTerminator() }, 60000 ); // move the rainfall overlay (if enabled) every 10 minutes function moveRainfall() { if (navigator.onLine && map.hasLayer(overlays["rainfall"])) { overlays["rainfall"]["_url"] = 'https://tilecache.rainviewer.com/v2/radar/' + parseInt(Date.now()/600000)*600 + '/256/{z}/{x}/{y}/2/1_1.png'; overlays["rainfall"].redraw(); } } setInterval( function() { moveRainfall() }, 600000 ); function setCluster(v) { clusterAt = v || 0; console.log("clusterAt set:",clusterAt); showMapCurrentZoom(); } // Search for markers with names of ... or icons of ... function doSearch() { var value = document.getElementById('search').value; marks = []; marksIndex = 0; for (var key in markers) { if ( (~(key.toLowerCase()).indexOf(value.toLowerCase())) && (mb.contains(markers[key].getLatLng()))) { marks.push(markers[key]); } if (markers[key].icon === value) { marks.push(markers[key]); } } moveToMarks(); if (marks.length === 0) { // If no markers found let's try a geolookup... var protocol = location.protocol; if (protocol == "file:") { protocol = "https:"; } var searchUrl = protocol + "//nominatim.openstreetmap.org/search?format=json&limit=1&q="; fetch(searchUrl + value) // Call the fetch function passing the url of the API as a parameter .then(function(resp) { return resp.json(); }) .then(function(data) { if (data.length > 0) { var bb = data[0].boundingbox; map.fitBounds([ [bb[0],bb[2]], [bb[1],bb[3]] ]); map.panTo([data[0].lat, data[0].lon]); } else { document.getElementById('searchResult').innerHTML = " Not Found"; } }) .catch(function(err) { if (err.toString() === "TypeError: Failed to fetch") { document.getElementById('searchResult').innerHTML = " Not Found"; } }); } else { if (lockit) { document.getElementById('searchResult').innerHTML = " Found "+marks.length+" results within bounds."; } else { document.getElementById('searchResult').innerHTML = " Found "+marks.length+" results."; } } } // Jump to a markers position - centralise it on map function moveToMarks() { if (marks.length > marksIndex) { var m = marks[marksIndex]; map.setView(m.getLatLng(), map.getZoom()); m.openPopup(); marksIndex++; setTimeout(moveToMarks, 2500); } } // Clear Search With Marker names function clearSearch() { var value = document.getElementById('search').value; marks = []; marksIndex = 0; for (var key in markers) { if ( (~(key.toLowerCase()).indexOf(value.toLowerCase())) && (mb.contains(markers[key].getLatLng()))) { marks.push(markers[key]); } } removeMarks(); if (lockit) { document.getElementById('searchResult').innerHTML = ""; } else { document.getElementById('searchResult').innerHTML = ""; } } function removeMarks() { if (marks.length > marksIndex) { var m = marks[marksIndex]; map.setView(m.getLatLng(), map.getZoom()); m.closePopup(); marksIndex++; } } function toggleMenu() { menuOpen = !menuOpen; if (menuOpen) { document.getElementById("menu").style.display = 'block'; } else { document.getElementById("menu").style.display = 'none'; dialogue.close(); } } function openMenu() { if (!menuOpen) { menuOpen = true; document.getElementById("menu").style.display = 'block'; } } function closeMenu() { if (menuOpen) { menuOpen = false; document.getElementById("menu").style.display = 'none'; } dialogue.close(); } document.getElementById("menu").style.display = 'none'; map.on('overlayadd', function(e) { if (typeof overlays[e.name].bringToFront === "function") { overlays[e.name].bringToFront(); } if (e.name == "satellite") { overlays["satellite"].bringToBack(); } if (e.name == "countries") { overlays["countries"].bringToBack(); } if (e.name == "heatmap") { // show heatmap button when it's layer is added. clrHeat.addTo(map); } if (e.name == "day/night") { layers["_daynight"].addLayer(L.terminator()); } if (e.name == "drawing") { overlays["drawing"].bringToFront(); map.addControl(drawControl); map.addControl(colorControl); } ws.send(JSON.stringify({action:"addlayer", name:e.name})); }); map.on('overlayremove', function(e) { if (e.name == "heatmap") { // hide heatmap button when it's layer is removed. clrHeat.removeFrom(map); } if (e.name == "day/night") { layers["_daynight"].clearLayers(); } if (e.name == "drawing") { map.removeControl(colorControl); map.removeControl(drawControl); } ws.send(JSON.stringify({action:"dellayer", name:e.name})); }); map.on('baselayerchange', function(e) { //console.log("base layer now :",e.name); baselayername = e.name; ws.send(JSON.stringify({action:"layer", name:e.name})); }); function showMapCurrentZoom() { console.log("zoom:",map.getZoom(),". clusterAt:",clusterAt); for (var l in layers) { if (layers[l].hasOwnProperty("_zoom")) { if (map.getZoom() >= clusterAt) { layers[l].disableClustering(); } else { layers[l].enableClustering(); } } } setTimeout( function() { for (var key in markers) { if (polygons[key]) { if (typeof layers[markers[key].lay].getVisibleParent === 'function') { var vis = layers[markers[key].lay].getVisibleParent(markers[key]); if ((vis) && (vis.hasOwnProperty("lay"))) { polygons[key].setStyle({opacity:1}); } else { polygons[key].setStyle({opacity:0}); } } try { if (polygons[key].hasOwnProperty("_layers")) { polygons[key].eachLayer(function(layer) { layer.redraw(); }); } else { polygons[key].redraw(); } } catch(e) { console.log(key,polygons[key],e) } } } },750); } map.on('zoomend', function() { showMapCurrentZoom(); window.localStorage.setItem("lastzoom", map.getZoom()); }); map.on('moveend', function() { window.localStorage.setItem("lastpos",JSON.stringify(map.getCenter())); }); //map.on('contextmenu', function(e) { // ws.send(JSON.stringify({action:"rightclick", lat:e.latlng.lat.toFixed(5), lon:e.latlng.lng.toFixed(5)})); //}); // single right click to add a marker var addmenu = "Add marker
"; var rightmenuMap = L.popup({keepInView:true, minWidth:250}).setContent(addmenu); var rclk; var hiderightclick = false; var addThing = function() { var thing = document.getElementById('rinput').value; map.closePopup(); //popped = false; var bits = thing.split(","); var icon = (bits[1] || "circle").trim(); var lay = (bits[2] || "_drawing").trim(); var colo = (bits[3] || "#910000").trim(); var hdg = parseFloat(bits[4] || 0); var drag = true; var regi = /^[S,G,E,I,O][A-Z]{4}.*/i; // if it looks like a SIDC code var d = {action:"point", name:bits[0].trim(), layer:lay, draggable:drag, lat:rclk.lat, lon:rclk.lng, hdg:hdg}; if (regi.test(icon)) { d.SIDC = (icon.toUpperCase()+"------------").substr(0,12); } else { d.icon = icon; d.iconColor = colo; } ws.send(JSON.stringify(d)); delete d.action; setMarker(d); map.addLayer(layers[lay]); } var feedback = function(n,v,a,c) { if (v === "$form") { v = form; } if (markers[n]) { var fp = markers[n]._latlng; ws.send(JSON.stringify({action:a||"feedback", name:n, value:v, layer:markers[n].lay, lat:fp.lat, lon:fp.lng})); } else { if (n === undefined) { n = "map"; } ws.send(JSON.stringify({action:a||"feedback", name:n, value:v, lat:rclk.lat, lon:rclk.lng,})); } if (c === true) { map.closePopup(); } } var form = {}; var addToForm = function(n,v) { form[n] = v; } // allow double right click to zoom out (if enabled) // single right click opens a message window that adds a marker var rclicked = false; var rtout = null; map.on('contextmenu', function(e) { if (rclicked) { rclicked = false; clearTimeout(rtout); if (map.doubleClickZoom.enabled()) { map.zoomOut(); } } else { rclicked = true; rtout = setTimeout( function() { rclicked = false; if ((hiderightclick !== true) && (addmenu.length > 0)) { rclk = e.latlng; form = {}; rightmenuMap.setLatLng(e.latlng); map.openPopup(rightmenuMap); setTimeout( function() { try { document.getElementById('rinput').focus(); } catch(e) {} }, 200); } }, 300); } }); // Add all the base layer maps if (navigator.onLine) { // Use this for OSM online maps var osmUrl='https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png'; //var osmUrl='https://{s}.tile.openstreetmap.fr/hot/{z}/{x}/{y}.png'; var osmAttrib='Map data © OpenStreetMap contributors'; var osmg = new L.TileLayer.Grayscale(osmUrl, {attribution:osmAttrib, maxNativeZoom:19, maxZoom:20}); basemaps["OSM grey"] = osmg; var osm = new L.TileLayer(osmUrl, {attribution:osmAttrib, maxNativeZoom:19, maxZoom:20}); basemaps["OSM"] = osm; // Extra Leaflet map layers from https://leaflet-extras.github.io/leaflet-providers/preview/ var Esri_WorldStreetMap = L.tileLayer('https://server.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer/tile/{z}/{y}/{x}', { attribution: 'Tiles © Esri', maxNativeZoom:19, maxZoom:20 }); basemaps["Esri"] = Esri_WorldStreetMap; var Esri_WorldImagery = L.tileLayer('https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}', { //var Esri_WorldImagery = L.tileLayer('http://clarity.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}', { attribution:'Tiles © Esri', maxNativeZoom:17, maxZoom:20 }); basemaps["Esri Satellite"] = Esri_WorldImagery; var Esri_WorldTopoMap = L.tileLayer('https://server.arcgisonline.com/ArcGIS/rest/services/World_Topo_Map/MapServer/tile/{z}/{y}/{x}', { attribution: 'Tiles © Esri — Esri, DeLorme, NAVTEQ, TomTom, Intermap, iPC, USGS, FAO, NPS, NRCAN, GeoBase, Kadaster NL, Ordnance Survey, Esri Japan, METI, Esri China (Hong Kong), and the GIS User Community' }); basemaps["Esri Topography"] = Esri_WorldTopoMap; // var Esri_WorldShadedRelief = L.tileLayer('https://server.arcgisonline.com/ArcGIS/rest/services/World_Shaded_Relief/MapServer/tile/{z}/{y}/{x}', { // attribution: 'Tiles © Esri', // maxNativeZoom:13 // }); // basemaps["Esri Terrain"] = Esri_WorldShadedRelief; var Esri_OceanBasemap = L.tileLayer('https://server.arcgisonline.com/ArcGIS/rest/services/Ocean_Basemap/MapServer/tile/{z}/{y}/{x}', { attribution: 'Tiles © Esri — Sources: GEBCO, NOAA, CHS, OSU, UNH, CSUMB, National Geographic, DeLorme, NAVTEQ, and Esri', maxZoom: 13 }); basemaps["Esri Ocean"] = Esri_OceanBasemap; var Esri_WorldGrayCanvas = L.tileLayer('https://server.arcgisonline.com/ArcGIS/rest/services/Canvas/World_Dark_Gray_Base/MapServer/tile/{z}/{y}/{x}', { attribution: 'Tiles © Esri — Esri, DeLorme, NAVTEQ', maxZoom: 16 }); basemaps["Esri Dark Grey"] = Esri_WorldGrayCanvas; // var OpenMapSurfer_Roads = L.tileLayer('https://korona.geog.uni-heidelberg.de/tiles/roads/x={x}&y={y}&z={z}', { // maxZoom: 18, // attribution: 'Imagery from University of Heidelberg — Map data © OpenStreetMap' // }); // basemaps["Mapsurfer"] = OpenMapSurfer_Roads; // var MapQuestOpen_OSM = L.tileLayer('https://otile{s}.mqcdn.com/tiles/1.0.0/{type}/{z}/{x}/{y}.{ext}', { // type: 'map', // ext: 'jpg', // attribution: 'Tiles Courtesy of MapQuest — Map data © OpenStreetMap', // subdomains: '1234', // maxNativeZoom: 17 // }); //basemaps["MapQuest OSM"] = MapQuestOpen_OSM; var Esri_NatGeoWorldMap = L.tileLayer('https://server.arcgisonline.com/ArcGIS/rest/services/NatGeo_World_Map/MapServer/tile/{z}/{y}/{x}', { attribution: 'Tiles © Esri', maxNativeZoom:12 }); basemaps["Nat Geo"] = Esri_NatGeoWorldMap; var NLS_OS_opendata = L.tileLayer('https://geo.nls.uk/maps/opendata/{z}/{x}/{y}.png', { attribution: 'National Library of Scotland Historic Maps', bounds: [[49.6, -12], [61.7, 3]], minZoom:1, maxNativeZoom:18, maxZoom:18, subdomains: '0123' }); basemaps["UK OS Opendata"] = NLS_OS_opendata; var Open_Topo_Map = L.tileLayer('https://{s}.tile.opentopomap.org/{z}/{x}/{y}.png', { subdomains: 'abc', maxZoom: 19, attribution: '© OpenTopoMap contributors' }); basemaps["Open Topo Map"] = Open_Topo_Map; var HikeBike_HikeBike = L.tileLayer('https://tiles.wmflabs.org/hikebike/{z}/{x}/{y}.png', { maxZoom: 19, attribution: '© OpenStreetMap contributors' }); basemaps["Hike Bike"] = HikeBike_HikeBike; var NLS_OS_1919_1947 = L.tileLayer( 'https://nls-{s}.tileserver.com/nls/{z}/{x}/{y}.jpg', { attribution: 'Historical Maps Layer, from NLS Maps', bounds: [[49.6, -12], [61.7, 3]], minZoom:1, maxZoom:18, subdomains: '0123' }); basemaps["UK OS 1919-47"] = NLS_OS_1919_1947; //var NLS_OS_1900 = L.tileLayer('https://nls-{s}.tileserver.com/NLS_API/{z}/{x}/{y}.jpg', { var NLS_OS_1900 = L.tileLayer('https://nls-{s}.tileserver.com/fpsUZbzrfb5d/{z}/{x}/{y}.jpg', { attribution: 'National Library of Scotland Historic Maps', bounds: [[49.6, -12], [61.7, 3]], minZoom:1, maxNativeZoom:19, maxZoom:20, subdomains: '0123' }); basemaps["UK OS 1900"] = NLS_OS_1900; //var CartoPos = L.tileLayer('https://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}.png', { // attribution: '© OpenStreetMap contributors, © CartoDB' //}); //basemaps["CartoDB Light"] = CartoPos; // Nice terrain based maps by Stamen Design var terrainUrl = "https://stamen-tiles-{s}.a.ssl.fastly.net/terrain/{z}/{x}/{y}.jpg"; basemaps["Terrain"] = L.tileLayer(terrainUrl, { subdomains: ['a','b','c','d'], minZoom: 0, maxZoom: 20, type: 'jpg', attribution: 'Map tiles by Stamen Design, under CC BY 3.0. Data by OpenStreetMap, under CC BY SA' }); // Nice watercolour based maps by Stamen Design var watercolorUrl = "https://stamen-tiles-{s}.a.ssl.fastly.net/watercolor/{z}/{x}/{y}.jpg"; basemaps["Watercolor"] = L.tileLayer(watercolorUrl, { subdomains: ['a','b','c','d'], minZoom: 0, maxZoom: 20, type: 'jpg', attribution: 'Map tiles by Stamen Design, under CC BY 3.0. Data by OpenStreetMap, under CC BY SA' }); } // Now add the overlays // Add the drawing layer for fun... layers["_drawing"] = new L.FeatureGroup(); overlays["drawing"] = layers["_drawing"]; map.options.drawControlTooltips = false; var drawCount = 0; var drawControl = new L.Control.Draw({ draw: { polyline: { shapeOptions: { clickable:true } }, marker: false, //circle: false, circle: { shapeOptions: { clickable:true } }, circlemarker: false, rectangle: { shapeOptions: { clickable:true } }, polygon: { shapeOptions: { clickable:true } } } //edit: none // { // featureGroup: layers["_drawing"], // remove: true, // edit: true // } }); var changeDrawColour = function(col) { drawControl.setDrawingOptions({ polyline: { shapeOptions: { color:col } }, circle: { shapeOptions: { color:col } }, rectangle: { shapeOptions: { color:col } }, polygon: { shapeOptions: { color:col } } }); } var shape; map.on('draw:created', function (e) { var name = e.layerType + drawCount; drawCount = drawCount + 1; e.layer.on('contextmenu', function(e) { L.DomEvent.stopPropagation(e); var rmen = L.popup({offset:[0,-12]}).setLatLng(e.latlng); rmen.setContent("
"); map.openPopup(rmen); }); var la, lo, cent; if (e.layer.hasOwnProperty("_latlng")) { la = e.layer._latlng.lat; lo = e.layer._latlng.lng; cent = e.layer._latlng; } else { cent = e.layer.getBounds().getCenter(); } var m = {action:"draw", name:name, layer:"_drawing", options:e.layer.options, radius:e.layer._mRadius, lat:la, lon:lo}; if (e.layer.hasOwnProperty("_latlngs")) { if (e.layer.options.fill === false) { m.line = e.layer._latlngs; } else { m.area = e.layer._latlngs[0]; } } shape = {m:m, layer:e.layer}; polygons[name] = shape.layer; polygons[name].lay = "_drawing"; polygons[name].name = name; layers["_drawing"].addLayer(shape.layer); var rightmenuMarker = L.popup({offset:[0,-12]}).setContent("
"); if (e.layer.options.fill === false && navigator.onLine) { rightmenuMarker = L.popup({offset:[0,-12]}).setContent("
"); } rightmenuMarker.setLatLng(cent); setTimeout(function() {map.openPopup(rightmenuMarker)},25); }); var defaultOptions = function () { var options = {}; options.precision = 5; options.factor = Math.pow(10, options.precision); options.dimension = 2; return options; }; var decode = function (encoded, options) { options = defaultOptions(options); var flatPoints = decodeDeltas(encoded); var points = []; for (var i = 0, len = flatPoints.length; i + (options.dimension - 1) < len;) { var point = []; for (var dim = 0; dim < options.dimension; ++dim) { point.push(flatPoints[i++]); } points.push(point); } return points; } var decodeDeltas = function (encoded, options) { options = defaultOptions(options); var lastNumbers = []; var numbers = decodeFloats(encoded, options); for (var i = 0, len = numbers.length; i < len;) { for (var d = 0; d < options.dimension; ++d, ++i) { numbers[i] = Math.round((lastNumbers[d] = numbers[i] + (lastNumbers[d] || 0)) * options.factor) / options.factor; } } return numbers; } var decodeFloats = function (encoded, options) { options = defaultOptions(options); var numbers = decodeSignedIntegers(encoded); for (var i = 0, len = numbers.length; i < len; ++i) { numbers[i] /= options.factor; } return numbers; } var decodeSignedIntegers = function (encoded) { var numbers = decodeUnsignedIntegers(encoded); for (var i = 0, len = numbers.length; i < len; ++i) { var num = numbers[i]; numbers[i] = (num & 1) ? ~(num >> 1) : (num >> 1); } return numbers; } var decodeUnsignedIntegers = function (encoded) { var numbers = []; var current = 0; var shift = 0; for (var i = 0, len = encoded.length; i < len; ++i) { var b = encoded.charCodeAt(i) - 63; current |= (b & 0x1f) << shift; if (b < 0x20) { numbers.push(current); current = 0; shift = 0; } else { shift += 5; } } return numbers; } var sendRoute = function(n) { var p = (polygons[n]._latlngs.map(function(x) { return x.lng+","+x.lat; })).join(';'); fetch('https://router.project-osrm.org/route/v1/driving/'+p) .then(response => response.json()) .then(data => { if (data.code !== "Ok") { sendDrawing(n); } var r = decode(data.routes[0].geometry).map( x => L.latLng(x[0],x[1]) ); polygons[n]._latlngs = r; shape.m.line = r; sendDrawing(n); }); } var sendDrawing = function(n) { var thing = document.getElementById('dinput').value; map.closePopup(); shape.m.name = thing; delMarker(n,true); polygons[thing] = shape.layer; polygons[thing].lay = "_drawing"; polygons[thing].name = thing; layers["_drawing"].addLayer(shape.layer); ws.send(JSON.stringify(shape.m)); } // Add the countries (world-110m) for offline use var customTopoLayer = L.geoJson(null, {clickable:false, style: {color:"blue", weight:2, fillColor:"#cf6", fillOpacity:0.04}}); layers["_countries"] = omnivore.topojson('images/world-50m-flat.json',null,customTopoLayer); overlays["countries"] = layers["_countries"]; // Add the day/night overlay layers["_daynight"] = new L.LayerGroup(); overlays["day/night"] = layers["_daynight"]; // Add live rain data if (navigator.onLine) { overlays["rainfall"] = new L.TileLayer('https://tilecache.rainviewer.com/v2/radar/' + parseInt(Date.now()/600000)*600 + '/256/{z}/{x}/{y}/2/1_1.png', { tileSize: 256, opacity: 0.4, transparent: true, attribution: 'rainviewer.com' }); // Add the buildings layer // overlays["buildings"] = new OSMBuildings(map).load(); // map.removeLayer(overlays["buildings"]); // Hide it at start // Add Roads // overlays["roads"] = L.tileLayer('https://{s}.tile.openstreetmap.se/hydda/roads_and_labels/{z}/{x}/{y}.png', { // maxZoom: 18, // attribution: 'Tiles courtesy of OpenStreetMap Sweden — Map data © OpenStreetMap', // opacity: 0.8 // }); // // Add Railways // overlays["railways"] = L.tileLayer('https://{s}.tiles.openrailwaymap.org/standard/{z}/{x}/{y}.png', { // maxZoom: 19, // attribution: 'Map data: © OpenStreetMap | Map style: © OpenRailwayMap (CC-BY-SA)' // }); // // Add Public Transport (Buses) // overlays["public transport"] = L.tileLayer('https://openptmap.org/tiles/{z}/{x}/{y}.png', { // maxZoom: 17, // attribution: 'Map data: © OpenPtMap contributors' // }); // Add the OpenSea markers layer overlays["ship nav"] = L.tileLayer('https://tiles.openseamap.org/seamark/{z}/{x}/{y}.png', { maxZoom: 19, attribution: 'Map data: © OpenSeaMap contributors' }); } // Add the heatmap layer var heat = L.heatLayer([], {radius:60, gradient:{0.2:'blue', 0.4:'lime', 0.6:'red', 0.8:'yellow', 1:'white'}}); layers["_heat"] = new L.LayerGroup().addLayer(heat); overlays["heatmap"] = layers["_heat"]; if (showUserMenu) { if ( window.localStorage.hasOwnProperty("lastlayer") ) { if ( basemaps[window.localStorage.getItem("lastlayer")] ) { baselayername = window.localStorage.getItem("lastlayer"); } } } if (navigator.onLine) { basemaps[baselayername].addTo(map); } // Layer control based on select box rather than radio buttons. //var layercontrol = L.control.selectLayers(basemaps, overlays).addTo(map); layercontrol = L.control.layers(basemaps, overlays); // Add the layers control widget if (!inIframe) { layercontrol.addTo(map); } else { showLayerMenu = false;} var coords = L.control.coordinates({ position:"bottomleft", //optional default "bottomright" decimals:4, //optional default 4 decimalSeperator:".", //optional default "." labelTemplateLat:" Lat: {y}", //optional default "Lat: {y}" labelTemplateLng:" Lon: {x}", //optional default "Lng: {x}" enableUserInput:false, //optional default true useDMS:true, //optional default false useLatLngOrder: true, //ordering of labels, default false-> lng-lat }); // Add an optional legend var legend = L.control({ position: "bottomleft" }); // Add the dialog box for messages var dialogue = L.control.dialog({initOpen:false, size:[600,400], anchor:[50,150]}).addTo(map); dialogue.freeze(); var doDialog = function(d) { //console.log("DIALOGUE",d); dialogue.setContent(d); dialogue.open(); } var helpText = '

Node-RED - Map all the things


'; helpText += '

Search - You may enter a name, or partial name, or icon name of an object to search for.'; helpText += 'The map will then jump to centre on each of the results in turn. If nothing is found locally it will try to'; helpText += 'search for a place name if connected to a network.

'; helpText += '

Set Max Age - You can set the time after which points'; helpText += 'that haven\'t been updated get removed.

'; helpText += '

Cluster at zoom - lower numbers mean less clustering. 0 means disable totally.

'; helpText += '

Auto Pan - When selected, the map will'; helpText += 'automatically move to centre on each data point as they arrive.

'; helpText += '

Lock Map - When selected will save the'; helpText += 'currently displayed area and basemap.'; helpText += 'Reloading the map in the current browser will return to the same view.'; helpText += 'This can be used to set your initial start position.'; helpText += 'While active it also restricts the "auto pan" and "search" to within that area.

'; helpText += '

Heatmap all layers - When selected'; helpText += 'all layers whether hidden or not will contribute to the heatmap.'; helpText += 'The default is that only visible layers add to the heatmap.

'; // Delete a marker (and notify websocket) var delMarker = function(dname,note) { if (note) { map.closePopup(); } if (typeof polygons[dname] != "undefined") { layers[polygons[dname].lay].removeLayer(polygons[dname]); delete polygons[dname]; } if (typeof polygons[dname+"_"] != "undefined") { layers[polygons[dname+"_"].lay].removeLayer(polygons[dname+"_"]); delete polygons[dname+"_"]; } if (typeof markers[dname] != "undefined") { layers[markers[dname].lay].removeLayer(markers[dname]); map.removeLayer(markers[dname]); delete markers[dname]; } delete allData[dname]; if (note) { ws.send(JSON.stringify({action:"delete", name:dname, deleted:true})); } } var editPoly = function(pname) { map.closePopup(); editFeatureGroup = L.featureGroup(); editToolbar = new L.EditToolbar({ featureGroup:editFeatureGroup }); editHandler = editToolbar.getModeHandlers()[0].handler; editHandler._map = map; polygons[pname].on("dblclick", function(e) { editHandler.disable(); editFeatureGroup.removeLayer(polygons[pname]); polygons[pname].off("dblclick"); L.DomEvent.stopPropagation(e); var la, lo; if (e.target.hasOwnProperty("_latlng")) { la = e.target._latlng.lat; lo = e.target._latlng.lng; } var m = {action:"draw", name:pname, layer:polygons[pname].lay, options:e.target.options, radius:e.target._mRadius, lat:la, lon:lo}; if (e.target.hasOwnProperty("_latlngs")) { if (e.target.options.fill === false) { m.line = e.target._latlngs; } else { m.area = e.target._latlngs[0]; } } ws.send(JSON.stringify(m)); }) editFeatureGroup.addLayer(polygons[pname]); editHandler.enable(); } var rangerings = function(latlng, options) { options = L.extend({ ranges: [250,500,750,1000], pan: 0, fov: 60, color: '#910000' }, options); var rings = L.featureGroup(); if (typeof options.ranges === "number") { options.ranges = [ options.ranges ]; } for (var i = 0; i < options.ranges.length; i++) { L.semiCircle(latlng, { radius: options.ranges[i], fill: false, color: options.color, weight: options.weight || 1 }).setDirection(options.pan, options.fov).addTo(rings); } return rings; } // the MAIN add something to map function function setMarker(data) { var rightmenu = function(m) { // customise right click context menu var rightcontext = ""; if (polygons[data.name] == undefined) { rightcontext = ""; } if (data.editable) { rightcontext = ""; } if ((data.contextmenu !== undefined) && (typeof data.contextmenu === "string")) { rightcontext = data.contextmenu.replace(/\$name/g,'"'+data.name+'"'); delete data.contextmenu; } if (rightcontext.length > 0) { var rightmenuMarker = L.popup({offset:[0,-12]}).setContent(""+data.name+"
"+rightcontext); if (hiderightclick !== true) { m.on('contextmenu', function(e) { L.DomEvent.stopPropagation(e); rightmenuMarker.setLatLng(e.latlng); map.openPopup(rightmenuMarker); }); } } else { if (hiderightclick !== true) { m.on('contextmenu', function(e) { L.DomEvent.stopPropagation(e); }); } } return m; } //console.log("DATA" typeof data, data); if (data.deleted) { // remove markers we are told to delMarker(data.name); return; } var ll; var lli = null; var opt = {}; opt.color = data.color || data.lineColor || "#910000"; opt.fillColor = data.fillColor || "#910000"; opt.stroke = (data.hasOwnProperty("stroke")) ? data.stroke : true; opt.weight = data.weight || 2; opt.opacity = data.opacity || 1; opt.fillOpacity = data.fillOpacity || 0.2; opt.clickable = (data.hasOwnProperty("clickable")) ? data.clickable : false; opt.fill = (data.hasOwnProperty("fill")) ? data.fill : true; if (data.hasOwnProperty("dashArray")) { opt.dashArray = data.dashArray; } // Replace building if (data.hasOwnProperty("building")) { if ((data.building === "") && layers.hasOwnProperty("buildings")) { map.removeLayer(layers["buildings"]); layercontrol._update(); layers["buildings"] = overlays["buildings"].set(""); return; } //layers["buildings"] = new OSMBuildings(map).set(data.building); layers["buildings"] = overlays["buildings"].set(data.building); map.addLayer(layers["buildings"]); return; } var lay = data.layer || "unknown"; if (!data.hasOwnProperty("action") || data.action.indexOf("layer") === -1) { if (typeof layers[lay] == "undefined") { // add layer if if doesn't exist if (clusterAt > 0) { layers[lay] = new L.MarkerClusterGroup({ maxClusterRadius:50, spiderfyDistanceMultiplier:1.8, disableClusteringAtZoom:clusterAt //zoomToBoundsOnClick:false }); } else { layers[lay] = new L.LayerGroup(); } overlays[lay] = layers[lay]; if (showLayerMenu !== false) { layercontrol.addOverlay(layers[lay],lay); } map.addLayer(overlays[lay]); //console.log("ADDED LAYER",lay,layers); } if (!allData.hasOwnProperty(data.name)) { allData[data.name] = {}; } delete data.action; Object.keys(data).forEach(function(key) { if (data[key] == null) { delete allData[data.name][key]; } else { allData[data.name][key] = data[key]; } }); data = Object.assign({},allData[data.name]); } delete data.action; if (typeof markers[data.name] != "undefined") { if (markers[data.name].lay !== lay) { delMarker(data.name); } else { try {layers[lay].removeLayer(markers[data.name]); } catch(e) { console.log("OOPS"); } } } if (typeof polygons[data.name] != "undefined") { layers[lay].removeLayer(polygons[data.name]); } if (data.hasOwnProperty("line") && Array.isArray(data.line)) { delete opt.fill; if (!data.hasOwnProperty("weight")) { opt.weight = 3; } //Standard settings different for lines if (!data.hasOwnProperty("opacity")) { opt.opacity = 0.8; } var polyln = L.polyline(data.line, opt); polygons[data.name] = rightmenu(polyln); } else if (data.hasOwnProperty("area") && Array.isArray(data.area)) { var polyarea; if (data.area.length === 2) { polyarea = L.rectangle(data.area, opt); } else { polyarea = L.polygon(data.area, opt); } polygons[data.name] = rightmenu(polyarea); } else if (data.hasOwnProperty("sdlat") && data.hasOwnProperty("sdlon")) { if (!data.hasOwnProperty("iconColor")) { opt.color = "blue"; } //different standard Color Settings if (!data.hasOwnProperty("fillColor")) { opt.fillColor = "blue"; } var ellipse = L.ellipse(new L.LatLng((data.lat*1), (data.lon*1)), [200000*data.sdlon*Math.cos(data.lat*Math.PI/180), 200000*data.sdlat], 0, opt); polygons[data.name] = rightmenu(ellipse); } else if (data.hasOwnProperty("radius")) { if (data.hasOwnProperty("lat") && data.hasOwnProperty("lon")) { var polycirc; if (Array.isArray(data.radius)) { polycirc = L.ellipse(new L.LatLng((data.lat*1), (data.lon*1)), [data.radius[0]*Math.cos(data.lat*Math.PI/180), data.radius[1]], data.tilt || 0, opt); } else { polycirc = L.circle(new L.LatLng((data.lat*1), (data.lon*1)), data.radius*1, opt); } polygons[data.name] = rightmenu(polycirc); if (!data.hasOwnProperty("icon")) { delete (data.lat); delete (data.lon); } } } else if (data.hasOwnProperty("arc")) { if (data.hasOwnProperty("lat") && data.hasOwnProperty("lon")) { polygons[data.name] = rangerings(new L.LatLng((data.lat*1), (data.lon*1)), data.arc); } } else if (data.hasOwnProperty("geojson")) { doGeojson(data.name,data.geojson,(data.layer || "unknown"),opt); } if (polygons[data.name] !== undefined) { polygons[data.name].lay = lay; if (opt.clickable === true) { var words = ""+data.name+""; if (data.popup) { words = words + "
" + data.popup; } polygons[data.name].bindPopup(words, {autoClose:false, closeButton:true, closeOnClick:false, minWidth:200}); } //polygons[data.name] = rightmenu(polygons[data.name]); // DCJ Investigate layers[lay].addLayer(polygons[data.name]); } if (typeof data.coordinates == "object") { ll = new L.LatLng(data.coordinates[1],data.coordinates[0]); } else if (data.hasOwnProperty("position") && data.position.hasOwnProperty("lat") && data.position.hasOwnProperty("lon")) { data.lat = data.position.lat*1; data.lon = data.position.lon*1; data.alt = data.position.alt; if (parseFloat(data.position.alt) == data.position.alt) { data.alt = data.position.alt + " m"; } delete data.position; ll = new L.LatLng((data.lat*1), (data.lon*1)); } else if (data.hasOwnProperty("lat") && data.hasOwnProperty("lon")) { ll = new L.LatLng((data.lat*1), (data.lon*1)); } else if (data.hasOwnProperty("latitude") && data.hasOwnProperty("longitude")) { ll = new L.LatLng((data.latitude*1), (data.longitude*1)); } else { // console.log("No location:",data); return; } // Adding new L.LatLng object (lli) when optional intensity value is defined. Only for use in heatmap layer if (typeof data.coordinates == "object") { lli = new L.LatLng(data.coordinates[2],data.coordinates[1],data.coordinates[0]); } else if (data.hasOwnProperty("lat") && data.hasOwnProperty("lon") && data.hasOwnProperty("intensity")) { lli = new L.LatLng((data.lat*1), (data.lon*1), (data.intensity*1)); } else if (data.hasOwnProperty("latitude") && data.hasOwnProperty("longitude") && data.hasOwnProperty("intensity")) { lli = new L.LatLng((data.latitude*1), (data.longitude*1), (data.intensity*1)); } else { lli = ll } // Create the icons... handle plane, car, ship, wind, earthquake as specials var marker, myMarker; var icon, q; var words = ""; var labelOffset = [12,0]; var drag = false; if (data.draggable === true) { drag = true; } if (data.hasOwnProperty("icon")) { var dir = parseFloat(data.hdg || data.heading || data.bearing || "0"); if (data.icon === "ship") { marker = L.boatMarker(ll, { title: data.name, color: (data.iconColor || "blue") }); marker.setHeading(dir); q = 'https://www.bing.com/images/search?q='+data.icon+'%20%2B"'+encodeURIComponent(data.name)+'"'; words += 'Pictures
'; } else if (data.icon === "plane") { data.iconColor = data.iconColor || "black"; if (data.hasOwnProperty("squawk")) { if (data.squawk == 7500 || data.squawk == 7600 || data.squawk == 7700) { data.iconColor = "red"; } } icon = ''; icon += ''; var svgplane = "data:image/svg+xml;base64," + btoa(icon); myMarker = L.divIcon({ className:"planeicon", iconAnchor: [16, 16], html:'' }); marker = L.marker(ll, {title:data.name, icon:myMarker, draggable:drag}); //q = 'https://www.bing.com/images/search?q='+data.icon+'%20'+encodeURIComponent(data.name); //words += 'Pictures
'; } else if (data.icon === "bus") { dir = dir - 90; var sc = 1; if (dir < -90 || dir >= 90) { sc = -1; } data.iconColor = data.iconColor || "#910000"; var p = "m595.5 97.332-30.898-68.199c-11.141-24.223-35.344-39.762-62.004-39.801h-443.3c-32.738 0.035157-59.266 26.562-59.301 59.305v148.2c0 17.949 14.551 32.5 32.5 32.5h48.5c4.7344 23.309 25.219 40.051 49 40.051s44.266-16.742 49-40.051h242c4.7344 23.309 25.219 40.051 49 40.051s44.266-16.742 49-40.051h53.203c12.348-0.003906 23.219-8.1484 26.699-20 0.72266-2.5391 1.0898-5.1602 1.0977-7.7969v-83.5c-0.003906-7.1445-1.5391-14.203-4.5-20.703zm-545.5 12c-5.5234 0-10-4.4766-10-10v-80c0-5.5195 4.4766-10 10-10h70c5.5234 0 10 4.4805 10 10v80c0 5.5234-4.4766 10-10 10zm80 140c-16.566 0-30-13.43-30-30 0-16.566 13.434-30 30-30s30 13.434 30 30c-0.046875 16.551-13.453 29.953-30 30zm110-150c0 5.5234-4.4766 10-10 10h-70c-5.5234 0-10-4.4766-10-10v-80c0-5.5195 4.4766-10 10-10h70c5.5234 0 10 4.4805 10 10zm110 0c0 5.5234-4.4766 10-10 10h-70c-5.5234 0-10-4.4766-10-10v-80c0-5.5195 4.4766-10 10-10h70c5.5234 0 10 4.4805 10 10zm30 10c-5.5234 0-10-4.4766-10-10v-80c0-5.5195 4.4766-10 10-10h70c5.5234 0 10 4.4805 10 10v80c0 5.5234-4.4766 10-10 10zm90 140c-16.566 0-30-13.43-30-30 0-16.566 13.434-30 30-30s30 13.434 30 30c-0.046875 16.551-13.453 29.953-30 30zm19.199-140c-5.1836-0.46094-9.168-4.793-9.1992-10v-80.086c0-5.4727 4.4375-9.9141 9.9141-9.9141h12.684c18.824 0.050781 35.914 11.012 43.805 28.102l30.898 68.199c1.6133 3.5547 2.5 7.3984 2.6016 11.297z"; icon = ''; icon += ''; var svgbus = "data:image/svg+xml;base64," + btoa(icon); myMarker = L.divIcon({ className:"busicon", iconAnchor: [16, 16], html:'' }); marker = L.marker(ll, {title:data.name, icon:myMarker, draggable:drag}); } else if (data.icon === "helicopter") { data.iconColor = data.iconColor || "black"; if (data.hasOwnProperty("squawk")) { if (data.squawk == 7500 || data.squawk == 7600 || data.squawk == 7700) { data.iconColor = "red"; } } icon = ''; icon += ''; var svgheli = "data:image/svg+xml;base64," + btoa(icon); myMarker = L.divIcon({ className:"heliicon", iconAnchor: [16, 16], html:'' }); marker = L.marker(ll, {title:data.name, icon:myMarker, draggable:drag}); } else if (data.icon === "uav") { data.iconColor = data.iconColor || "black"; if (data.hasOwnProperty("squawk")) { if (data.squawk == 7500 || data.squawk == 7600 || data.squawk == 7700) { data.iconColor = "red"; } } icon = ''; icon+= ''; var svguav = "data:image/svg+xml;base64," + btoa(icon); myMarker = L.divIcon({ className:"uavicon", iconAnchor: [16, 16], html:'', }); marker = L.marker(ll, {title:data.name, icon:myMarker, draggable:drag}); } else if (data.icon === "car") { data.iconColor = data.iconColor || "black"; icon = ''; icon += ''; var svgcar = "data:image/svg+xml;base64," + btoa(icon); myMarker = L.divIcon({ className:"caricon", iconAnchor: [16, 16], html:'', }); marker = L.marker(ll, {title:data.name, icon:myMarker, draggable:drag}); } else if (data.icon === "arrow") { data.iconColor = data.iconColor || "black"; icon = ''; icon += ''; var svgarrow = "data:image/svg+xml;base64," + btoa(icon); myMarker = L.divIcon({ className:"arrowicon", iconAnchor: [16, 16], html:"'", }); marker = L.marker(ll, {title:data.name, icon:myMarker, draggable:drag}); } else if (data.icon === "wind") { data.iconColor = data.iconColor || "black"; icon = ''; icon += ''; var svgwind = "data:image/svg+xml;base64," + btoa(icon); myMarker = L.divIcon({ className:"windicon", iconAnchor: [16, 16], html:'', }); marker = L.marker(ll, {title:data.name, icon:myMarker, draggable:drag}); } else if (data.icon === "satellite") { data.iconColor = data.iconColor || "black"; icon = ''; icon += ''; icon += ''; icon += ''; icon += ''; icon += ''; icon += ''; var svgsat = "data:image/svg+xml;base64," + btoa(icon); myMarker = L.divIcon({ className:"satelliteicon", iconAnchor: [16, 16], html:'', }); marker = L.marker(ll, {title:data.name, icon:myMarker, draggable:drag}); } else if ((data.icon === "iss") || (data.icon === "ISS")) { data.iconColor = data.iconColor || "black"; icon = ''; icon += ''; icon += ''; var svgiss = "data:image/svg+xml;base64," + btoa(icon); myMarker = L.divIcon({ className:"issicon", iconAnchor: [25, 25], html:'', }); marker = L.marker(ll, {title:data.name, icon:myMarker, draggable:drag}); } else if (data.icon === "locate") { data.iconColor = data.iconColor || "cyan"; icon = ''; icon += ''; icon += ''; icon += ''; icon += ''; //icon += ''; icon += ''; var svglocate = "data:image/svg+xml;base64," + btoa(icon); myMarker = L.divIcon({ className:"locateicon", iconAnchor: [16, 16], html:'', }); marker = L.marker(ll, {title:data.name, icon:myMarker, draggable:drag}); labelOffset = [12,-4]; } else if (data.icon === "friend") { marker = L.marker(ll, { icon: L.divIcon({ className: 'circle f', iconSize: [20, 12] }), title: data.name, draggable:drag }); } else if (data.icon === "hostile") { marker = L.marker(ll, { icon: L.divIcon({ className: 'circle h', iconSize: [16, 16] }), title: data.name, draggable:drag }); } else if (data.icon === "neutral") { marker = L.marker(ll, { icon: L.divIcon({ className: 'circle n', iconSize: [16, 16] }), title: data.name, draggable:drag }); } else if (data.icon === "unknown") { marker = L.marker(ll, { icon: L.divIcon({ className: 'circle', iconSize: [16, 16] }), title: data.name, draggable:drag }); } else if (data.icon === "danger") { marker = L.marker(ll, { icon: L.divIcon({ className: 'up-triangle' }), title: data.name, draggable:drag }); } else if (data.icon === "earthquake") { marker = L.marker(ll, { icon: L.divIcon({ className: 'circle e', iconSize: [data.mag*5, data.mag*5] }), title: data.name, draggable:drag }); } else if (data.icon.match(/^:.*:$/g)) { var em = emojify(data.icon); var col = data.iconColor || "#910000"; myMarker = L.divIcon({ className:"emicon", html: '
'+em+'
', iconSize: [32, 32] }); marker = L.marker(ll, {title:data.name, icon:myMarker, draggable:drag}); labelOffset = [12,-4]; } else if (data.icon.match(/^https?:.*$/)) { var sz = data.iconSize || 32; myMarker = L.icon({ iconUrl: data.icon, iconSize: [sz, sz], iconAnchor: [sz/2, sz/2], popupAnchor: [0, -sz/2] }); marker = L.marker(ll, {title:data.name, icon:myMarker, draggable:drag, rotationAngle:dir, rotationOrigin:"center"}); labelOffset = [sz/2-4,-4]; delete data.iconSize; } else if (data.icon.substr(0,3) === "fa-") { var col = data.iconColor || "#910000"; var imod = ""; if (data.icon.indexOf(" ") === -1) { imod = "fa-2x "; } myMarker = L.divIcon({ className:"faicon", html: '
', iconSize: [32, 32], iconAnchor: [16, 12], popupAnchor: [0, -16] }); marker = L.marker(ll, {title:data.name, icon:myMarker, draggable:drag}); labelOffset = [8,-8]; } else if (data.icon.substr(0,3) === "wi-") { var col = data.iconColor || "#910000"; var imod = ""; if (data.icon.indexOf(" ") === -1) { imod = "wi-2x "; } myMarker = L.divIcon({ className:"wiicon", html: '
', iconSize: [32, 32], iconAnchor: [16, 16], popupAnchor: [0, -16] }); marker = L.marker(ll, {title:data.name, icon:myMarker, draggable:drag}); labelOffset = [16,-16]; } else { myMarker = L.VectorMarkers.icon({ icon: data.icon || "circle", markerColor: (data.iconColor || "#910000"), prefix: 'fa', iconColor: 'white' }); marker = L.marker(ll, {title:data.name, icon:myMarker, draggable:drag}); labelOffset = [6,-6]; } } else if (data.hasOwnProperty("SIDC")) { // "SIDC":"SFGPU------E***","name":"1.C2 komp","fullname":"1.C2 komp/FTS/INSS" myMarker = new ms.Symbol( data.SIDC.toUpperCase(), { uniqueDesignation:data.name }); // Now that we have a symbol we can ask for the echelon and set the symbol size var opts = data.options || {}; var sz = 30; if (myMarker.hasOwnProperty("getProperties") && myMarker.getProperties().hasOwnProperty("echelon")) { sz = iconSz[myMarker.getProperties().echelon]; } opts.size = opts.size || sz; opts.size = opts.size * 0.8 * (opts.scale || 1); myMarker = myMarker.setOptions(opts); var myicon = L.icon({ iconUrl: myMarker.toDataURL(), iconAnchor: [myMarker.getAnchor().x, myMarker.getAnchor().y], className: "natoicon", }); marker = L.marker(ll, { title:data.name, icon:myicon, draggable:drag }); } else { myMarker = L.VectorMarkers.icon({ icon: "circle", markerColor: (data.iconColor || "#910000"), prefix: 'fa', iconColor: 'white' }); marker = L.marker(ll, {title:data.name, icon:myMarker, draggable:drag}); labelOffset = [6,-6]; } marker.name = data.name; // var createLabelIcon = function(labelText) { // return L.marker(new L.LatLng(51.05, -1.35), {icon:L.divIcon({ html:labelText })}); // } // send new position at end of move event if point is draggable if (data.draggable === true) { if (data.icon) { marker.icon = data.icon; } if (data.iconColor) { marker.iconColor = data.iconColor; } if (data.SIDC) { marker.SIDC = data.SIDC.toUpperCase(); } var oldll; marker.on('dragstart', function (e) { oldll = marker.getLatLng(); var ola = parseFloat(oldll.lat.toFixed(6)); var olo = parseFloat(oldll.lng.toFixed(6)); oldll = {lat:ola, lon:olo}; }); marker.on('dragend', function (e) { var l = marker.getLatLng().toString().replace('LatLng(','lat, lon : ').replace(')','') marker.setPopupContent(marker.getPopup().getContent().split("lat, lon")[0] + l); var b = marker.getPopup().getContent().split("heading : "); if (b.length === 2) { b = parseFloat(b[1].split(""; delete data.photourl; } if (data.hasOwnProperty("photoUrl")) { words += ""; delete data.photoUrl; } if (data.hasOwnProperty("videoUrl")) { words += ''; delete data.videoUrl; } if (data.hasOwnProperty("ttl")) { // save expiry time for this marker if (data.ttl != 0) { marker.ts = parseInt(Date.now()/1000) + Number(data.ttl); } delete data.ttl; } else if (maxage != 0) { marker.ts = parseInt(Date.now()/1000) + Number(maxage); } if (data.hasOwnProperty("weblink")) { if (!Array.isArray(data.weblink) || !data.weblink.length) { if (typeof data.weblink === "string") { words += "more information...
"; } else { var tgt = data.weblink.target || "_new"; words += "" + data.weblink.name + "
"; } } else { data.weblink.forEach(function(weblink){ if (typeof weblink === "string") { words += "more information...
"; } else { var tgt = weblink.target || "_new"; words += "" + weblink.name + "
"; } }); } delete data.weblink; } var p; if (data.hasOwnProperty("popped") && (data.popped === true)) { p = true; delete data.popped; } if (data.hasOwnProperty("popped") && (data.popped === false)) { marker.closePopup(); p = false; delete data.popped; } // If .label then use that rather than name tooltip if (data.label) { if (typeof data.label === "boolean" && data.label === true) { marker.bindTooltip(data.name, { permanent:true, direction:"right", offset:labelOffset }); } else if (typeof data.label === "string" && data.label.length > 0) { marker.bindTooltip(data.label, { permanent:true, direction:"right", offset:labelOffset }); } delete marker.options.title; delete data.label; } // otherwise check for .tooltip then use that rather than name tooltip else if (data.tooltip) { if (typeof data.tooltip === "string" && data.tooltip.length > 0) { marker.bindTooltip(data.tooltip, { direction:"bottom", offset:[0,4] }); delete marker.options.title; delete data.tooltip; } } marker = rightmenu(marker); // Add any remaining properties to the info box var llc = data.lineColor || data.color; delete data.lat; delete data.lon; if (data.arc) { delete data.arc; } if (data.layer) { delete data.layer; } if (data.lineColor) { delete data.lineColor; } if (data.color) { delete data.color; } if (data.weight) { delete data.weight; } if (data.tracklength) { delete data.tracklength; } if (data.dashArray) { delete data.dashArray; } if (data.fill) { delete data.fill; } if (data.draggable) { delete data.draggable; } if (data.hasOwnProperty("clickable")) { delete data.clickable; } if (data.hasOwnProperty("fillColor")) { delete data.fillColor; } if (data.hasOwnProperty("radius")) { delete data.radius; } for (var i in data) { if ((i != "name") && (i != "length")) { if (typeof data[i] === "object") { words += i +" : "+JSON.stringify(data[i])+"
"; } else { words += i +" : "+data[i]+"
"; } } } if (data.popup) { words = data.popup; } else { words = words + marker.getLatLng().toString().replace('LatLng(','lat, lon : ').replace(')',''); } words = ""+data.name+"
" + words; //"
" + words; marker.bindPopup(words, {autoClose:false, closeButton:true, closeOnClick:false, minWidth:200}); marker._popup.dname = data.name; marker.lay = lay; // and the layer it is on marker.on('click', function(e) { ws.send(JSON.stringify({action:"click",name:marker.name,layer:marker.lay,icon:marker.icon,iconColor:marker.iconColor,SIDC:marker.SIDC,draggable:true,lat:parseFloat(marker.getLatLng().lat.toFixed(6)),lon:parseFloat(marker.getLatLng().lng.toFixed(6))})); }); if ((data.addtoheatmap !== "false") || (!data.hasOwnProperty("addtoheatmap"))) { // Added to give ability to control if points from active layer contribute to heatmap if (heatAll || map.hasLayer(layers[lay])) { heat.addLatLng(lli); } } markers[data.name] = marker; layers[lay].addLayer(marker); var track; if (data.track !== undefined) { track = data.track; } else if (data.hdg !== undefined) { track = data.hdg; } else if (data.heading !== undefined) { track = data.heading; } else if (data.bearing !== undefined) { track = data.bearing; } if (track != undefined) { // if there is a heading if (data.speed != null) { data.length = parseFloat(data.speed || "0") * 60; } // and a speed if (data.length != null) { if (polygons[data.name] != null && !polygons[data.name].hasOwnProperty("_layers")) { map.removeLayer(polygons[data.name]); } if (polygons[data.name] != null && polygons[data.name].hasOwnProperty("name") ) { delete(layers[lay]._layers[polygons[data.name]._leaflet_id]); } var x = ll.lng * 1; // X coordinate var y = ll.lat * 1; // Y coordinate var ll1 = ll; var angle = parseFloat(track); var lengthAsDegrees = parseFloat(data.length || "0") / 110540; // metres in a degree..ish var polygon = null; if (data.accuracy != null) { data.accuracy = Number(data.accuracy); var y2 = y + Math.sin((90-angle+data.accuracy)/180*Math.PI)*lengthAsDegrees; var x2 = x + Math.cos((90-angle+data.accuracy)/180*Math.PI)*lengthAsDegrees/Math.cos(y/180*Math.PI); var ll2 = new L.LatLng(y2,x2); var y3 = y + Math.sin((90-angle-data.accuracy)/180*Math.PI)*lengthAsDegrees; var x3 = x + Math.cos((90-angle-data.accuracy)/180*Math.PI)*lengthAsDegrees/Math.cos(y/180*Math.PI); var ll3 = new L.LatLng(y3,x3); polygon = L.polygon([ ll1, ll2, ll3 ], {weight:2, color:llc||'#900', fillOpacity:0.06, clickable:false}); } else { var ya = y + Math.sin((90-angle)/180*Math.PI)*lengthAsDegrees; var xa = x + Math.cos((90-angle)/180*Math.PI)*lengthAsDegrees/Math.cos(y/180*Math.PI); var lla = new L.LatLng(ya,xa); polygon = L.polygon([ ll1, lla ], {weight:2, color:llc||'#900', clickable:false}); } if (typeof layers[lay].getVisibleParent === 'function') { var vis = layers[lay].getVisibleParent(marker); if ((polygon !== null) && (vis !== null) && (!vis.hasOwnProperty("lay"))) { polygon.setStyle({opacity:0}); } } polygon.name = data.name; if (polygons[data.name] != null && polygons[data.name].hasOwnProperty("_layers")) { polygons[data.name].addLayer(polygon); } else { polygons[data.name] = polygon; } polygons[data.name].lay = lay; layers[lay].addLayer(polygon); } } if (panit) { map.setView(ll,map.getZoom()); } if (p === true) { marker.openPopup(); } } // handle any incoming COMMANDS to control the map remotely function doCommand(cmd) { //console.log("COMMAND",cmd); if (cmd.hasOwnProperty("toptitle")) { if (!inIframe ) { document.title = cmd.toptitle; document.getElementById("topwords").innerText = cmd.toptitle; } } if (cmd.hasOwnProperty("clear")) { doTidyUp(cmd.clear); } if (cmd.hasOwnProperty("panit")) { if (cmd.panit == "true") { panit = true; } else { panit = false; } document.getElementById("panit").checked = panit; } if (cmd.hasOwnProperty("hiderightclick")) { if (cmd.hiderightclick == "true" || cmd.hiderightclick == true) { hiderightclick = true; } else { hiderightclick = false; } } if (cmd.hasOwnProperty("showmenu")) { if ((cmd.showmenu === "hide") && (showUserMenu === true)) { showUserMenu = false; if (inIframe) { if (menuButton) { try { map.removeControl(menuButton); } catch(e) {} } } else { document.getElementById("bars").style.display="none"; } } else if ((cmd.showmenu === "show") && (showUserMenu === false)) { showUserMenu = true; if (inIframe) { map.addControl(menuButton); } else { document.getElementById("bars").style.display="unset"; } } } if (cmd.hasOwnProperty("showlayers")) { if ((cmd.showlayers === "hide") && (showLayerMenu === true)) { showLayerMenu = false; if (layercontrol) { map.removeControl(layercontrol); } } else if ((cmd.showlayers === "show") && (showLayerMenu === false)) { showLayerMenu = true; layercontrol = L.control.layers(basemaps, overlays).addTo(map); } } if (cmd.hasOwnProperty("grid")) { if (cmd.grid.hasOwnProperty("showgrid")) { var changed = false; if ((cmd.grid.showgrid == "true" || cmd.grid.showgrid == true ) && !showGrid) { changed = true; } if ((cmd.grid.showgrid == "false" || cmd.grid.showgrid == false ) && showGrid) { changed = true; } if (changed) { showGrid = !showGrid; if (showGrid) { Lgrid.addTo(map); rulerButton.addTo(map); } else { Lgrid.removeFrom(map); rulerButton.remove(); } } } if (cmd.grid.hasOwnProperty("opt")) { Lgrid.initialize(cmd.grid.opt); if (showGrid) { Lgrid.removeFrom(map); Lgrid.addTo(map); } } } if (cmd.hasOwnProperty("button")) { if (cmd.button.icon) { if (!buttons[cmd.button.name]) { buttons[cmd.button.name] = L.easyButton( cmd.button.icon, function() { ws.send(JSON.stringify({action:"button",name:cmd.button.name})); }, cmd.button.name, { position:cmd.button.position||'topright' }).addTo(map); } } else { if (buttons[cmd.button.name]) { buttons[cmd.button.name].removeFrom(map); delete buttons[cmd.button.name]; } } } if (cmd.hasOwnProperty("contextmenu")) { if (typeof cmd.contextmenu === "string") { addmenu = cmd.contextmenu; rightmenuMap.setContent(addmenu); } } if (cmd.hasOwnProperty("allowFileDrop")) { if (typeof cmd.allowFileDrop === "string") { allowFileDrop = cmd.allowFileDrop === "false" ? false : true; } } if (cmd.hasOwnProperty("coords")) { try { coords.removeFrom(map); } catch(e) {} if (cmd.coords == "dms") { coords.options.useDMS = true; showMouseCoords = "dms"; coords.addTo(map); } if (cmd.coords == "deg") { coords.options.useDMS = false; showMouseCoords = "deg"; coords.addTo(map); } } if (cmd.hasOwnProperty("legend")) { if (typeof cmd.legend === "string" && cmd.legend.length > 0) { if (!legend.getContainer()) { //if legend not exist create it legend.onAdd = function() { var div = L.DomUtil.create("div", "legend"); div.innerHTML = cmd.legend; return div; }; legend.addTo(map); }; legend.getContainer().style.visibility = 'visible'; // if already exist use visibility to show/hide legend.getContainer().innerHTML = cmd.legend; // set content of legend } else { if (legend.getContainer()) { legend.getContainer().style.visibility = 'hidden'; //if empty string and legend already created hide it } } } var existsalready = false; // Add a new base map layer if (cmd.map && cmd.map.hasOwnProperty("name") && cmd.map.hasOwnProperty("url") && cmd.map.hasOwnProperty("opt")) { console.log("BASE",cmd.map); if (basemaps.hasOwnProperty(cmd.map.name)) { existsalready = true; } if (cmd.map.hasOwnProperty("wms")) { // special case for wms console.log("New WMS:",cmd.map.name); if (cmd.map.wms === "grey") { basemaps[cmd.map.name] = L.tileLayer.graywms(cmd.map.url, cmd.map.opt); } else { basemaps[cmd.map.name] = L.tileLayer.wms(cmd.map.url, cmd.map.opt); } } else { console.log("New Map:",cmd.map.name); basemaps[cmd.map.name] = L.tileLayer(cmd.map.url, cmd.map.opt); } //if (!existsalready && !inIframe) { if (!existsalready) { layercontrol.addBaseLayer(basemaps[cmd.map.name],cmd.map.name); } } // Add or swap new minimap layer if (cmd.map && cmd.map.hasOwnProperty("minimap")) { if (minimap) { map.removeControl(minimap); } if (cmd.map.minimap == false) { return; } if (basemaps[cmd.map.minimap]) { minimap = new L.Control.MiniMap(basemaps[cmd.map.minimap], cmd.map.opt).addTo(map); } else { console.log("Invalid base layer for minimap:",cmd.map.minimap); } } // Remove one or more map layers (base or overlay) if (cmd.map && cmd.map.hasOwnProperty("delete")) { if (!Array.isArray(cmd.map.delete)) { cmd.map.delete = [cmd.map.delete]; } for (var a=0; a < cmd.map.delete.length; a++) { if (basemaps.hasOwnProperty(cmd.map.delete[a])) { delete basemaps[cmd.map.delete[a]]; } if (overlays.hasOwnProperty(cmd.map.delete[a])) { delete overlays[cmd.map.delete[a]]; } } if (showLayerMenu) { map.removeControl(layercontrol); layercontrol = L.control.layers(basemaps, overlays).addTo(map); } } // Add a new geojson overlay layer if (cmd.map && cmd.map.hasOwnProperty("overlay") && cmd.map.hasOwnProperty("geojson") ) { if (overlays.hasOwnProperty(cmd.map.overlay)) { map.removeLayer(overlays[cmd.map.overlay]); existsalready = true; } var opt = cmd.map.opt || { style:function(feature) { var st = { stroke:true, weight:2, fill:true }; if (feature.hasOwnProperty("properties")) { st.color = feature.properties.color||feature.properties.roofColor||"black"; if (feature.properties.hasOwnProperty("color")) { delete feature.properties.color; } if (feature.properties.hasOwnProperty("roofColor")) { delete feature.properties.roofColor; } } if (feature.hasOwnProperty("properties") && feature.properties.hasOwnProperty('style')) { if (feature.properties.style.hasOwnProperty('stroke')) { st.color = feature.properties.style.stroke; } if (feature.properties.style.hasOwnProperty('stroke-width')) { st.weight = feature.properties.style["stroke-width"]; } if (feature.properties.style.hasOwnProperty('stroke-opacity')) { st.opacity = feature.properties.style["stroke-opacity"]; } if (feature.properties.style.hasOwnProperty('fill')) { if (feature.properties.style.fill == "none") { st.fill = false; } else { st.fillColor = feature.properties.style.fill; } } if (feature.properties.style.hasOwnProperty('fill-opacity')) { st.fillOpacity = feature.properties.style["fill-opacity"]; } } delete feature.properties.style; return st; }}; opt.onEachFeature = function (f,l) { l.bindPopup('
'+JSON.stringify(f.properties,null,' ').replace(/[\{\}"]/g,'')+'
'); } overlays[cmd.map.overlay] = L.geoJson(cmd.map.geojson,opt); if (!existsalready) { layercontrol.addOverlay(overlays[cmd.map.overlay],cmd.map.overlay); } if (!cmd.map.hasOwnProperty("visible") || (cmd.map.visible != false)) { map.addLayer(overlays[cmd.map.overlay]); } if (cmd.map.hasOwnProperty("fit") && (cmd.map.fit === true)) { map.fitBounds(overlays[cmd.map.overlay].getBounds()); } } // Add a new NVG XML overlay layer if (cmd.map && cmd.map.hasOwnProperty("overlay") && cmd.map.hasOwnProperty("nvg") ) { if (overlays.hasOwnProperty(cmd.map.overlay)) { map.removeLayer(overlays[cmd.map.overlay]); existsalready = true; } var parser = new NVG(cmd.map.nvg); var geoj = parser.toGeoJSON(); overlays[cmd.map.overlay] = L.geoJson(geoj,{ style: function(feature) { var st = { stroke:true, color:"black", weight:2, fill:true }; if (feature.hasOwnProperty("properties") && feature.properties.hasOwnProperty('style')) { if (feature.properties.style.hasOwnProperty('stroke')) { st.color = feature.properties.style.stroke; } if (feature.properties.style.hasOwnProperty('stroke-width')) { st.weight = feature.properties.style["stroke-width"]; } if (feature.properties.style.hasOwnProperty('stroke-opacity')) { st.opacity = feature.properties.style["stroke-opacity"]; } if (feature.properties.style.hasOwnProperty('fill')) { if (feature.properties.style.fill == "none") { st.fill = false; } else { st.fillColor = feature.properties.style.fill; } } if (feature.properties.style.hasOwnProperty('fill-opacity')) { st.fillOpacity = feature.properties.style["fill-opacity"]; } } return st; }, pointToLayer: function (feature, latlng) { if (feature.hasOwnProperty("properties") && feature.properties.hasOwnProperty('symbol')) { var sidc = feature.properties.symbol.toUpperCase().replace("APP6A:",'')//.substr(0,13); var country; if (sidc.length > 12) { country = sidc.substr(12).replace(/-/g,''); sidc = sidc.substr(0,12); } myMarker = new ms.Symbol( sidc, { uniqueDesignation:feature.properties.label, country:country, direction:feature.properties.course, additionalInformation:feature.properties.modifier, size:24 }); var myicon = L.icon({ iconUrl: myMarker.toDataURL(), iconAnchor: [myMarker.getAnchor().x, myMarker.getAnchor().y], className: "natoicon", }); return L.marker(latlng, { name:feature.properties.label, icon:myicon }); } else { var geojsonMarkerOptions = { radius: 10, fillColor: "#ff7800", color: "#000", weight: 1, opacity: 1, fillOpacity: 0.8 }; return L.circleMarker(latlng, geojsonMarkerOptions); } } }); if (!existsalready) { layercontrol.addOverlay(overlays[cmd.map.overlay],cmd.map.overlay); } if (!cmd.map.hasOwnProperty("visible") || (cmd.map.visible != false)) { map.addLayer(overlays[cmd.map.overlay]); } if (cmd.map.hasOwnProperty("fit")) { map.fitBounds(overlays[cmd.map.overlay].getBounds()); } } var custIco = function() { var col = cmd.map.iconColor || "#910000"; var myMarker = L.VectorMarkers.icon({ icon: "circle", markerColor: col, prefix: 'fa', iconColor: 'white' }); if (cmd.map.hasOwnProperty("icon")) { myMarker = L.divIcon({ className:"faicon", html: '
', iconSize: [16, 16], }); } var customLayer = L.geoJson(null, { pointToLayer: function(geoJsonPoint, latlng) { //console.log("KML/GPX point",geoJsonPoint) var d = (geoJsonPoint.properties.description || "").trim(); var mypop = ''+geoJsonPoint.properties.name + '
'+d+'
lat,lon : ' + geoJsonPoint.geometry.coordinates[1] + ', ' + geoJsonPoint.geometry.coordinates[0]; if (geoJsonPoint.geometry.coordinates[2]) { mypop = ''+geoJsonPoint.properties.name + '
'+d+'
lat,lon.alt : ' + geoJsonPoint.geometry.coordinates[1] + ', ' + geoJsonPoint.geometry.coordinates[0] + ', ' + geoJsonPoint.geometry.coordinates[2]; } return L.marker(latlng, {icon:myMarker, title:geoJsonPoint.properties.name}).bindPopup(mypop); } }); return customLayer; } // Add a new KML overlay layer if (cmd.map && cmd.map.hasOwnProperty("overlay") && cmd.map.hasOwnProperty("kml") ) { if (overlays.hasOwnProperty(cmd.map.overlay)) { overlays[cmd.map.overlay].removeFrom(map); existsalready = true; } //var opt = {async:true}; overlays[cmd.map.overlay] = omnivore.kml.parse(cmd.map.kml, null, custIco()); if (!existsalready) { layercontrol.addOverlay(overlays[cmd.map.overlay],cmd.map.overlay); } if (!cmd.map.hasOwnProperty("visible") || (cmd.map.visible != false)) { overlays[cmd.map.overlay].addTo(map); } if (cmd.map.hasOwnProperty("fit")) { map.fitBounds(overlays[cmd.map.overlay].getBounds()); } } // Add a new TOPOJSON overlay layer if (cmd.map && cmd.map.hasOwnProperty("overlay") && cmd.map.hasOwnProperty("topojson") ) { if (overlays.hasOwnProperty(cmd.map.overlay)) { overlays[cmd.map.overlay].removeFrom(map); existsalready = true; } overlays[cmd.map.overlay] = omnivore.topojson.parse(cmd.map.topojson); if (!existsalready) { layercontrol.addOverlay(overlays[cmd.map.overlay],cmd.map.overlay); } if (!cmd.map.hasOwnProperty("visible") || (cmd.map.visible != false)) { overlays[cmd.map.overlay].addTo(map); } if (cmd.map.hasOwnProperty("fit")) { map.fitBounds(overlays[cmd.map.overlay].getBounds()); } } // Add a new GPX overlay layer if (cmd.map && cmd.map.hasOwnProperty("overlay") && cmd.map.hasOwnProperty("gpx") ) { if (overlays.hasOwnProperty(cmd.map.overlay)) { overlays[cmd.map.overlay].removeFrom(map); existsalready = true; } overlays[cmd.map.overlay] = omnivore.gpx.parse(cmd.map.gpx, null, custIco()); if (!existsalready) { layercontrol.addOverlay(overlays[cmd.map.overlay],cmd.map.overlay); } if (!cmd.map.hasOwnProperty("visible") || (cmd.map.visible != false)) { overlays[cmd.map.overlay].addTo(map); } if (cmd.map.hasOwnProperty("fit")) { map.fitBounds(overlays[cmd.map.overlay].getBounds()); } } // Add a new velocity overlay layer if (cmd.map && cmd.map.hasOwnProperty("overlay") && cmd.map.hasOwnProperty("velocity") ) { if (overlays.hasOwnProperty(cmd.map.overlay)) { overlays[cmd.map.overlay].removeFrom(map); layercontrol.removeOverlay(overlays[cmd.map.overlay]); } overlays[cmd.map.overlay] = L.velocityLayer(cmd.map.velocity); layercontrol.addOverlay(overlays[cmd.map.overlay],cmd.map.overlay); if (!cmd.map.hasOwnProperty("visible") || (cmd.map.visible != false)) { overlays[cmd.map.overlay].addTo(map); } if (cmd.map.hasOwnProperty("fit")) { map.fitBounds(overlays[cmd.map.overlay].getBounds()); } } // Add a new overlay layer if (cmd.map && cmd.map.hasOwnProperty("overlay") && cmd.map.hasOwnProperty("url") && cmd.map.hasOwnProperty("opt")) { console.log("New overlay:",cmd.map.overlay); if (overlays.hasOwnProperty(cmd.map.overlay)) { existsalready = true; } if (cmd.map.hasOwnProperty("wms")) { // special case for wms if (cmd.map.wms === "grey") { overlays[cmd.map.overlay] = L.tileLayer.graywms(cmd.map.url, cmd.map.opt); } else { overlays[cmd.map.overlay] = L.tileLayer.wms(cmd.map.url, cmd.map.opt); } } else if (cmd.map.hasOwnProperty("bounds")) { //Image Overlay in the bounds specified (2D Array) if (cmd.map.bounds.length === 2 && cmd.map.bounds[0].length === 2 && cmd.map.bounds[1].length === 2) { overlays[cmd.map.overlay] = new L.imageOverlay(cmd.map.url, L.latLngBounds(cmd.map.bounds), cmd.map.opt); } } else { overlays[cmd.map.overlay] = L.tileLayer(cmd.map.url, cmd.map.opt); } //if (!existsalready && !inIframe) { if (!existsalready) { layercontrol.addOverlay(overlays[cmd.map.overlay],cmd.map.overlay); } if (!cmd.map.hasOwnProperty("visible") || (cmd.map.visible != false)) { overlays[cmd.map.overlay].addTo(map); } } // Swap a base layer if (cmd.layer && basemaps.hasOwnProperty(cmd.layer)) { map.removeLayer(basemaps[baselayername]); baselayername = cmd.layer; basemaps[baselayername].addTo(map); } if (cmd.layer && (cmd.layer === "none")) { map.removeLayer(basemaps[baselayername]); baselayername = cmd.layer; } // Add search command if (cmd.hasOwnProperty("search") && (typeof cmd.search === "string")) { document.getElementById('search').value = cmd.search; if (cmd.search !== "") { openMenu(); doSearch(); } else { closeMenu(); clearSearch(); } } // Add side by side control if (cmd.side && (cmd.side === "none")) { sidebyside.remove(); map.removeLayer(basemaps[sidebyside.lay]); sidebyside = undefined; } if (cmd.side && basemaps.hasOwnProperty(cmd.side)) { if (sidebyside) { sidebyside.remove(); map.removeLayer(basemaps[sidebyside.lay]); } basemaps[cmd.side].addTo(map); sidebyside = L.control.sideBySide(basemaps[baselayername], basemaps[cmd.side]); sidebyside.addTo(map); sidebyside.lay = cmd.side; } if (cmd.split && sidebyside && (cmd.split <= 100) && (cmd.split >= 0)) { sidebyside.setSplit(cmd.split); } // Turn on an existing overlay(s) if (cmd.hasOwnProperty("showlayer")) { if (typeof cmd.showlayer === "string") { cmd.showlayer = [ cmd.showlayer ]; } for (var i=0; i < cmd.showlayer.length; i++) { if (overlays.hasOwnProperty(cmd.showlayer[i])) { map.addLayer(overlays[cmd.showlayer[i]]); } } } // Turn off an existing overlay(s) if (cmd.hasOwnProperty("hidelayer")) { if (typeof cmd.hidelayer === "string") { cmd.hidelayer = [ cmd.hidelayer ]; } for (var i=0; i < cmd.hidelayer.length; i++) { if (overlays.hasOwnProperty(cmd.hidelayer[i])) { map.removeLayer(overlays[cmd.hidelayer[i]]); } } } // Lock the pan so map can be moved if (cmd.hasOwnProperty("panlock")) { if (cmd.panlock == "true" || cmd.panlock == true) { lockit = true; } else { lockit = false; doLock(false); } document.getElementById("lockit").checked = lockit; } // move to a new position var clat = map.getCenter().lat; var clon = map.getCenter().lng; var czoom = map.getZoom(); if (cmd.hasOwnProperty("lat")) { clat = cmd.lat; } if (cmd.hasOwnProperty("lon")) { clon = cmd.lon; } if (cmd.hasOwnProperty("zoom")) { czoom = cmd.zoom; } map.setView([clat,clon],czoom); if (cmd.hasOwnProperty("cluster")) { clusterAt = cmd.cluster; document.getElementById("setclus").value = cmd.cluster; setCluster(clusterAt); } if (cmd.hasOwnProperty("maxage")) { document.getElementById("maxage").value = cmd.maxage; setMaxAge(); } if (cmd.hasOwnProperty("heatmap")) { heat.setOptions(cmd.heatmap); document.getElementById("heatall").checked = !!cmd.heatmap; heat.redraw(); } if (cmd.hasOwnProperty("panlock") && lockit === true) { doLock(true); } if (cmd.hasOwnProperty("zoomlock")) { if (cmd.zoomlock == "true" || cmd.zoomlock == true) { if (map.doubleClickZoom.enabled()) { map.removeControl(map.zoomControl); } map.doubleClickZoom.disable(); map.scrollWheelZoom.disable(); map.touchZoom.disable(); } else { if (!map.doubleClickZoom.enabled()) { map.addControl(map.zoomControl); } map.doubleClickZoom.enable(); map.scrollWheelZoom.enable(); map.touchZoom.enable(); } } } // handle any incoming GEOJSON directly - may style badly function doGeojson(n,g,l,o) { var lay = l || g.name || "unknown"; // if (!basemaps[lay]) { var opt = { style: function(feature) { var st = { stroke:true, color:"#910000", weight:1, fill:true, fillColor:"#910000", fillOpacity:0.15 }; st = Object.assign(st,o); if (feature.hasOwnProperty("properties")) { //console.log("GPROPS", feature.properties) st.color = feature.properties["stroke"] || st.color; st.weight = feature.properties["stroke-width"] || st.weight; st.fillColor = feature.properties["fill-color"] || feature.properties["fill"] || st.fillColor; st.fillOpacity = feature.properties["fill-opacity"] || st.fillOpacity; delete feature.properties["stroke"]; delete feature.properties["stroke-width"]; delete feature.properties["fill-color"]; delete feature.properties["fill"]; delete feature.properties["fill-opacity"]; delete feature.properties["stroke-opacity"]; } if (feature.hasOwnProperty("style")) { //console.log("GSTYLE", feature.style) st.color = feature.style["stroke"] || st.color; st.weight = feature.style["stroke-width"] || st.weight; st.fillColor = feature.style["fill-color"] || feature.style["fill"] || st.fillColor; st.fillOpacity = feature.style["fill-opacity"] || st.fillOpacity; } if (feature.hasOwnProperty("geometry") && feature.geometry.hasOwnProperty("type") && feature.geometry.type === "LineString") { st.fill = false; } return st; }} opt.pointToLayer = function (feature, latlng) { var myMarker = L.VectorMarkers.icon({ icon: feature.properties["marker-symbol"] || "circle", markerColor: (feature.properties["marker-color"] || "#910000"), prefix: 'fa', iconColor: 'white' }); if (!feature.properties.hasOwnProperty("title")) { feature.properties.title = feature.properties["marker-symbol"]; } if (feature.properties.hasOwnProperty("url")) { feature.properties.url = ""+feature.properties.url+""; } delete feature.properties["marker-symbol"]; delete feature.properties["marker-color"]; delete feature.properties["marker-size"]; var nf = {title:feature.properties.title, name:feature.properties.name}; feature.properties = Object.assign(nf, feature.properties); return L.marker(latlng, {title:feature.properties.title || "", icon:myMarker}); } opt.onEachFeature = function (f,l) { if (f.properties) { l.bindPopup('
'+JSON.stringify(f.properties,null,' ').replace(/[\{\}"]/g,'')+'
'); } } markers[n] = L.geoJson(g,opt); markers[n].lay = lay; if (typeof layers[lay] == "undefined") { // add layer if if doesn't exist layers[lay] = new L.LayerGroup(); overlays[lay] = layers[lay]; layercontrol.addOverlay(overlays[lay],lay); } layers[lay].addLayer(markers[n]); map.addLayer(layers[lay]); } connect();