Initial work, enough to get the map to display

This commit is contained in:
James Lyne 2021-08-22 17:11:17 +01:00
parent 93f65a894e
commit ecc026cd34
3 changed files with 406 additions and 479 deletions

View file

@ -1,450 +1,396 @@
var DynmapProjection = L.Class.extend({ var DynmapProjection = L.Class.extend({
initialize: function(options) { initialize: function(options) {
L.Util.setOptions(this, options); L.Util.setOptions(this, options);
}, },
fromLocationToLatLng: function(location) { fromLocationToLatLng: function(location) {
throw "fromLocationToLatLng not implemented"; throw "fromLocationToLatLng not implemented";
}, },
fromLatLngToLocation: function(location) { fromLatLngToLocation: function(location) {
return null; return null;
} }
}); });
if (!Array.prototype.indexOf) { // polyfill for IE < 9 if (!Array.prototype.indexOf) { // polyfill for IE < 9
Array.prototype.indexOf = function (searchElement /*, fromIndex */ ) { Array.prototype.indexOf = function (searchElement /*, fromIndex */ ) {
"use strict"; "use strict";
if (this === void 0 || this === null) { if (this === void 0 || this === null) {
throw new TypeError(); throw new TypeError();
} }
var t = Object(this); var t = Object(this);
var len = t.length >>> 0; var len = t.length >>> 0;
if (len === 0) { if (len === 0) {
return -1; return -1;
} }
var n = 0; var n = 0;
if (arguments.length > 0) { if (arguments.length > 0) {
n = Number(arguments[1]); n = Number(arguments[1]);
if (n !== n) { // shortcut for verifying if it's NaN if (n !== n) { // shortcut for verifying if it's NaN
n = 0; n = 0;
} else if (n !== 0 && n !== (1 / 0) && n !== -(1 / 0)) { } else if (n !== 0 && n !== (1 / 0) && n !== -(1 / 0)) {
n = (n > 0 || -1) * Math.floor(Math.abs(n)); n = (n > 0 || -1) * Math.floor(Math.abs(n));
} }
} }
if (n >= len) { if (n >= len) {
return -1; return -1;
} }
var k = n >= 0 ? n : Math.max(len - Math.abs(n), 0); var k = n >= 0 ? n : Math.max(len - Math.abs(n), 0);
for (; k < len; k++) { for (; k < len; k++) {
if (k in t && t[k] === searchElement) { if (k in t && t[k] === searchElement) {
return k; return k;
} }
} }
return -1; return -1;
} }
} }
var DynmapLayerControl = L.Control.Layers.extend({ var DynmapLayerControl = L.Control.Layers.extend({
getPosition: function() { getPosition: function() {
return 'topleft'; return 'topleft';
}, },
// Function override to include pos // Function override to include pos
addOverlay: function(layer, name, pos) { addOverlay: function(layer, name, pos) {
this._addLayer(layer, name, true, pos); this._addLayer(layer, name, true, pos);
this._update(); this._update();
return this; return this;
}, },
// Function override to order layers by pos // Function override to order layers by pos
_addLayer: function (layer, name, overlay, pos) { _addLayer: function (layer, name, overlay, pos) {
var id = L.stamp(layer); var id = L.stamp(layer);
this._layers[pos] = { this._layers[pos] = {
layer: layer, layer: layer,
name: name, name: name,
overlay: overlay, overlay: overlay,
id: id id: id
}; };
if (this.options.autoZIndex && layer.setZIndex) { if (this.options.autoZIndex && layer.setZIndex) {
this._lastZIndex++; this._lastZIndex++;
layer.setZIndex(this._lastZIndex); layer.setZIndex(this._lastZIndex);
} }
}, },
// Function override to convert the position-based ordering into the id-based ordering // Function override to convert the position-based ordering into the id-based ordering
_onInputClick: function () { _onInputClick: function () {
var i, input, obj, var i, input, obj,
inputs = this._form.getElementsByTagName('input'), inputs = this._form.getElementsByTagName('input'),
inputsLen = inputs.length, inputsLen = inputs.length,
baseLayer; baseLayer;
this._handlingClick = true; this._handlingClick = true;
// Convert ID to pos // Convert ID to pos
var id2pos = {}; var id2pos = {};
for (i in this._layers) { for (i in this._layers) {
id2pos[this._layers[i].id] = i; id2pos[this._layers[i].id] = i;
} }
for (i = 0; i < inputsLen; i++) { for (i = 0; i < inputsLen; i++) {
input = inputs[i]; input = inputs[i];
obj = this._layers[id2pos[input.layerId]]; obj = this._layers[id2pos[input.layerId]];
if (input.checked && !this._map.hasLayer(obj.layer)) { if (input.checked && !this._map.hasLayer(obj.layer)) {
this._map.addLayer(obj.layer); this._map.addLayer(obj.layer);
if (!obj.overlay) { if (!obj.overlay) {
baseLayer = obj.layer; baseLayer = obj.layer;
} }
} else if (!input.checked && this._map.hasLayer(obj.layer)) { } else if (!input.checked && this._map.hasLayer(obj.layer)) {
this._map.removeLayer(obj.layer); this._map.removeLayer(obj.layer);
} }
} }
if (baseLayer) { if (baseLayer) {
this._map.setZoom(this._map.getZoom()); this._map.setZoom(this._map.getZoom());
this._map.fire('baselayerchange', {layer: baseLayer}); this._map.fire('baselayerchange', {layer: baseLayer});
} }
this._handlingClick = false; this._handlingClick = false;
}, },
}); });
var DynmapTileLayer = L.TileLayer.extend({ var DynmapTileLayer = L.TileLayer.extend({
_currentzoom: undefined, _namedTiles: {},
getProjection: function() { _cachedTileUrls: {},
return this.projection; _loadQueue: [],
}, _loadingTiles: [],
onTileUpdated: function(tile, tileName) {
var src = this.dynmap.getTileUrl(tileName); getTileUrl: function(coords) {
tile.attr('src', src); var tileName = this.getTileName(coords),
tile.show(); url = this._cachedTileUrls[tileName];
},
if (!url) {
getTileName: function(tilePoint, zoom) { this._cachedTileUrls[tileName] = url = this.options.dynmap.getTileUrl(tileName);
throw "getTileName not implemented"; }
},
return url;
getTileUrl: function(tilePoint, zoom) { },
var tileName = this.getTileName(tilePoint, zoom);
var url = this._cachedTileUrls[tileName]; createTile: function(coords, done) {
if (!url) { var me = this,
this._cachedTileUrls[tileName] = url = this.options.dynmap.getTileUrl(tileName); tile = document.createElement('img');
}
return url; if (this.options.crossOrigin || this.options.crossOrigin === '') {
}, tile.crossOrigin = this.options.crossOrigin === true ? '' : this.options.crossOrigin;
}
updateNamedTile: function(name) {
var tile = this._namedTiles[name]; tile.alt = '';
delete this._cachedTileUrls[name]; tile.setAttribute('role', 'presentation');
if (tile) {
this.updateTile(tile); //Dynmap - Tile names
} tile.tileName = this.getTileName(coords);
}, this._namedTiles[tile.tileName] = tile;
updateTile: function(tile) { tile.onload = function() {
this._loadTile(tile, tile.tilePoint, this._map.getZoom()); me._tileOnLoad(done, tile);
},
// Override to fix loads completing after layer removed //Dynmap - Update load queue
_addTilesFromCenterOut: function(bounds) { me._loadingTiles.splice(me._loadingTiles.indexOf(tile), 1);
if(this._container == null) // Ignore if we've stopped being active layer me._tickLoadQueue();
return; };
var queue = [],
center = bounds.getCenter(); tile.onerror = function() {
me._tileOnError(done, tile);
for (var j = bounds.min.y; j <= bounds.max.y; j++) {
for (var i = bounds.min.x; i <= bounds.max.x; i++) { //Dynmap - Update load queue
if ((i + ':' + j) in this._tiles) { continue; } me._loadingTiles.splice(me._loadingTiles.indexOf(tile), 1);
queue.push(new L.Point(i, j)); me._tickLoadQueue();
} };
}
//Dynmap - Queue for loading
// load tiles in order of their distance to center tile.url = this.getTileUrl(coords);
queue.sort(function(a, b) { this._loadQueue.push(tile);
return a.distanceTo(center) - b.distanceTo(center); this._tickLoadQueue();
});
return tile;
var fragment = document.createDocumentFragment(); },
this._tilesToLoad = queue.length; _abortLoading: function() {
for (var k = 0, len = this._tilesToLoad; k < len; k++) { var tile;
this._addTile(queue[k], fragment);
} for (var i in this._tiles) {
if (!Object.prototype.hasOwnProperty.call(this._tiles, i)) {
this._container.appendChild(fragment); continue;
}, }
//Copy and mod of Leaflet method - marked changes with Dynmap: to simplify reintegration
_addTile: function(tilePoint, container) { tile = this._tiles[i];
var tilePos = this._getTilePos(tilePoint),
zoom = this._map.getZoom(), //Dynmap - remove namedTiles entry
key = tilePoint.x + ':' + tilePoint.y, if (tile.coords.z !== this._tileZoom) {
name = this.getTileName(tilePoint, zoom), //Dynmap if (tile.loaded && tile.el && tile.el.tileName) {
tileLimit = (1 << zoom); delete this._namedTiles[tile.el.tileName];
}
// wrap tile coordinates
if (!this.options.continuousWorld) { if(this._loadQueue.indexOf(tile.el) > -1) {
if (!this.options.noWrap) { this._loadQueue.splice(this._loadQueue.indexOf(tile.el), 1);
tilePoint.x = ((tilePoint.x % tileLimit) + tileLimit) % tileLimit; }
} else if (tilePoint.x < 0 || tilePoint.x >= tileLimit) {
this._tilesToLoad--; if(this._loadingTiles.indexOf(tile.el) > -1) {
return; this._loadingTiles.splice(this._loadingTiles.indexOf(tile.el), 1);
} }
}
if (tilePoint.y < 0 || tilePoint.y >= tileLimit) { }
this._tilesToLoad--;
return; L.TileLayer.prototype._abortLoading.call(this);
} },
}
_removeTile: function(key) {
// create tile var tile = this._tiles[key];
var tile = this._createTile();
tile.tileName = name; //Dynmap if (!tile) {
tile.tilePoint = tilePoint; //Dynmap return;
L.DomUtil.setPosition(tile, tilePos); }
this._tiles[key] = tile; //Dynmap - remove namedTiles entry
this._namedTiles[name] = tile; //Dynmap var tileName = tile.el.tileName;
if (this.options.scheme == 'tms') { if (tileName) {
tilePoint.y = tileLimit - tilePoint.y - 1; delete this._namedTiles[tileName];
} }
this._loadTile(tile, tilePoint, zoom); //Dynmap - remove from load queue
if(this._loadingTiles.indexOf(tile.el) > -1) {
container.appendChild(tile); this._loadingTiles.splice(this._loadingTiles.indexOf(tile.el), 1);
}, }
_loadTile: function(tile, tilePoint, zoom) {
var me = this; if(this._loadQueue.indexOf(tile.el) > -1) {
tile._layer = this; this._loadQueue.splice(this._loadQueue.indexOf(tile.el), 1);
function done() { }
me._loadingTiles.splice(me._loadingTiles.indexOf(tile), 1);
me._nextLoadTile(); tile.el.onerror = null;
} tile.el.onload = null;
tile.onload = function(e) {
me._tileOnLoad.apply(this, [e]); L.TileLayer.prototype._removeTile.call(this, key);
done(); },
}
tile.onerror = function() { getProjection: function() {
me._tileOnError.apply(this); return this.projection;
done(); },
}
tile.loadSrc = function() { _tickLoadQueue: function() {
me._loadingTiles.push(tile); if (this._loadingTiles.length > 4) {
tile.src = me.getTileUrl(tilePoint, zoom); return;
}; }
this._loadQueue.push(tile);
this._nextLoadTile(); var next = this._loadQueue.shift();
},
_nextLoadTile: function() { if (!next) {
if (this._loadingTiles.length > 4) { return; } return;
var next = this._loadQueue.shift(); }
if (!next) { return; }
this._loadingTiles.push(next);
next.loadSrc(); next.src = next.url;
}, },
_removeOtherTiles: function(bounds) { onTileUpdated: function(tile, tileName) {
var kArr, x, y, key; var src = this.dynmap.getTileUrl(tileName);
tile.attr('src', src);
for (key in this._tiles) { tile.show();
if (this._tiles.hasOwnProperty(key)) { },
kArr = key.split(':');
x = parseInt(kArr[0], 10); getTileName: function(coords) {
y = parseInt(kArr[1], 10); throw "getTileName not implemented";
},
// 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) { updateNamedTile: function(name) {
var tile = this._tiles[key]; var tile = this._namedTiles[name];
if (tile.parentNode === this._container) { delete this._cachedTileUrls[name];
this._container.removeChild(this._tiles[key]); if (tile) {
} this.updateTile(tile);
delete this._namedTiles[tile.tileName]; }
delete this._tiles[key]; },
}
} updateTile: function(tile) {
} this._loadTile(tile, tile.tilePoint, this._map.getZoom());
}, },
_updateTileSize: function() {
var newzoom = this._map.getZoom(); // Some helper functions.
if (this._currentzoom !== newzoom) { zoomprefix: function(amount) {
var newTileSize = this.calculateTileSize(newzoom); return 'zzzzzzzzzzzzzzzzzzzzzz'.substr(0, amount);
this._currentzoom = newzoom; },
if (newTileSize !== this.options.tileSize) {
this.setTileSize(newTileSize); getTileInfo: function(coords) {
} // zoom: max zoomed in = this.options.maxZoom, max zoomed out = 0
} // izoom: max zoomed in = 0, max zoomed out = this.options.maxZoom
}, // zoomoutlevel: izoom < mapzoomin -> 0, else -> izoom - mapzoomin (which ranges from 0 till mapzoomout)
var izoom = this._getZoomForUrl(),
_reset: function() { zoomoutlevel = Math.max(0, izoom - this.options.mapzoomin),
this._updateTileSize(); scale = 1 << zoomoutlevel,
this._tiles = {}; x = scale * coords.x,
this._namedTiles = {}; y = scale * coords.y;
this._loadQueue = [];
this._loadingTiles = []; return {
this._cachedTileUrls = {}; prefix: this.options.prefix,
this._initContainer(); nightday: (this.options.nightandday && this.options.dynmap.serverday) ? '_day' : '',
this._container.innerHTML = ''; scaledx: x >> 5,
}, scaledy: y >> 5,
zoom: this.zoomprefix(zoomoutlevel),
_update: function() { zoomprefix: (zoomoutlevel==0)?"":(this.zoomprefix(zoomoutlevel)+"_"),
this._updateTileSize(); x: x,
var bounds = this._map.getPixelBounds(), y: y,
tileSize = this.options.tileSize; fmt: this.options['image-format'] || 'png'
};
var nwTilePoint = new L.Point( }
Math.floor(bounds.min.x / tileSize), });
Math.floor(bounds.min.y / tileSize)),
seTilePoint = new L.Point( function loadjs(url, completed) {
Math.floor(bounds.max.x / tileSize), var script = document.createElement('script');
Math.floor(bounds.max.y / tileSize)), script.setAttribute('src', url);
tileBounds = new L.Bounds(nwTilePoint, seTilePoint); script.setAttribute('type', 'text/javascript');
var isloaded = false;
this._addTilesFromCenterOut(tileBounds); script.onload = function() {
if (isloaded) { return; }
if (this.options.unloadInvisibleTiles) { isloaded = true;
this._removeOtherTiles(tileBounds); completed();
} };
},
/*calculateTileSize: function(zoom) { // Hack for IE, don't know whether this still applies to IE9.
return this.options.tileSize; script.onreadystatechange = function() {
},*/ if (script.readyState == 'loaded' || script.readyState == 'complete')
calculateTileSize: function(zoom) { script.onload();
// zoomoutlevel: 0 when izoom > mapzoomin, else mapzoomin - izoom (which ranges from 0 till mapzoomin) };
var izoom = this.options.maxZoom - zoom; (document.head || document.getElementsByTagName('head')[0]).appendChild(script);
var zoominlevel = Math.max(0, this.options.mapzoomin - izoom); }
return 128 << zoominlevel;
}, function loadcss(url, completed) {
setTileSize: function(tileSize) { var link = document.createElement('link');
this.options.tileSize = tileSize; link.setAttribute('href', url);
this._tiles = {}; link.setAttribute('rel', 'stylesheet');
this._createTileProto(); var isloaded = false;
}, if (completed) {
updateTileSize: function(zoom) {}, link.onload = function() {
if (isloaded) { return; }
// Some helper functions. isloaded = true;
zoomprefix: function(amount) { completed();
return 'zzzzzzzzzzzzzzzzzzzzzz'.substr(0, amount); };
},
getTileInfo: function(tilePoint, zoom) { // Hack for IE, don't know whether this still applies to IE9.
// zoom: max zoomed in = this.options.maxZoom, max zoomed out = 0 link.onreadystatechange = function() {
// izoom: max zoomed in = 0, max zoomed out = this.options.maxZoom link.onload();
// zoomoutlevel: izoom < mapzoomin -> 0, else -> izoom - mapzoomin (which ranges from 0 till mapzoomout) };
var izoom = this.options.maxZoom - zoom; }
var zoomoutlevel = Math.max(0, izoom - this.options.mapzoomin);
var scale = 1 << zoomoutlevel; (document.head || document.getElementsByTagName('head')[0]).appendChild(link);
var x = scale*tilePoint.x; }
var y = scale*tilePoint.y;
return { function splitArgs(s) {
prefix: this.options.prefix, var r = s.split(' ');
nightday: (this.options.nightandday && this.options.dynmap.serverday) ? '_day' : '', delete arguments[0];
scaledx: x >> 5, var obj = {};
scaledy: y >> 5, var index = 0;
zoom: this.zoomprefix(zoomoutlevel), $.each(arguments, function(argumentIndex, argument) {
zoomprefix: (zoomoutlevel==0)?"":(this.zoomprefix(zoomoutlevel)+"_"), if (!argumentIndex) { return; }
x: x, var value = r[argumentIndex-1];
y: y, obj[argument] = value;
fmt: this.options['image-format'] || 'png' });
}; return obj;
} }
});
function swtch(value, options, defaultOption) {
function loadjs(url, completed) { return (options[value] || defaultOption || function(){})(value);
var script = document.createElement('script'); }
script.setAttribute('src', url); (function( $ ){
script.setAttribute('type', 'text/javascript'); $.fn.scrollHeight = function(height) {
var isloaded = false; return this[0].scrollHeight;
script.onload = function() { };
if (isloaded) { return; } })($);
isloaded = true;
completed(); function Location(world, x, y, z) {
}; this.world = world;
this.x = x;
// Hack for IE, don't know whether this still applies to IE9. this.y = y;
script.onreadystatechange = function() { this.z = z;
if (script.readyState == 'loaded' || script.readyState == 'complete') }
script.onload();
}; function namedReplace(str, obj)
(document.head || document.getElementsByTagName('head')[0]).appendChild(script); {
} var startIndex = 0;
var result = '';
function loadcss(url, completed) { while(true) {
var link = document.createElement('link'); var variableBegin = str.indexOf('{', startIndex);
link.setAttribute('href', url); var variableEnd = str.indexOf('}', variableBegin+1);
link.setAttribute('rel', 'stylesheet'); if (variableBegin < 0 || variableEnd < 0) {
var isloaded = false; result += str.substr(startIndex);
if (completed) { break;
link.onload = function() { }
if (isloaded) { return; } if (variableBegin < variableEnd) {
isloaded = true; var variableName = str.substring(variableBegin+1, variableEnd);
completed(); result += str.substring(startIndex, variableBegin);
}; result += obj[variableName];
} else /* found '{}' */ {
// Hack for IE, don't know whether this still applies to IE9. result += str.substring(startIndex, variableBegin-1);
link.onreadystatechange = function() { result += '';
link.onload(); }
}; startIndex = variableEnd+1;
} }
return result;
(document.head || document.getElementsByTagName('head')[0]).appendChild(link); }
}
function concatURL(base, addition) {
function splitArgs(s) { if(base.indexOf('?') >= 0)
var r = s.split(' '); return base + escape(addition);
delete arguments[0];
var obj = {}; return base + addition;
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;
}
function namedReplace(str, obj)
{
var startIndex = 0;
var result = '';
while(true) {
var variableBegin = str.indexOf('{', startIndex);
var variableEnd = str.indexOf('}', variableBegin+1);
if (variableBegin < 0 || variableEnd < 0) {
result += str.substr(startIndex);
break;
}
if (variableBegin < variableEnd) {
var variableName = str.substring(variableBegin+1, variableEnd);
result += str.substring(startIndex, variableBegin);
result += obj[variableName];
} else /* found '{}' */ {
result += str.substring(startIndex, variableBegin-1);
result += '';
}
startIndex = variableEnd+1;
}
return result;
}
function concatURL(base, addition) {
if(base.indexOf('?') >= 0)
return base + escape(addition);
return base + addition;
}

View file

@ -23,17 +23,20 @@ var HDMapType = DynmapTileLayer.extend({
projection: undefined, projection: undefined,
options: { options: {
minZoom: 0, minZoom: 0,
maxZoom: 0,
errorTileUrl: 'images/blank.png', errorTileUrl: 'images/blank.png',
continuousWorld: true tileSize: 128,
zoomReverse: true,
}, },
initialize: function(options) { initialize: function(options) {
options.maxZoom = options.mapzoomin + options.mapzoomout; options.maxZoom = options.mapzoomin + options.mapzoomout;
L.Util.setOptions(this, options); options.maxNativeZoom = options.mapzoomout;
this.projection = new HDProjection($.extend({map: this}, options)); this.projection = new HDProjection($.extend({map: this}, options));
L.Util.setOptions(this, options);
}, },
getTileName: function(tilePoint, zoom) { getTileName: function(coords) {
var info = this.getTileInfo(tilePoint, zoom); var info = this.getTileInfo(coords);
// Y is inverted for HD-map. // Y is inverted for HD-map.
info.y = -info.y; info.y = -info.y;
info.scaledy = info.y >> 5; info.scaledy = info.y >> 5;

View file

@ -177,34 +177,12 @@ DynMap.prototype = {
zoomAnimation: true, zoomAnimation: true,
zoomControl: !me.nogui, zoomControl: !me.nogui,
attributionControl: false, attributionControl: false,
crs: L.extend({}, L.CRS, { crs: L.CRS.Simple,
code: 'simple',
projection: {
project: function(latlng) {
// Direct translation of lat -> x, lng -> y.
return new L.Point(latlng.lat, latlng.lng);
},
unproject: function(point) {
// Direct translation of x -> lat, y -> lng.
return new L.LatLng(point.x, point.y);
}
},
// a = 1; b = 2; c = 1; d = 0
// x = a * x + b; y = c * y + d
// End result is 1:1 values during transformation.
transformation: new L.Transformation(1, 0, 1, 0),
scale: function(zoom) {
// Equivalent to 2 raised to the power of zoom, but faster.
return (1 << zoom);
}
}),
continuousWorld: true,
worldCopyJump: false worldCopyJump: false
}); });
window.map = map; // Placate Leaflet need for top-level 'map'.... window.map = map; // Placate Leaflet need for top-level 'map'....
map.on('zoomend', function() { map.on('zoomend', function() {
me.maptype.updateTileSize(me.map.getZoom());
$(me).trigger('zoomchanged'); $(me).trigger('zoomchanged');
}); });
@ -754,7 +732,7 @@ DynMap.prototype = {
} }
); );
}, },
getTileUrl: function(tileName, always) { getTileUrl: function(tileName) {
var me = this; var me = this;
var tile = me.registeredTiles[tileName]; var tile = me.registeredTiles[tileName];