/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for
* full list of contributors). Published under the Clear BSD license.
* See http://svn.openlayers.org/trunk/openlayers/license.txt for the
* full text of the license. */
/*
* Development supported by a R&D grant DC08P02OUK006 - Old Maps Online
* (www.oldmapsonline.org) from Ministry of Culture of the Czech Republic.
*/
/**
* @requires OpenLayers/Layer/Grid.js
*/
/**
* Class: OpenLayers.Layer.Zoomify
*
* Inherits from:
* - <OpenLayers.Layer.Grid>
*/
OpenLayers.Layer.Zoomify = OpenLayers.Class(OpenLayers.Layer.Grid, {
/**
* Property: url
* {String} URL for root directory with TileGroupX subdirectories.
*/
url: null,
/**
* Property: size
* {<OpenLayers.Size>} The Zoomify image size in pixels.
*/
size: null,
/**
* APIProperty: isBaseLayer
* {Boolean}
*/
isBaseLayer: true,
/**
* Property: standardTileSize
* {Integer} The size of a standard (non-border) square tile in pixels.
*/
standardTileSize: 256,
/**
* Property: numberOfTiers
* {Integer} Depth of the Zoomify pyramid, number of tiers (zoom levels)
* - filled during Zoomify pyramid initialization.
*/
numberOfTiers: 0,
/**
* Property: tileCountUpToTier
* {Array(Integer)} Number of tiles up to the given tier of pyramid.
* - filled during Zoomify pyramid initialization.
*/
tileCountUpToTier: new Array(),
/**
* Property: tierSizeInTiles
* {Array(<OpenLayers.Size>)} Size (in tiles) for each tier of pyramid.
* - filled during Zoomify pyramid initialization.
*/
tierSizeInTiles: new Array(),
/**
* Property: tierImageSize
* {Array(<OpenLayers.Size>)} Image size in pixels for each pyramid tier.
* - filled during Zoomify pyramid initialization.
*/
tierImageSize: new Array(),
/**
* Constructor: OpenLayers.Layer.Zoomify
*
* Parameters:
* name - {String} A name for the layer.
* url - {String} - Relative or absolute path to the image or more
* precisly to the TileGroup[X] directories root.
* Flash plugin use the variable name "zoomifyImagePath" for this.
* size - {<OpenLayers.Size>} The size (in pixels) of the image.
* options - {Object} Hashtable of extra options to tag onto the layer
*/
initialize: function(name, url, size, options) {
// initilize the Zoomify pyramid for given size
this.initializeZoomify( size );
var newArguments = [];
newArguments.push(name, url, size, {}, options);
OpenLayers.Layer.Grid.prototype.initialize.apply(this, newArguments);
},
/**
* Method: initializeZoomify
* It generates constants for all tiers of the Zoomify pyramid
*
* Parameters:
* size - {<OpenLayers.Size>} The size of the image in pixels
*
*/
initializeZoomify: function( size ) {
var imageSize = size.clone()
var tiles = new OpenLayers.Size(
Math.ceil( imageSize.w / this.standardTileSize ),
Math.ceil( imageSize.h / this.standardTileSize )
);
this.tierSizeInTiles.push( tiles );
this.tierImageSize.push( imageSize );
while (imageSize.w > this.standardTileSize ||
imageSize.h > this.standardTileSize ) {
imageSize = new OpenLayers.Size(
Math.floor( imageSize.w / 2 ),
Math.floor( imageSize.h / 2 )
);
tiles = new OpenLayers.Size(
Math.ceil( imageSize.w / this.standardTileSize ),
Math.ceil( imageSize.h / this.standardTileSize )
);
this.tierSizeInTiles.push( tiles );
this.tierImageSize.push( imageSize );
}
this.tierSizeInTiles.reverse();
this.tierImageSize.reverse();
this.numberOfTiers = this.tierSizeInTiles.length;
this.tileCountUpToTier[0] = 0;
for (var i = 1; i < this.numberOfTiers; i++) {
this.tileCountUpToTier.push(
this.tierSizeInTiles[i-1].w * this.tierSizeInTiles[i-1].h +
this.tileCountUpToTier[i-1]
);
}
},
/**
* APIMethod:destroy
*/
destroy: function() {
// for now, nothing special to do here.
OpenLayers.Layer.Grid.prototype.destroy.apply(this, arguments);
// Remove from memory the Zoomify pyramid - is that enough?
this.tileCountUpToTier.length = 0
this.tierSizeInTiles.length = 0
this.tierImageSize.length = 0
},
/**
* APIMethod: clone
*
* Parameters:
* obj - {Object}
*
* Returns:
* {<OpenLayers.Layer.Zoomify>} An exact clone of this <OpenLayers.Layer.Zoomify>
*/
clone: function (obj) {
if (obj == null) {
obj = new OpenLayers.Layer.Zoomify(this.name,
this.url,
this.size,
this.options);
}
//get all additions from superclasses
obj = OpenLayers.Layer.Grid.prototype.clone.apply(this, [obj]);
// copy/set any non-init, non-simple values here
return obj;
},
/**
* Method: getURL
*
* Parameters:
* bounds - {<OpenLayers.Bounds>}
*
* Returns:
* {String} A string with the layer's url and parameters and also the
* passed-in bounds and appropriate tile size specified as
* parameters
*/
getURL: function (bounds) {
bounds = this.adjustBounds(bounds);
var res = this.map.getResolution();
var x = Math.round((bounds.left - this.tileOrigin.lon) / (res * this.tileSize.w));
var y = Math.round((this.tileOrigin.lat - bounds.top) / (res * this.tileSize.h));
var z = this.map.getZoom();
var tileIndex = x + y * this.tierSizeInTiles[z].w + this.tileCountUpToTier[z];
var path = "TileGroup" + Math.floor( (tileIndex) / 256 ) +
"/" + z + "-" + x + "-" + y + ".jpg";
var url = this.url;
if (url instanceof Array) {
url = this.selectUrl(path, url);
}
return url + path;
},
/**
* Method: getImageSize
* getImageSize returns size for a particular tile. If bounds are given as
* first argument, size is calculated (bottom-right tiles are non square).
*
*/
getImageSize: function() {
if (arguments.length > 0) {
bounds = this.adjustBounds(arguments[0]);
var res = this.map.getResolution();
var x = Math.round((bounds.left - this.tileOrigin.lon) / (res * this.tileSize.w));
var y = Math.round((this.tileOrigin.lat - bounds.top) / (res * this.tileSize.h));
var z = this.map.getZoom();
var w = this.standardTileSize;
var h = this.standardTileSize;
if (x == this.tierSizeInTiles[z].w -1 ) {
var w = this.tierImageSize[z].w % this.standardTileSize;
};
if (y == this.tierSizeInTiles[z].h -1 ) {
var h = this.tierImageSize[z].h % this.standardTileSize;
};
return (new OpenLayers.Size(w, h));
} else {
return this.tileSize;
}
},
/**
* Method: addTile
* addTile creates a tile, initializes it, and adds it to the layer div.
*
* Parameters:
* bounds - {<OpenLayers.Bounds>}
* position - {<OpenLayers.Pixel>}
*
* Returns:
* {<OpenLayers.Tile.Image>} The added OpenLayers.Tile.Image
*/
addTile:function(bounds,position) {
return new OpenLayers.Tile.Image(this, position, bounds,
null, this.tileSize);
},
/**
* APIMethod: setMap
* When the layer is added to a map, then we can fetch our origin
* (if we don't have one.)
*
* Parameters:
* map - {<OpenLayers.Map>}
*/
setMap: function(map) {
OpenLayers.Layer.Grid.prototype.setMap.apply(this, arguments);
this.tileOrigin = new OpenLayers.LonLat(this.map.maxExtent.left,
this.map.maxExtent.top);
},
/**
* Method: calculateGridLayout
* Generate parameters for the grid layout. This
*
* Parameters:
* bounds - {<OpenLayers.Bound>}
* extent - {<OpenLayers.Bounds>}
* resolution - {Number}
*
* Returns:
* Object containing properties tilelon, tilelat, tileoffsetlat,
* tileoffsetlat, tileoffsetx, tileoffsety
*/
calculateGridLayout: function(bounds, extent, resolution) {
var tilelon = resolution * this.tileSize.w;
var tilelat = resolution * this.tileSize.h;
var offsetlon = bounds.left - extent.left;
var tilecol = Math.floor(offsetlon/tilelon) - this.buffer;
var tilecolremain = offsetlon/tilelon - tilecol;
var tileoffsetx = -tilecolremain * this.tileSize.w;
var tileoffsetlon = extent.left + tilecol * tilelon;
var offsetlat = extent.top - bounds.top + tilelat;
var tilerow = Math.floor(offsetlat/tilelat) - this.buffer;
var tilerowremain = tilerow - offsetlat/tilelat;
var tileoffsety = tilerowremain * this.tileSize.h;
var tileoffsetlat = extent.top - tilelat*tilerow;
return {
tilelon: tilelon, tilelat: tilelat,
tileoffsetlon: tileoffsetlon, tileoffsetlat: tileoffsetlat,
tileoffsetx: tileoffsetx, tileoffsety: tileoffsety
};
},
CLASS_NAME: "OpenLayers.Layer.Zoomify"
});