diff --git a/web/config.js b/web/config.js index 00b68fbd..949e0620 100644 --- a/web/config.js +++ b/web/config.js @@ -13,5 +13,4 @@ var config = { }, tileWidth: 128, tileHeight: 128 -}; - +}; \ No newline at end of file diff --git a/web/index.html b/web/index.html index fd05e68f..be5671cc 100644 --- a/web/index.html +++ b/web/index.html @@ -17,39 +17,16 @@ - + +
-
Updating...
-
- -
-
-
-
-
-
-
-
- - - - -
-
- diff --git a/web/kzedmaps.js b/web/kzedmaps.js index 5b92fdf6..20f300d9 100644 --- a/web/kzedmaps.js +++ b/web/kzedmaps.js @@ -26,9 +26,9 @@ KzedProjection.prototype = { } }; -KzedMapType.prototype = new DynMapType(); function KzedMapType() {} KzedMapType.prototype = { + __proto__: new DynMapType(), constructor: KzedMapType, projection: new KzedProjection(), tileSize: new google.maps.Size(128, 128), @@ -98,7 +98,7 @@ KzedMapType.prototype = { } if (tileName) { img = $('') - .attr('src', getTileUrl(tileName)) + .attr('src', this.dynmap.getTileUrl(tileName)) .error(function() { img.hide(); }) .css({ width: imgSize + 'px', @@ -108,14 +108,15 @@ KzedMapType.prototype = { marginTop: offset.y + 'px' }) .appendTo(tile); - registerTile(this, tileName, img); + this.dynmap.registerTile(this, tileName, img); } else { - unregisterTile(this, tileName); + this.dynmap.unregisterTile(this, tileName); } return tile.get(0); }, }; + DefaultMapType.prototype = new KzedMapType(); DefaultMapType.prototype.constructor = DefaultMapType; function DefaultMapType(){} diff --git a/web/map.js b/web/map.js index fbb65766..be4d87d7 100644 --- a/web/map.js +++ b/web/map.js @@ -1,9 +1,26 @@ if (!console) console = { log: function() {} }; +function splitArgs(s) { + var r = s.split(' '); + delete arguments[0]; + var obj = {}; + var index = 0; + for(var argumentIndex in arguments) { + var argument = arguments[argumentIndex]; + var value = r[argumentIndex-1]; + obj[argument] = value; + } + return obj; +} + +function swtch(value, options, defaultOption) { + return (options[value] || defaultOption)(value); +} + function DynMapType() { } DynMapType.prototype = { onTileUpdated: function(tile, tileName) { - var src = getTileUrl(tileName); + var src = this.dynmap.getTileUrl(tileName); tile.attr('src', src); tile.show(); } @@ -50,217 +67,66 @@ MinecraftClock.prototype = { } }; -var registeredTiles = new Array(); -var clock = null; -var markers = new Array(); -var lasttimestamp = '0'; -var followingPlayer = ''; - -function getTileUrl(tileName, always) { - var tile = registeredTiles[tileName]; - - if(tile) { - return config.tileUrl + tileName + '.png?' + tile.lastseen; - } else { - return config.tileUrl + tileName + '.png?0'; - } +function DynMap(options) { + this.options = options; + this.initialize(); } - -function registerTile(mapType, tileName, tile) { - registeredTiles[tileName] = { - tileElement: tile, - mapType: mapType, - lastseen: '0' - }; -} - -function unregisterTile(mapType, tileName) { - delete registeredTiles[tileName]; -} - -function onTileUpdated(tileName) { - var tile = registeredTiles[tileName]; - - if (tile) { - tile.lastseen = lasttimestamp; - tile.mapType.onTileUpdated(tile.tileElement, tileName); - } -} - -function updateMarker(mi) { - if(mi.id in markers) { - var m = markers[mi.id]; - m.toggle(mi.visible); - m.setPosition(mi.position); - } else { - var contentfun = function(div,mi) { - $(div) - .addClass('Marker') - .addClass(mi.type + 'Marker') - .append($('').attr({src: mi.type + '.png'})) - .append($('').text(mi.text)); - }; - if (mi.type == 'player') { - contentfun = function(div, mi) { - $(div) - .addClass('Marker') - .addClass('playerMarker') - .append($('') - .addClass('playerName') - .text(mi.text)); - - getMinecraftHead(mi.text, 32, function(head) { - $(head) - .addClass('playerIcon') - .prependTo(div); - }); - }; - } - var marker = new CustomMarker(mi.position, map, contentfun, mi); - marker.markerType = mi.type; +DynMap.prototype = { + registeredTiles: new Array(), + clock: null, + markers: new Array(), + lasttimestamp: '0', + followingPlayer: '', + initialize: function() { + var me = this; - markers[mi.id] = marker; - - if (mi.type == 'player') { - marker.playerRow = $('
') - .attr({ id: 'playerrow_' + mi.text }) - .addClass('playerrow') - .append(marker.followButton = $('') - .attr({ type: 'checkbox', - name: 'followPlayer', - checked: false, - value: mi.text - }) - .addClass('followButton') - .click(function(e) { - followPlayer(mi.id != followingPlayer ? mi.id : ''); - })) - .append(marker.playerIconContainer = $('')) - .append($('') - .text(mi.text) - .attr({ href: '#' }) - .click(function(e) { map.panTo(markers[mi.id].getPosition()); }) - ); - - getMinecraftHead(mi.text, 16, function(head) { - marker.playerRow.icon = $(head) - .addClass('playerIcon') - .appendTo(marker.playerIconContainer); - }); - - $('#playerlst').append(marker.playerRow); - } - } - - if(mi.id == followingPlayer) { - map.panTo(markers[mi.id].getPosition()); - } -} - -function mapUpdate() -{ - $.ajax({ - url: config.updateUrl + lasttimestamp, - success: function(res) { - $('#alert') - .hide(); - var typeVisibleMap = { - 'warp': document.getElementById('showWarps').checked, - 'sign': document.getElementById('showSigns').checked, - 'home': document.getElementById('showHomes').checked, - 'spawn': document.getElementById('showSpawn').checked - }; - - var typeCount = {}; - - var rows = res.split('\n'); - var loggedin = new Array(); - var firstRow = rows[0].split(' '); - lasttimestamp = firstRow[0]; - delete rows[0]; - - var servertime = firstRow[1]; - clock.setTime(getMinecraftTime(servertime)); - - for(var line in rows) { - var p = rows[line].split(' '); - - if (p[0] == '') continue; - - ({ tile: function() { - onTileUpdated(p[1]); - } - }[p[0]] || function() { - var mi = { - id: p[0] + '_' + p[1], - text: p[1], - type: p[0], - position: map.getProjection().fromWorldToLatLng(p[2], p[3], p[4]), - visible: ((p[0] in typeVisibleMap) ? typeVisibleMap[p[0]] : true) - }; - - updateMarker(mi); - loggedin[mi.id] = 1; - if (!mi.type in typeCount) typeCount[mi.type] = 0; - typeCount[mi.type]++; - })(); - } - - for(var m in markers) { - if(!(m in loggedin)) { - markers[m].remove(null); - if (markers[m].playerRow) { - markers[m].playerRow.remove(); - } - delete markers[m]; - } - } - setTimeout(mapUpdate, config.updateRate); - document.getElementById('warpsDiv').style.display = (typeCount['warps'] == 0)?'none':''; - document.getElementById('signsDiv').style.display = (typeCount['signs'] == 0)?'none':''; - document.getElementById('homesDiv').style.display = (typeCount['homes'] == 0)?'none':''; - document.getElementById('spawnsDiv').style.display = (typeCount['spawns'] == 0)?'none':''; - }, - error: function(request, statusText, ex) { - $('#alert') - .text('Could not update map') - .show(); - setTimeout(mapUpdate, config.updateRate); - } - }); -} - -window.onload = function initialize() { - var mapOptions = { - zoom: 1, - center: new google.maps.LatLng(0, 1), - navigationControl: true, - navigationControlOptions: { - style: google.maps.NavigationControlStyle.DEFAULT - }, - scaleControl: false, - mapTypeControl: false, - streetViewControl: false, - backgroundColor: '#000' - }; - map = new google.maps.Map(document.getElementById("mcmap"), mapOptions); - - google.maps.event.addListener(map, 'dragstart', function(mEvent) { - followPlayer(''); - }); - google.maps.event.addListener(map, 'zoom_changed', function() { - makeLink(); - }); - google.maps.event.addListener(map, 'center_changed', function() { - makeLink(); - }); - map.dragstart = followPlayer(''); - - $.each(config.maps, function(name, mapType){ - map.mapTypes.set(name, mapType); + var container = $(me.options.container); - var mapButton; - $('#maplist').append($('
') + var mapContainer; + (mapContainer = $('
')) + .addClass('map') + .appendTo(container); + + var map = this.map = new google.maps.Map(mapContainer.get(0), { + zoom: 1, + center: new google.maps.LatLng(0, 1), + navigationControl: true, + navigationControlOptions: { + style: google.maps.NavigationControlStyle.DEFAULT + }, + scaleControl: false, + mapTypeControl: false, + streetViewControl: false, + backgroundColor: '#000' + }); + + google.maps.event.addListener(map, 'dragstart', function(mEvent) { + me.followPlayer(''); + }); + // TODO: Enable hash-links. + /*google.maps.event.addListener(map, 'zoom_changed', function() { + me.updateLink(); + }); + google.maps.event.addListener(map, 'center_changed', function() { + me.updateLink(); + });*/ + + // The sidebar + var sidebar = me.sidebar = $('
') + .addClass('sidebar') + .appendTo(container); + + // The map list. + var maplist = me.maplist = $('
') + .addClass('maplist') + .appendTo(sidebar); + + $.each(me.options.maps, function(name, mapType){ + mapType.dynmap = me; + map.mapTypes.set(name, mapType); + + var mapButton; + $('
') .addClass('maprow') .append(mapButton = $('') .addClass('maptype_' + name) @@ -269,42 +135,237 @@ window.onload = function initialize() { name: 'map', id: 'maptypebutton_' + name }) - .attr('checked', config.defaultMap == name ? 'checked' : null) + .attr('checked', me.options.defaultMap == name ? 'checked' : null) ) .append($('
') + .addClass('playerlist') + .appendTo(sidebar); + + // The Clock + var clock = me.clock = new MinecraftClock( + $('
') + .addClass('clock') + .appendTo(sidebar) + ); + + // TODO: Enable hash-links. + /* + var link; + var linkbox = me.linkbox = $('
') + .addClass('linkbox') + .append(link=$('')) + .data('link', link) + .appendTo(container);*/ + + var alertbox = me.alertbox = $('
') + .addClass('alertbox') + .appendTo(container); + + setTimeout(function() { me.update(); }, me.options.updateRate); + }, + update: function() { + var me = this; + $.ajax({ + url: me.options.updateUrl + me.lasttimestamp, + success: function(res) { + if (!res) { + me.alertbox + .text('Invalid response') + .show(); + } + + me.alertbox.hide(); + var rows = res.split('\n'); + var row = splitArgs(rows[0], 'timestamp', 'servertime'); + delete rows[0]; + + me.lasttimestamp = row.timestamp; + me.clock.setTime(getMinecraftTime(row.servertime)); - map.setMapTypeId(config.defaultMap); - - clock = new MinecraftClock($('#clock')); - - setTimeout(mapUpdate, config.updateRate); -} + var typeVisibleMap = {}; + var newmarkers = {}; + + for(var rowIndex in rows) { + var line = rows[rowIndex]; + row = splitArgs(line, 'type', 'name', 'posx', 'posy', 'posz'); -function followPlayer(name) { - $('.followButton').removeAttr('checked'); - - if(name in markers) { - var m = markers[name]; - $(m.followButton).attr('checked', 'checked'); - map.panTo(m.getPosition()); - } - followingPlayer = name; -} + if (!row.type) continue; + + swtch(row.type, { + tile: function() { + me.onTileUpdated(row.name); + } + }, function() { + var mi = { + id: row.type + '_' + row.name, + text: row.name, + type: row.type, + position: me.map.getProjection().fromWorldToLatLng(parseFloat(row.posx), parseFloat(row.posy), parseFloat(row.posz)), + visible: true + }; -function makeLink() { - var a=location.href.substring(0,location.href.lastIndexOf("/")+1) - + "?lat=" + map.getCenter().lat().toFixed(6) - + "&lng=" + map.getCenter().lng().toFixed(6) - + "&zoom=" + map.getZoom(); - document.getElementById("link").innerHTML = a; -} + me.updateMarker(mi); + newmarkers[mi.id] = mi; + }); + } + + for(var m in me.markers) { + var marker = me.markers[m]; + if(!(m in newmarkers)) { + marker.remove(null); + if (marker.playerRow) { + marker.playerRow.remove(); + } + delete me.markers[m]; + } + } + setTimeout(function() { me.update(); }, me.options.updateRate); + }, + error: function(request, statusText, ex) { + me.alertbox + .text('Could not update map') + .show(); + setTimeout(function() { me.update(); }, me.options.updateRate); + } + }); + }, + onTileUpdated: function(tileName) { + var me = this; + var tile = this.registeredTiles[tileName]; + + if (tile) { + tile.lastseen = this.lasttimestamp; + tile.mapType.onTileUpdated(tile.tileElement, tileName); + } + }, + updateMarker: function(mi) { + var me = this; + var markers = me.markers; + var map = me.map; + + if(mi.id in markers) { + var m = markers[mi.id]; + m.toggle(mi.visible); + m.setPosition(mi.position); + } else { + var contentfun = function(div,mi) { + $(div) + .addClass('Marker') + .addClass(mi.type + 'Marker') + .append($('').attr({src: mi.type + '.png'})) + .append($('').text(mi.text)); + }; + if (mi.type == 'player') { + contentfun = function(div, mi) { + $(div) + .addClass('Marker') + .addClass('playerMarker') + .append($('') + .addClass('playerName') + .text(mi.text)); + + getMinecraftHead(mi.text, 32, function(head) { + $(head) + .addClass('playerIcon') + .prependTo(div); + }); + }; + } + var marker = new CustomMarker(mi.position, map, contentfun, mi); + marker.markerType = mi.type; + + markers[mi.id] = marker; + + if (mi.type == 'player') { + marker.playerRow = $('
') + .attr({ id: 'playerrow_' + mi.text }) + .addClass('playerrow') + .append(marker.followButton = $('') + .attr({ type: 'checkbox', + name: 'followPlayer', + checked: false, + value: mi.text + }) + .addClass('followButton') + .click(function(e) { + me.followPlayer(mi.id != me.followingPlayer ? mi.id : ''); + })) + .append(marker.playerIconContainer = $('')) + .append($('') + .text(mi.text) + .attr({ href: '#' }) + .click(function(e) { map.panTo(markers[mi.id].getPosition()); }) + ); + + getMinecraftHead(mi.text, 16, function(head) { + marker.playerRow.icon = $(head) + .addClass('playerIcon') + .appendTo(marker.playerIconContainer); + }); + + me.playerlist.append(marker.playerRow); + } + } + + if(mi.id == me.followingPlayer) { + map.panTo(markers[mi.id].getPosition()); + } + }, + followPlayer: function(name) { + var me = this; + $('.followButton', me.playerlist).removeAttr('checked'); + + var m = me.markers[name]; + if(m) { + $(m.followButton).attr('checked', 'checked'); + me.map.panTo(m.getPosition()); + } + this.followingPlayer = name; + }, + getTileUrl: function(tileName, always) { + var me = this; + var tile = me.registeredTiles[tileName]; + + if(tile) { + return me.options.tileUrl + tileName + '.png?' + tile.lastseen; + } else { + return me.options.tileUrl + tileName + '.png?0'; + } + }, + registerTile: function(mapType, tileName, tile) { + this.registeredTiles[tileName] = { + tileElement: tile, + mapType: mapType, + lastseen: '0' + }; + }, + unregisterTile: function(mapType, tileName) { + delete registeredTiles[tileName]; + }, + // TODO: Enable hash-links. +/* updateLink: function() { + var me = this; + var url = location.href.match(/^[^#]+/); + + var a=url + + "#lat=" + me.map.getCenter().lat().toFixed(6) + + "&lng=" + me.map.getCenter().lng().toFixed(6) + + "&zoom=" + me.map.getZoom(); + me.linkbox.data('link').val(a); + }*/ +} \ No newline at end of file diff --git a/web/style.css b/web/style.css index ea53131d..049f1ca2 100644 --- a/web/style.css +++ b/web/style.css @@ -1,7 +1,12 @@ html { height: 100% } body { height: 100%; margin: 0px; padding: 0px ; background-color: #000; } #mcmap { width:100%; height: 100% } -#plist { + +.map { + width: 100%; height: 100%; +} + +.sidebar { position: absolute; top: 8px; right: 8px; @@ -15,51 +20,34 @@ input { margin: 0px; } -#lst, label { +.sidebar, label { clear:both; font-family: sans-serif; font-size: 8pt; color: white; } -#plistbtn { - float:right; - cursor:pointer; -} -#cavebtn { - float:right; - cursor:pointer; -} -#link { + +.linkbox { position: absolute; bottom: 4px; left: 80px; - border: 1px solid #808080; - background: #000; +} + +.linkbox input { opacity: 0.6; + border: 1px solid #808080; padding: 2px; + background: #000; font-size: 8pt; color: #ddd; + width: 10em; } -#controls { - position: absolute; - top: 12px; - left: 45px; - border: 1px solid #808080; - background: #000; - opacity: 0.6; - padding: 2px; - font-size: 8pt; - color: #ddd; - text-align:right; -} -#controls img{ - height:14px; - width:14px; -} + a, a:visited, label { color: white; text-decoration: none; } + .labels { font-size: 10pt; font-family: sans-serif; @@ -79,15 +67,16 @@ a, a:visited, label { background-color:#000; border: 0px; } -#clock { + +.clock { padding-left: 16px; color: #dede90; background-repeat: no-repeat; } -#clock.night { background-image: url(clock_night.png); } -#clock.day { background-image: url(clock_day.png); } +.clock.night { background-image: url(clock_night.png); } +.clock.day { background-image: url(clock_day.png); } -#alert { +.alertbox { padding: 5px; position: fixed; margin: auto;