source: binary-improvements/webserver/js/index.js@ 228

Last change on this file since 228 was 201, checked in by alloc, 10 years ago

webserver: landclaim coordinates

  • Property svn:executable set to *
File size: 13.8 KB
RevLine 
[173]1// ===============================================================================================
2// Constants
3
[150]4var REGIONSIZE = 512;
5var CHUNKSIZE = 16;
6var TILESIZE = 128;
7var MAXZOOM = 4;
8
[163]9var BAG_COLS = 8;
10var BAG_ROWS = 4;
11var BELT_COLS = 8;
12var INV_ITEM_WIDTH = 58;
13var INV_ITEM_HEIGHT = 40;
14
[173]15
[186]16function initMap() {
17 // ===============================================================================================
18 // 7dtd coordinate transformations
[173]19
[186]20 SDTD_Projection = {
21 project: function (latlng) {
22 return new L.Point(
23 (latlng.lat) / Math.pow(2, MAXZOOM),
24 (latlng.lng) / Math.pow(2, MAXZOOM) );
25 },
26
27 unproject: function (point) {
28 return new L.LatLng(
29 point.x * Math.pow(2, MAXZOOM),
30 point.y * Math.pow(2, MAXZOOM) );
31 }
32 };
[133]33
[186]34 SDTD_CRS = L.extend({}, L.CRS.Simple, {
35 projection: SDTD_Projection,
36 transformation: new L.Transformation(1, 0, -1, 0),
[133]37
[186]38 scale: function (zoom) {
39 return Math.pow(2, zoom);
40 }
41 });
[133]42
[186]43 var CoordToChunk = function(latlng) {
44 var x = Math.floor(((latlng.lat + 16777216) / CHUNKSIZE) - (16777216 / CHUNKSIZE));
45 var y = Math.floor(((latlng.lng + 16777216) / CHUNKSIZE) - (16777216 / CHUNKSIZE));
46 return L.latLng(x, y);
[133]47 }
48
[186]49 var CoordToRegion = function(latlng) {
50 var x = Math.floor(((latlng.lat + 16777216) / REGIONSIZE) - (16777216 / REGIONSIZE));
51 var y = Math.floor(((latlng.lng + 16777216) / REGIONSIZE) - (16777216 / REGIONSIZE));
52 return L.latLng(x, y);
53 }
[149]54
[186]55 var FormatCoord = function(latlng) {
56 return "" +
57 Math.abs(latlng.lng) + (latlng.lng>=0 ? " N" : " S") + " / " +
58 Math.abs(latlng.lat) + (latlng.lat>=0 ? " E" : " W");
59 }
[149]60
[186]61 var FormatRegionFileName = function(latlng) {
62 return "r." + latlng.lat + "." + latlng.lng + ".7rg";
63 }
[149]64
[150]65
[173]66
[186]67 // ===============================================================================================
68 // Map and basic tile layers
[173]69
[186]70 var tileTime = new Date().getTime();
[173]71
[186]72 map = L.map('map', {
73 zoomControl: false, // Added by Zoomslider
74 zoomsliderControl: true,
75 attributionControl: false,
76 crs: SDTD_CRS
77 }).setView([0, 0], Math.max(0, MAXZOOM-5));
[179]78
[186]79 var tileLayer = L.tileLayer('../map/{z}/{x}/{y}.png?t={time}', {
80 maxZoom:MAXZOOM+1,
81 minZoom: Math.max(0, MAXZOOM-5),
82 maxNativeZoom: MAXZOOM,
83 tileSize: TILESIZE,
84 continuousWorld: true,
85 tms: true,
86 unloadInvisibleTiles: false,
87 time: function() { return tileTime; }
88 }).addTo(map);
[190]89
90 // TileLayer w/ TMS=true fix for zoomlevel >= 8
91 tileLayer._getWrapTileNum = function () {
92 return L.point(0, 0);
93 };
[133]94
[186]95 var tileLayerMiniMap = L.tileLayer('../map/{z}/{x}/{y}.png?t={time}', {
96 maxZoom: MAXZOOM,
97 minZoom: 0,
98 maxNativeZoom: MAXZOOM,
99 tileSize: TILESIZE,
100 continuousWorld: true,
101 tms: true,
102 unloadInvisibleTiles: false,
103 time: function() { return tileTime; }
104 });
[150]105
[186]106 var regionLayer = L.tileLayer.canvas({
107 maxZoom: MAXZOOM+1,
108 minZoom: 0,
109 maxNativeZoom: MAXZOOM+1,
110 tileSize: TILESIZE,
111 continuousWorld: true
112 });
[173]113
[186]114 regionLayer.drawTile = function(canvas, tilePoint, zoom) {
115 var blockWorldSize = TILESIZE * Math.pow(2, MAXZOOM-zoom);
116 var tileLeft = tilePoint.x * blockWorldSize;
117 var tileBottom = (-1-tilePoint.y) * blockWorldSize;
118 var blockPos = L.latLng(tileLeft, tileBottom);
[150]119
[186]120 var ctx = canvas.getContext('2d');
[150]121
[186]122 ctx.strokeStyle = "lightblue";
123 ctx.fillStyle = "lightblue";
124 ctx.lineWidth = 1;
125 ctx.font="14px Arial";
[150]126
[186]127 var lineCount = blockWorldSize / REGIONSIZE;
128 if (lineCount >= 1) {
129 var pos = 0;
130 while (pos < TILESIZE) {
131 // Vertical
132 ctx.beginPath();
133 ctx.moveTo(pos, 0);
134 ctx.lineTo(pos, TILESIZE);
135 ctx.stroke();
[150]136
[186]137 // Horizontal
138 ctx.beginPath();
139 ctx.moveTo(0, pos);
140 ctx.lineTo(TILESIZE, pos);
141 ctx.stroke();
[150]142
[186]143 pos += TILESIZE / lineCount;
144 }
[150]145 ctx.fillText(FormatRegionFileName(CoordToRegion(blockPos)), 4, TILESIZE-5);
[186]146 } else {
147 if ((tileLeft % REGIONSIZE) == 0) {
148 // Vertical
149 ctx.beginPath();
150 ctx.moveTo(0, 0);
151 ctx.lineTo(0, TILESIZE);
152 ctx.stroke();
153 }
154 if ((tileBottom % REGIONSIZE) == 0) {
155 // Horizontal
156 ctx.beginPath();
157 ctx.moveTo(0, TILESIZE);
158 ctx.lineTo(TILESIZE, TILESIZE);
159 ctx.stroke();
160 }
161 if ((tileLeft % REGIONSIZE) == 0 && (tileBottom % REGIONSIZE) == 0) {
162 ctx.fillText(FormatRegionFileName(CoordToRegion(blockPos)), 4, TILESIZE-5);
163 }
[150]164 }
165
[186]166 }
[150]167
[173]168
[186]169 // ===============================================================================================
170 // Reload control
[179]171
[186]172 L.Control.ReloadTiles = L.Control.extend({
173 options: {
174 position: 'bottomleft'
175 },
[173]176
[186]177 onAdd: function (map) {
178 var name = 'control-reloadtiles',
179 container = L.DomUtil.create('div', name + ' leaflet-bar');
[179]180
[186]181 this._map = map;
[179]182
[186]183 this._reloadbutton = this._createButton(
184 "Reload tiles", "Reload tiles",
185 name + "-btn", container, this._reload, this);
[179]186
[186]187 return container;
188 },
[179]189
[186]190 onRemove: function (map) {
191 },
[179]192
[186]193 _reload: function (e) {
194 tileTime = new Date().getTime();
195 tileLayer.redraw();
196 tileLayerMiniMap.redraw();
197 },
[179]198
[186]199 _createButton: function (html, title, className, container, fn, context) {
200 var link = L.DomUtil.create('a', className, container);
201 link.innerHTML = html;
202 link.href = '#';
203 link.title = title;
[179]204
[186]205 var stop = L.DomEvent.stopPropagation;
[179]206
[186]207 L.DomEvent
208 .on(link, 'click', stop)
209 .on(link, 'mousedown', stop)
210 .on(link, 'dblclick', stop)
211 .on(link, 'click', L.DomEvent.preventDefault)
212 .on(link, 'click', fn, context)
213 .on(link, 'click', this._refocusOnMap, context);
[179]214
[186]215 return link;
216 }
[179]217
[186]218 });
[179]219
[186]220 new L.Control.ReloadTiles({
221 }).addTo(map);
[179]222
223
[186]224 // ===============================================================================================
225 // Coordinates control
226 // <div id="info">
227 // MouseCoords: <span id="pos"></span>
228 // </div>
[179]229
[186]230 L.Control.Coordinates = L.Control.extend({
231 options: {
232 position: 'bottomleft'
233 },
[179]234
[186]235 onAdd: function (map) {
236 var name = 'control-coordinates',
237 container = L.DomUtil.create('div', name + ' leaflet-bar');
[179]238
[186]239 container.innerHTML = "- N / - E"
[179]240
[186]241 this._map = map;
242 this._div = container;
[179]243
[186]244 map.on('mousemove', this._onMouseMove, this);
[179]245
[186]246 return container;
247 },
[179]248
[186]249 onRemove: function (map) {
250 },
[179]251
[186]252 _onMouseMove: function (e) {
253 this._div.innerHTML = FormatCoord(e.latlng);
254 }
[179]255
256
[186]257 });
[179]258
[186]259 new L.Control.Coordinates({
260 }).addTo(map);
[179]261
262
263
264
[186]265 // ===============================================================================================
266 // Overlays and controls
[153]267
[186]268 var playersOnlineMarkerGroup = L.layerGroup();
269 var playersOfflineMarkerGroup = L.markerClusterGroup({
270 maxClusterRadius: function(zoom) { return zoom == MAXZOOM ? 10 : 50; }
271 });
[150]272
273
[186]274 var landClaimsGroup = L.layerGroup();
275 var landClaimsClusterGroup = L.markerClusterGroup({
276 disableClusteringAtZoom: MAXZOOM,
277 singleMarkerMode: true,
278 maxClusterRadius: 50
279 });
280 var landClaimsRectGroup = L.layerGroup();
281 landClaimsGroup.addLayer(landClaimsClusterGroup);
282 landClaimsGroup.addLayer(landClaimsRectGroup);
283 var maxZoomForCluster = 4;
[133]284
[186]285 var baseLayers = {
286 //"Map": tileLayer
287 };
[153]288
[186]289 var overlays = {
290 "Land claims" : landClaimsGroup,
291 "Players (offline) (<span id='mapControlOfflineCount'>0</span>)" : playersOfflineMarkerGroup,
292 "Players (online) (<span id='mapControlOnlineCount'>0</span>)" : playersOnlineMarkerGroup,
293 "Region files": regionLayer,
294 };
[173]295
[186]296
297 L.control.layers(baseLayers, overlays, {
298 collapsed: false
299 }).addTo(map);
[173]300
[186]301 var miniMap = new L.Control.MiniMap(tileLayerMiniMap, {
302 zoomLevelOffset: -6,
303 toggleDisplay: true
304 }).addTo(map);
[173]305
306
[186]307 var playersMappingList = {};
[173]308
[186]309
310
311 // ===============================================================================================
312 // Inventory dialog
313
314 var showInv = function(steamid) {
315 $.getJSON( "../api/getplayerinventory", { steamid: steamid })
316 .done(function(data) {
317 $("#invPlayerName").text(playersMappingList[steamid].name);
318 for (var y = 0; y < BAG_ROWS; y++) {
319 for (var x = 0; x < BAG_COLS; x++) {
320 if (data.bag[y*BAG_COLS+x].count > 0) {
321 $("#bagField"+x+"_"+y).attr("style", "background-image: url(itemimages/" + data.bag[y*BAG_COLS+x].name + ".png);");
322 $("#bagFieldText"+x+"_"+y).text(data.bag[y*BAG_COLS+x].count);
323 } else {
324 $("#bagField"+x+"_"+y).attr("style", "background-image: none;");
325 $("#bagFieldText"+x+"_"+y).text("");
326 }
[163]327 }
328 }
329
[186]330 for (var x = 0; x < BELT_COLS; x++) {
331 if (data.belt[x].count > 0) {
332 $("#beltField"+x).attr("style", "background-image: url(itemimages/" + data.belt[x].name + ".png);");
333 $("#beltFieldText"+x).text(data.belt[x].count);
334 } else {
335 $("#beltField"+x).attr("style", "background-image: none;");
336 $("#beltFieldText"+x).text("");
337 }
[163]338 }
339
[186]340 $( "#playerInventoryDialog" ).css("z-index", "1010").dialog({
341 modal: true,
342 width: BAG_COLS*(INV_ITEM_WIDTH+14) + 20,
343 buttons: {
344 Ok: function() {
345 $( this ).dialog( "close" );
346 }
[163]347 }
[186]348 });
349 })
350 .fail(function(jqxhr, textStatus, error) {
351 console.log("Error fetching player inventory");
352 })
353 .always(function() {
[163]354 });
[186]355 };
[163]356
[186]357 for (var y = 0; y < BAG_ROWS; y++) {
358 $("#bagTable").append("<tr id=\"bagRow"+y+"\"></tr>");
359 for (var x = 0; x < BAG_COLS; x++) {
360 $("#bagRow"+y).append(
361 "<td class=\"invField\" id=\"bagField"+x+"_"+y+"\">" +
362 "<span class=\"invFieldText\" id=\"bagFieldText"+x+"_"+y+"\"></span>" +
363 "</td>");
364 }
365 }
366
367 $("#beltTable").append("<tr id=\"beltRow0\"></tr>");
368 for (var x = 0; x < BELT_COLS; x++) {
369 $("#beltRow0").append(
370 "<td class=\"invField\" id=\"beltField"+x+"\">" +
371 "<span class=\"invFieldText\" id=\"beltFieldText"+x+"\"></span>" +
[163]372 "</td>");
373 }
374
375
[173]376
[186]377 // ===============================================================================================
378 // Player markers
[173]379
[186]380 $(".leaflet-popup-pane").on('click.action', '.inventoryButton', function(event) {
381 showInv($(this).data('steamid'));
382 });
[173]383
[186]384 var setPlayerMarkers = function(data) {
385 var online = 0;
386 var offline = 0;
387 $.each( data, function( key, val ) {
388 var marker;
389 if (playersMappingList.hasOwnProperty(val.steamid)) {
390 marker = playersMappingList[val.steamid].currentPosMarker;
391 marker.setLatLng([val.position.x, val.position.z]);
[153]392 } else {
[186]393 marker = L.marker([val.position.x, val.position.z]).bindPopup(
394 "Player: " + val.name + "<br/>" +
395 "<a class='inventoryButton' data-steamid='"+val.steamid+"'>Show inventory</a>"
396 );
397 playersMappingList[val.steamid] = { online: !val.online };
[153]398 }
[186]399 if (playersMappingList[val.steamid].online != val.online) {
400 if (val.online) {
401 marker.setOpacity(1.0);
402 playersOfflineMarkerGroup.removeLayer(marker);
403 playersOnlineMarkerGroup.addLayer(marker);
404 } else {
405 marker.setOpacity(0.5);
406 playersOnlineMarkerGroup.removeLayer(marker);
407 playersOfflineMarkerGroup.addLayer(marker);
408 }
409 }
410 val.currentPosMarker = marker;
411 playersMappingList[val.steamid] = val;
[157]412
[186]413 if (val.online)
414 online++;
415 else
416 offline++;
417 });
418 $( "#mapControlOnlineCount" ).text( online );
419 $( "#mapControlOfflineCount" ).text( offline );
420 }
[153]421
[186]422 var updatePlayerEvent = function() {
423 $.getJSON( "../api/getplayerslocation")
424 .done(setPlayerMarkers)
425 .fail(function(jqxhr, textStatus, error) {
426 console.log("Error fetching players list");
427 })
428 .always(function() {
429 window.setTimeout(updatePlayerEvent, 2000);
430 });
431 }
[153]432
[186]433 window.setTimeout(updatePlayerEvent, 500);
[153]434
[173]435
436
[186]437 // ===============================================================================================
438 // Land claim markers
[173]439
[186]440 var setLandClaims = function(data) {
441 landClaimsClusterGroup.clearLayers();
442 landClaimsRectGroup.clearLayers();
443
444 var claimPower = Math.floor(Math.log(data.claimsize) / Math.LN2);
445 var maxClusterZoomUnlimited = MAXZOOM - (claimPower - 3);
446 var maxClusterZoomLimitedMax = Math.min(maxClusterZoomUnlimited, MAXZOOM+1);
447 maxZoomForCluster = Math.max(maxClusterZoomLimitedMax, 0);
448
449 checkClaimClustering({target: map});
[173]450
[186]451 var sizeHalf = Math.floor(data.claimsize / 2);
452
453 $.each( data.claimowners, function( key, val ) {
454 var steamid = val.steamid;
455 var active = val.claimactive;
456 var color = active ? "#55ff55" : "#ff0000";
[173]457
[186]458 $.each( val.claims, function( key, val ) {
459 var pos = L.latLng(val.x, val.z);
460 var bounds = L.latLngBounds(L.latLng(val.x - sizeHalf, val.z - sizeHalf), L.latLng(val.x + sizeHalf, val.z + sizeHalf));
461 var r = L.rectangle(bounds, {color: color, weight: 1, opacity: 0.8, fillOpacity: 0.15});
462 var m = L.marker(pos, { clickable: false, keyboard: false, zIndexOffset:-1000, iconSize: [0,0], icon: L.divIcon({className: 'invisIcon', iconSize:[0,0]}) });
463 if (playersMappingList.hasOwnProperty(steamid)) {
[201]464 var name = playersMappingList[steamid].name;
[186]465 } else {
[201]466 var name = "unknown"
[186]467 }
[201]468 r.bindPopup("Owner: " + name + " ("+steamid+")<br/>Position: " + val.x + " / " + val.y + " / " + val.z);
[186]469 landClaimsRectGroup.addLayer(r);
470 landClaimsClusterGroup.addLayer(m);
471 });
[173]472 });
[186]473 }
474
475 var updateClaimsEvent = function() {
476 $.getJSON( "../api/getlandclaims")
477 .done(setLandClaims)
478 .fail(function(jqxhr, textStatus, error) {
479 console.log("Error fetching land claim list");
480 })
481 .always(function() {
482 //updateClaimTimer = window.setTimeout(updateClaimsEvent, 3000);
483 });
484 }
485
486
487
488 // ===============================================================================================
489 // Layer events
490
491 var updateClaimTimer;
492 map.on('overlayadd', function(e) {
493 if (e.layer == landClaimsGroup) {
494 updateClaimsEvent();
495 }
[173]496 });
497
[186]498 map.on('overlayremove', function(e) {
499 if (e.layer == landClaimsGroup) {
500 //window.clearTimeout(updateClaimTimer);
501 }
[173]502 });
503
[186]504 var checkClaimClustering = function(e) {
505 if (e.target._zoom >= maxZoomForCluster) {
506 landClaimsGroup.removeLayer(landClaimsClusterGroup);
507 } else {
508 landClaimsGroup.addLayer(landClaimsClusterGroup);
509 }
510 };
[173]511
[186]512 map.on('zoomend', checkClaimClustering);
[179]513
[186]514}
[179]515
516
[186]517
518$.getJSON( "../map/mapinfo.json")
519.done(function(data) {
520 TILESIZE = data.blockSize;
521 MAXZOOM = data.maxZoom;
522})
523.fail(function(jqxhr, textStatus, error) {
524 console.log("Error fetching map information");
525})
526.always(function() {
[193]527 initMap();
[179]528});
529
Note: See TracBrowser for help on using the repository browser.