var mapinfo = { regionsize: 512, chunksize: 16, tilesize: 128, maxzoom: 4 } function InitMap() { // =============================================================================================== // 7dtd coordinate transformations SDTD_Projection = { project: function (latlng) { return new L.Point( (latlng.lat) / Math.pow(2, mapinfo.maxzoom), (latlng.lng) / Math.pow(2, mapinfo.maxzoom) ); }, unproject: function (point) { return new L.LatLng( point.x * Math.pow(2, mapinfo.maxzoom), point.y * Math.pow(2, mapinfo.maxzoom) ); } }; SDTD_CRS = L.extend({}, L.CRS.Simple, { projection: SDTD_Projection, transformation: new L.Transformation(1, 0, -1, 0), scale: function (zoom) { return Math.pow(2, zoom); } }); // =============================================================================================== // Map and basic tile layers map = L.map('tab_map', { zoomControl: false, // Added by Zoomslider zoomsliderControl: true, attributionControl: false, crs: SDTD_CRS, // For the below options read section "Fractional zoom" here: https://leafletjs.com/examples/zoom-levels/ zoomSnap: 1, // Defines the zoom levels that can be achieved at all zoomDelta: 1, // Defines how much the zoom is changed with keyboard +/- and the zoom slider control wheelPxPerZoomLevel: 60 // Defines how much mouse scrolling is needed per zoom level. If zoomDelta is e.g. 0.25 and you want the mouse scroll zoom to match that make this 4 times as high, i.e. 240 }).setView([0, 0], Math.max(0, mapinfo.maxzoom - 5)); var initTime = new Date().getTime(); var tileLayer = GetSdtdTileLayer (mapinfo, initTime); var tileLayerMiniMap = GetSdtdTileLayer (mapinfo, initTime, true); // player icon var playerIcon = L.icon({ iconUrl: '/static/leaflet/images/marker-survivor.png', iconRetinaUrl: '/static/leaflet/images/marker-survivor-2x.png', iconSize: [25, 48], iconAnchor: [12, 24], popupAnchor: [0, -20] }); // hostile icon var hostileIcon = L.icon({ iconUrl: '/static/leaflet/images/marker-zombie.png', iconRetinaUrl: '/static/leaflet/images/marker-zombie-2x.png', iconSize: [25, 33], iconAnchor: [12, 16], popupAnchor: [0, -10] }); // animal icon var animalIcon = L.icon({ iconUrl: '/static/leaflet/images/marker-animal.png', iconRetinaUrl: '/static/leaflet/images/marker-animal-2x.png', iconSize: [25, 26], iconAnchor: [12, 13], popupAnchor: [0, -10] }); // =============================================================================================== // Overlays and controls var playersOnlineMarkerGroup = L.markerClusterGroup({ maxClusterRadius: function(zoom) { return zoom >= mapinfo.maxzoom ? 10 : 50; } }); var playersOfflineMarkerGroup = L.markerClusterGroup({ maxClusterRadius: function(zoom) { return zoom >= mapinfo.maxzoom ? 10 : 50; } }); var hostilesMarkerGroup = L.markerClusterGroup({ maxClusterRadius: function(zoom) { return zoom >= mapinfo.maxzoom ? 10 : 50; } }); var animalsMarkerGroup = L.markerClusterGroup({ maxClusterRadius: function(zoom) { return zoom >= mapinfo.maxzoom ? 10 : 50; } }); var densityMismatchMarkerGroupAir = L.markerClusterGroup({ maxClusterRadius: function(zoom) { return zoom >= mapinfo.maxzoom ? 10 : 50; } }); var densityMismatchMarkerGroupTerrain = L.markerClusterGroup({ maxClusterRadius: function(zoom) { return zoom >= mapinfo.maxzoom ? 10 : 50; } }); var densityMismatchMarkerGroupNonTerrain = L.markerClusterGroup({ maxClusterRadius: function(zoom) { return zoom >= mapinfo.maxzoom ? 10 : 50; } }); var layerControl = L.control.layers({ //"Map": tileLayer }, null, { collapsed: false } ); var layerCount = 0; tileLayer.addTo(map); new L.Control.Coordinates({}).addTo(map); new L.Control.ReloadTiles({ autoreload_enable: true, autoreload_minInterval: 30, autoreload_interval: 120, autoreload_defaultOn: false, layers: [tileLayer, tileLayerMiniMap] }).addTo(map); layerControl.addOverlay (GetRegionLayer (mapinfo), "Region files"); layerCount++; var miniMap = new L.Control.MiniMap(tileLayerMiniMap, { zoomLevelOffset: -6, toggleDisplay: true }).addTo(map); var measure = L.control.measure({ units: { sdtdMeters: { factor: 0.00001, display: 'XMeters', decimals: 0 }, sdtdSqMeters: { factor: 0.000000001, display: 'XSqMeters', decimals: 0 } }, primaryLengthUnit: "sdtdMeters", primaryAreaUnit: "sdtdSqMeters", //activeColor: "#ABE67E", //completedColor: "#C8F2BE", position: "bottomleft" }); //measure.addTo(map); new L.Control.GameTime({}).addTo(map); if (HasPermission ("webapi.getlandclaims")) { layerControl.addOverlay (GetLandClaimsLayer (map, mapinfo), "Land claims"); layerCount++; } if (HasPermission ("webapi.gethostilelocation")) { layerControl.addOverlay (hostilesMarkerGroup, "Hostiles (0)"); layerCount++; } if (HasPermission ("webapi.getanimalslocation")) { layerControl.addOverlay (animalsMarkerGroup, "Animals (0)"); layerCount++; } if (HasPermission ("webapi.getplayerslocation")) { layerControl.addOverlay (playersOfflineMarkerGroup, "Players (offline) (0)"); layerControl.addOverlay (playersOnlineMarkerGroup, "Players (online) (0)"); layerCount++; } if (layerCount > 0) { layerControl.addTo(map); } var hostilesMappingList = {}; var animalsMappingList = {}; var playersMappingList = {}; // =============================================================================================== // Player markers $(".leaflet-popup-pane").on('click.action', '.inventoryButton', function(event) { ShowInventoryDialog ($(this).data('steamid')); }); var updatingMarkers = false; var setPlayerMarkers = function(data) { var onlineIds = []; updatingMarkers = true; $.each( data, function( key, val ) { var marker; if (playersMappingList.hasOwnProperty(val.steamid)) { marker = playersMappingList[val.steamid].currentPosMarker; } else { marker = L.marker([val.position.x, val.position.z], {icon: playerIcon}).bindPopup( "Player: " + $("
").text(val.name).html() + (HasPermission ("webapi.getplayerinventory") ? "
Show inventory" : "") ); marker.on("move", function ( e ) { if ( this.isPopupOpen () ) { map.flyTo (e.latlng, map.getZoom ()); } }); playersMappingList[val.steamid] = { online: !val.online }; } if (val.online) { onlineIds.push (val.steamid); } oldpos = marker.getLatLng (); if ( playersMappingList[val.steamid].online != val.online ) { if (playersMappingList[val.steamid].online) { playersOnlineMarkerGroup.removeLayer(marker); playersOfflineMarkerGroup.addLayer(marker); } else { playersOfflineMarkerGroup.removeLayer(marker); playersOnlineMarkerGroup.addLayer(marker); } } if ( oldpos.lat != val.position.x || oldpos.lng != val.position.z ) { marker.setLatLng([val.position.x, val.position.z]); if (val.online) { marker.setOpacity(1.0); } else { marker.setOpacity(0.5); } } val.currentPosMarker = marker; playersMappingList[val.steamid] = val; }); var online = 0; var offline = 0; $.each ( playersMappingList, function ( key, val ) { if ( val.online && onlineIds.indexOf (key) < 0 ) { var marker = val.currentPosMarker; playersOnlineMarkerGroup.removeLayer(marker); playersOfflineMarkerGroup.addLayer(marker); val.online = false; } if (val.online) { online++; } else { offline++; } }); updatingMarkers = false; $( "#mapControlOnlineCount" ).text( online ); $( "#mapControlOfflineCount" ).text( offline ); } var updatePlayerTimeout; var playerUpdateCount = -1; var updatePlayerEvent = function() { playerUpdateCount++; $.getJSON( "../api/getplayerslocation" + ((playerUpdateCount % 15) == 0 ? "?offline=true" : "")) .done(setPlayerMarkers) .fail(function(jqxhr, textStatus, error) { console.log("Error fetching players list"); }) .always(function() { updatePlayerTimeout = window.setTimeout(updatePlayerEvent, 4000); }); } tabs.on ("tabbedcontenttabopened", function (event, data) { if (data.newTab === "#tab_map") { if (HasPermission ("webapi.getplayerslocation")) { updatePlayerEvent (); } } else { window.clearTimeout (updatePlayerTimeout); } }); if (tabs.tabbedContent ("isTabOpen", "tab_map")) { if (HasPermission ("webapi.getplayerslocation")) { updatePlayerEvent (); } } // =============================================================================================== // Hostiles markers var setHostileMarkers = function(data) { updatingMarkersHostile = true; var hostileCount = 0; hostilesMarkerGroup.clearLayers(); $.each( data, function( key, val ) { var marker; if (hostilesMappingList.hasOwnProperty(val.id)) { marker = hostilesMappingList[val.id].currentPosMarker; } else { marker = L.marker([val.position.x, val.position.z], {icon: hostileIcon}).bindPopup( "Hostile: " + val.name ); //hostilesMappingList[val.id] = { }; hostilesMarkerGroup.addLayer(marker); } var bAbort = false; oldpos = marker.getLatLng (); //if ( oldpos.lat != val.position.x || oldpos.lng != val.position.z ) { // hostilesMarkerGroup.removeLayer(marker); marker.setLatLng([val.position.x, val.position.z]); marker.setOpacity(1.0); hostilesMarkerGroup.addLayer(marker); //} val.currentPosMarker = marker; hostilesMappingList[val.id] = val; hostileCount++; }); $( "#mapControlHostileCount" ).text( hostileCount ); updatingMarkersHostile = false; } var updateHostileTimeout; var updateHostileEvent = function() { $.getJSON( "../api/gethostilelocation") .done(setHostileMarkers) .fail(function(jqxhr, textStatus, error) { console.log("Error fetching hostile list"); }) .always(function() { updateHostileTimeout = window.setTimeout(updateHostileEvent, 4000); }); } tabs.on ("tabbedcontenttabopened", function (event, data) { if (data.newTab === "#tab_map") { if (HasPermission ("webapi.gethostilelocation")) { updateHostileEvent (); } } else { window.clearTimeout (updateHostileTimeout); } }); if (tabs.tabbedContent ("isTabOpen", "tab_map")) { if (HasPermission ("webapi.gethostilelocation")) { updateHostileEvent (); } } // =============================================================================================== // Animals markers var setAnimalMarkers = function(data) { updatingMarkersAnimals = true; var animalsCount = 0; animalsMarkerGroup.clearLayers(); $.each( data, function( key, val ) { var marker; if (animalsMappingList.hasOwnProperty(val.id)) { marker = animalsMappingList[val.id].currentPosMarker; } else { marker = L.marker([val.position.x, val.position.z], {icon: animalIcon}).bindPopup( "Animal: " + val.name ); //animalsMappingList[val.id] = { }; animalsMarkerGroup.addLayer(marker); } var bAbort = false; oldpos = marker.getLatLng (); //if ( oldpos.lat != val.position.x || oldpos.lng != val.position.z ) { // animalsMarkerGroup.removeLayer(marker); marker.setLatLng([val.position.x, val.position.z]); marker.setOpacity(1.0); animalsMarkerGroup.addLayer(marker); //} val.currentPosMarker = marker; animalsMappingList[val.id] = val; animalsCount++; }); $( "#mapControlAnimalsCount" ).text( animalsCount ); updatingMarkersAnimals = false; } var updateAnimalsTimeout; var updateAnimalsEvent = function() { $.getJSON( "../api/getanimalslocation") .done(setAnimalMarkers) .fail(function(jqxhr, textStatus, error) { console.log("Error fetching animals list"); }) .always(function() { updateAnimalsTimeout = window.setTimeout(updateAnimalsEvent, 4000); }); } tabs.on ("tabbedcontenttabopened", function (event, data) { if (data.newTab === "#tab_map") { if (HasPermission ("webapi.getanimalslocation")) { updateAnimalsEvent (); } } else { window.clearTimeout (updateAnimalsTimeout); } }); if (tabs.tabbedContent ("isTabOpen", "tab_map")) { if (HasPermission ("webapi.getanimalslocation")) { updateAnimalsEvent (); } } // =============================================================================================== // Density markers var setDensityMarkers = function(data) { var densityCountAir = 0; var densityCountTerrain = 0; var densityCountNonTerrain = 0; densityMismatchMarkerGroupAir.clearLayers(); densityMismatchMarkerGroupTerrain.clearLayers(); densityMismatchMarkerGroupNonTerrain.clearLayers(); var downloadCsv = true; var downloadJson = false; if (downloadJson) { var jsonAir = []; var jsonTerrain = []; var jsonNonTerrain = []; } if (downloadCsv) { var csvAir = "x;y;z;Density;IsTerrain;BvType\r\n"; var csvTerrain = "x;y;z;Density;IsTerrain;BvType\r\n"; var csvNonTerrain = "x;y;z;Density;IsTerrain;BvType\r\n"; } $.each( data, function( key, val ) { if (val.bvtype == 0) { marker = L.marker([val.x, val.z]).bindPopup( "Density Mismatch:
Position: " + val.x + " " + val.y + " " + val.z + "
Density: " + val.density + "
isTerrain: " + val.terrain + "
bv.type: " + val.bvtype ); densityMismatchMarkerGroupAir.addLayer(marker); densityCountAir++; if (downloadJson) { jsonAir.push (val); } if (downloadCsv) { csvAir += val.x + ";" + val.y + ";" + val.z + ";" + val.density + ";" + val.terrain + ";" + val.bvtype + "\r\n"; } } else if (val.terrain) { marker = L.marker([val.x, val.z]).bindPopup( "Density Mismatch:
Position: " + val.x + " " + val.y + " " + val.z + "
Density: " + val.density + "
isTerrain: " + val.terrain + "
bv.type: " + val.bvtype ); densityMismatchMarkerGroupTerrain.addLayer(marker); densityCountTerrain++; if (downloadJson) { jsonTerrain.push (val); } if (downloadCsv) { csvTerrain += val.x + ";" + val.y + ";" + val.z + ";" + val.density + ";" + val.terrain + ";" + val.bvtype + "\r\n"; } } else { marker = L.marker([val.x, val.z]).bindPopup( "Density Mismatch:
Position: " + val.x + " " + val.y + " " + val.z + "
Density: " + val.density + "
isTerrain: " + val.terrain + "
bv.type: " + val.bvtype ); densityMismatchMarkerGroupNonTerrain.addLayer(marker); densityCountNonTerrain++; if (downloadJson) { jsonNonTerrain.push (val); } if (downloadCsv) { csvNonTerrain += val.x + ";" + val.y + ";" + val.z + ";" + val.density + ";" + val.terrain + ";" + val.bvtype + "\r\n"; } } }); layerControl.addOverlay (densityMismatchMarkerGroupAir, "Density Mismatches Air (0)"); layerControl.addOverlay (densityMismatchMarkerGroupTerrain, "Density Mismatches Terrain (0)"); layerControl.addOverlay (densityMismatchMarkerGroupNonTerrain, "Density Mismatches NonTerrain (0)"); $( "#mapControlDensityCountAir" ).text( densityCountAir ); $( "#mapControlDensityCountTerrain" ).text( densityCountTerrain ); $( "#mapControlDensityCountNonTerrain" ).text( densityCountNonTerrain ); if (downloadJson) { download ("air-negative-density.json", JSON.stringify(jsonAir, null, '\t')); download ("terrain-positive-density.json", JSON.stringify(jsonTerrain, null, '\t')); download ("nonterrain-negative-density.json", JSON.stringify(jsonNonTerrain, null, '\t')); } if (downloadCsv) { download ("air-negative-density.csv", csvAir); download ("terrain-positive-density.csv", csvTerrain); download ("nonterrain-negative-density.csv", csvNonTerrain); } function download(filename, text) { var element = document.createElement('a'); var file = new Blob([text], {type: 'text/plain'}); element.href = URL.createObjectURL(file); element.download = filename; element.style.display = 'none'; document.body.appendChild(element); element.click(); document.body.removeChild(element); } } $.getJSON("densitymismatch.json") .done(setDensityMarkers) .fail(function(jqxhr, textStatus, error) { console.log("Error fetching density mismatch list"); }); } function StartMapModule () { $.getJSON( "../map/mapinfo.json") .done(function(data) { mapinfo.tilesize = data.blockSize; mapinfo.maxzoom = data.maxZoom; }) .fail(function(jqxhr, textStatus, error) { console.log ("Error fetching map information"); }) .always(function() { InitMap (); }); }