git-svn-id: http://svn.openlayers.org/trunk/openlayers@6452 dc9f47b5-9b13-0410-9fdd-eb0c1a62fdaf
392 lines
13 KiB
JavaScript
392 lines
13 KiB
JavaScript
/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
|
|
* license. See http://svn.openlayers.org/trunk/openlayers/license.txt for the
|
|
* full text of the license. */
|
|
|
|
|
|
/*
|
|
* @requires OpenLayers/Util.js
|
|
*/
|
|
|
|
/*
|
|
* Class: OpenLayers.Tile
|
|
* This is a class designed to designate a single tile, however
|
|
* it is explicitly designed to do relatively little. Tiles store
|
|
* information about themselves -- such as the URL that they are related
|
|
* to, and their size - but do not add themselves to the layer div
|
|
* automatically, for example. Create a new tile with the
|
|
* <OpenLayers.Tile> constructor, or a subclass.
|
|
*
|
|
* TBD 3.0 - remove reference to url in above paragraph
|
|
*
|
|
*/
|
|
OpenLayers.Tile = OpenLayers.Class({
|
|
|
|
/**
|
|
* Constant: EVENT_TYPES
|
|
* {Array(String)} Supported application event types
|
|
*/
|
|
EVENT_TYPES: [ "loadstart", "loadend", "reload"],
|
|
|
|
/**
|
|
* APIProperty: events
|
|
* {<OpenLayers.Events>} An events object that handles all
|
|
* events on the tile.
|
|
*/
|
|
events: null,
|
|
|
|
/**
|
|
* Property: id
|
|
* {String} null
|
|
*/
|
|
id: null,
|
|
|
|
/**
|
|
* Property: layer
|
|
* {<OpenLayers.Layer>} layer the tile is attached to
|
|
*/
|
|
layer: null,
|
|
|
|
/**
|
|
* Property: url
|
|
* {String} url of the request.
|
|
*
|
|
* TBD 3.0
|
|
* Deprecated. The base tile class does not need an url. This should be
|
|
* handled in subclasses. Does not belong here.
|
|
*/
|
|
url: null,
|
|
|
|
/**
|
|
* APIProperty: bounds
|
|
* {<OpenLayers.Bounds>} null
|
|
*/
|
|
bounds: null,
|
|
|
|
/**
|
|
* Property: size
|
|
* {<OpenLayers.Size>} null
|
|
*/
|
|
size: null,
|
|
|
|
/**
|
|
* Property: position
|
|
* {<OpenLayers.Pixel>} Top Left pixel of the tile
|
|
*/
|
|
position: null,
|
|
|
|
/**
|
|
* Property: isLoading
|
|
* {Boolean} Is the tile loading?
|
|
*/
|
|
isLoading: false,
|
|
|
|
/**
|
|
* Property: isBackBuffer
|
|
* {Boolean} Is this tile a back buffer tile?
|
|
*/
|
|
isBackBuffer: false,
|
|
|
|
/**
|
|
* Property: lastRatio
|
|
* {Float} Used in transition code only. This is the previous ratio
|
|
* of the back buffer tile resolution to the map resolution. Compared
|
|
* with the current ratio to determine if zooming occurred.
|
|
*/
|
|
lastRatio: 1,
|
|
|
|
/**
|
|
* Property: isFirstDraw
|
|
* {Boolean} Is this the first time the tile is being drawn?
|
|
* This is used to force resetBackBuffer to synchronize
|
|
* the backBufferTile with the foreground tile the first time
|
|
* the foreground tile loads so that if the user zooms
|
|
* before the layer has fully loaded, the backBufferTile for
|
|
* tiles that have been loaded can be used.
|
|
*/
|
|
isFirstDraw: true,
|
|
|
|
/**
|
|
* Property: backBufferTile
|
|
* {<OpenLayers.Tile>} A clone of the tile used to create transition
|
|
* effects when the tile is moved or changes resolution.
|
|
*/
|
|
backBufferTile: null,
|
|
|
|
/** TBD 3.0 -- remove 'url' from the list of parameters to the constructor.
|
|
* there is no need for the base tile class to have a url.
|
|
*
|
|
* Constructor: OpenLayers.Tile
|
|
* Constructor for a new <OpenLayers.Tile> instance.
|
|
*
|
|
* Parameters:
|
|
* layer - {<OpenLayers.Layer>} layer that the tile will go in.
|
|
* position - {<OpenLayers.Pixel>}
|
|
* bounds - {<OpenLayers.Bounds>}
|
|
* url - {<String>}
|
|
* size - {<OpenLayers.Size>}
|
|
*/
|
|
initialize: function(layer, position, bounds, url, size) {
|
|
this.layer = layer;
|
|
this.position = position.clone();
|
|
this.bounds = bounds.clone();
|
|
this.url = url;
|
|
this.size = size.clone();
|
|
|
|
//give the tile a unique id based on its BBOX.
|
|
this.id = OpenLayers.Util.createUniqueID("Tile_");
|
|
|
|
this.events = new OpenLayers.Events(this, null, this.EVENT_TYPES);
|
|
},
|
|
|
|
/**
|
|
* APIMethod: destroy
|
|
* Nullify references to prevent circular references and memory leaks.
|
|
*/
|
|
destroy:function() {
|
|
if (OpenLayers.Util.indexOf(this.layer.SUPPORTED_TRANSITIONS,
|
|
this.layer.transitionEffect) != -1) {
|
|
this.layer.events.unregister("loadend", this, this.resetBackBuffer);
|
|
this.events.unregister('loadend', this, this.resetBackBuffer);
|
|
} else {
|
|
this.events.unregister('loadend', this, this.showTile);
|
|
}
|
|
this.layer = null;
|
|
this.bounds = null;
|
|
this.size = null;
|
|
this.position = null;
|
|
|
|
this.events.destroy();
|
|
this.events = null;
|
|
|
|
/* clean up the backBufferTile if it exists */
|
|
if (this.backBufferTile) {
|
|
this.backBufferTile.destroy();
|
|
this.backBufferTile = null;
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Method: clone
|
|
*
|
|
* Parameters:
|
|
* obj - {<OpenLayers.Tile>} The tile to be cloned
|
|
*
|
|
* Returns:
|
|
* {<OpenLayers.Tile>} An exact clone of this <OpenLayers.Tile>
|
|
*/
|
|
clone: function (obj) {
|
|
if (obj == null) {
|
|
obj = new OpenLayers.Tile(this.layer,
|
|
this.position,
|
|
this.bounds,
|
|
this.url,
|
|
this.size);
|
|
}
|
|
|
|
// catch any randomly tagged-on properties
|
|
OpenLayers.Util.applyDefaults(obj, this);
|
|
|
|
return obj;
|
|
},
|
|
|
|
/**
|
|
* Method: draw
|
|
* Clear whatever is currently in the tile, then return whether or not
|
|
* it should actually be re-drawn.
|
|
*
|
|
* Returns:
|
|
* {Boolean} Whether or not the tile should actually be drawn. Note that
|
|
* this is not really the best way of doing things, but such is
|
|
* the way the code has been developed. Subclasses call this and
|
|
* depend on the return to know if they should draw or not.
|
|
*/
|
|
draw: function() {
|
|
var maxExtent = this.layer.maxExtent;
|
|
var withinMaxExtent = (maxExtent &&
|
|
this.bounds.intersectsBounds(maxExtent, false));
|
|
|
|
// The only case where we *wouldn't* want to draw the tile is if the
|
|
// tile is outside its layer's maxExtent.
|
|
var drawTile = (withinMaxExtent || this.layer.displayOutsideMaxExtent);
|
|
|
|
if (OpenLayers.Util.indexOf(this.layer.SUPPORTED_TRANSITIONS, this.layer.transitionEffect) != -1) {
|
|
if (drawTile) {
|
|
//we use a clone of this tile to create a double buffer for visual
|
|
//continuity. The backBufferTile is used to create transition
|
|
//effects while the tile in the grid is repositioned and redrawn
|
|
if (!this.backBufferTile) {
|
|
this.backBufferTile = this.clone();
|
|
this.backBufferTile.hide();
|
|
// this is important. It allows the backBuffer to place itself
|
|
// appropriately in the DOM. The Image subclass needs to put
|
|
// the backBufferTile behind the main tile so the tiles can
|
|
// load over top and display as soon as they are loaded.
|
|
this.backBufferTile.isBackBuffer = true;
|
|
|
|
// potentially end any transition effects when the tile loads
|
|
this.events.register('loadend', this, this.resetBackBuffer);
|
|
|
|
// clear transition back buffer tile only after all tiles in
|
|
// this layer have loaded to avoid visual glitches
|
|
this.layer.events.register("loadend", this, this.resetBackBuffer);
|
|
}
|
|
// run any transition effects
|
|
this.startTransition();
|
|
} else {
|
|
// if we aren't going to draw the tile, then the backBuffer should
|
|
// be hidden too!
|
|
if (this.backBufferTile) {
|
|
this.backBufferTile.clear();
|
|
}
|
|
}
|
|
} else {
|
|
if (drawTile && this.isFirstDraw) {
|
|
this.events.register('loadend', this, this.showTile);
|
|
this.isFirstDraw = false;
|
|
}
|
|
}
|
|
this.shouldDraw = drawTile;
|
|
|
|
//clear tile's contents and mark as not drawn
|
|
this.clear();
|
|
|
|
return drawTile;
|
|
},
|
|
|
|
/**
|
|
* Method: moveTo
|
|
* Reposition the tile.
|
|
*
|
|
* Parameters:
|
|
* bounds - {<OpenLayers.Bounds>}
|
|
* position - {<OpenLayers.Pixel>}
|
|
* redraw - {Boolean} Call draw method on tile after moving.
|
|
* Default is true
|
|
*/
|
|
moveTo: function (bounds, position, redraw) {
|
|
if (redraw == null) {
|
|
redraw = true;
|
|
}
|
|
|
|
this.bounds = bounds.clone();
|
|
this.position = position.clone();
|
|
if (redraw) {
|
|
this.draw();
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Method: clear
|
|
* Clear the tile of any bounds/position-related data so that it can
|
|
* be reused in a new location. To be implemented by subclasses.
|
|
*/
|
|
clear: function() {
|
|
// to be implemented by subclasses
|
|
},
|
|
|
|
/**
|
|
* Method: getBoundsFromBaseLayer
|
|
* Take the pixel locations of the corner of the tile, and pass them to
|
|
* the base layer and ask for the location of those pixels, so that
|
|
* displaying tiles over Google works fine.
|
|
*
|
|
* Parameters:
|
|
* position - {<OpenLayers.Pixel>}
|
|
*
|
|
* Returns:
|
|
* bounds - {<OpenLayers.Bounds>}
|
|
*/
|
|
getBoundsFromBaseLayer: function(position) {
|
|
var msg = OpenLayers.i18n('reprojectDeprecated',
|
|
{'layerName':this.layer.name});
|
|
OpenLayers.Console.warn(msg);
|
|
var topLeft = this.layer.map.getLonLatFromLayerPx(position);
|
|
var bottomRightPx = position.clone();
|
|
bottomRightPx.x += this.size.w;
|
|
bottomRightPx.y += this.size.h;
|
|
var bottomRight = this.layer.map.getLonLatFromLayerPx(bottomRightPx);
|
|
// Handle the case where the base layer wraps around the date line.
|
|
// Google does this, and it breaks WMS servers to request bounds in
|
|
// that fashion.
|
|
if (topLeft.lon > bottomRight.lon) {
|
|
if (topLeft.lon < 0) {
|
|
topLeft.lon = -180 - (topLeft.lon+180);
|
|
} else {
|
|
bottomRight.lon = 180+bottomRight.lon+180;
|
|
}
|
|
}
|
|
var bounds = new OpenLayers.Bounds(topLeft.lon,
|
|
bottomRight.lat,
|
|
bottomRight.lon,
|
|
topLeft.lat);
|
|
return bounds;
|
|
},
|
|
|
|
/**
|
|
* Method: startTransition
|
|
* Prepare the tile for a transition effect. To be
|
|
* implemented by subclasses.
|
|
*/
|
|
startTransition: function() {},
|
|
|
|
/**
|
|
* Method: resetBackBuffer
|
|
* Triggered by two different events, layer loadend, and tile loadend.
|
|
* In any of these cases, we check to see if we can hide the
|
|
* backBufferTile yet and update its parameters to match the
|
|
* foreground tile.
|
|
*
|
|
* Basic logic:
|
|
* - If the backBufferTile hasn't been drawn yet, reset it
|
|
* - If layer is still loading, show foreground tile but don't hide
|
|
* the backBufferTile yet
|
|
* - If layer is done loading, reset backBuffer tile and show
|
|
* foreground tile
|
|
*/
|
|
resetBackBuffer: function() {
|
|
this.showTile();
|
|
if (this.backBufferTile &&
|
|
(this.isFirstDraw || !this.layer.numLoadingTiles)) {
|
|
this.isFirstDraw = false;
|
|
// check to see if the backBufferTile is within the max extents
|
|
// before rendering it
|
|
var maxExtent = this.layer.maxExtent;
|
|
var withinMaxExtent = (maxExtent &&
|
|
this.bounds.intersectsBounds(maxExtent, false));
|
|
if (withinMaxExtent) {
|
|
this.backBufferTile.position = this.position;
|
|
this.backBufferTile.bounds = this.bounds;
|
|
this.backBufferTile.size = this.size;
|
|
this.backBufferTile.imageSize = this.layer.imageSize || this.size;
|
|
this.backBufferTile.imageOffset = this.layer.imageOffset;
|
|
this.backBufferTile.resolution = this.layer.getResolution();
|
|
this.backBufferTile.renderTile();
|
|
}
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Method: showTile
|
|
* Show the tile only if it should be drawn.
|
|
*/
|
|
showTile: function() {
|
|
if (this.shouldDraw) {
|
|
this.show();
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Method: show
|
|
* Show the tile. To be implemented by subclasses.
|
|
*/
|
|
show: function() { },
|
|
|
|
/**
|
|
* Method: hide
|
|
* Hide the tile. To be implemented by subclasses.
|
|
*/
|
|
hide: function() { },
|
|
|
|
CLASS_NAME: "OpenLayers.Tile"
|
|
});
|