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 lll = "unknown";
if (markers.hasOwnProperty(data.name) && markers[data.name].hasOwnProperty("lay")) {
lll = markers[data.name].lay;
}
var lay = data.layer || lll;
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 = '';
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 = '';
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 = '';
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 = '';
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 = '';
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 = '';
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 = '';
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 = '';
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 = '';
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 === "mayflower") {
data.iconColor = data.iconColor || "#910000";
icon = '';
var svgmay = "data:image/svg+xml;base64," + btoa(icon);
myMarker = L.divIcon({
className:"mayflowericon",
iconAnchor: [12, 24],
html:'',
});
marker = L.marker(ll, {title:data.name, icon:myMarker, draggable:drag});
}
else if (data.icon === "locate") {
data.iconColor = data.iconColor || "cyan";
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('