/* Copyright (c) 2006-2011 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. */ /** * @requires OpenLayers/Tile/BackBufferable.js */ /** * Class: OpenLayers.Tile.Image * Instances of OpenLayers.Tile.Image are used to manage the image tiles * used by various layers. Create a new image tile with the * constructor. * * Inherits from: * - */ OpenLayers.Tile.Image = OpenLayers.Class(OpenLayers.Tile.BackBufferable, { /** * Property: url * {String} The URL of the image being requested. No default. Filled in by * layer.getURL() function. */ url: null, /** * Property: imgDiv * {HTMLImageElement} The image for this tile. */ imgDiv: null, /** * Property: frame * {DOMElement} The image element is appended to the frame. Any gutter on * the image will be hidden behind the frame. */ frame: null, /** * Property: blankImageUrl * {String} Does not result in a blank image on all browsers, but this is * only required in some browsers as transparent backgroundImage, or as * temporary image src while the tile is invisible and loading, so we don't * care. */ blankImageUrl: "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAQAIBRAA7", /** * Property: imageReloadAttempts * {Integer} Attempts to load the image. */ imageReloadAttempts: null, /** * Property: layerAlphaHack * {Boolean} True if the png alpha hack needs to be applied on the layer's div. */ layerAlphaHack: null, /** * Property: asyncRequestId * {Integer} ID of an request to see if request is still valid. This is a * number which increments by 1 for each asynchronous request. */ asyncRequestId: null, /** * APIProperty: maxGetUrlLength * {Number} If set, requests that would result in GET urls with more * characters than the number provided will be made using form-encoded * HTTP POST. It is good practice to avoid urls that are longer than 2048 * characters. * * Caution: * Older versions of Gecko based browsers (e.g. Firefox < 3.5) and most * Opera versions do not fully support this option. On all browsers, * transition effects are not supported if POST requests are used. */ maxGetUrlLength: null, /** TBD 3.0 - reorder the parameters to the init function to remove * URL. the getUrl() function on the layer gets called on * each draw(), so no need to specify it here. * * Constructor: OpenLayers.Tile.Image * Constructor for a new instance. * * Parameters: * layer - {} layer that the tile will go in. * position - {} * bounds - {} * url - {} Deprecated. Remove me in 3.0. * size - {} * options - {Object} */ initialize: function(layer, position, bounds, url, size, options) { OpenLayers.Tile.BackBufferable.prototype.initialize.apply(this, arguments); this.url = url; //deprecated remove me this.frame = document.createElement("div"); this.frame.style.position = "absolute"; this.frame.style.overflow = "hidden"; this.layerAlphaHack = this.layer.alpha && OpenLayers.Util.alphaHack(); if (this.maxGetUrlLength != null) { OpenLayers.Util.extend(this, OpenLayers.Tile.Image.IFrame); } }, /** * APIMethod: destroy * nullify references to prevent circular references and memory leaks */ destroy: function() { if (this.frame != null) { this.clear(); this.imgDiv = null; this.frame = null; } // don't handle async requests any more this.asyncRequestId = null; OpenLayers.Tile.BackBufferable.prototype.destroy.apply(this, arguments); }, /** * Method: draw * Check that a tile should be drawn, and draw it. * * Returns: * {Boolean} Was a tile drawn? */ draw: function() { var drawn = OpenLayers.Tile.BackBufferable.prototype.draw.apply(this, arguments); if (drawn) { if (this.layer != this.layer.map.baseLayer && this.layer.reproject) { this.bounds = this.getBoundsFromBaseLayer(this.position); } if (this.isLoading) { //if we're already loading, send 'reload' instead of 'loadstart'. this.events.triggerEvent("reload"); } else { this.isLoading = true; this.events.triggerEvent("loadstart"); } this.positionTile(); this.renderTile(); } else { this.unload(); } return drawn; }, /** * Method: renderTile * Internal function to actually initialize the image tile, * position it correctly, and set its url. */ renderTile: function() { this.layer.div.appendChild(this.frame); if (this.layer.async) { // Asynchronous image requests call the asynchronous getURL method // on the layer to fetch an image that covers 'this.bounds', in the scope of // 'this', setting the 'url' property of the layer itself, and running // the callback 'initImage' when the image request returns. var myId = this.asyncRequestId = (this.asyncRequestId || 0) + 1; this.layer.getURLasync(this.bounds, this, "url", function() { if (myId == this.asyncRequestId) { this.initImage(); } }); } else { // synchronous image requests get the url immediately. this.url = this.layer.getURL(this.bounds); this.initImage(); } }, /** * Method: positionTile * Using the properties currenty set on the layer, position the tile correctly. * This method is used both by the async and non-async versions of the Tile.Image * code. */ positionTile: function() { var style = this.frame.style; style.left = this.position.x + "px"; style.top = this.position.y + "px"; style.width = this.size.w + "px"; style.height = this.size.h + "px"; }, /** * Method: clear * Remove the tile from the DOM, clear it of any image related data so that * it can be reused in a new location. */ clear: function() { var img = this.imgDiv; if (img) { OpenLayers.Event.stopObservingElement(img); if (this.frame.parentNode === this.layer.div) { this.layer.div.removeChild(this.frame); } this.setImgSrc(); if (this.layerAlphaHack === true) { img.style.filter = ""; } OpenLayers.Element.removeClass(img, "olImageLoadError"); } }, /** * Method: createImage * Creates the content for the frame on the tile. */ createImage: function() { var img = document.createElement("img"); this.imgDiv = img; img.className = "olTileImage"; // avoid image gallery menu in IE6 img.galleryImg = "no"; var style = img.style, gutter = this.layer.gutter; if (gutter) { var tileSize = this.layer.tileSize, left = (gutter / tileSize.w * 100), top = (gutter / tileSize.h * 100); style.left = -left + "%"; style.top = -top + "%"; style.width = (2 * left + 100) + "%"; style.height = (2 * top + 100) + "%"; style.position = "absolute"; } else { style.width = "100%"; style.height = "100%"; } if (this.layer.opacity < 1) { OpenLayers.Util.modifyDOMElement(img, null, null, null, null, null, null, this.layer.opacity); } if (this.layerAlphaHack) { // move the image out of sight style.paddingTop = style.height; style.height = "0"; } this.frame.appendChild(img); return img; }, /** * Method: initImage * Creates the content for the frame on the tile. */ initImage: function() { var img = this.imgDiv || this.createImage(); if (this.url && img.getAttribute("src") == this.url) { this.onImageLoad(); } else { OpenLayers.Event.observe( img, "load", OpenLayers.Function.bind(this.onImageLoad, this) ); OpenLayers.Event.observe( img, "error", OpenLayers.Function.bind(this.onImageError, this) ); this.imageReloadAttempts = 0; this.setImgSrc(this.url); } }, /** * Method: setImgSrc * Sets the source for the tile image * * Parameters: * url - {String} or undefined to hide the image */ setImgSrc: function(url) { var img = this.imgDiv; img.style.display = "none"; img.src = url ? url : this.blankImageUrl; }, /** * Method: getTile * Get the tile's markup. * * Returns: * {DOMElement} The tile's markup */ getTile: function() { return this.frame; }, /** * Method: createBackBuffer * Create a copy of this tile's markup for the 's backBufferDiv * * Returns: * {DOMElement} a clone of the tile content */ createBackBuffer: function() { var frame = this.frame.cloneNode(false); OpenLayers.Event.stopObservingElement(this.imgDiv); frame.appendChild(this.imgDiv); this.imgDiv = null; return frame; }, /** * Method: onImageLoad * Handler for the image onload event */ onImageLoad: function() { var img = this.imgDiv; img.style.display = ""; this.isLoading = false; this.events.triggerEvent("loadend"); if (this.layerAlphaHack === true) { img.style.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + img.src + "', sizingMethod='scale')"; } }, /** * Method: onImageError * Handler for the image onerror event */ onImageError: function() { var img = this.imgDiv; if (img.src != null) { this.imageReloadAttempts++; if (this.imageReloadAttempts <= OpenLayers.IMAGE_RELOAD_ATTEMPTS) { this.setImgSrc(this.layer.getURL(this.bounds)); } else { OpenLayers.Element.addClass(img, "olImageLoadError"); this.onImageLoad(); } } }, CLASS_NAME: "OpenLayers.Tile.Image" });