source: binary-improvements/webserver/js/map.js@ 372

Last change on this file since 372 was 366, checked in by alloc, 3 years ago

Map: Added options for fractional zoom to map.js lines 42 - 46

File size: 16.7 KB
RevLine 
[245]1var mapinfo = {
2 regionsize: 512,
3 chunksize: 16,
4 tilesize: 128,
5 maxzoom: 4
6}
7
8function InitMap() {
9 // ===============================================================================================
10 // 7dtd coordinate transformations
11
12 SDTD_Projection = {
13 project: function (latlng) {
14 return new L.Point(
15 (latlng.lat) / Math.pow(2, mapinfo.maxzoom),
16 (latlng.lng) / Math.pow(2, mapinfo.maxzoom) );
17 },
18
19 unproject: function (point) {
20 return new L.LatLng(
21 point.x * Math.pow(2, mapinfo.maxzoom),
22 point.y * Math.pow(2, mapinfo.maxzoom) );
23 }
24 };
25
26 SDTD_CRS = L.extend({}, L.CRS.Simple, {
27 projection: SDTD_Projection,
28 transformation: new L.Transformation(1, 0, -1, 0),
29
30 scale: function (zoom) {
31 return Math.pow(2, zoom);
32 }
33 });
34
35 // ===============================================================================================
36 // Map and basic tile layers
37
38 map = L.map('tab_map', {
39 zoomControl: false, // Added by Zoomslider
40 zoomsliderControl: true,
41 attributionControl: false,
[366]42 crs: SDTD_CRS,
43 // For the below options read section "Fractional zoom" here: https://leafletjs.com/examples/zoom-levels/
44 zoomSnap: 1, // Defines the zoom levels that can be achieved at all
45 zoomDelta: 1, // Defines how much the zoom is changed with keyboard +/- and the zoom slider control
46 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
[245]47 }).setView([0, 0], Math.max(0, mapinfo.maxzoom - 5));
48
49
[249]50 var initTime = new Date().getTime();
51 var tileLayer = GetSdtdTileLayer (mapinfo, initTime);
52 var tileLayerMiniMap = GetSdtdTileLayer (mapinfo, initTime, true);
[245]53
[251]54 // player icon
55 var playerIcon = L.icon({
56 iconUrl: '/static/leaflet/images/marker-survivor.png',
57 iconRetinaUrl: '/static/leaflet/images/marker-survivor-2x.png',
58 iconSize: [25, 48],
59 iconAnchor: [12, 24],
60 popupAnchor: [0, -20]
61 });
62
63 // hostile icon
64 var hostileIcon = L.icon({
65 iconUrl: '/static/leaflet/images/marker-zombie.png',
66 iconRetinaUrl: '/static/leaflet/images/marker-zombie-2x.png',
67 iconSize: [25, 33],
68 iconAnchor: [12, 16],
69 popupAnchor: [0, -10]
70 });
71
72 // animal icon
73 var animalIcon = L.icon({
74 iconUrl: '/static/leaflet/images/marker-animal.png',
75 iconRetinaUrl: '/static/leaflet/images/marker-animal-2x.png',
76 iconSize: [25, 26],
77 iconAnchor: [12, 13],
78 popupAnchor: [0, -10]
79 });
80
[245]81
82
83 // ===============================================================================================
84 // Overlays and controls
85
86 var playersOnlineMarkerGroup = L.markerClusterGroup({
[347]87 maxClusterRadius: function(zoom) { return zoom >= mapinfo.maxzoom ? 10 : 50; }
[245]88 });
89 var playersOfflineMarkerGroup = L.markerClusterGroup({
[347]90 maxClusterRadius: function(zoom) { return zoom >= mapinfo.maxzoom ? 10 : 50; }
[245]91 });
[251]92 var hostilesMarkerGroup = L.markerClusterGroup({
[347]93 maxClusterRadius: function(zoom) { return zoom >= mapinfo.maxzoom ? 10 : 50; }
[251]94 });
95 var animalsMarkerGroup = L.markerClusterGroup({
[347]96 maxClusterRadius: function(zoom) { return zoom >= mapinfo.maxzoom ? 10 : 50; }
[251]97 });
[245]98
[306]99 var densityMismatchMarkerGroupAir = L.markerClusterGroup({
[347]100 maxClusterRadius: function(zoom) { return zoom >= mapinfo.maxzoom ? 10 : 50; }
[306]101 });
102 var densityMismatchMarkerGroupTerrain = L.markerClusterGroup({
[347]103 maxClusterRadius: function(zoom) { return zoom >= mapinfo.maxzoom ? 10 : 50; }
[306]104 });
105 var densityMismatchMarkerGroupNonTerrain = L.markerClusterGroup({
[347]106 maxClusterRadius: function(zoom) { return zoom >= mapinfo.maxzoom ? 10 : 50; }
[306]107 });
[245]108
[306]109
[249]110 var layerControl = L.control.layers({
111 //"Map": tileLayer
112 }, null, {
113 collapsed: false
114 }
115 );
[245]116
117 var layerCount = 0;
118
119
120 tileLayer.addTo(map);
[249]121
[245]122 new L.Control.Coordinates({}).addTo(map);
[249]123
124 new L.Control.ReloadTiles({
125 autoreload_enable: true,
126 autoreload_minInterval: 30,
127 autoreload_interval: 120,
128 autoreload_defaultOn: false,
129 layers: [tileLayer, tileLayerMiniMap]
130 }).addTo(map);
131
[245]132 layerControl.addOverlay (GetRegionLayer (mapinfo), "Region files");
[306]133 layerCount++;
[249]134
[245]135 var miniMap = new L.Control.MiniMap(tileLayerMiniMap, {
136 zoomLevelOffset: -6,
137 toggleDisplay: true
138 }).addTo(map);
139
[249]140 var measure = L.control.measure({
[253]141 units: {
142 sdtdMeters: {
143 factor: 0.00001,
144 display: 'XMeters',
145 decimals: 0
146 },
147 sdtdSqMeters: {
148 factor: 0.000000001,
149 display: 'XSqMeters',
150 decimals: 0
151 }
152 },
153 primaryLengthUnit: "sdtdMeters",
154 primaryAreaUnit: "sdtdSqMeters",
[249]155 //activeColor: "#ABE67E",
156 //completedColor: "#C8F2BE",
157 position: "bottomleft"
158 });
159 //measure.addTo(map);
160
[315]161 new L.Control.GameTime({}).addTo(map);
[249]162
[245]163 if (HasPermission ("webapi.getlandclaims")) {
164 layerControl.addOverlay (GetLandClaimsLayer (map, mapinfo), "Land claims");
165 layerCount++;
166 }
[249]167
[251]168 if (HasPermission ("webapi.gethostilelocation")) {
169 layerControl.addOverlay (hostilesMarkerGroup, "Hostiles (<span id='mapControlHostileCount'>0</span>)");
170 layerCount++;
171 }
172
173 if (HasPermission ("webapi.getanimalslocation")) {
174 layerControl.addOverlay (animalsMarkerGroup, "Animals (<span id='mapControlAnimalsCount'>0</span>)");
175 layerCount++;
176 }
177
[245]178 if (HasPermission ("webapi.getplayerslocation")) {
179 layerControl.addOverlay (playersOfflineMarkerGroup, "Players (offline) (<span id='mapControlOfflineCount'>0</span>)");
180 layerControl.addOverlay (playersOnlineMarkerGroup, "Players (online) (<span id='mapControlOnlineCount'>0</span>)");
181 layerCount++;
182 }
[306]183
[245]184 if (layerCount > 0) {
185 layerControl.addTo(map);
186 }
187
188
189
190
[251]191 var hostilesMappingList = {};
192 var animalsMappingList = {};
[245]193 var playersMappingList = {};
194
[251]195
[245]196
197 // ===============================================================================================
198 // Player markers
199
200 $(".leaflet-popup-pane").on('click.action', '.inventoryButton', function(event) {
201 ShowInventoryDialog ($(this).data('steamid'));
202 });
203
[250]204 var updatingMarkers = false;
205
206
[245]207 var setPlayerMarkers = function(data) {
[315]208 var onlineIds = [];
[250]209 updatingMarkers = true;
[245]210 $.each( data, function( key, val ) {
211 var marker;
212 if (playersMappingList.hasOwnProperty(val.steamid)) {
213 marker = playersMappingList[val.steamid].currentPosMarker;
214 } else {
[251]215 marker = L.marker([val.position.x, val.position.z], {icon: playerIcon}).bindPopup(
[320]216 "Player: " + $("<div>").text(val.name).html() +
[245]217 (HasPermission ("webapi.getplayerinventory") ?
218 "<br/><a class='inventoryButton' data-steamid='"+val.steamid+"'>Show inventory</a>"
219 : "")
220 );
[315]221 marker.on("move", function ( e ) {
222 if ( this.isPopupOpen () ) {
223 map.flyTo (e.latlng, map.getZoom ());
224 }
225 });
[245]226 playersMappingList[val.steamid] = { online: !val.online };
227 }
[250]228
[315]229 if (val.online) {
230 onlineIds.push (val.steamid);
231 }
232
[250]233 oldpos = marker.getLatLng ();
[315]234 if ( playersMappingList[val.steamid].online != val.online ) {
[250]235 if (playersMappingList[val.steamid].online) {
236 playersOnlineMarkerGroup.removeLayer(marker);
[315]237 playersOfflineMarkerGroup.addLayer(marker);
[250]238 } else {
239 playersOfflineMarkerGroup.removeLayer(marker);
[315]240 playersOnlineMarkerGroup.addLayer(marker);
[250]241 }
[315]242 }
243 if ( oldpos.lat != val.position.x || oldpos.lng != val.position.z ) {
[250]244 marker.setLatLng([val.position.x, val.position.z]);
245 if (val.online) {
246 marker.setOpacity(1.0);
247 } else {
248 marker.setOpacity(0.5);
249 }
[249]250 }
251
[245]252 val.currentPosMarker = marker;
253 playersMappingList[val.steamid] = val;
[315]254 });
[245]255
[315]256 var online = 0;
257 var offline = 0;
258 $.each ( playersMappingList, function ( key, val ) {
259 if ( val.online && onlineIds.indexOf (key) < 0 ) {
260 var marker = val.currentPosMarker;
261 playersOnlineMarkerGroup.removeLayer(marker);
262 playersOfflineMarkerGroup.addLayer(marker);
263 val.online = false;
264 }
265 if (val.online) {
[245]266 online++;
[315]267 } else {
[245]268 offline++;
[315]269 }
[245]270 });
[315]271
[250]272 updatingMarkers = false;
[315]273
[245]274 $( "#mapControlOnlineCount" ).text( online );
275 $( "#mapControlOfflineCount" ).text( offline );
276 }
277
[250]278 var updatePlayerTimeout;
[315]279 var playerUpdateCount = -1;
[245]280 var updatePlayerEvent = function() {
[315]281 playerUpdateCount++;
282
283 $.getJSON( "../api/getplayerslocation" + ((playerUpdateCount % 15) == 0 ? "?offline=true" : ""))
[245]284 .done(setPlayerMarkers)
285 .fail(function(jqxhr, textStatus, error) {
286 console.log("Error fetching players list");
287 })
288 .always(function() {
[250]289 updatePlayerTimeout = window.setTimeout(updatePlayerEvent, 4000);
[245]290 });
291 }
292
[250]293 tabs.on ("tabbedcontenttabopened", function (event, data) {
294 if (data.newTab === "#tab_map") {
295 if (HasPermission ("webapi.getplayerslocation")) {
296 updatePlayerEvent ();
297 }
298 } else {
299 window.clearTimeout (updatePlayerTimeout);
300 }
301 });
302
303 if (tabs.tabbedContent ("isTabOpen", "tab_map")) {
304 if (HasPermission ("webapi.getplayerslocation")) {
305 updatePlayerEvent ();
306 }
[245]307 }
308
309
[251]310
311
312 // ===============================================================================================
313 // Hostiles markers
314
315 var setHostileMarkers = function(data) {
316 updatingMarkersHostile = true;
317
318 var hostileCount = 0;
319
320 hostilesMarkerGroup.clearLayers();
321
322 $.each( data, function( key, val ) {
323 var marker;
324 if (hostilesMappingList.hasOwnProperty(val.id)) {
325 marker = hostilesMappingList[val.id].currentPosMarker;
326 } else {
327 marker = L.marker([val.position.x, val.position.z], {icon: hostileIcon}).bindPopup(
328 "Hostile: " + val.name
329 );
330 //hostilesMappingList[val.id] = { };
331 hostilesMarkerGroup.addLayer(marker);
332 }
333
334 var bAbort = false;
335
336 oldpos = marker.getLatLng ();
337
338 //if ( oldpos.lat != val.position.x || oldpos.lng != val.position.z ) {
339 // hostilesMarkerGroup.removeLayer(marker);
340 marker.setLatLng([val.position.x, val.position.z]);
341 marker.setOpacity(1.0);
342 hostilesMarkerGroup.addLayer(marker);
343 //}
344
345 val.currentPosMarker = marker;
346 hostilesMappingList[val.id] = val;
347
348 hostileCount++;
349 });
350
351 $( "#mapControlHostileCount" ).text( hostileCount );
352
353 updatingMarkersHostile = false;
354 }
355
356 var updateHostileTimeout;
357 var updateHostileEvent = function() {
358 $.getJSON( "../api/gethostilelocation")
359 .done(setHostileMarkers)
360 .fail(function(jqxhr, textStatus, error) {
361 console.log("Error fetching hostile list");
362 })
363 .always(function() {
364 updateHostileTimeout = window.setTimeout(updateHostileEvent, 4000);
365 });
366 }
367
368 tabs.on ("tabbedcontenttabopened", function (event, data) {
369 if (data.newTab === "#tab_map") {
370 if (HasPermission ("webapi.gethostilelocation")) {
371 updateHostileEvent ();
372 }
373 } else {
374 window.clearTimeout (updateHostileTimeout);
375 }
376 });
377
378 if (tabs.tabbedContent ("isTabOpen", "tab_map")) {
379 if (HasPermission ("webapi.gethostilelocation")) {
380 updateHostileEvent ();
381 }
382 }
383
384
385
386 // ===============================================================================================
387 // Animals markers
388
389 var setAnimalMarkers = function(data) {
390 updatingMarkersAnimals = true;
391
392 var animalsCount = 0;
393
394 animalsMarkerGroup.clearLayers();
395
396 $.each( data, function( key, val ) {
397 var marker;
398 if (animalsMappingList.hasOwnProperty(val.id)) {
399 marker = animalsMappingList[val.id].currentPosMarker;
400 } else {
401 marker = L.marker([val.position.x, val.position.z], {icon: animalIcon}).bindPopup(
402 "Animal: " + val.name
403 );
404 //animalsMappingList[val.id] = { };
405 animalsMarkerGroup.addLayer(marker);
406 }
407
408 var bAbort = false;
409
410 oldpos = marker.getLatLng ();
411
412 //if ( oldpos.lat != val.position.x || oldpos.lng != val.position.z ) {
413 // animalsMarkerGroup.removeLayer(marker);
414 marker.setLatLng([val.position.x, val.position.z]);
415 marker.setOpacity(1.0);
416 animalsMarkerGroup.addLayer(marker);
417 //}
418
419 val.currentPosMarker = marker;
420 animalsMappingList[val.id] = val;
421
422 animalsCount++;
423 });
424
425 $( "#mapControlAnimalsCount" ).text( animalsCount );
426
427 updatingMarkersAnimals = false;
428 }
429
430 var updateAnimalsTimeout;
431 var updateAnimalsEvent = function() {
432 $.getJSON( "../api/getanimalslocation")
433 .done(setAnimalMarkers)
434 .fail(function(jqxhr, textStatus, error) {
435 console.log("Error fetching animals list");
436 })
437 .always(function() {
438 updateAnimalsTimeout = window.setTimeout(updateAnimalsEvent, 4000);
439 });
440 }
441
442 tabs.on ("tabbedcontenttabopened", function (event, data) {
443 if (data.newTab === "#tab_map") {
444 if (HasPermission ("webapi.getanimalslocation")) {
445 updateAnimalsEvent ();
446 }
447 } else {
448 window.clearTimeout (updateAnimalsTimeout);
449 }
450 });
451
452 if (tabs.tabbedContent ("isTabOpen", "tab_map")) {
453 if (HasPermission ("webapi.getanimalslocation")) {
454 updateAnimalsEvent ();
455 }
456 }
457
[306]458
459
460
461
462
463
464
465
466 // ===============================================================================================
467 // Density markers
468
469 var setDensityMarkers = function(data) {
470 var densityCountAir = 0;
471 var densityCountTerrain = 0;
472 var densityCountNonTerrain = 0;
473
474 densityMismatchMarkerGroupAir.clearLayers();
475 densityMismatchMarkerGroupTerrain.clearLayers();
476 densityMismatchMarkerGroupNonTerrain.clearLayers();
477
478
479 var downloadCsv = true;
480 var downloadJson = false;
481
482 if (downloadJson) {
483 var jsonAir = [];
484 var jsonTerrain = [];
485 var jsonNonTerrain = [];
486 }
487 if (downloadCsv) {
488 var csvAir = "x;y;z;Density;IsTerrain;BvType\r\n";
489 var csvTerrain = "x;y;z;Density;IsTerrain;BvType\r\n";
490 var csvNonTerrain = "x;y;z;Density;IsTerrain;BvType\r\n";
491 }
492
493 $.each( data, function( key, val ) {
494 if (val.bvtype == 0) {
495 marker = L.marker([val.x, val.z]).bindPopup(
496 "Density Mismatch: <br>Position: " + val.x + " " + val.y + " " + val.z + "<br>Density: " + val.density + "<br>isTerrain: " + val.terrain + "<br>bv.type: " + val.bvtype
497 );
498 densityMismatchMarkerGroupAir.addLayer(marker);
499 densityCountAir++;
500 if (downloadJson) {
501 jsonAir.push (val);
502 }
503 if (downloadCsv) {
504 csvAir += val.x + ";" + val.y + ";" + val.z + ";" + val.density + ";" + val.terrain + ";" + val.bvtype + "\r\n";
505 }
506 } else if (val.terrain) {
507 marker = L.marker([val.x, val.z]).bindPopup(
508 "Density Mismatch: <br>Position: " + val.x + " " + val.y + " " + val.z + "<br>Density: " + val.density + "<br>isTerrain: " + val.terrain + "<br>bv.type: " + val.bvtype
509 );
510 densityMismatchMarkerGroupTerrain.addLayer(marker);
511 densityCountTerrain++;
512 if (downloadJson) {
513 jsonTerrain.push (val);
514 }
515 if (downloadCsv) {
516 csvTerrain += val.x + ";" + val.y + ";" + val.z + ";" + val.density + ";" + val.terrain + ";" + val.bvtype + "\r\n";
517 }
518 } else {
519 marker = L.marker([val.x, val.z]).bindPopup(
520 "Density Mismatch: <br>Position: " + val.x + " " + val.y + " " + val.z + "<br>Density: " + val.density + "<br>isTerrain: " + val.terrain + "<br>bv.type: " + val.bvtype
521 );
522 densityMismatchMarkerGroupNonTerrain.addLayer(marker);
523 densityCountNonTerrain++;
524 if (downloadJson) {
525 jsonNonTerrain.push (val);
526 }
527 if (downloadCsv) {
528 csvNonTerrain += val.x + ";" + val.y + ";" + val.z + ";" + val.density + ";" + val.terrain + ";" + val.bvtype + "\r\n";
529 }
530 }
531 });
532
533 layerControl.addOverlay (densityMismatchMarkerGroupAir, "Density Mismatches Air (<span id='mapControlDensityCountAir'>0</span>)");
534 layerControl.addOverlay (densityMismatchMarkerGroupTerrain, "Density Mismatches Terrain (<span id='mapControlDensityCountTerrain'>0</span>)");
535 layerControl.addOverlay (densityMismatchMarkerGroupNonTerrain, "Density Mismatches NonTerrain (<span id='mapControlDensityCountNonTerrain'>0</span>)");
536
537 $( "#mapControlDensityCountAir" ).text( densityCountAir );
538 $( "#mapControlDensityCountTerrain" ).text( densityCountTerrain );
539 $( "#mapControlDensityCountNonTerrain" ).text( densityCountNonTerrain );
540
541 if (downloadJson) {
542 download ("air-negative-density.json", JSON.stringify(jsonAir, null, '\t'));
543 download ("terrain-positive-density.json", JSON.stringify(jsonTerrain, null, '\t'));
544 download ("nonterrain-negative-density.json", JSON.stringify(jsonNonTerrain, null, '\t'));
545 }
546 if (downloadCsv) {
547 download ("air-negative-density.csv", csvAir);
548 download ("terrain-positive-density.csv", csvTerrain);
549 download ("nonterrain-negative-density.csv", csvNonTerrain);
550 }
551
552 function download(filename, text) {
553 var element = document.createElement('a');
554 var file = new Blob([text], {type: 'text/plain'});
555 element.href = URL.createObjectURL(file);
556 element.download = filename;
557
558 element.style.display = 'none';
559 document.body.appendChild(element);
560
561 element.click();
562
563 document.body.removeChild(element);
564 }
565 }
566
567 $.getJSON("densitymismatch.json")
568 .done(setDensityMarkers)
569 .fail(function(jqxhr, textStatus, error) {
570 console.log("Error fetching density mismatch list");
571 });
572
[245]573}
574
575
576
577
578
579function StartMapModule () {
580 $.getJSON( "../map/mapinfo.json")
581 .done(function(data) {
582 mapinfo.tilesize = data.blockSize;
583 mapinfo.maxzoom = data.maxZoom;
584 })
585 .fail(function(jqxhr, textStatus, error) {
586 console.log ("Error fetching map information");
587 })
588 .always(function() {
589 InitMap ();
590 });
591}
592
593
Note: See TracBrowser for help on using the repository browser.