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 ();
});
}