Added (proper) initial Leaflet support.

This commit is contained in:
FrozenCow 2011-07-16 23:53:15 +02:00
parent bf85b2a8be
commit baf7bf83c5
17 changed files with 950 additions and 178 deletions

View file

@ -1,90 +1,111 @@
function CustomMarker(latlng, map, oncreated) {
google.maps.OverlayView.call(this);
this.latlng_ = latlng;
// Once the LatLng and text are set, add the overlay to the map. This will
// trigger a call to panes_changed which should in turn call draw.
this.setMap(map);
this.oncreated = oncreated;
}
L.CustomMarker = L.Class.extend({
CustomMarker.prototype = new google.maps.OverlayView();
CustomMarker.prototype.draw = function() {
var me = this;
if (this.removed)
return;
// Check if the div has been created.
var div = this.div_;
if (!div) {
// Create a overlay text DIV
div = this.div_ = document.createElement('DIV');
// Create the DIV representing our CustomMarker
div.style.position = "absolute";
includes: L.Mixin.Events,
options: {
contentCreator: undefined,
shadowCreator: undefined,
clickable: true,
draggable: false
},
initialize: function(latlng, options) {
L.Util.setOptions(this, options);
this._latlng = latlng;
},
onAdd: function(map) {
this._map = map;
google.maps.event.addDomListener(div, "click", function(event) {
google.maps.event.trigger(me, "click");
});
if (!this._element && this.options.elementCreator) {
this._element = this.options.elementCreator();
// TODO: Pass this fix to Leaflet-dev(s), it may be a bug in Leaflet.
this._element.style.position = 'absolute';
this._initInteraction();
}
if (!this._shadow && this.options.shadowCreator) {
this._shadow = this.options.shadowCreator();
}
this.oncreated(div);
if (this._element) {
map._panes.markerPane.appendChild(this._element);
}
if (this._shadow) {
map._panes.shadowPane.appendChild(this._shadow);
}
// Then add the overlay to the DOM
var panes = this.getPanes();
panes.overlayLayer.appendChild(div);
}
map.on('viewreset', this._reset, this);
this._reset();
},
// Position the overlay
var point = this.getProjection().fromLatLngToDivPixel(this.latlng_);
if (point) {
div.style.left = point.x + 'px';
div.style.top = point.y + 'px';
}
};
onRemove: function(map) {
if (this._element) {
map._panes.markerPane.removeChild(this._element);
}
if (this._shadow) {
map._panes.shadowPane.removeChild(this._elementShadow);
}
map.off('viewreset', this._reset, this);
},
getLatLng: function() {
return this._latlng;
},
setLatLng: function(latlng) {
this._latlng = latlng;
this._reset();
},
_reset: function() {
var pos = this._map.latLngToLayerPoint(this._latlng);
if (this._element) {
L.DomUtil.setPosition(this._element, pos);
}
if (this._shadow) {
L.DomUtil.setPosition(this._shadow, pos);
}
if (this._element) {
this._element.style.zIndex = pos.y;
}
},
_initInteraction: function() {
if (this._element && this.options.clickable) {
this._element.className += ' leaflet-clickable';
L.DomEvent.addListener(this._element, 'click', this._onMouseClick, this);
CustomMarker.prototype.setPosition = function(p) {
this.latlng_ = p;
var projection = this.getProjection();
if (projection) {
var point = projection.fromLatLngToDivPixel(this.latlng_);
this.div_.style.left = point.x + 'px';
this.div_.style.top = point.y + 'px';
var events = ['dblclick', 'mousedown', 'mouseover', 'mouseout'];
for (var i = 0; i < events.length; i++) {
L.DomEvent.addListener(this._element, events[i], this._fireMouseEvent, this);
}
}
if (this._element && L.Handler.MarkerDrag) {
this.dragging = new L.Handler.MarkerDrag(this);
if (this.options.draggable) {
this.dragging.enable();
}
}
},
_onMouseClick: function(e) {
L.DomEvent.stopPropagation(e);
if (this.dragging && this.dragging.moved()) { return; }
this.fire(e.type);
},
_fireMouseEvent: function(e) {
this.fire(e.type);
L.DomEvent.stopPropagation(e);
}
};
CustomMarker.prototype.getPosition = function(p) {
return this.latlng_;
};
CustomMarker.prototype.hide = function() {
if (this.div_ && !this.isHidden) {
this.div_.style.display = 'none';
this.isHidden = true;
}
}
CustomMarker.prototype.show = function() {
if (this.div_ && this.isHidden) {
this.div_.style.display = 'block';
this.isHidden = false;
}
}
CustomMarker.prototype.toggle = function(t) {
if ((typeof t) == "boolean") {
if (t) { this.show(); }
else { this.hide(); }
} else {
this.toggle((this.isHidden) == true);
}
}
CustomMarker.prototype.remove = function() {
// Check if the overlay was on the map and needs to be removed.
if (this.div_) {
this.div_.parentNode.removeChild(this.div_);
this.div_ = null;
this.removed = true;
}
};
});

181
web/js/dynmaputils.js Normal file
View file

@ -0,0 +1,181 @@
var DynmapProjection = L.Class.extend({
fromLocationToLatLng: function(location) {
throw "fromLocationToLatLng not implemented";
}
});
var DynmapTileLayer = L.TileLayer.extend({
_currentzoom: undefined,
getProjection: function() {
return this.projection;
},
onTileUpdated: function(tile, tileName) {
var src = this.dynmap.getTileUrl(tileName);
tile.attr('src', src);
tile.show();
},
getTileName: function(tilePoint, zoom) {
throw "getTileName not implemented";
},
getTileUrl: function(tilePoint, zoom) {
var tileName = this.getTileName(tilePoint, zoom);
var url = this._cachedTileUrls[tileName];
if (!url) {
this._cachedTileUrls[tileName] = url = this.options.dynmap.getTileUrl(tileName) + '?' + new Date().getUTCMilliseconds();
}
return url;
},
updateNamedTile: function(name) {
var tile = this._namedTiles[name];
delete this._cachedTileUrls[name];
if (tile) {
this.updateTile(tile);
}
},
updateTile: function(tile) {
this._loadTile(tile, tile.tilePoint, this._map.getZoom());
},
// We should override this, since Leaflet does modulo on tilePoint by default. (https://github.com/CloudMade/Leaflet/blob/master/src/layer/tile/TileLayer.js#L151)
_addTile: function(tilePoint) {
var tilePos = this._getTilePos(tilePoint),
zoom = this._map.getZoom(),
key = tilePoint.x + ':' + tilePoint.y,
name = this.getTileName(tilePoint, zoom);
// create tile
var tile = this._createTile();
tile.tileName = name;
tile.tilePoint = tilePoint;
L.DomUtil.setPosition(tile, tilePos);
this._tiles[key] = tile;
this._namedTiles[name] = tile;
this._loadTile(tile, tilePoint, zoom);
this._container.appendChild(tile);
},
_removeOtherTiles: function(bounds) {
var kArr, x, y, key;
for (key in this._tiles) {
if (this._tiles.hasOwnProperty(key)) {
kArr = key.split(':');
x = parseInt(kArr[0], 10);
y = parseInt(kArr[1], 10);
// remove tile if it's out of bounds
if (x < bounds.min.x || x > bounds.max.x || y < bounds.min.y || y > bounds.max.y) {
var tile = this._tiles[key];
if (tile.parentNode === this._container) {
this._container.removeChild(this._tiles[key]);
}
delete this._namedTiles[tile.tileName];
delete this._tiles[key];
}
}
}
},
_updateTileSize: function() {
var newzoom = this._map.getZoom();
if (this._currentzoom !== newzoom) {
var newTileSize = this.calculateTileSize(newzoom);
this._currentzoom = newzoom;
if (newTileSize !== this.options.tileSize) {
this.setTileSize(newTileSize);
}
}
},
_reset: function() {
this._updateTileSize();
this._tiles = {};
this._namedTiles = {};
this._cachedTileUrls = {};
this._initContainer();
this._container.innerHTML = '';
},
_update: function() {
this._updateTileSize();
var bounds = this._map.getPixelBounds(),
tileSize = this.options.tileSize;
var nwTilePoint = new L.Point(
Math.floor(bounds.min.x / tileSize),
Math.floor(bounds.min.y / tileSize)),
seTilePoint = new L.Point(
Math.floor(bounds.max.x / tileSize),
Math.floor(bounds.max.y / tileSize)),
tileBounds = new L.Bounds(nwTilePoint, seTilePoint);
this._addTilesFromCenterOut(tileBounds);
if (this.options.unloadInvisibleTiles) {
this._removeOtherTiles(tileBounds);
}
},
calculateTileSize: function(zoom) {
return this.options.tileSize;
},
setTileSize: function(tileSize) {
this.options.tileSize = tileSize;
this._tiles = {};
this._container.innerHTML = '';
this._createTileProto();
},
updateTileSize: function(zoom) {}
});
function loadjs(url, completed) {
var script = document.createElement('script');
script.setAttribute('src', url);
script.setAttribute('type', 'text/javascript');
var isloaded = false;
script.onload = function() {
if (isloaded) { return; }
isloaded = true;
completed();
};
// Hack for IE, don't know whether this still applies to IE9.
script.onreadystatechange = function() {
script.onload();
};
(document.head || document.getElementsByTagName('head')[0]).appendChild(script);
}
function splitArgs(s) {
var r = s.split(' ');
delete arguments[0];
var obj = {};
var index = 0;
$.each(arguments, function(argumentIndex, argument) {
if (!argumentIndex) { return; }
var value = r[argumentIndex-1];
obj[argument] = value;
});
return obj;
}
function swtch(value, options, defaultOption) {
return (options[value] || defaultOption || function(){})(value);
}
(function( $ ){
$.fn.scrollHeight = function(height) {
return this[0].scrollHeight;
};
})($);
function Location(world, x, y, z) {
this.world = world;
this.x = x;
this.y = y;
this.z = z;
}

View file

@ -1,23 +1,39 @@
function FlatProjection() {}
FlatProjection.prototype = {
extrazoom: 0,
fromLatLngToPoint: function(latLng) {
return new google.maps.Point(latLng.lat()*config.tileWidth, latLng.lng()*config.tileHeight);
},
fromPointToLatLng: function(point) {
return new google.maps.LatLng(point.x/config.tileWidth, point.y/config.tileHeight);
},
fromWorldToLatLng: function(x, y, z) {
return new google.maps.LatLng(-z / config.tileWidth / (1 << this.extrazoom), x / config.tileHeight / (1 << this.extrazoom));
}
};
var FlatProjection = DynmapProjection.extend({
fromLocationToLatLng: function(location) {
return new L.LatLng(-location.z, location.x, true);
}
});
var FlatMapType = DynmapTileLayer.extend({
projection: new FlatProjection({}),
options: {
minZoom: 0,
maxZoom: 4
},
initialize: function(options) {
L.Util.setOptions(this, options);
},
getTileName: function(tilePoint, zoom) {
var tileName;
var dnprefix = '';
if(this.options.nightandday && this.dynmap.serverday) {
dnprefix = '_day';
}
tileName = this.options.prefix + dnprefix + '_128_' + tilePoint.x + '_' + tilePoint.y + '.png';
return tileName;
},
calculateTileSize: function(zoom) {
return Math.pow(2, 7+zoom);
}
})
/*
function FlatMapType(configuration) {
$.extend(this, configuration); }
FlatMapType.prototype = $.extend(new DynMapType(), {
constructor: FlatMapType,
projection: new FlatProjection(),
tileSize: new google.maps.Size(128.0, 128.0),
tileSize: 128.0,
minZoom: 0,
maxZoom: 3,
prefix: null,
@ -81,8 +97,8 @@ FlatMapType.prototype = $.extend(new DynMapType(), {
else {
size = Math.pow(2, 7+zoom-extrazoom);
}
this.tileSize = new google.maps.Size(size, size);
this.tileSize = size;
}
});
maptypes.FlatMapType = function(configuration) { return new FlatMapType(configuration); };
*/
maptypes.FlatMapType = function(options) { return new FlatMapType(options); };

View file

@ -158,17 +158,25 @@ DynMap.prototype = {
if(urlzoom != null)
me.options.defaultzoom = urlzoom;
var map = this.map = new google.maps.Map(mapContainer.get(0), {
zoom: me.options.defaultzoom || 0,
center: new google.maps.LatLng(0, 1),
navigationControl: true,
navigationControlOptions: {
style: google.maps.NavigationControlStyle.DEFAULT
},
scaleControl: false,
mapTypeControl: false,
streetViewControl: false,
backgroundColor: '#000000'
var map = this.map = new L.Map(mapContainer.get(0), {
zoom: 1, //TODO: me.options.defaultzoom || 1,
center: new L.LatLng(0, 0),
zoomAnimation: true,
crs: L.Util.extend({}, L.CRS, {
code: 'simple',
projection: {
project: function(latlng) {
return new L.Point(latlng.lat, latlng.lng);
},
unproject: function(point, unbounded) {
return new L.LatLng(point.x, point.y, true);
}
},
transformation: new L.Transformation(1, 0, 1, 0)
}),
scale: function(zoom) {
return (1 << zoom);
}
});
map.zoom_changed = function() {
@ -176,18 +184,9 @@ DynMap.prototype = {
$(me).trigger('zoomchanged');
};
google.maps.event.addListener(map, 'dragstart', function(mEvent) {
/*google.maps.event.addListener(map, 'dragstart', function(mEvent) {
me.followPlayer(null);
});
// TODO: Enable hash-links.
/*
google.maps.event.addListener(map, 'zoom_changed', function() {
me.updateLink();
});
google.maps.event.addListener(map, 'center_changed', function() {
me.updateLink();
});
*/
});*/
// Sidebar
var panel;
@ -239,7 +238,7 @@ DynMap.prototype = {
.appendTo(worldlist);
$.each(world.maps, function(index, map) {
me.map.mapTypes.set(map.world.name + '.' + map.name, map);
//me.map.mapTypes.set(map.world.name + '.' + map.name, map);
map.element = $('<li/>')
.addClass('map')
@ -349,14 +348,17 @@ DynMap.prototype = {
});
});
},
getProjection: function() { return this.maptype.getProjection(); },
selectMap: function(map, completed) {
if (!map) { throw "Cannot select map " + map; }
console.log('Selecting map...');
var me = this;
if (me.maptype === map) {
return;
}
$(me).trigger('mapchanging');
var mapWorld = map.options.world;
if (me.maptype) {
$('.compass').removeClass('compass_' + me.maptype.compassview);
$('.compass').removeClass('compass_' + me.maptype.name);
@ -364,31 +366,33 @@ DynMap.prototype = {
$('.compass').addClass('compass_' + map.compassview);
$('.compass').addClass('compass_' + map.name);
var worldChanged = me.world !== map.world;
var projectionChanged = me.map.getProjection() !== map.projection;
me.map.setMapTypeId('none');
me.world = map.world;
var projectionChanged = (me.maptype && me.maptype.getProjection()) !== (map && map.projection);
if (me.maptype) {
me.map.removeLayer(me.maptype);
}
me.world = mapWorld;
me.maptype = map;
me.maptype.updateTileSize(me.map.zoom);
window.setTimeout(function() {
me.map.setMapTypeId(map.world.name + '.' + map.name);
if (worldChanged) {
$(me).trigger('worldchanged');
}
if (projectionChanged || worldChanged) {
if (map.world.center) {
me.map.panTo(map.projection.fromWorldToLatLng(map.world.center.x||0,map.world.center.y||64,map.world.center.z||0));
} else {
me.map.panTo(map.projection.fromWorldToLatLng(0,64,0));
}
}
$(me).trigger('mapchanged');
if (completed) {
completed();
}
}, 1);
me.map.addLayer(me.maptype);
if (worldChanged) {
$(me).trigger('worldchanged');
}
if (projectionChanged || worldChanged) {
var centerLocation = $.extend({ x: 0, y: 64, z: 0 }, mapWorld.center);
var centerPoint = map.getProjection().fromLocationToLatLng(centerLocation);
me.map.setView(centerPoint, 0, true);
}
$(me).trigger('mapchanged');
$('.map', me.worldlist).removeClass('selected');
$(map.element).addClass('selected');
me.updateBackground();
if (completed) {
completed();
}
console.log('Map selected.');
},
selectWorld: function(world, completed) {
var me = this;
@ -399,12 +403,34 @@ DynMap.prototype = {
}
me.selectMap(world.defaultmap, completed);
},
panTo: function(location, completed) {
panToLocation: function(location, completed) {
var me = this;
me.selectWorld(location.world, function() {
var position = me.map.getProjection().fromWorldToLatLng(location.x, location.y, location.z);
me.map.panTo(position);
});
var pan = function() {
var latlng = me.maptype.getProjection().fromLocationToLatLng(location);
me.panToLatLng(latlng, completed);
};
if (location.world) {
me.selectWorld(location.world, function() {
pan();
});
} else {
pan();
}
},
panToLayerPoint: function(point, completed) {
var me = this;
var latlng = me.map.layerPointToLatLng(point);
me.map.panToLatLng(latlng);
if (completed) {
completed();
}
},
panToLatLng: function(latlng, completed) {
this.map.panTo(latlng);
if (completed) {
completed();
}
},
update: function() {
var me = this;
@ -473,12 +499,13 @@ DynMap.prototype = {
if(me.serverday != oldday) {
me.updateBackground();
var mtid = me.map.mapTypeId;
if(me.map.mapTypes[mtid].nightandday) {
console.log('TODO: RENDER NIGHTANDDAY!!!')
/*if(me.map.mapTypes[mtid].nightandday) {
me.map.setMapTypeId('none');
window.setTimeout(function() {
me.map.setMapTypeId(mtid);
}, 0.1);
}
}*/
}
$(me).trigger('worldupdated', [ update ]);
@ -526,6 +553,7 @@ DynMap.prototype = {
tile.lastseen = timestamp;
tile.mapType.onTileUpdated(tile.tileElement, tileName);
}
me.maptype.updateNamedTile(tileName);
},
addPlayer: function(update) {
var me = this;
@ -563,7 +591,7 @@ DynMap.prototype = {
if (me.followingPlayer !== player) {
me.followPlayer(null);
}
me.panTo(player.location);
me.panToLocation(player.location);
})
.appendTo(me.playerlist);
if (me.options.showplayerfacesinmenu) {
@ -586,7 +614,7 @@ DynMap.prototype = {
if (player === me.followingPlayer) {
// Follow the updated player.
me.panTo(player.location);
me.panToLocation(player.location);
}
},
removePlayer: function(player) {
@ -605,7 +633,7 @@ DynMap.prototype = {
if(player) {
$(player.menuitem).addClass('following');
me.panTo(player.location);
me.panToLocation(player.location);
}
this.followingPlayer = player;
},

View file

@ -2,11 +2,12 @@ componentconstructors['playermarkers'] = function(dynmap, configuration) {
var me = this;
$(dynmap).bind('playeradded', function(event, player) {
// Create the player-marker.
var markerPosition = dynmap.map.getProjection().fromWorldToLatLng(player.location.x, player.location.y, player.location.z);
player.marker = new CustomMarker(markerPosition, dynmap.map, function(div) {
var markerPosition = dynmap.getProjection().fromLocationToLatLng(player.location);
player.marker = new L.CustomMarker(markerPosition, { elementCreator: function() {
var div = document.createElement('div');
var playerImage;
player.marker.toggle(dynmap.world === player.location.world);
$(player.marker._element).toggle(dynmap.world === player.location.world);
$(div)
.addClass('Marker')
@ -62,17 +63,19 @@ componentconstructors['playermarkers'] = function(dynmap, configuration) {
player.healthContainer.css('display','none');
}
}
});
return div;
}});
dynmap.map.addLayer(player.marker);
});
$(dynmap).bind('playerremoved', function(event, player) {
// Remove the marker.
player.marker.remove();
dynmap.map.removeLayer(player.marker);
});
$(dynmap).bind('playerupdated', function(event, player) {
// Update the marker.
var markerPosition = dynmap.map.getProjection().fromWorldToLatLng(player.location.x, player.location.y, player.location.z);
player.marker.toggle(dynmap.world === player.location.world);
player.marker.setPosition(markerPosition);
var markerPosition = dynmap.getProjection().fromLocationToLatLng(player.location);
$(player.marker._element).toggle(dynmap.world === player.location.world);
player.marker.setLatLng(markerPosition);
// Update health
if (configuration.showplayerhealth) {
if (player.health !== undefined && player.armor !== undefined) {
@ -90,7 +93,7 @@ componentconstructors['playermarkers'] = function(dynmap, configuration) {
for(name in dynmap.players) {
var player = dynmap.players[name];
// Turn off marker - let update turn it back on
player.marker.hide();
$(player.marker._element).toggle(false);
}
});
// Remove marker on map change - let update place it again
@ -98,9 +101,9 @@ componentconstructors['playermarkers'] = function(dynmap, configuration) {
var name;
for(name in dynmap.players) {
var player = dynmap.players[name];
var markerPosition = dynmap.map.getProjection().fromWorldToLatLng(player.location.x, player.location.y, player.location.z);
player.marker.setPosition(markerPosition);
player.marker.toggle(dynmap.world === player.location.world);
var markerPosition = dynmap.getProjection().fromLocationToLatLng(player.location);
player.marker.setLatLng(markerPosition);
$(player.marker._element).toggle(dynmap.world === player.location.world);
}
});
};

31
web/js/projectiontest.js Normal file
View file

@ -0,0 +1,31 @@
componentconstructors['projectiontest'] = function(dynmap, configuration) {
var me = this;
var marker = new L.CustomMarker(new L.LatLng(0,0,true), {
elementCreator: function() {
var div = document.createElement('div');
var textContainer;
$(div)
.css({margin: '10px 10px 10px 10px'})
.append(
textContainer = $('<span/>')
.css({'white-space': 'pre'})
.text('')
);
marker.setText = function(text) {
$(textContainer).text(text);
};
return div;
}
});
dynmap.map.addLayer(marker);
dynmap.map.on('mousemove', function(event) {
marker.setLatLng(event.latlng);
if (marker.setText) {
marker.setText('LatLng: (' + event.latlng.lat + ',' + event.latlng.lng + ')\n'+
'LayerPoint: (' + event.layerPoint.x + ',' + event.layerPoint.y + ')\n'+
'World: (?,?,?)'
);
}
});
};