130 lines
4.6 KiB
JavaScript
130 lines
4.6 KiB
JavaScript
/*
|
|
* L.TileLayer.Zoomify display Zoomify tiles with Leaflet
|
|
*
|
|
* Based on the Leaflet.Zoomify (https://github.com/turban/Leaflet.Zoomify)
|
|
* from turban (https://github.com/turban)
|
|
*
|
|
*/
|
|
|
|
L.TileLayer.Zoomify = L.TileLayer.extend({
|
|
options: {
|
|
width: -1, // Must be set by user, max zoom image width
|
|
height: -1, // Must be set by user, max zoom image height
|
|
tileGroupPrefix: 'TileGroup',
|
|
tilesPerTileGroup: 256
|
|
},
|
|
|
|
initialize: function (url, options) {
|
|
L.TileLayer.prototype.initialize.call(this, url, options);
|
|
|
|
// Replace with automatic loading from ImageProperties.xml
|
|
if (this.options.width < 0 || this.options.height < 0) {
|
|
throw new Error('The user must set the Width and Height of the Zoomify image');
|
|
}
|
|
},
|
|
|
|
beforeAdd: function (map) {
|
|
var imageSize = L.point(this.options.width, this.options.height);
|
|
|
|
// Build the zoom sizes of the pyramid and cache them in an array
|
|
this._imageSize = [imageSize];
|
|
this._gridSize = [this._getGridSize(imageSize)];
|
|
|
|
// Register the image size in pixels and the grid size in # of tiles for each zoom level
|
|
while (imageSize.x > this.options.tileSize || imageSize.y > this.options.tileSize) {
|
|
imageSize = imageSize.divideBy(2).ceil();
|
|
this._imageSize.push(imageSize);
|
|
this._gridSize.push(this._getGridSize(imageSize));
|
|
}
|
|
|
|
// We built the cache from bottom to top, but leaflet uses a top to bottom index for the zoomlevel,
|
|
// so reverse it for easy indexing by current zoomlevel
|
|
this._imageSize.reverse();
|
|
this._gridSize.reverse();
|
|
|
|
// Register our max supported zoom level
|
|
var maxNativeZoom = this._gridSize.length - 1;
|
|
this.options.maxNativeZoom = maxNativeZoom;
|
|
|
|
// Register our bounds for this zoomify layer based on the maximum zoom
|
|
var maxZoomGrid = this._gridSize[maxNativeZoom],
|
|
maxX = maxZoomGrid.x * this.options.tileSize,
|
|
maxY = maxZoomGrid.y * this.options.tileSize,
|
|
southEast = map.unproject([maxX, maxY], maxNativeZoom);
|
|
this.options.bounds = new L.LatLngBounds([[0, 0], southEast]);
|
|
|
|
L.TileLayer.prototype.beforeAdd.call(this, map);
|
|
},
|
|
|
|
// Calculate the grid size for a given image size (based on tile size)
|
|
_getGridSize: function (imageSize) {
|
|
var tileSize = this.options.tileSize;
|
|
return L.point(Math.ceil(imageSize.x / tileSize), Math.ceil(imageSize.y / tileSize));
|
|
},
|
|
|
|
// Extend the add tile function to update our arbitrary sized border tiles
|
|
_addTile: function (coords, container) {
|
|
// Load the tile via the original leaflet code
|
|
L.TileLayer.prototype._addTile.call(this, coords, container);
|
|
|
|
// Get out imagesize in pixels for this zoom level and our grid size
|
|
var imageSize = this._imageSize[this._getZoomForUrl()],
|
|
gridSize = this._gridSize[this._getZoomForUrl()];
|
|
|
|
// The real tile size (default:256) and the display tile size (if zoom > maxNativeZoom)
|
|
var realTileSize = L.GridLayer.prototype.getTileSize.call(this),
|
|
displayTileSize = L.TileLayer.prototype.getTileSize.call(this);
|
|
|
|
// Get the current tile to adjust
|
|
var key = this._tileCoordsToKey(coords),
|
|
tile = this._tiles[key].el;
|
|
|
|
// Calculate the required size of the border tiles
|
|
var scaleFactor = L.point( (imageSize.x % realTileSize.x),
|
|
(imageSize.y % realTileSize.y)).unscaleBy(realTileSize);
|
|
|
|
// Update tile dimensions if we are on a border
|
|
if ((imageSize.x % realTileSize.x) > 0 && coords.x === gridSize.x - 1) {
|
|
tile.style.width = displayTileSize.scaleBy(scaleFactor).x + 'px';
|
|
}
|
|
|
|
if ((imageSize.y % realTileSize.y) > 0 && coords.y === gridSize.y - 1) {
|
|
tile.style.height = displayTileSize.scaleBy(scaleFactor).y + 'px';
|
|
}
|
|
},
|
|
|
|
// Construct the tile url, by inserting our tilegroup before we template the url
|
|
getTileUrl: function (coords) {
|
|
// Set our TileGroup variable, and then let the original tile templater do the work
|
|
this.options.g = this.options.tileGroupPrefix + this._getTileGroup(coords);
|
|
|
|
// Call the original templater
|
|
return L.TileLayer.prototype.getTileUrl.call(this, coords);
|
|
},
|
|
|
|
// Calculates the TileGroup number, each group contains 256 tiles. The tiles are stored from topleft to bottomright
|
|
_getTileGroup: function (coords) {
|
|
var zoom = this._getZoomForUrl(),
|
|
num = 0,
|
|
gridSize;
|
|
|
|
// Get the total number of tiles from the lowest zoom level to our zoomlevel
|
|
for (var z = 0; z < zoom; z++) {
|
|
gridSize = this._gridSize[z];
|
|
num += gridSize.x * gridSize.y;
|
|
}
|
|
|
|
// Add the remaining tiles from this zoom layer to the running total of tiles
|
|
num += coords.y * this._gridSize[zoom].x + coords.x;
|
|
return Math.floor(num / this.options.tilesPerTileGroup);
|
|
},
|
|
|
|
getBounds: function () {
|
|
return this.options.bounds;
|
|
}
|
|
|
|
});
|
|
|
|
L.tileLayer.zoomify = function (url, options) {
|
|
return new L.TileLayer.Zoomify(url, options);
|
|
}; |