Made dynmap's javascript self-contained, which allows for multiple maps on a single page.

This commit is contained in:
FrozenCow 2011-01-14 20:08:23 +01:00
parent 77b0bc1664
commit dfe33efdc3
5 changed files with 333 additions and 306 deletions

View File

@ -14,4 +14,3 @@ var config = {
tileWidth: 128,
tileHeight: 128
};

View File

@ -18,38 +18,15 @@
<script type="text/javascript" src="map.js"></script>
<script type="text/javascript" src="kzedmaps.js"></script>
<script type="text/javascript" src="config.js"></script>
<script type="text/javascript">
$(document).ready(function() {
new DynMap($.extend({
container: $('#mcmap'),
}, config));
});
</script>
</head>
<body>
<div id="mcmap"></div>
<div id="alert">Updating...</div>
<div id="plist">
<input type="checkbox" onclick="$('#lst').toggle()" title="Toggle Player List" checked="checked"/>
<div id="lst">
<div id="maplist"></div>
<div id="playerlst"></div>
<div id="clock"></div>
</div>
</div>
<div id="controls">
<form action="#" method="get">
<div id="warpsDiv" style="display:none;">
<img src="warp.png" alt="Warps" title="Warps" />
<input type="checkbox" checked="checked" id="showWarps" />
</div>
<div id="signsDiv" style="display:none;">
<img src="sign.png" alt="Signs" title="Signs" />
<input type="checkbox" checked="checked" id="showSigns" /><br />
</div>
<div id="homesDiv" style="display:none;">
<img src="home.png" alt="Homes" title="Homes" />
<input type="checkbox" checked="checked" id="showHomes" /><br />
</div>
<div id="spawnsDiv" style="display:none;">
<img src="spawn.png" alt="Spawn" title="Spawn" />
<input type="checkbox" checked="checked" id="showSpawn" /><br />
</div>
</form>
</div>
<div id="link"></div>
</body>
</html>

View File

@ -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 = $('<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(){}

View File

@ -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();
}
DynMap.prototype = {
registeredTiles: new Array(),
clock: null,
markers: new Array(),
lasttimestamp: '0',
followingPlayer: '',
initialize: function() {
var me = this;
function registerTile(mapType, tileName, tile) {
registeredTiles[tileName] = {
tileElement: tile,
mapType: mapType,
lastseen: '0'
};
}
var container = $(me.options.container);
function unregisterTile(mapType, tileName) {
delete registeredTiles[tileName];
}
var mapContainer;
(mapContainer = $('<div/>'))
.addClass('map')
.appendTo(container);
function onTileUpdated(tileName) {
var tile = registeredTiles[tileName];
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'
});
if (tile) {
tile.lastseen = lasttimestamp;
tile.mapType.onTileUpdated(tile.tileElement, tileName);
}
}
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();
});*/
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($('<img/>').attr({src: mi.type + '.png'}))
.append($('<span/>').text(mi.text));
};
if (mi.type == 'player') {
contentfun = function(div, mi) {
$(div)
.addClass('Marker')
.addClass('playerMarker')
.append($('<span/>')
.addClass('playerName')
.text(mi.text));
// The sidebar
var sidebar = me.sidebar = $('<div/>')
.addClass('sidebar')
.appendTo(container);
getMinecraftHead(mi.text, 32, function(head) {
$(head)
.addClass('playerIcon')
.prependTo(div);
});
};
}
var marker = new CustomMarker(mi.position, map, contentfun, mi);
marker.markerType = mi.type;
// The map list.
var maplist = me.maplist = $('<div/>')
.addClass('maplist')
.appendTo(sidebar);
markers[mi.id] = marker;
$.each(me.options.maps, function(name, mapType){
mapType.dynmap = me;
map.mapTypes.set(name, mapType);
if (mi.type == 'player') {
marker.playerRow = $('<div/>')
.attr({ id: 'playerrow_' + mi.text })
.addClass('playerrow')
.append(marker.followButton = $('<input/>')
.attr({ type: 'checkbox',
name: 'followPlayer',
checked: false,
value: mi.text
})
.addClass('followButton')
.click(function(e) {
followPlayer(mi.id != followingPlayer ? mi.id : '');
}))
.append(marker.playerIconContainer = $('<span/>'))
.append($('<a/>')
.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 mapButton;
$('#maplist').append($('<div/>')
var mapButton;
$('<div/>')
.addClass('maprow')
.append(mapButton = $('<input/>')
.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($('<label/>')
.attr('for', 'maptypebutton_' + name)
.text(name)
)
.click(function() {
$('.mapbutton').removeAttr('checked');
$('.mapbutton', maplist).removeAttr('checked');
map.setMapTypeId(name);
mapButton.attr('checked', 'checked');
})
);
});
.data('maptype', mapType)
.appendTo(maplist);
});
map.setMapTypeId(me.options.defaultMap);
map.setMapTypeId(config.defaultMap);
// The Player List
var playerlist = me.playerlist = $('<div/>')
.addClass('playerlist')
.appendTo(sidebar);
clock = new MinecraftClock($('#clock'));
// The Clock
var clock = me.clock = new MinecraftClock(
$('<div/>')
.addClass('clock')
.appendTo(sidebar)
);
setTimeout(mapUpdate, config.updateRate);
}
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;
}
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;
// TODO: Enable hash-links.
/*
var link;
var linkbox = me.linkbox = $('<div/>')
.addClass('linkbox')
.append(link=$('<input type="text" />'))
.data('link', link)
.appendTo(container);*/
var alertbox = me.alertbox = $('<div/>')
.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));
var typeVisibleMap = {};
var newmarkers = {};
for(var rowIndex in rows) {
var line = rows[rowIndex];
row = splitArgs(line, 'type', 'name', 'posx', 'posy', 'posz');
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
};
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($('<img/>').attr({src: mi.type + '.png'}))
.append($('<span/>').text(mi.text));
};
if (mi.type == 'player') {
contentfun = function(div, mi) {
$(div)
.addClass('Marker')
.addClass('playerMarker')
.append($('<span/>')
.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 = $('<div/>')
.attr({ id: 'playerrow_' + mi.text })
.addClass('playerrow')
.append(marker.followButton = $('<input/>')
.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 = $('<span/>'))
.append($('<a/>')
.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);
}*/
}

View File

@ -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;