/* 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/BaseTypes.js
* @requires OpenLayers/Lang/en.js
*/
var OpenLayers = {
singleFile: true
};
(function() {
/**
* Before creating the OpenLayers namespace, check to see if
* OpenLayers.singleFile is true.  This occurs if the
* OpenLayers/SingleFile.js script is included before this one - as is the
* case with single file builds.
*/
var singleFile = (typeof OpenLayers == "object" && OpenLayers.singleFile);
/**
* Namespace: OpenLayers
* The OpenLayers object provides a namespace for all things OpenLayers
*/
window.OpenLayers = {
/**
* Property: _scriptName
* {String} Relative path of this script.
*/
_scriptName: (!singleFile) ? "lib/OpenLayers.js" : "OpenLayers.js",
/**
* Function: _getScriptLocation
* Return the path to this script.
*
* Returns:
* {String} Path to this script
*/
_getScriptLocation: function () {
/*            var scriptLocation = "";
var scriptName = OpenLayers._scriptName;
var scripts = document.getElementsByTagName('script');
for (var i = 0; i < scripts.length; i++) {
var src = scripts[i].getAttribute('src');
if (src) {
var index = src.lastIndexOf(scriptName);
// set path length for src up to a query string
var pathLength = src.lastIndexOf('?');
if (pathLength < 0) {
pathLength = src.length;
}
// is it found, at the end of the URL?
if ((index > -1) && (index + scriptName.length == pathLength)) {
scriptLocation = src.slice(0, pathLength - scriptName.length);
break;
}
}
}
console.info(scriptLocation);
return scriptLocation;
*/
return "/js/OpenLayers-2.6/";
}
};
})();
/**
* Constant: VERSION_NUMBER
*/
OpenLayers.VERSION_NUMBER="$Revision: 6819 $";
/* 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. */
/**
* Namespace: Util
*/
OpenLayers.Util = {};
/**
* Function: getElement
* This is the old $() from prototype
*/
OpenLayers.Util.getElement = function() {
var elements = [];
for (var i = 0; i < arguments.length; i++) {
var element = arguments[i];
if (typeof element == 'string') {
element = document.getElementById(element);
}
if (arguments.length == 1) {
return element;
}
elements.push(element);
}
return elements;
};
/**
* Maintain $() from prototype
*/
if ($ == null) {
var $ = OpenLayers.Util.getElement;
}
/**
* APIFunction: extend
* Copy all properties of a source object to a destination object.  Modifies
*     the passed in destination object.  Any properties on the source object
*     that are set to undefined will not be (re)set on the destination object.
*
* Parameters:
* destination - {Object} The object that will be modified
* source - {Object} The object with properties to be set on the destination
*
* Returns:
* {Object} The destination object.
*/
OpenLayers.Util.extend = function(destination, source) {
if(destination && source) {
for(var property in source) {
var value = source[property];
if(value !== undefined) {
destination[property] = value;
}
}
/**
* IE doesn't include the toString property when iterating over an object's
* properties with the for(property in object) syntax.  Explicitly check if
* the source has its own toString property.
*/
/*
* FF/Windows < 2.0.0.13 reports "Illegal operation on WrappedNative
* prototype object" when calling hawOwnProperty if the source object
* is an instance of window.Event.
*/
var sourceIsEvt = typeof window.Event == "function"
&& source instanceof window.Event;
if(!sourceIsEvt
&& source.hasOwnProperty && source.hasOwnProperty('toString')) {
destination.toString = source.toString;
}
}
return destination;
};
/**
* Function: removeItem
* Remove an object from an array. Iterates through the array
*     to find the item, then removes it.
*
* Parameters:
* array - {Array}
* item - {Object}
*
* Return
* {Array} A reference to the array
*/
OpenLayers.Util.removeItem = function(array, item) {
for(var i = array.length - 1; i >= 0; i--) {
if(array[i] == item) {
array.splice(i,1);
//break;more than once??
}
}
return array;
};
/**
* Function: clearArray
* *Deprecated*. This function will disappear in 3.0.
* Please use "array.length = 0" instead.
*
* Parameters:
* array - {Array}
*/
OpenLayers.Util.clearArray = function(array) {
OpenLayers.Console.warn(
OpenLayers.i18n(
"methodDeprecated", {'newMethod': 'array = []'}
)
);
array.length = 0;
};
/**
* Function: indexOf
* Seems to exist already in FF, but not in MOZ.
*
* Parameters:
* array - {Array}
* obj - {Object}
*
* Returns:
* {Integer} The index at, which the object was found in the array.
*           If not found, returns -1.
*/
OpenLayers.Util.indexOf = function(array, obj) {
for(var i=0; i < array.length; i++) {
if (array[i] == obj) {
return i;
}
}
return -1;
};
/**
* Function: modifyDOMElement
*
* Modifies many properties of a DOM element all at once.  Passing in
* null to an individual parameter will avoid setting the attribute.
*
* Parameters:
* id - {String} The element id attribute to set.
* px - {<OpenLayers.Pixel>} The left and top style position.
* sz - {<OpenLayers.Size>}  The width and height style attributes.
* position - {String}       The position attribute.  eg: absolute,
*                           relative, etc.
* border - {String}         The style.border attribute.  eg:
*                           solid black 2px
* overflow - {String}       The style.overview attribute.
* opacity - {Float}         Fractional value (0.0 - 1.0)
*/
OpenLayers.Util.modifyDOMElement = function(element, id, px, sz, position,
border, overflow, opacity) {
if (id) {
element.id = id;
}
if (px) {
element.style.left = px.x + "px";
element.style.top = px.y + "px";
}
if (sz) {
element.style.width = sz.w + "px";
element.style.height = sz.h + "px";
}
if (position) {
element.style.position = position;
}
if (border) {
element.style.border = border;
}
if (overflow) {
element.style.overflow = overflow;
}
if (parseFloat(opacity) >= 0.0 && parseFloat(opacity) < 1.0) {
element.style.filter = 'alpha(opacity=' + (opacity * 100) + ')';
element.style.opacity = opacity;
} else if (parseFloat(opacity) == 1.0) {
element.style.filter = '';
element.style.opacity = '';
}
};
/**
* Function: createDiv
* Creates a new div and optionally set some standard attributes.
* Null may be passed to each parameter if you do not wish to
* set a particular attribute.d
*
* Note: zIndex is NOT set
*
* Parameters:
* id - {String} An identifier for this element.  If no id is
*               passed an identifier will be created
*               automatically.
* px - {<OpenLayers.Pixel>} The element left and top position.
* sz - {<OpenLayers.Size>} The element width and height.
* imgURL - {String} A url pointing to an image to use as a
*                   background image.
* position - {String} The style.position value. eg: absolute,
*                     relative etc.
* border - {String} The the style.border value.
*                   eg: 2px solid black
* overflow - {String} The style.overflow value. Eg. hidden
* opacity - {Float} Fractional value (0.0 - 1.0)
*
* Returns:
* {DOMElement} A DOM Div created with the specified attributes.
*/
OpenLayers.Util.createDiv = function(id, px, sz, imgURL, position,
border, overflow, opacity) {
var dom = document.createElement('div');
if (imgURL) {
dom.style.backgroundImage = 'url(' + imgURL + ')';
}
//set generic properties
if (!id) {
id = OpenLayers.Util.createUniqueID("OpenLayersDiv");
}
if (!position) {
position = "absolute";
}
OpenLayers.Util.modifyDOMElement(dom, id, px, sz, position,
border, overflow, opacity);
return dom;
};
/**
* Function: createImage
* Creates an img element with specific attribute values.
*
* Parameters:
* id - {String} The id field for the img.  If none assigned one will be
*               automatically generated.
* px - {<OpenLayers.Pixel>} The left and top positions.
* sz - {<OpenLayers.Size>} The style.width and style.height values.
* imgURL - {String} The url to use as the image source.
* position - {String} The style.position value.
* border - {String} The border to place around the image.
* delayDisplay - {Boolean} If true waits until the image has been
*                          loaded.
* opacity - {Float} Fractional value (0.0 - 1.0)
*
* Returns:
* {DOMElement} A DOM Image created with the specified attributes.
*/
OpenLayers.Util.createImage = function(id, px, sz, imgURL, position, border,
opacity, delayDisplay) {
var image = document.createElement("img");
//set generic properties
if (!id) {
id = OpenLayers.Util.createUniqueID("OpenLayersDiv");
}
if (!position) {
position = "relative";
}
OpenLayers.Util.modifyDOMElement(image, id, px, sz, position,
border, null, opacity);
if(delayDisplay) {
image.style.display = "none";
OpenLayers.Event.observe(image, "load",
OpenLayers.Function.bind(OpenLayers.Util.onImageLoad, image));
OpenLayers.Event.observe(image, "error",
OpenLayers.Function.bind(OpenLayers.Util.onImageLoadError, image));
}
//set special properties
image.style.alt = id;
image.galleryImg = "no";
if (imgURL) {
image.src = imgURL;
}
return image;
};
/**
* Function: setOpacity
* *Deprecated*.  This function has been deprecated. Instead, please use
*     <OpenLayers.Util.modifyDOMElement>
*     or
*     <OpenLayers.Util.modifyAlphaImageDiv>
*
* Set the opacity of a DOM Element
*     Note that for this function to work in IE, elements must "have layout"
*     according to:
*     http://msdn.microsoft.com/workshop/author/dhtml/reference/properties/haslayout.asp
*
* Parameters:
* element - {DOMElement} Set the opacity on this DOM element
* opacity - {Float} Opacity value (0.0 - 1.0)
*/
OpenLayers.Util.setOpacity = function(element, opacity) {
OpenLayers.Util.modifyDOMElement(element, null, null, null,
null, null, null, opacity);
};
/**
* Function: onImageLoad
* Bound to image load events.  For all images created with <createImage> or
*     <createAlphaImageDiv>, this function will be bound to the load event.
*/
OpenLayers.Util.onImageLoad = function() {
// The complex check here is to solve issues described in #480.
// Every time a map view changes, it increments the 'viewRequestID'
// property. As the requests for the images for the new map view are sent
// out, they are tagged with this unique viewRequestID.
//
// If an image has no viewRequestID property set, we display it regardless,
// but if it does have a viewRequestID property, we check that it matches
// the viewRequestID set on the map.
//
// If the viewRequestID on the map has changed, that means that the user
// has changed the map view since this specific request was sent out, and
// therefore this tile does not need to be displayed (so we do not execute
// this code that turns its display on).
//
if (!this.viewRequestID ||
(this.map && this.viewRequestID == this.map.viewRequestID)) {
this.style.backgroundColor = null;
this.style.display = "";
}
};
/**
* Property: onImageLoadErrorColor
* {String} The color tiles with load errors will turn.
*          Default is "pink"
*/
OpenLayers.Util.onImageLoadErrorColor = "pink";
/**
* Property: IMAGE_RELOAD_ATTEMPTS
* {Integer} How many times should we try to reload an image before giving up?
*           Default is 0
*/
OpenLayers.IMAGE_RELOAD_ATTEMPTS = 0;
/**
* Function: onImageLoadError
*/
OpenLayers.Util.onImageLoadError = function() {
this._attempts = (this._attempts) ? (this._attempts + 1) : 1;
if(this._attempts <= OpenLayers.IMAGE_RELOAD_ATTEMPTS) {
this.src = this.src;
} else {
this.style.backgroundColor = OpenLayers.Util.onImageLoadErrorColor;
}
this.style.display = "";
};
/**
* Function: alphaHack
* Checks whether it's necessary (and possible) to use the png alpha
* hack which allows alpha transparency for png images under Internet
* Explorer.
*
* Returns:
* {Boolean} true if alpha has is necessary and possible, false otherwise.
*/
OpenLayers.Util.alphaHack = function() {
var arVersion = navigator.appVersion.split("MSIE");
var version = parseFloat(arVersion[1]);
var filter = false;
// IEs4Lin dies when trying to access document.body.filters, because
// the property is there, but requires a DLL that can't be provided. This
// means that we need to wrap this in a try/catch so that this can
// continue.
try {
filter = !!(document.body.filters);
} catch (e) {
}
return ( filter &&
(version >= 5.5) && (version < 7) );
};
/**
* Function: modifyAlphaImageDiv
*
* div - {DOMElement} Div containing Alpha-adjusted Image
* id - {String}
* px - {<OpenLayers.Pixel>}
* sz - {<OpenLayers.Size>}
* imgURL - {String}
* position - {String}
* border - {String}
* sizing {String} 'crop', 'scale', or 'image'. Default is "scale"
* opacity - {Float} Fractional value (0.0 - 1.0)
*/
OpenLayers.Util.modifyAlphaImageDiv = function(div, id, px, sz, imgURL,
position, border, sizing,
opacity) {
OpenLayers.Util.modifyDOMElement(div, id, px, sz,
null, null, null, opacity);
var img = div.childNodes[0];
if (imgURL) {
img.src = imgURL;
}
OpenLayers.Util.modifyDOMElement(img, div.id + "_innerImage", null, sz,
"relative", border);
if (OpenLayers.Util.alphaHack()) {
div.style.display = "inline-block";
if (sizing == null) {
sizing = "scale";
}
div.style.filter = "progid:DXImageTransform.Microsoft" +
".AlphaImageLoader(src='" + img.src + "', " +
"sizingMethod='" + sizing + "')";
if (parseFloat(div.style.opacity) >= 0.0 &&
parseFloat(div.style.opacity) < 1.0) {
div.style.filter += " alpha(opacity=" + div.style.opacity * 100 + ")";
}
img.style.filter = "alpha(opacity=0)";
}
};
/**
* Function: createAlphaImageDiv
*
* id - {String}
* px - {<OpenLayers.Pixel>}
* sz - {<OpenLayers.Size>}
* imgURL - {String}
* position - {String}
* border - {String}
* sizing {String} 'crop', 'scale', or 'image'. Default is "scale"
* delayDisplay{Boolean}
*
* Returns:
* {DOMElement} A DOM Div created with a DOM Image inside it. If the hack is
*              needed for transparency in IE, it is added.
*/
OpenLayers.Util.createAlphaImageDiv = function(id, px, sz, imgURL,
position, border, sizing,
opacity, delayDisplay) {
var div = OpenLayers.Util.createDiv();
var img = OpenLayers.Util.createImage(null, null, null, null, null, null,
null, false);
div.appendChild(img);
if (delayDisplay) {
img.style.display = "none";
OpenLayers.Event.observe(img, "load",
OpenLayers.Function.bind(OpenLayers.Util.onImageLoad, div));
OpenLayers.Event.observe(img, "error",
OpenLayers.Function.bind(OpenLayers.Util.onImageLoadError, div));
}
OpenLayers.Util.modifyAlphaImageDiv(div, id, px, sz, imgURL, position,
border, sizing, opacity);
return div;
};
/**
* Function: upperCaseObject
* Creates a new hashtable and copies over all the keys from the
*     passed-in object, but storing them under an uppercased
*     version of the key at which they were stored.
*
* Parameters:
* object - {Object}
*
* Returns:
* {Object} A new Object with all the same keys but uppercased
*/
OpenLayers.Util.upperCaseObject = function (object) {
var uObject = {};
for (var key in object) {
uObject[key.toUpperCase()] = object[key];
}
return uObject;
};
/**
* Function: applyDefaults
* Takes an object and copies any properties that don't exist from
*     another properties, by analogy with OpenLayers.Util.extend() from
*     Prototype.js.
*
* Parameters:
* to - {Object} The destination object.
* from - {Object} The source object.  Any properties of this object that
*     are undefined in the to object will be set on the to object.
*
* Returns:
* {Object} A reference to the to object.  Note that the to argument is modified
*     in place and returned by this function.
*/
OpenLayers.Util.applyDefaults = function (to, from) {
/*
* FF/Windows < 2.0.0.13 reports "Illegal operation on WrappedNative
* prototype object" when calling hawOwnProperty if the source object is an
* instance of window.Event.
*/
var fromIsEvt = typeof window.Event == "function"
&& from instanceof window.Event;
for (var key in from) {
if (to[key] === undefined ||
(!fromIsEvt && from.hasOwnProperty
&& from.hasOwnProperty(key) && !to.hasOwnProperty(key))) {
to[key] = from[key];
}
}
/**
* IE doesn't include the toString property when iterating over an object's
* properties with the for(property in object) syntax.  Explicitly check if
* the source has its own toString property.
*/
if(!fromIsEvt && from.hasOwnProperty
&& from.hasOwnProperty('toString') && !to.hasOwnProperty('toString')) {
to.toString = from.toString;
}
return to;
};
/**
* Function: getParameterString
*
* Parameters:
* params - {Object}
*
* Returns:
* {String} A concatenation of the properties of an object in
*          http parameter notation.
*          (ex. <i>"key1=value1&key2=value2&key3=value3"</i>)
*          If a parameter is actually a list, that parameter will then
*          be set to a comma-seperated list of values (foo,bar) instead
*          of being URL escaped (foo%3Abar).
*/
OpenLayers.Util.getParameterString = function(params) {
var paramsArray = [];
for (var key in params) {
var value = params[key];
if ((value != null) && (typeof value != 'function')) {
var encodedValue;
if (typeof value == 'object' && value.constructor == Array) {
/* value is an array; encode items and separate with "," */
var encodedItemArray = [];
for (var itemIndex=0; itemIndex<value.length; itemIndex++) {
encodedItemArray.push(encodeURIComponent(value[itemIndex]));
}
encodedValue = encodedItemArray.join(",");
}
else {
/* value is a string; simply encode */
encodedValue = encodeURIComponent(value);
}
paramsArray.push(encodeURIComponent(key) + "=" + encodedValue);
}
}
return paramsArray.join("&");
};
/**
* Property: ImgPath
* {String} Default is ''.
*/
OpenLayers.ImgPath = '';
/**
* Function: getImagesLocation
*
* Returns:
* {String} The fully formatted image location string
*/
OpenLayers.Util.getImagesLocation = function() {
return OpenLayers.ImgPath || (OpenLayers._getScriptLocation() + "img/");
};
/**
* Function: Try
* Execute functions until one of them doesn't throw an error.
*     Capitalized because "try" is a reserved word in JavaScript.
*     Taken directly from OpenLayers.Util.Try()
*
* Parameters:
* [*] - {Function} Any number of parameters may be passed to Try()
*    It will attempt to execute each of them until one of them
*    successfully executes.
*    If none executes successfully, returns null.
*
* Returns:
* {*} The value returned by the first successfully executed function.
*/
OpenLayers.Util.Try = function() {
var returnValue = null;
for (var i = 0; i < arguments.length; i++) {
var lambda = arguments[i];
try {
returnValue = lambda();
break;
} catch (e) {}
}
return returnValue;
};
/**
* Function: getNodes
*
* These could/should be made namespace aware?
*
* Parameters:
* p - {}
* tagName - {String}
*
* Returns:
* {Array}
*/
OpenLayers.Util.getNodes=function(p, tagName) {
var nodes = OpenLayers.Util.Try(
function () {
return OpenLayers.Util._getNodes(p.documentElement.childNodes,
tagName);
},
function () {
return OpenLayers.Util._getNodes(p.childNodes, tagName);
}
);
return nodes;
};
/**
* Function: _getNodes
*
* Parameters:
* nodes - {Array}
* tagName - {String}
*
* Returns:
* {Array}
*/
OpenLayers.Util._getNodes=function(nodes, tagName) {
var retArray = [];
for (var i=0;i<nodes.length;i++) {
if (nodes[i].nodeName==tagName) {
retArray.push(nodes[i]);
}
}
return retArray;
};
/**
* Function: getTagText
*
* Parameters:
* parent - {}
* item - {String}
* index - {Integer}
*
* Returns:
* {String}
*/
OpenLayers.Util.getTagText = function (parent, item, index) {
var result = OpenLayers.Util.getNodes(parent, item);
if (result && (result.length > 0))
{
if (!index) {
index=0;
}
if (result[index].childNodes.length > 1) {
return result.childNodes[1].nodeValue;
}
else if (result[index].childNodes.length == 1) {
return result[index].firstChild.nodeValue;
}
} else {
return "";
}
};
/**
* Function: getXmlNodeValue
*
* Parameters:
* node - {XMLNode}
*
* Returns:
* {String} The text value of the given node, without breaking in firefox or IE
*/
OpenLayers.Util.getXmlNodeValue = function(node) {
var val = null;
OpenLayers.Util.Try(
function() {
val = node.text;
if (!val) {
val = node.textContent;
}
if (!val) {
val = node.firstChild.nodeValue;
}
},
function() {
val = node.textContent;
});
return val;
};
/**
* Function: mouseLeft
*
* Parameters:
* evt - {Event}
* div - {HTMLDivElement}
*
* Returns:
* {Boolean}
*/
OpenLayers.Util.mouseLeft = function (evt, div) {
// start with the element to which the mouse has moved
var target = (evt.relatedTarget) ? evt.relatedTarget : evt.toElement;
// walk up the DOM tree.
while (target != div && target != null) {
target = target.parentNode;
}
// if the target we stop at isn't the div, then we've left the div.
return (target != div);
};
/**
* Function: rad
*
* Parameters:
* x - {Float}
*
* Returns:
* {Float}
*/
OpenLayers.Util.rad = function(x) {return x*Math.PI/180;};
/**
* Function: distVincenty
*
* Parameters:
* p1 - {<OpenLayers.LonLat>} (or any object with both .lat, .lon properties)
* p2 - {<OpenLayers.LonLat>} (or any object with both .lat, .lon properties)
*
* Returns:
* {Float}
*/
OpenLayers.Util.distVincenty=function(p1, p2) {
var a = 6378137, b = 6356752.3142,  f = 1/298.257223563;
var L = OpenLayers.Util.rad(p2.lon - p1.lon);
var U1 = Math.atan((1-f) * Math.tan(OpenLayers.Util.rad(p1.lat)));
var U2 = Math.atan((1-f) * Math.tan(OpenLayers.Util.rad(p2.lat)));
var sinU1 = Math.sin(U1), cosU1 = Math.cos(U1);
var sinU2 = Math.sin(U2), cosU2 = Math.cos(U2);
var lambda = L, lambdaP = 2*Math.PI;
var iterLimit = 20;
while (Math.abs(lambda-lambdaP) > 1e-12 && --iterLimit>0) {
var sinLambda = Math.sin(lambda), cosLambda = Math.cos(lambda);
var sinSigma = Math.sqrt((cosU2*sinLambda) * (cosU2*sinLambda) +
(cosU1*sinU2-sinU1*cosU2*cosLambda) * (cosU1*sinU2-sinU1*cosU2*cosLambda));
if (sinSigma==0) {
return 0;  // co-incident points
}
var cosSigma = sinU1*sinU2 + cosU1*cosU2*cosLambda;
var sigma = Math.atan2(sinSigma, cosSigma);
var alpha = Math.asin(cosU1 * cosU2 * sinLambda / sinSigma);
var cosSqAlpha = Math.cos(alpha) * Math.cos(alpha);
var cos2SigmaM = cosSigma - 2*sinU1*sinU2/cosSqAlpha;
var C = f/16*cosSqAlpha*(4+f*(4-3*cosSqAlpha));
lambdaP = lambda;
lambda = L + (1-C) * f * Math.sin(alpha) *
(sigma + C*sinSigma*(cos2SigmaM+C*cosSigma*(-1+2*cos2SigmaM*cos2SigmaM)));
}
if (iterLimit==0) {
return NaN;  // formula failed to converge
}
var uSq = cosSqAlpha * (a*a - b*b) / (b*b);
var A = 1 + uSq/16384*(4096+uSq*(-768+uSq*(320-175*uSq)));
var B = uSq/1024 * (256+uSq*(-128+uSq*(74-47*uSq)));
var deltaSigma = B*sinSigma*(cos2SigmaM+B/4*(cosSigma*(-1+2*cos2SigmaM*cos2SigmaM)-
B/6*cos2SigmaM*(-3+4*sinSigma*sinSigma)*(-3+4*cos2SigmaM*cos2SigmaM)));
var s = b*A*(sigma-deltaSigma);
var d = s.toFixed(3)/1000; // round to 1mm precision
return d;
};
/**
* Function: getParameters
* Parse the parameters from a URL or from the current page itself into a
*     JavaScript Object. Note that parameter values with commas are separated
*     out into an Array.
*
* Parameters:
* url - {String} Optional url used to extract the query string.
*                If null, query string is taken from page location.
*
* Returns:
* {Object} An object of key/value pairs from the query string.
*/
OpenLayers.Util.getParameters = function(url) {
// if no url specified, take it from the location bar
url = url || window.location.href;
//parse out parameters portion of url string
var paramsString = "";
if (OpenLayers.String.contains(url, '?')) {
var start = url.indexOf('?') + 1;
var end = OpenLayers.String.contains(url, "#") ?
url.indexOf('#') : url.length;
paramsString = url.substring(start, end);
}
var parameters = {};
var pairs = paramsString.split(/[&;]/);
for(var i = 0; i < pairs.length; ++i) {
var keyValue = pairs[i].split('=');
if (keyValue[0]) {
var key = decodeURIComponent(keyValue[0]);
var value = keyValue[1] || ''; //empty string if no value
//decode individual values
value = value.split(",");
for(var j=0; j < value.length; j++) {
value[j] = decodeURIComponent(value[j]);
}
//if there's only one value, do not return as array
if (value.length == 1) {
value = value[0];
}
parameters[key] = value;
}
}
return parameters;
};
/**
* Function: getArgs
* *Deprecated*.  Will be removed in 3.0.  Please use instead
*     <OpenLayers.Util.getParameters>
*
* Parameters:
* url - {String} Optional url used to extract the query string.
*                If null, query string is taken from page location.
*
* Returns:
* {Object} An object of key/value pairs from the query string.
*/
OpenLayers.Util.getArgs = function(url) {
OpenLayers.Console.warn(
OpenLayers.i18n(
"methodDeprecated", {'newMethod': 'OpenLayers.Util.getParameters'}
)
);
return OpenLayers.Util.getParameters(url);
};
/**
* Property: lastSeqID
* {Integer} The ever-incrementing count variable.
*           Used for generating unique ids.
*/
OpenLayers.Util.lastSeqID = 0;
/**
* Function: createUniqueID
* Create a unique identifier for this session.  Each time this function
*     is called, a counter is incremented.  The return will be the optional
*     prefix (defaults to "id_") appended with the counter value.
*
* Parameters:
* prefix {String} Optionsal string to prefix unique id. Default is "id_".
*
* Returns:
* {String} A unique id string, built on the passed in prefix.
*/
OpenLayers.Util.createUniqueID = function(prefix) {
if (prefix == null) {
prefix = "id_";
}
OpenLayers.Util.lastSeqID += 1;
return prefix + OpenLayers.Util.lastSeqID;
};
/**
* Constant: INCHES_PER_UNIT
* {Object} Constant inches per unit -- borrowed from MapServer mapscale.c
* derivation of nautical miles from http://en.wikipedia.org/wiki/Nautical_mile
*/
OpenLayers.INCHES_PER_UNIT = {
'inches': 1.0,
'ft': 12.0,
'mi': 63360.0,
'm': 39.3701,
'km': 39370.1,
'dd': 4374754,
'yd': 36
};
OpenLayers.INCHES_PER_UNIT["in"]= OpenLayers.INCHES_PER_UNIT.inches;
OpenLayers.INCHES_PER_UNIT["degrees"] = OpenLayers.INCHES_PER_UNIT.dd;
OpenLayers.INCHES_PER_UNIT["nmi"] = 1852 * OpenLayers.INCHES_PER_UNIT.m;
/**
* Constant: DOTS_PER_INCH
* {Integer} 72 (A sensible default)
*/
OpenLayers.DOTS_PER_INCH = 72;
/**
* Function: normalzeScale
*
* Parameters:
* scale - {float}
*
* Returns:
* {Float} A normalized scale value, in 1 / X format.
*         This means that if a value less than one ( already 1/x) is passed
*         in, it just returns scale directly. Otherwise, it returns
*         1 / scale
*/
OpenLayers.Util.normalizeScale = function (scale) {
var normScale = (scale > 1.0) ? (1.0 / scale)
: scale;
return normScale;
};
/**
* Function: getResolutionFromScale
*
* Parameters:
* scale - {Float}
* units - {String} Index into OpenLayers.INCHES_PER_UNIT hashtable.
*                  Default is degrees
*
* Returns:
* {Float} The corresponding resolution given passed-in scale and unit
*         parameters.
*/
OpenLayers.Util.getResolutionFromScale = function (scale, units) {
if (units == null) {
units = "degrees";
}
var normScale = OpenLayers.Util.normalizeScale(scale);
var resolution = 1 / (normScale * OpenLayers.INCHES_PER_UNIT[units]
* OpenLayers.DOTS_PER_INCH);
return resolution;
};
/**
* Function: getScaleFromResolution
*
* Parameters:
* resolution - {Float}
* units - {String} Index into OpenLayers.INCHES_PER_UNIT hashtable.
*                  Default is degrees
*
* Returns:
* {Float} The corresponding scale given passed-in resolution and unit
*         parameters.
*/
OpenLayers.Util.getScaleFromResolution = function (resolution, units) {
if (units == null) {
units = "degrees";
}
var scale = resolution * OpenLayers.INCHES_PER_UNIT[units] *
OpenLayers.DOTS_PER_INCH;
return scale;
};
/**
* Function: safeStopPropagation
* *Deprecated*. This function has been deprecated. Please use directly
*     <OpenLayers.Event.stop> passing 'true' as the 2nd
*     argument (preventDefault)
*
* Safely stop the propagation of an event *without* preventing
*   the default browser action from occurring.
*
* Parameter:
* evt - {Event}
*/
OpenLayers.Util.safeStopPropagation = function(evt) {
OpenLayers.Event.stop(evt, true);
};
/**
* Function: pagePositon
* Calculates the position of an element on the page.
*
* Parameters:
* forElement - {DOMElement}
*
* Returns:
* {Array} two item array, L value then T value.
*/
OpenLayers.Util.pagePosition = function(forElement) {
var valueT = 0, valueL = 0;
var element = forElement;
var child = forElement;
while(element) {
if(element == document.body) {
// FIXME: IE, when passed 'window' as the forElement, treats it as
// equal to document.body, but window.style fails, so getStyle
// fails, so we are paranoid and check this here. This check should
// probably move into element.getStyle in 2.6.
if(child && child.style &&
OpenLayers.Element.getStyle(child, 'position') == 'absolute') {
break;
}
}
valueT += element.offsetTop  || 0;
valueL += element.offsetLeft || 0;
child = element;
try {
// wrapping this in a try/catch because IE chokes on the offsetParent
element = element.offsetParent;
} catch(e) {
OpenLayers.Console.error(OpenLayers.i18n(
"pagePositionFailed",{'elemId':element.id}));
break;
}
}
element = forElement;
while(element) {
valueT -= element.scrollTop  || 0;
valueL -= element.scrollLeft || 0;
element = element.parentNode;
}
return [valueL, valueT];
};
/**
* Function: isEquivalentUrl
* Test two URLs for equivalence.
*
* Setting 'ignoreCase' allows for case-independent comparison.
*
* Comparison is based on:
*  - Protocol
*  - Host (evaluated without the port)
*  - Port (set 'ignorePort80' to ignore "80" values)
*  - Hash ( set 'ignoreHash' to disable)
*  - Pathname (for relative <-> absolute comparison)
*  - Arguments (so they can be out of order)
*
* Parameters:
* url1 - {String}
* url2 - {String}
* options - {Object} Allows for customization of comparison:
*                    'ignoreCase' - Default is True
*                    'ignorePort80' - Default is True
*                    'ignoreHash' - Default is True
*
* Returns:
* {Boolean} Whether or not the two URLs are equivalent
*/
OpenLayers.Util.isEquivalentUrl = function(url1, url2, options) {
options = options || {};
OpenLayers.Util.applyDefaults(options, {
ignoreCase: true,
ignorePort80: true,
ignoreHash: true
});
var urlObj1 = OpenLayers.Util.createUrlObject(url1, options);
var urlObj2 = OpenLayers.Util.createUrlObject(url2, options);
//compare all keys (host, port, etc)
for(var key in urlObj1) {
if (options.test) {
alert(key + "\n1:" + urlObj1[key] + "\n2:" + urlObj2[key]);
}
var val1 = urlObj1[key];
var val2 = urlObj2[key];
switch(key) {
case "args":
//do nothing, they'll be treated below
break;
case "host":
case "port":
case "protocol":
if ((val1 == "") || (val2 == "")) {
//these will be blank for relative urls, so no need to
// compare them here -- call break.
//
break;
}
// otherwise continue with default compare
//
default:
if ( (key != "args") && (urlObj1[key] != urlObj2[key]) ) {
return false;
}
break;
}
}
// compare search args - irrespective of order
for(var key in urlObj1.args) {
if(urlObj1.args[key] != urlObj2.args[key]) {
return false;
}
delete urlObj2.args[key];
}
// urlObj2 shouldn't have any args left
for(var key in urlObj2.args) {
return false;
}
return true;
};
/**
* Function: createUrlObject
*
* Parameters:
* url - {String}
* options - {Object} A hash of options.  Can be one of:
*            ignoreCase: lowercase url,
*            ignorePort80: don't include explicit port if port is 80,
*            ignoreHash: Don't include part of url after the hash (#).
*
* Returns:
* {Object} An object with separate url, a, port, host, and args parsed out
*          and ready for comparison
*/
OpenLayers.Util.createUrlObject = function(url, options) {
options = options || {};
var urlObject = {};
if (options.ignoreCase) {
url = url.toLowerCase();
}
var a = document.createElement('a');
a.href = url;
//host (without port)
urlObject.host = a.host;
var port = a.port;
if (port.length <= 0) {
var newHostLength = urlObject.host.length - (port.length);
urlObject.host = urlObject.host.substring(0, newHostLength);
}
//protocol
urlObject.protocol = a.protocol;
//port
urlObject.port = ((port == "80") && (options.ignorePort80)) ? "" : port;
//hash
urlObject.hash = (options.ignoreHash) ? "" : a.hash;
//args
var queryString = a.search;
if (!queryString) {
var qMark = url.indexOf("?");
queryString = (qMark != -1) ? url.substr(qMark) : "";
}
urlObject.args = OpenLayers.Util.getParameters(queryString);
//pathname (this part allows for relative <-> absolute comparison)
if ( ((urlObject.protocol == "file:") && (url.indexOf("file:") != -1)) ||
((urlObject.protocol != "file:") && (urlObject.host != "")) ) {
urlObject.pathname = a.pathname;
//Test to see if the pathname includes the arguments (Opera)
var qIndex = urlObject.pathname.indexOf("?");
if (qIndex != -1) {
urlObject.pathname = urlObject.pathname.substring(0, qIndex);
}
} else {
var relStr = OpenLayers.Util.removeTail(url);
var backs = 0;
do {
var index = relStr.indexOf("../");
if (index == 0) {
backs++;
relStr = relStr.substr(3);
} else if (index >= 0) {
var prevChunk = relStr.substr(0,index - 1);
var slash = prevChunk.indexOf("/");
prevChunk = (slash != -1) ? prevChunk.substr(0, slash +1)
: "";
var postChunk = relStr.substr(index + 3);
relStr = prevChunk + postChunk;
}
} while(index != -1)
var windowAnchor = document.createElement("a");
var windowUrl = window.location.href;
if (options.ignoreCase) {
windowUrl = windowUrl.toLowerCase();
}
windowAnchor.href = windowUrl;
//set protocol of window
urlObject.protocol = windowAnchor.protocol;
var splitter = (windowAnchor.pathname.indexOf("/") != -1) ? "/" : "\\";
var dirs = windowAnchor.pathname.split(splitter);
dirs.pop(); //remove filename
while ((backs > 0) && (dirs.length > 0)) {
dirs.pop();
backs--;
}
relStr = dirs.join("/") + "/"+ relStr;
urlObject.pathname = relStr;
}
if ((urlObject.protocol == "file:") || (urlObject.protocol == "")) {
urlObject.host = "localhost";
}
return urlObject;
};
/**
* Function: removeTail
* Takes a url and removes everything after the ? and #
*
* Parameters:
* url - {String} The url to process
*
* Returns:
* {String} The string with all queryString and Hash removed
*/
OpenLayers.Util.removeTail = function(url) {
var head = null;
var qMark = url.indexOf("?");
var hashMark = url.indexOf("#");
if (qMark == -1) {
head = (hashMark != -1) ? url.substr(0,hashMark) : url;
} else {
head = (hashMark != -1) ? url.substr(0,Math.min(qMark, hashMark))
: url.substr(0, qMark);
}
return head;
};
/**
* Function: getBrowserName
*
* Returns:
* {String} A string which specifies which is the current
*          browser in which we are running.
*
*          Currently-supported browser detection and codes:
*           * 'opera' -- Opera
*           * 'msie'  -- Internet Explorer
*           * 'safari' -- Safari
*           * 'firefox' -- FireFox
*           * 'mozilla' -- Mozilla
*
*          If we are unable to property identify the browser, we
*           return an empty string.
*/
OpenLayers.Util.getBrowserName = function() {
var browserName = "";
var ua = navigator.userAgent.toLowerCase();
if ( ua.indexOf( "opera" ) != -1 ) {
browserName = "opera";
} else if ( ua.indexOf( "msie" ) != -1 ) {
browserName = "msie";
} else if ( ua.indexOf( "safari" ) != -1 ) {
browserName = "safari";
} else if ( ua.indexOf( "mozilla" ) != -1 ) {
if ( ua.indexOf( "firefox" ) != -1 ) {
browserName = "firefox";
} else {
browserName = "mozilla";
}
}
return browserName;
};
/**
* Method: getRenderedDimensions
* Renders the contentHTML offscreen to determine actual dimensions for
*     popup sizing. As we need layout to determine dimensions the content
*     is rendered -9999px to the left and absolute to ensure the
*     scrollbars do not flicker
*
* Parameters:
* size - {<OpenLayers.Size>} If either the 'w' or 'h' properties is
*     specified, we fix that dimension of the div to be measured. This is
*     useful in the case where we have a limit in one dimension and must
*     therefore meaure the flow in the other dimension.
*
* Returns:
* {OpenLayers.Size}
*/
OpenLayers.Util.getRenderedDimensions = function(contentHTML, size) {
var w = h = null;
// create temp container div with restricted size
var container = document.createElement("div");
container.style.overflow= "";
container.style.position = "absolute";
container.style.left = "-9999px";
//fix a dimension, if specified.
if (size) {
if (size.w) {
w = container.style.width = size.w;
} else if (size.h) {
h = container.style.height = size.h;
}
}
// create temp content div and assign content
var content = document.createElement("div");
content.innerHTML = contentHTML;
// add content to restricted container
container.appendChild(content);
// append container to body for rendering
document.body.appendChild(container);
// calculate scroll width of content and add corners and shadow width
if (!w) {
w = parseInt(content.scrollWidth);
// update container width to allow height to adjust
container.style.width = w + "px";
}
// capture height and add shadow and corner image widths
if (!h) {
h = parseInt(content.scrollHeight);
}
// remove elements
container.removeChild(content);
document.body.removeChild(container);
return new OpenLayers.Size(w, h);
};
/**
* APIFunction: getScrollbarWidth
* This function has been modified by the OpenLayers from the original version,
*     written by Matthew Eernisse and released under the Apache 2
*     license here:
*
*     http://www.fleegix.org/articles/2006/05/30/getting-the-scrollbar-width-in-pixels
*
*     It has been modified simply to cache its value, since it is physically
*     impossible that this code could ever run in more than one browser at
*     once.
*
* Returns:
* {Integer}
*/
OpenLayers.Util.getScrollbarWidth = function() {
var scrollbarWidth = OpenLayers.Util._scrollbarWidth;
if (scrollbarWidth == null) {
var scr = null;
var inn = null;
var wNoScroll = 0;
var wScroll = 0;
// Outer scrolling div
scr = document.createElement('div');
scr.style.position = 'absolute';
scr.style.top = '-1000px';
scr.style.left = '-1000px';
scr.style.width = '100px';
scr.style.height = '50px';
// Start with no scrollbar
scr.style.overflow = 'hidden';
// Inner content div
inn = document.createElement('div');
inn.style.width = '100%';
inn.style.height = '200px';
// Put the inner div in the scrolling div
scr.appendChild(inn);
// Append the scrolling div to the doc
document.body.appendChild(scr);
// Width of the inner div sans scrollbar
wNoScroll = inn.offsetWidth;
// Add the scrollbar
scr.style.overflow = 'scroll';
// Width of the inner div width scrollbar
wScroll = inn.offsetWidth;
// Remove the scrolling div from the doc
document.body.removeChild(document.body.lastChild);
// Pixel width of the scroller
OpenLayers.Util._scrollbarWidth = (wNoScroll - wScroll);
scrollbarWidth = OpenLayers.Util._scrollbarWidth;
}
return scrollbarWidth;
};
/* 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/BaseTypes/Class.js
* @requires OpenLayers/BaseTypes/LonLat.js
* @requires OpenLayers/BaseTypes/Size.js
* @requires OpenLayers/BaseTypes/Pixel.js
* @requires OpenLayers/BaseTypes/Bounds.js
* @requires OpenLayers/BaseTypes/Element.js
* @requires OpenLayers/Lang/en.js
*/
/**
* Header: OpenLayers Base Types
* OpenLayers custom string, number and function functions are described here.
*/
/**
* Namespace: OpenLayers.String
* Contains convenience functions for string manipulation.
*/
OpenLayers.String = {
/**
* APIFunction: startsWith
* Test whether a string starts with another string.
*
* Parameters:
* str - {String} The string to test.
* sub - {Sring} The substring to look for.
*
* Returns:
* {Boolean} The first string starts with the second.
*/
startsWith: function(str, sub) {
return (str.indexOf(sub) == 0);
},
/**
* APIFunction: contains
* Test whether a string contains another string.
*
* Parameters:
* str - {String} The string to test.
* sub - {String} The substring to look for.
*
* Returns:
* {Boolean} The first string contains the second.
*/
contains: function(str, sub) {
return (str.indexOf(sub) != -1);
},
/**
* APIFunction: trim
* Removes leading and trailing whitespace characters from a string.
*
* Parameters:
* str - {String} The (potentially) space padded string.  This string is not
*     modified.
*
* Returns:
* {String} A trimmed version of the string with all leading and
*     trailing spaces removed.
*/
trim: function(str) {
return str.replace(/^\s*(.*?)\s*$/, "$1");
},
/**
* APIFunction: camelize
* Camel-case a hyphenated string.
*     Ex. "chicken-head" becomes "chickenHead", and
*     "-chicken-head" becomes "ChickenHead".
*
* Parameters:
* str - {String} The string to be camelized.  The original is not modified.
*
* Returns:
* {String} The string, camelized
*/
camelize: function(str) {
var oStringList = str.split('-');
var camelizedString = oStringList[0];
for (var i = 1; i < oStringList.length; i++) {
var s = oStringList[i];
camelizedString += s.charAt(0).toUpperCase() + s.substring(1);
}
return camelizedString;
},
/**
* APIFunction: format
* Given a string with tokens in the form ${token}, return a string
*     with tokens replaced with properties from the given context
*     object.  Represent a literal "${" by doubling it, e.g. "${${".
*
* Parameters:
* template - {String} A string with tokens to be replaced.  A template
*     has the form "literal ${token}" where the token will be replaced
*     by the value of context["token"].
* context - {Object} An optional object with properties corresponding
*     to the tokens in the format string.  If no context is sent, the
*     window object will be used.
* args - {Array} Optional arguments to pass to any functions found in
*     the context.  If a context property is a function, the token
*     will be replaced by the return from the function called with
*     these arguments.
*
* Returns:
* {String} A string with tokens replaced from the context object.
*/
format: function(template, context, args) {
if(!context) {
context = window;
}
var tokens = template.split("${");
var item, last, replacement;
for(var i=1; i<tokens.length; i++) {
item = tokens[i];
last = item.indexOf("}");
if(last > 0) {
replacement = context[item.substring(0, last)];
if(typeof replacement == "function") {
replacement = args ?
replacement.apply(null, args) :
replacement();
}
tokens[i] = replacement + item.substring(++last);
} else {
tokens[i] = "${" + item;
}
}
return tokens.join("");
}
};
if (!String.prototype.startsWith) {
/**
* APIMethod: String.startsWith
* *Deprecated*. Whether or not a string starts with another string.
*
* Parameters:
* sStart - {Sring} The string we're testing for.
*
* Returns:
* {Boolean} Whether or not this string starts with the string passed in.
*/
String.prototype.startsWith = function(sStart) {
OpenLayers.Console.warn(OpenLayers.i18n("methodDeprecated",
{'newMethod':'OpenLayers.String.startsWith'}));
return OpenLayers.String.startsWith(this, sStart);
};
}
if (!String.prototype.contains) {
/**
* APIMethod: String.contains
* *Deprecated*. Whether or not a string contains another string.
*
* Parameters:
* str - {String} The string that we're testing for.
*
* Returns:
* {Boolean} Whether or not this string contains with the string passed in.
*/
String.prototype.contains = function(str) {
OpenLayers.Console.warn(OpenLayers.i18n("methodDeprecated",
{'newMethod':'OpenLayers.String.contains'}));
return OpenLayers.String.contains(this, str);
};
}
if (!String.prototype.trim) {
/**
* APIMethod: String.trim
* *Deprecated*. Removes leading and trailing whitespace characters from a string.
*
* Returns:
* {String} A trimmed version of the string - all leading and
*          trailing spaces removed
*/
String.prototype.trim = function() {
OpenLayers.Console.warn(OpenLayers.i18n("methodDeprecated",
{'newMethod':'OpenLayers.String.trim'}));
return OpenLayers.String.trim(this);
};
}
if (!String.prototype.camelize) {
/**
* APIMethod: String.camelize
* *Deprecated*. Camel-case a hyphenated string.
*     Ex. "chicken-head" becomes "chickenHead", and
*     "-chicken-head" becomes "ChickenHead".
*
* Returns:
* {String} The string, camelized
*/
String.prototype.camelize = function() {
OpenLayers.Console.warn(OpenLayers.i18n("methodDeprecated",
{'newMethod':'OpenLayers.String.camelize'}));
return OpenLayers.String.camelize(this);
};
}
/**
* Namespace: OpenLayers.Number
* Contains convenience functions for manipulating numbers.
*/
OpenLayers.Number = {
/**
* Property: decimalSeparator
* Decimal separator to use when formatting numbers.
*/
decimalSeparator: ".",
/**
* Property: thousandsSeparator
* Thousands separator to use when formatting numbers.
*/
thousandsSeparator: ",",
/**
* APIFunction: limitSigDigs
* Limit the number of significant digits on a float.
*
* Parameters:
* num - {Float}
* sig - {Integer}
*
* Returns:
* {Float} The number, rounded to the specified number of significant
*     digits.
*/
limitSigDigs: function(num, sig) {
var fig = 0;
if (sig > 0) {
fig = parseFloat(num.toPrecision(sig));
}
return fig;
},
/**
* APIFunction: format
* Formats a number for output.
*
* Parameters:
* num  - {Float}
* dec  - {Integer} Number of decimal places to round to.
*        Defaults to 0. Set to null to leave decimal places unchanged.
* tsep - {String} Thousands separator.
*        Default is ",".
* dsep - {String} Decimal separator.
*        Default is ".".
*
* Returns:
* {String} A string representing the formatted number.
*/
format: function(num, dec, tsep, dsep) {
dec = (typeof dec != "undefined") ? dec : 0;
tsep = (typeof tsep != "undefined") ? tsep :
OpenLayers.Number.thousandsSeparator;
dsep = (typeof dsep != "undefined") ? dsep :
OpenLayers.Number.decimalSeparator;
if (dec != null) {
num = parseFloat(num.toFixed(dec));
}
var parts = num.toString().split(".");
if (parts.length == 1 && dec == null) {
// integer where we do not want to touch the decimals
dec = 0;
}
var integer = parts[0];
if (tsep) {
var thousands = /(-?[0-9]+)([0-9]{3})/;
while(thousands.test(integer)) {
integer = integer.replace(thousands, "$1" + tsep + "$2");
}
}
var str;
if (dec == 0) {
str = integer;
} else {
var rem = parts.length > 1 ? parts[1] : "0";
if (dec != null) {
rem = rem + new Array(dec - rem.length + 1).join("0");
}
str = integer + dsep + rem;
}
return str;
}
};
if (!Number.prototype.limitSigDigs) {
/**
* APIMethod: Number.limitSigDigs
* *Deprecated*. Limit the number of significant digits on an integer. Does *not*
*     work with floats!
*
* Parameters:
* sig - {Integer}
*
* Returns:
* {Integer} The number, rounded to the specified number of significant digits.
*           If null, 0, or negative value passed in, returns 0
*/
Number.prototype.limitSigDigs = function(sig) {
OpenLayers.Console.warn(OpenLayers.i18n("methodDeprecated",
{'newMethod':'OpenLayers.String.limitSigDigs'}));
return OpenLayers.Number.limitSigDigs(this, sig);
};
}
/**
* Namespace: OpenLayers.Function
* Contains convenience functions for function manipulation.
*/
OpenLayers.Function = {
/**
* APIFunction: bind
* Bind a function to an object.  Method to easily create closures with
*     'this' altered.
*
* Parameters:
* func - {Function} Input function.
* object - {Object} The object to bind to the input function (as this).
*
* Returns:
* {Function} A closure with 'this' set to the passed in object.
*/
bind: function(func, object) {
// create a reference to all arguments past the second one
var args = Array.prototype.slice.apply(arguments, [2]);
return function() {
// Push on any additional arguments from the actual function call.
// These will come after those sent to the bind call.
var newArgs = args.concat(
Array.prototype.slice.apply(arguments, [0])
);
return func.apply(object, newArgs);
};
},
/**
* APIFunction: bindAsEventListener
* Bind a function to an object, and configure it to receive the event
*     object as first parameter when called.
*
* Parameters:
* func - {Function} Input function to serve as an event listener.
* object - {Object} A reference to this.
*
* Returns:
* {Function}
*/
bindAsEventListener: function(func, object) {
return function(event) {
return func.call(object, event || window.event);
};
}
};
if (!Function.prototype.bind) {
/**
* APIMethod: Function.bind
* *Deprecated*. Bind a function to an object.
* Method to easily create closures with 'this' altered.
*
* Parameters:
* object - {Object} the this parameter
*
* Returns:
* {Function} A closure with 'this' altered to the first
*            argument.
*/
Function.prototype.bind = function() {
OpenLayers.Console.warn(OpenLayers.i18n("methodDeprecated",
{'newMethod':'OpenLayers.String.bind'}));
// new function takes the same arguments with this function up front
Array.prototype.unshift.apply(arguments, [this]);
return OpenLayers.Function.bind.apply(null, arguments);
};
}
if (!Function.prototype.bindAsEventListener) {
/**
* APIMethod: Function.bindAsEventListener
* *Deprecated*. Bind a function to an object, and configure it to receive the
*     event object as first parameter when called.
*
* Parameters:
* object - {Object} A reference to this.
*
* Returns:
* {Function}
*/
Function.prototype.bindAsEventListener = function(object) {
OpenLayers.Console.warn(OpenLayers.i18n("methodDeprecated",
{'newMethod':'OpenLayers.String.bindAsEventListener'}));
return OpenLayers.Function.bindAsEventListener(this, object);
};
}
/**
* Namespace: OpenLayers.Array
* Contains convenience functions for array manipulation.
*/
OpenLayers.Array = {
/**
* APIMethod: filter
* Filter an array.  Provides the functionality of the
*     Array.prototype.filter extension to the ECMA-262 standard.  Where
*     available, Array.prototype.filter will be used.
*
* Based on well known example from http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Objects:Array:filter
*
* Parameters:
* array - {Array} The array to be filtered.  This array is not mutated.
*     Elements added to this array by the callback will not be visited.
* callback - {Function} A function that is called for each element in
*     the array.  If this function returns true, the element will be
*     included in the return.  The function will be called with three
*     arguments: the element in the array, the index of that element, and
*     the array itself.  If the optional caller parameter is specified
*     the callback will be called with this set to caller.
* caller - {Object} Optional object to be set as this when the callback
*     is called.
*
* Returns:
* {Array} An array of elements from the passed in array for which the
*     callback returns true.
*/
filter: function(array, callback, caller) {
var selected = [];
if (Array.prototype.filter) {
selected = array.filter(callback, caller);
} else {
var len = array.length;
if (typeof callback != "function") {
throw new TypeError();
}
for(var i=0; i<len; i++) {
if (i in array) {
var val = array[i];
if (callback.call(caller, val, i, array)) {
selected.push(val);
}
}
}
}
return selected;
}
};
/* 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. */
/**
* Constructor: OpenLayers.Class
* Base class used to construct all other classes. Includes support for
*     multiple inheritance.
*
* This constructor is new in OpenLayers 2.5.  At OpenLayers 3.0, the old
*     syntax for creating classes and dealing with inheritance
*     will be removed.
*
* To create a new OpenLayers-style class, use the following syntax:
* > var MyClass = OpenLayers.Class(prototype);
*
* To create a new OpenLayers-style class with multiple inheritance, use the
*     following syntax:
* > var MyClass = OpenLayers.Class(Class1, Class2, prototype);
*
*/
OpenLayers.Class = function() {
var Class = function() {
/**
* This following condition can be removed at 3.0 - this is only for
* backwards compatibility while the Class.inherit method is still
* in use.  So at 3.0, the following three lines would be replaced with
* simply:
* this.initialize.apply(this, arguments);
*/
if (arguments && arguments[0] != OpenLayers.Class.isPrototype) {
this.initialize.apply(this, arguments);
}
};
var extended = {};
var parent;
for(var i=0; i<arguments.length; ++i) {
if(typeof arguments[i] == "function") {
// get the prototype of the superclass
parent = arguments[i].prototype;
} else {
// in this case we're extending with the prototype
parent = arguments[i];
}
OpenLayers.Util.extend(extended, parent);
}
Class.prototype = extended;
return Class;
};
/**
* Property: isPrototype
* *Deprecated*.  This is no longer needed and will be removed at 3.0.
*/
OpenLayers.Class.isPrototype = function () {};
/**
* APIFunction: OpenLayers.create
* *Deprecated*.  Old method to create an OpenLayers style class.  Use the
*     <OpenLayers.Class> constructor instead.
*
* Returns:
* An OpenLayers class
*/
OpenLayers.Class.create = function() {
return function() {
if (arguments && arguments[0] != OpenLayers.Class.isPrototype) {
this.initialize.apply(this, arguments);
}
};
};
/**
* APIFunction: inherit
* *Deprecated*.  Old method to inherit from one or more OpenLayers style
*     classes.  Use the <OpenLayers.Class> constructor instead.
*
* Parameters:
* class - One or more classes can be provided as arguments
*
* Returns:
* An object prototype
*/
OpenLayers.Class.inherit = function () {
var superClass = arguments[0];
var proto = new superClass(OpenLayers.Class.isPrototype);
for (var i = 1; i < arguments.length; i++) {
if (typeof arguments[i] == "function") {
var mixin = arguments[i];
arguments[i] = new mixin(OpenLayers.Class.isPrototype);
}
OpenLayers.Util.extend(proto, arguments[i]);
}
return proto;
};
/* 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. */
/**
* Class: OpenLayers.Bounds
* Instances of this class represent bounding boxes.  Data stored as left,
* bottom, right, top floats. All values are initialized to null, however,
* you should make sure you set them before using the bounds for anything.
*
* Possible use case:
* > bounds = new OpenLayers.Bounds();
* > bounds.extend(new OpenLayers.LonLat(4,5));
* > bounds.extend(new OpenLayers.LonLat(5,6));
* > bounds.toBBOX(); // returns 4,5,5,6
*/
OpenLayers.Bounds = OpenLayers.Class({
/**
* Property: left
* {Number} Minimum horizontal coordinate.
*/
left: null,
/**
* Property: bottom
* {Number} Minimum vertical coordinate.
*/
bottom: null,
/**
* Property: right
* {Number} Maximum horizontal coordinate.
*/
right: null,
/**
* Property: top
* {Number} Maximum vertical coordinate.
*/
top: null,
/**
* Constructor: OpenLayers.Bounds
* Construct a new bounds object.
*
* Parameters:
* left - {Number} The left bounds of the box.  Note that for width
*        calculations, this is assumed to be less than the right value.
* bottom - {Number} The bottom bounds of the box.  Note that for height
*          calculations, this is assumed to be more than the top value.
* right - {Number} The right bounds.
* top - {Number} The top bounds.
*/
initialize: function(left, bottom, right, top) {
if (left != null) {
this.left = parseFloat(left);
}
if (bottom != null) {
this.bottom = parseFloat(bottom);
}
if (right != null) {
this.right = parseFloat(right);
}
if (top != null) {
this.top = parseFloat(top);
}
},
/**
* Method: clone
* Create a cloned instance of this bounds.
*
* Returns:
* {<OpenLayers.Bounds>} A fresh copy of the bounds
*/
clone:function() {
return new OpenLayers.Bounds(this.left, this.bottom,
this.right, this.top);
},
/**
* Method: equals
* Test a two bounds for equivalence.
*
* Parameters:
* bounds - {<OpenLayers.Bounds>}
*
* Returns:
* {Boolean} The passed-in bounds object has the same left,
*           right, top, bottom components as this.  Note that if bounds
*           passed in is null, returns false.
*/
equals:function(bounds) {
var equals = false;
if (bounds != null) {
equals = ((this.left == bounds.left) &&
(this.right == bounds.right) &&
(this.top == bounds.top) &&
(this.bottom == bounds.bottom));
}
return equals;
},
/**
* APIMethod: toString
*
* Returns:
* {String} String representation of bounds object.
*          (ex.<i>"left-bottom=(5,42) right-top=(10,45)"</i>)
*/
toString:function() {
return ( "left-bottom=(" + this.left + "," + this.bottom + ")"
+ " right-top=(" + this.right + "," + this.top + ")" );
},
/**
* APIMethod: toArray
*
* Returns:
* {Array} array of left, bottom, right, top
*/
toArray: function() {
return [this.left, this.bottom, this.right, this.top];
},
/**
* APIMethod: toBBOX
*
* Parameters:
* decimal - {Integer} How many significant digits in the bbox coords?
*                     Default is 6
*
* Returns:
* {String} Simple String representation of bounds object.
*          (ex. <i>"5,42,10,45"</i>)
*/
toBBOX:function(decimal) {
if (decimal== null) {
decimal = 6;
}
var mult = Math.pow(10, decimal);
var bbox = Math.round(this.left * mult) / mult + "," +
Math.round(this.bottom * mult) / mult + "," +
Math.round(this.right * mult) / mult + "," +
Math.round(this.top * mult) / mult;
return bbox;
},
/**
* APIMethod: toGeometry
* Create a new polygon geometry based on this bounds.
*
* Returns:
* {<OpenLayers.Geometry.Polygon>} A new polygon with the coordinates
*     of this bounds.
*/
toGeometry: function() {
return new OpenLayers.Geometry.Polygon([
new OpenLayers.Geometry.LinearRing([
new OpenLayers.Geometry.Point(this.left, this.bottom),
new OpenLayers.Geometry.Point(this.right, this.bottom),
new OpenLayers.Geometry.Point(this.right, this.top),
new OpenLayers.Geometry.Point(this.left, this.top)
])
]);
},
/**
* APIMethod: getWidth
*
* Returns:
* {Float} The width of the bounds
*/
getWidth:function() {
return (this.right - this.left);
},
/**
* APIMethod: getHeight
*
* Returns:
* {Float} The height of the bounds (top minus bottom).
*/
getHeight:function() {
return (this.top - this.bottom);
},
/**
* APIMethod: getSize
*
* Returns:
* {<OpenLayers.Size>} The size of the box.
*/
getSize:function() {
return new OpenLayers.Size(this.getWidth(), this.getHeight());
},
/**
* APIMethod: getCenterPixel
*
* Returns:
* {<OpenLayers.Pixel>} The center of the bounds in pixel space.
*/
getCenterPixel:function() {
return new OpenLayers.Pixel( (this.left + this.right) / 2,
(this.bottom + this.top) / 2);
},
/**
* APIMethod: getCenterLonLat
*
* Returns:
* {<OpenLayers.LonLat>} The center of the bounds in map space.
*/
getCenterLonLat:function() {
return new OpenLayers.LonLat( (this.left + this.right) / 2,
(this.bottom + this.top) / 2);
},
/**
* APIMethod: add
*
* Parameters:
* x - {Float}
* y - {Float}
*
* Returns:
* {<OpenLayers.Bounds>} A new bounds whose coordinates are the same as
*     this, but shifted by the passed-in x and y values.
*/
add:function(x, y) {
if ( (x == null) || (y == null) ) {
var msg = OpenLayers.i18n("boundsAddError");
OpenLayers.Console.error(msg);
return null;
}
return new OpenLayers.Bounds(this.left + x, this.bottom + y,
this.right + x, this.top + y);
},
/**
* APIMethod: extend
* Extend the bounds to include the point, lonlat, or bounds specified.
*     Note, this function assumes that left < right and bottom < top.
*
* Parameters:
* object - {Object} Can be LonLat, Point, or Bounds
*/
extend:function(object) {
var bounds = null;
if (object) {
switch(object.CLASS_NAME) {
case "OpenLayers.LonLat":
bounds = new OpenLayers.Bounds(object.lon, object.lat,
object.lon, object.lat);
break;
case "OpenLayers.Geometry.Point":
bounds = new OpenLayers.Bounds(object.x, object.y,
object.x, object.y);
break;
case "OpenLayers.Bounds":
bounds = object;
break;
}
if (bounds) {
if ( (this.left == null) || (bounds.left < this.left)) {
this.left = bounds.left;
}
if ( (this.bottom == null) || (bounds.bottom < this.bottom) ) {
this.bottom = bounds.bottom;
}
if ( (this.right == null) || (bounds.right > this.right) ) {
this.right = bounds.right;
}
if ( (this.top == null) || (bounds.top > this.top) ) {
this.top = bounds.top;
}
}
}
},
/**
* APIMethod: containsLonLat
*
* Parameters:
* ll - {<OpenLayers.LonLat>}
* inclusive - {Boolean} Whether or not to include the border.
*     Default is true.
*
* Returns:
* {Boolean} The passed-in lonlat is within this bounds.
*/
containsLonLat:function(ll, inclusive) {
return this.contains(ll.lon, ll.lat, inclusive);
},
/**
* APIMethod: containsPixel
*
* Parameters:
* px - {<OpenLayers.Pixel>}
* inclusive - {Boolean} Whether or not to include the border. Default is
*     true.
*
* Returns:
* {Boolean} The passed-in pixel is within this bounds.
*/
containsPixel:function(px, inclusive) {
return this.contains(px.x, px.y, inclusive);
},
/**
* APIMethod: contains
*
* Parameters:
* x - {Float}
* y - {Float}
* inclusive - {Boolean} Whether or not to include the border. Default is
*     true.
*
* Returns:
* {Boolean} Whether or not the passed-in coordinates are within this
*     bounds.
*/
contains:function(x, y, inclusive) {
//set default
if (inclusive == null) {
inclusive = true;
}
var contains = false;
if (inclusive) {
contains = ((x >= this.left) && (x <= this.right) &&
(y >= this.bottom) && (y <= this.top));
} else {
contains = ((x > this.left) && (x < this.right) &&
(y > this.bottom) && (y < this.top));
}
return contains;
},
/**
* APIMethod: intersectsBounds
*
* Parameters:
* bounds - {<OpenLayers.Bounds>}
* inclusive - {Boolean} Whether or not to include the border.  Default
*     is true.
*
* Returns:
* {Boolean} The passed-in OpenLayers.Bounds object intersects this bounds.
*     Simple math just check if either contains the other, allowing for
*     partial.
*/
intersectsBounds:function(bounds, inclusive) {
if (inclusive == null) {
inclusive = true;
}
var inBottom = (bounds.bottom == this.bottom && bounds.top == this.top) ?
true : (((bounds.bottom > this.bottom) && (bounds.bottom < this.top)) ||
((this.bottom > bounds.bottom) && (this.bottom < bounds.top)));
var inTop = (bounds.bottom == this.bottom && bounds.top == this.top) ?
true : (((bounds.top > this.bottom) && (bounds.top < this.top)) ||
((this.top > bounds.bottom) && (this.top < bounds.top)));
var inRight = (bounds.right == this.right && bounds.left == this.left) ?
true : (((bounds.right > this.left) && (bounds.right < this.right)) ||
((this.right > bounds.left) && (this.right < bounds.right)));
var inLeft = (bounds.right == this.right && bounds.left == this.left) ?
true : (((bounds.left > this.left) && (bounds.left < this.right)) ||
((this.left > bounds.left) && (this.left < bounds.right)));
return (this.containsBounds(bounds, true, inclusive) ||
bounds.containsBounds(this, true, inclusive) ||
((inTop || inBottom ) && (inLeft || inRight )));
},
/**
* APIMethod: containsBounds
*
* bounds - {<OpenLayers.Bounds>}
* partial - {Boolean} If true, only part of passed-in bounds needs be
*     within this bounds.  If false, the entire passed-in bounds must be
*     within. Default is false
* inclusive - {Boolean} Whether or not to include the border. Default is
*     true.
*
* Returns:
* {Boolean} The passed-in bounds object is contained within this bounds.
*/
containsBounds:function(bounds, partial, inclusive) {
//set defaults
if (partial == null) {
partial = false;
}
if (inclusive == null) {
inclusive = true;
}
var inLeft;
var inTop;
var inRight;
var inBottom;
if (inclusive) {
inLeft = (bounds.left >= this.left) && (bounds.left <= this.right);
inTop = (bounds.top >= this.bottom) && (bounds.top <= this.top);
inRight= (bounds.right >= this.left) && (bounds.right <= this.right);
inBottom = (bounds.bottom >= this.bottom) && (bounds.bottom <= this.top);
} else {
inLeft = (bounds.left > this.left) && (bounds.left < this.right);
inTop = (bounds.top > this.bottom) && (bounds.top < this.top);
inRight= (bounds.right > this.left) && (bounds.right < this.right);
inBottom = (bounds.bottom > this.bottom) && (bounds.bottom < this.top);
}
return (partial) ? (inTop || inBottom ) && (inLeft || inRight )
: (inTop && inLeft && inBottom && inRight);
},
/**
* APIMethod: determineQuadrant
*
* Parameters:
* lonlat - {<OpenLayers.LonLat>}
*
* Returns:
* {String} The quadrant ("br" "tr" "tl" "bl") of the bounds in which the
*     coordinate lies.
*/
determineQuadrant: function(lonlat) {
var quadrant = "";
var center = this.getCenterLonLat();
quadrant += (lonlat.lat < center.lat) ? "b" : "t";
quadrant += (lonlat.lon < center.lon) ? "l" : "r";
return quadrant;
},
/**
* APIMethod: transform
* Transform the Bounds object from source to dest.
*
* Parameters:
* source - {<OpenLayers.Projection>} Source projection.
* dest   - {<OpenLayers.Projection>} Destination projection.
*
* Returns:
* {<OpenLayers.Bounds>} Itself, for use in chaining operations.
*/
transform: function(source, dest) {
var ll = OpenLayers.Projection.transform(
{'x': this.left, 'y': this.bottom}, source, dest);
var lr = OpenLayers.Projection.transform(
{'x': this.right, 'y': this.bottom}, source, dest);
var ul = OpenLayers.Projection.transform(
{'x': this.left, 'y': this.top}, source, dest);
var ur = OpenLayers.Projection.transform(
{'x': this.right, 'y': this.top}, source, dest);
this.left   = Math.min(ll.x, ul.x);
this.bottom = Math.min(ll.y, lr.y);
this.right  = Math.max(lr.x, ur.x);
this.top    = Math.max(ul.y, ur.y);
return this;
},
/**
* APIMethod: wrapDateLine
*
* Parameters:
* maxExtent - {<OpenLayers.Bounds>}
* options - {Object} Some possible options are:
*                    leftTolerance - {float} Allow for a margin of error
*                                            with the 'left' value of this
*                                            bound.
*                                            Default is 0.
*                    rightTolerance - {float} Allow for a margin of error
*                                             with the 'right' value of
*                                             this bound.
*                                             Default is 0.
*
* Returns:
* {<OpenLayers.Bounds>} A copy of this bounds, but wrapped around the
*                       "dateline" (as specified by the borders of
*                       maxExtent). Note that this function only returns
*                       a different bounds value if this bounds is
*                       *entirely* outside of the maxExtent. If this
*                       bounds straddles the dateline (is part in/part
*                       out of maxExtent), the returned bounds will be
*                       merely a copy of this one.
*/
wrapDateLine: function(maxExtent, options) {
options = options || {};
var leftTolerance = options.leftTolerance || 0;
var rightTolerance = options.rightTolerance || 0;
var newBounds = this.clone();
if (maxExtent) {
//shift right?
while ( newBounds.left < maxExtent.left &&
(newBounds.right - rightTolerance) <= maxExtent.left ) {
newBounds = newBounds.add(maxExtent.getWidth(), 0);
}
//shift left?
while ( (newBounds.left + leftTolerance) >= maxExtent.right &&
newBounds.right > maxExtent.right ) {
newBounds = newBounds.add(-maxExtent.getWidth(), 0);
}
}
return newBounds;
},
CLASS_NAME: "OpenLayers.Bounds"
});
/**
* APIFunction: fromString
* Alternative constructor that builds a new OpenLayers.Bounds from a
*     parameter string
*
* Parameters:
* str - {String}Comma-separated bounds string. (ex. <i>"5,42,10,45"</i>)
*
* Returns:
* {<OpenLayers.Bounds>} New bounds object built from the
*                       passed-in String.
*/
OpenLayers.Bounds.fromString = function(str) {
var bounds = str.split(",");
return OpenLayers.Bounds.fromArray(bounds);
};
/**
* APIFunction: fromArray
* Alternative constructor that builds a new OpenLayers.Bounds
*     from an array
*
* Parameters:
* bbox - {Array(Float)} Array of bounds values (ex. <i>[5,42,10,45]</i>)
*
* Returns:
* {<OpenLayers.Bounds>} New bounds object built from the passed-in Array.
*/
OpenLayers.Bounds.fromArray = function(bbox) {
return new OpenLayers.Bounds(parseFloat(bbox[0]),
parseFloat(bbox[1]),
parseFloat(bbox[2]),
parseFloat(bbox[3]));
};
/**
* APIFunction: fromSize
* Alternative constructor that builds a new OpenLayers.Bounds
*     from a size
*
* Parameters:
* size - {<OpenLayers.Size>}
*
* Returns:
* {<OpenLayers.Bounds>} New bounds object built from the passed-in size.
*/
OpenLayers.Bounds.fromSize = function(size) {
return new OpenLayers.Bounds(0,
size.h,
size.w,
0);
};
/**
* Function: oppositeQuadrant
* Get the opposite quadrant for a given quadrant string.
*
* Parameters:
* quadrant - {String} two character quadrant shortstring
*
* Returns:
* {String} The opposing quadrant ("br" "tr" "tl" "bl"). For Example, if
*          you pass in "bl" it returns "tr", if you pass in "br" it
*          returns "tl", etc.
*/
OpenLayers.Bounds.oppositeQuadrant = function(quadrant) {
var opp = "";
opp += (quadrant.charAt(0) == 't') ? 'b' : 't';
opp += (quadrant.charAt(1) == 'l') ? 'r' : 'l';
return opp;
};
/* 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. */
/**
* Namespace: OpenLayers.Element
*/
OpenLayers.Element = {
/**
* APIFunction: visible
*
* Parameters:
* element - {DOMElement}
*
* Returns:
* {Boolean} Is the element visible?
*/
visible: function(element) {
return OpenLayers.Util.getElement(element).style.display != 'none';
},
/**
* APIFunction: toggle
* Toggle the visibility of element(s) passed in
*
* Parameters:
* element - {DOMElement} Actually user can pass any number of elements
*/
toggle: function() {
for (var i = 0; i < arguments.length; i++) {
var element = OpenLayers.Util.getElement(arguments[i]);
var display = OpenLayers.Element.visible(element) ? 'hide'
: 'show';
OpenLayers.Element[display](element);
}
},
/**
* APIFunction: hide
* Hide element(s) passed in
*
* Parameters:
* element - {DOMElement} Actually user can pass any number of elements
*/
hide: function() {
for (var i = 0; i < arguments.length; i++) {
var element = OpenLayers.Util.getElement(arguments[i]);
element.style.display = 'none';
}
},
/**
* APIFunction: show
* Show element(s) passed in
*
* Parameters:
* element - {DOMElement} Actually user can pass any number of elements
*/
show: function() {
for (var i = 0; i < arguments.length; i++) {
var element = OpenLayers.Util.getElement(arguments[i]);
element.style.display = '';
}
},
/**
* APIFunction: remove
* Remove the specified element from the DOM.
*
* Parameters:
* element - {DOMElement}
*/
remove: function(element) {
element = OpenLayers.Util.getElement(element);
element.parentNode.removeChild(element);
},
/**
* APIFunction: getHeight
*
* Parameters:
* element - {DOMElement}
*
* Returns:
* {Integer} The offset height of the element passed in
*/
getHeight: function(element) {
element = OpenLayers.Util.getElement(element);
return element.offsetHeight;
},
/**
* APIFunction: getDimensions
*
* Parameters:
* element - {DOMElement}
*
* Returns:
* {Object} Object with 'width' and 'height' properties which are the
*          dimensions of the element passed in.
*/
getDimensions: function(element) {
element = OpenLayers.Util.getElement(element);
if (OpenLayers.Element.getStyle(element, 'display') != 'none') {
return {width: element.offsetWidth, height: element.offsetHeight};
}
// All *Width and *Height properties give 0 on elements with display none,
// so enable the element temporarily
var els = element.style;
var originalVisibility = els.visibility;
var originalPosition = els.position;
els.visibility = 'hidden';
els.position = 'absolute';
els.display = '';
var originalWidth = element.clientWidth;
var originalHeight = element.clientHeight;
els.display = 'none';
els.position = originalPosition;
els.visibility = originalVisibility;
return {width: originalWidth, height: originalHeight};
},
/**
* APIFunction: getStyle
*
* Parameters:
* element - {DOMElement}
* style - {?}
*
* Returns:
* {?}
*/
getStyle: function(element, style) {
element = OpenLayers.Util.getElement(element);
var value = element.style[OpenLayers.String.camelize(style)];
if (!value) {
if (document.defaultView &&
document.defaultView.getComputedStyle) {
var css = document.defaultView.getComputedStyle(element, null);
value = css ? css.getPropertyValue(style) : null;
} else if (element.currentStyle) {
value = element.currentStyle[OpenLayers.String.camelize(style)];
}
}
var positions = ['left', 'top', 'right', 'bottom'];
if (window.opera &&
(OpenLayers.Util.indexOf(positions,style) != -1) &&
(OpenLayers.Element.getStyle(element, 'position') == 'static')) {
value = 'auto';
}
return value == 'auto' ? null : value;
}
};
/* 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. */
/**
* Class: OpenLayers.LonLat
* This class represents a longitude and latitude pair
*/
OpenLayers.LonLat = OpenLayers.Class({
/**
* APIProperty: lon
* {Float} The x-axis coodinate in map units
*/
lon: 0.0,
/**
* APIProperty: lat
* {Float} The y-axis coordinate in map units
*/
lat: 0.0,
/**
* Constructor: OpenLayers.LonLat
* Create a new map location.
*
* Parameters:
* lon - {Number} The x-axis coordinate in map units.  If your map is in
*     a geographic projection, this will be the Longitude.  Otherwise,
*     it will be the x coordinate of the map location in your map units.
* lat - {Number} The y-axis coordinate in map units.  If your map is in
*     a geographic projection, this will be the Latitude.  Otherwise,
*     it will be the y coordinate of the map location in your map units.
*/
initialize: function(lon, lat) {
this.lon = parseFloat(lon);
this.lat = parseFloat(lat);
},
/**
* Method: toString
* Return a readable string version of the lonlat
*
* Returns:
* {String} String representation of OpenLayers.LonLat object.
*           (ex. <i>"lon=5,lat=42"</i>)
*/
toString:function() {
return ("lon=" + this.lon + ",lat=" + this.lat);
},
/**
* APIMethod: toShortString
*
* Returns:
* {String} Shortened String representation of OpenLayers.LonLat object.
*         (ex. <i>"5, 42"</i>)
*/
toShortString:function() {
return (this.lon + ", " + this.lat);
},
/**
* APIMethod: clone
*
* Returns:
* {<OpenLayers.LonLat>} New OpenLayers.LonLat object with the same lon
*                       and lat values
*/
clone:function() {
return new OpenLayers.LonLat(this.lon, this.lat);
},
/**
* APIMethod: add
*
* Parameters:
* lon - {Float}
* lat - {Float}
*
* Returns:
* {<OpenLayers.LonLat>} A new OpenLayers.LonLat object with the lon and
*                       lat passed-in added to this's.
*/
add:function(lon, lat) {
if ( (lon == null) || (lat == null) ) {
var msg = OpenLayers.i18n("lonlatAddError");
OpenLayers.Console.error(msg);
return null;
}
return new OpenLayers.LonLat(this.lon + lon, this.lat + lat);
},
/**
* APIMethod: equals
*
* Parameters:
* ll - {<OpenLayers.LonLat>}
*
* Returns:
* {Boolean} Boolean value indicating whether the passed-in
*           <OpenLayers.LonLat> object has the same lon and lat
*           components as this.
*           Note: if ll passed in is null, returns false
*/
equals:function(ll) {
var equals = false;
if (ll != null) {
equals = ((this.lon == ll.lon && this.lat == ll.lat) ||
(isNaN(this.lon) && isNaN(this.lat) && isNaN(ll.lon) && isNaN(ll.lat)));
}
return equals;
},
/**
* APIMethod: transform
* Transform the LonLat object from source to dest.
*
* Parameters:
* source - {<OpenLayers.Projection>} Source projection.
* dest   - {<OpenLayers.Projection>} Destination projection.
*
* Returns:
* {<OpenLayers.LonLat>} Itself, for use in chaining operations.
*/
transform: function(source, dest) {
var point = OpenLayers.Projection.transform(
{'x': this.lon, 'y': this.lat}, source, dest);
this.lon = point.x;
this.lat = point.y;
return this;
},
/**
* APIMethod: wrapDateLine
*
* Parameters:
* maxExtent - {<OpenLayers.Bounds>}
*
* Returns:
* {<OpenLayers.LonLat>} A copy of this lonlat, but wrapped around the
*                       "dateline" (as specified by the borders of
*                       maxExtent)
*/
wrapDateLine: function(maxExtent) {
var newLonLat = this.clone();
if (maxExtent) {
//shift right?
while (newLonLat.lon < maxExtent.left) {
newLonLat.lon +=  maxExtent.getWidth();
}
//shift left?
while (newLonLat.lon > maxExtent.right) {
newLonLat.lon -= maxExtent.getWidth();
}
}
return newLonLat;
},
CLASS_NAME: "OpenLayers.LonLat"
});
/**
* Function: fromString
* Alternative constructor that builds a new <OpenLayers.LonLat> from a
*     parameter string
*
* Parameters:
* str - {String} Comma-separated Lon,Lat coordinate string.
*                 (ex. <i>"5,40"</i>)
*
* Returns:
* {<OpenLayers.LonLat>} New <OpenLayers.LonLat> object built from the
*                       passed-in String.
*/
OpenLayers.LonLat.fromString = function(str) {
var pair = str.split(",");
return new OpenLayers.LonLat(parseFloat(pair[0]),
parseFloat(pair[1]));
};
/* 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. */
/**
* Class: OpenLayers.Pixel
* This class represents a screen coordinate, in x and y coordinates
*/
OpenLayers.Pixel = OpenLayers.Class({
/**
* APIProperty: x
* {Number} The x coordinate
*/
x: 0.0,
/**
* APIProperty: y
* {Number} The y coordinate
*/
y: 0.0,
/**
* Constructor: OpenLayers.Pixel
* Create a new OpenLayers.Pixel instance
*
* Parameters:
* x - {Number} The x coordinate
* y - {Number} The y coordinate
*
* Returns:
* An instance of OpenLayers.Pixel
*/
initialize: function(x, y) {
this.x = parseFloat(x);
this.y = parseFloat(y);
},
/**
* Method: toString
* Cast this object into a string
*
* Returns:
* {String} The string representation of Pixel. ex: "x=200.4,y=242.2"
*/
toString:function() {
return ("x=" + this.x + ",y=" + this.y);
},
/**
* APIMethod: clone
* Return a clone of this pixel object
*
* Returns:
* {<OpenLayers.Pixel>} A clone pixel
*/
clone:function() {
return new OpenLayers.Pixel(this.x, this.y);
},
/**
* APIMethod: equals
* Determine whether one pixel is equivalent to another
*
* Parameters:
* px - {<OpenLayers.Pixel>}
*
* Returns:
* {Boolean} The point passed in as parameter is equal to this. Note that
* if px passed in is null, returns false.
*/
equals:function(px) {
var equals = false;
if (px != null) {
equals = ((this.x == px.x && this.y == px.y) ||
(isNaN(this.x) && isNaN(this.y) && isNaN(px.x) && isNaN(px.y)));
}
return equals;
},
/**
* APIMethod: add
*
* Parameters:
* x - {Integer}
* y - {Integer}
*
* Returns:
* {<OpenLayers.Pixel>} A new Pixel with this pixel's x&y augmented by the
* values passed in.
*/
add:function(x, y) {
if ( (x == null) || (y == null) ) {
var msg = OpenLayers.i18n("pixelAddError");
OpenLayers.Console.error(msg);
return null;
}
return new OpenLayers.Pixel(this.x + x, this.y + y);
},
/**
* APIMethod: offset
*
* Parameters
* px - {<OpenLayers.Pixel>}
*
* Returns:
* {<OpenLayers.Pixel>} A new Pixel with this pixel's x&y augmented by the
*                      x&y values of the pixel passed in.
*/
offset:function(px) {
var newPx = this.clone();
if (px) {
newPx = this.add(px.x, px.y);
}
return newPx;
},
CLASS_NAME: "OpenLayers.Pixel"
});
/* 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. */
/**
* Class: OpenLayers.Size
* Instances of this class represent a width/height pair
*/
OpenLayers.Size = OpenLayers.Class({
/**
* APIProperty: w
* {Number} width
*/
w: 0.0,
/**
* APIProperty: h
* {Number} height
*/
h: 0.0,
/**
* Constructor: OpenLayers.Size
* Create an instance of OpenLayers.Size
*
* Parameters:
* w - {Number} width
* h - {Number} height
*/
initialize: function(w, h) {
this.w = parseFloat(w);
this.h = parseFloat(h);
},
/**
* Method: toString
* Return the string representation of a size object
*
* Returns:
* {String} The string representation of OpenLayers.Size object.
* (ex. <i>"w=55,h=66"</i>)
*/
toString:function() {
return ("w=" + this.w + ",h=" + this.h);
},
/**
* APIMethod: clone
* Create a clone of this size object
*
* Returns:
* {<OpenLayers.Size>} A new OpenLayers.Size object with the same w and h
* values
*/
clone:function() {
return new OpenLayers.Size(this.w, this.h);
},
/**
*
* APIMethod: equals
* Determine where this size is equal to another
*
* Parameters:
* sz - {<OpenLayers.Size>}
*
* Returns:
* {Boolean} The passed in size has the same h and w properties as this one.
* Note that if sz passed in is null, returns false.
*
*/
equals:function(sz) {
var equals = false;
if (sz != null) {
equals = ((this.w == sz.w && this.h == sz.h) ||
(isNaN(this.w) && isNaN(this.h) && isNaN(sz.w) && isNaN(sz.h)));
}
return equals;
},
CLASS_NAME: "OpenLayers.Size"
});
/* 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. */
/**
* Namespace: OpenLayers.Console
* The OpenLayers.Console namespace is used for debugging and error logging.
* If the Firebug Lite (../Firebug/firebug.js) is included before this script,
* calls to OpenLayers.Console methods will get redirected to window.console.
* This makes use of the Firebug extension where available and allows for
* cross-browser debugging Firebug style.
*
* Note:
* Note that behavior will differ with the Firebug extention and Firebug Lite.
* Most notably, the Firebug Lite console does not currently allow for
* hyperlinks to code or for clicking on object to explore their properties.
*
*/
OpenLayers.Console = {
/**
* Create empty functions for all console methods.  The real value of these
* properties will be set if Firebug Lite (../Firebug/firebug.js script) is
* included.  We explicitly require the Firebug Lite script to trigger
* functionality of the OpenLayers.Console methods.
*/
/**
* APIFunction: log
* Log an object in the console.  The Firebug Lite console logs string
* representation of objects.  Given multiple arguments, they will
* be cast to strings and logged with a space delimiter.  If the first
* argument is a string with printf-like formatting, subsequent arguments
* will be used in string substitution.  Any additional arguments (beyond
* the number substituted in a format string) will be appended in a space-
* delimited line.
*
* Parameters:
* object - {Object}
*/
log: function() {},
/**
* APIFunction: debug
* Writes a message to the console, including a hyperlink to the line
* where it was called.
*
* May be called with multiple arguments as with OpenLayers.Console.log().
*
* Parameters:
* object - {Object}
*/
debug: function() {},
/**
* APIFunction: info
* Writes a message to the console with the visual "info" icon and color
* coding and a hyperlink to the line where it was called.
*
* May be called with multiple arguments as with OpenLayers.Console.log().
*
* Parameters:
* object - {Object}
*/
info: function() {},
/**
* APIFunction: warn
* Writes a message to the console with the visual "warning" icon and
* color coding and a hyperlink to the line where it was called.
*
* May be called with multiple arguments as with OpenLayers.Console.log().
*
* Parameters:
* object - {Object}
*/
warn: function() {},
/**
* APIFunction: error
* Writes a message to the console with the visual "error" icon and color
* coding and a hyperlink to the line where it was called.
*
* May be called with multiple arguments as with OpenLayers.Console.log().
*
* Parameters:
* object - {Object}
*/
error: function() {},
/**
* APIFunction: assert
* Tests that an expression is true. If not, it will write a message to
* the console and throw an exception.
*
* May be called with multiple arguments as with OpenLayers.Console.log().
*
* Parameters:
* object - {Object}
*/
assert: function() {},
/**
* APIFunction: dir
* Prints an interactive listing of all properties of the object. This
* looks identical to the view that you would see in the DOM tab.
*
* Parameters:
* object - {Object}
*/
dir: function() {},
/**
* APIFunction: dirxml
* Prints the XML source tree of an HTML or XML element. This looks
* identical to the view that you would see in the HTML tab. You can click
* on any node to inspect it in the HTML tab.
*
* Parameters:
* object - {Object}
*/
dirxml: function() {},
/**
* APIFunction: trace
* Prints an interactive stack trace of JavaScript execution at the point
* where it is called.  The stack trace details the functions on the stack,
* as well as the values that were passed as arguments to each function.
* You can click each function to take you to its source in the Script tab,
* and click each argument value to inspect it in the DOM or HTML tabs.
*
*/
trace: function() {},
/**
* APIFunction: group
* Writes a message to the console and opens a nested block to indent all
* future messages sent to the console. Call OpenLayers.Console.groupEnd()
* to close the block.
*
* May be called with multiple arguments as with OpenLayers.Console.log().
*
* Parameters:
* object - {Object}
*/
group: function() {},
/**
* APIFunction: groupEnd
* Closes the most recently opened block created by a call to
* OpenLayers.Console.group
*/
groupEnd: function() {},
/**
* APIFunction: time
* Creates a new timer under the given name. Call
* OpenLayers.Console.timeEnd(name)
* with the same name to stop the timer and print the time elapsed.
*
* Parameters:
* name - {String}
*/
time: function() {},
/**
* APIFunction: timeEnd
* Stops a timer created by a call to OpenLayers.Console.time(name) and
* writes the time elapsed.
*
* Parameters:
* name - {String}
*/
timeEnd: function() {},
/**
* APIFunction: profile
* Turns on the JavaScript profiler. The optional argument title would
* contain the text to be printed in the header of the profile report.
*
* This function is not currently implemented in Firebug Lite.
*
* Parameters:
* title - {String} Optional title for the profiler
*/
profile: function() {},
/**
* APIFunction: profileEnd
* Turns off the JavaScript profiler and prints its report.
*
* This function is not currently implemented in Firebug Lite.
*/
profileEnd: function() {},
/**
* APIFunction: count
* Writes the number of times that the line of code where count was called
* was executed. The optional argument title will print a message in
* addition to the number of the count.
*
* This function is not currently implemented in Firebug Lite.
*
* Parameters:
* title - {String} Optional title to be printed with count
*/
count: function() {},
CLASS_NAME: "OpenLayers.Console"
};
/**
* Execute an anonymous function to extend the OpenLayers.Console namespace
* if the firebug.js script is included.  This closure is used so that the
* "scripts" and "i" variables don't pollute the global namespace.
*/
(function() {
/**
* If Firebug Lite is included (before this script), re-route all
* OpenLayers.Console calls to the console object.
*/
if(window.console) {
var scripts = document.getElementsByTagName("script");
for(var i=0; i<scripts.length; ++i) {
if(scripts[i].src.indexOf("firebug.js") != -1) {
OpenLayers.Util.extend(OpenLayers.Console, console);
break;
}
}
}
})();
/* 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. */
/**
* Namespace: OpenLayers.Tween
*/
OpenLayers.Tween = OpenLayers.Class({
/**
* Constant: INTERVAL
* {int} Interval in milliseconds between 2 steps
*/
INTERVAL: 10,
/**
* APIProperty: easing
* {<OpenLayers.Easing>(Function)} Easing equation used for the animation
*     Defaultly set to OpenLayers.Easing.Expo.easeOut
*/
easing: null,
/**
* APIProperty: begin
* {Object} Values to start the animation with
*/
begin: null,
/**
* APIProperty: finish
* {Object} Values to finish the animation with
*/
finish: null,
/**
* APIProperty: duration
* {int} duration of the tween (number of steps)
*/
duration: null,
/**
* APIProperty: callbacks
* {Object} An object with start, eachStep and done properties whose values
*     are functions to be call during the animation. They are passed the
*     current computed value as argument.
*/
callbacks: null,
/**
* Property: time
* {int} Step counter
*/
time: null,
/**
* Property: interval
* {int} Interval id returned by window.setInterval
*/
interval: null,
/**
* Property: playing
* {Boolean} Tells if the easing is currently playing
*/
playing: false,
/**
* Constructor: OpenLayers.Tween
* Creates a Tween.
*
* Parameters:
* easing - {<OpenLayers.Easing>(Function)} easing function method to use
*/
initialize: function(easing) {
this.easing = (easing) ? easing : OpenLayers.Easing.Expo.easeOut;
},
/**
* APIMethod: start
* Plays the Tween, and calls the callback method on each step
*
* Parameters:
* begin - {Object} values to start the animation with
* finish - {Object} values to finish the animation with
* duration - {int} duration of the tween (number of steps)
* options - {Object} hash of options (for example callbacks (start, eachStep, done))
*/
start: function(begin, finish, duration, options) {
this.playing = true;
this.begin = begin;
this.finish = finish;
this.duration = duration;
this.callbacks = options.callbacks;
this.time = 0;
if (this.interval) {
window.clearInterval(this.interval);
this.interval = null;
}
if (this.callbacks && this.callbacks.start) {
this.callbacks.start.call(this, this.begin);
}
this.interval = window.setInterval(
OpenLayers.Function.bind(this.play, this), this.INTERVAL);
},
/**
* APIMethod: stop
* Stops the Tween, and calls the done callback
*     Doesn't do anything if animation is already finished
*/
stop: function() {
if (!this.playing) {
return;
}
if (this.callbacks && this.callbacks.done) {
this.callbacks.done.call(this, this.finish);
}
window.clearInterval(this.interval);
this.interval = null;
this.playing = false;
},
/**
* Method: play
* Calls the appropriate easing method
*/
play: function() {
var value = {};
for (var i in this.begin) {
var b = this.begin[i];
var f = this.finish[i];
if (b == null || f == null || isNaN(b) || isNaN(f)) {
OpenLayers.Console.error('invalid value for Tween');
}
var c = f - b;
value[i] = this.easing.apply(this, [this.time, b, c, this.duration]);
}
this.time++;
if (this.callbacks && this.callbacks.eachStep) {
this.callbacks.eachStep.call(this, value);
}
if (this.time > this.duration) {
if (this.callbacks && this.callbacks.done) {
this.callbacks.done.call(this, this.finish);
this.playing = false;
}
window.clearInterval(this.interval);
this.interval = null;
}
},
/**
* Create empty functions for all easing methods.
*/
CLASS_NAME: "OpenLayers.Tween"
});
/**
* Namespace: OpenLayers.Easing
*
* Credits:
*      Easing Equations by Robert Penner, <http://www.robertpenner.com/easing/>
*/
OpenLayers.Easing = {
/**
* Create empty functions for all easing methods.
*/
CLASS_NAME: "OpenLayers.Easing"
};
/**
* Namespace: OpenLayers.Easing.Linear
*/
OpenLayers.Easing.Linear = {
/**
* Function: easeIn
*
* Parameters:
* t - {Float} time
* b - {Float} beginning position
* c - {Float} total change
* d - {Float} duration of the transition
*/
easeIn: function(t, b, c, d) {
return c*t/d + b;
},
/**
* Function: easeOut
*
* Parameters:
* t - {Float} time
* b - {Float} beginning position
* c - {Float} total change
* d - {Float} duration of the transition
*/
easeOut: function(t, b, c, d) {
return c*t/d + b;
},
/**
* Function: easeInOut
*
* Parameters:
* t - {Float} time
* b - {Float} beginning position
* c - {Float} total change
* d - {Float} duration of the transition
*/
easeInOut: function(t, b, c, d) {
return c*t/d + b;
},
CLASS_NAME: "OpenLayers.Easing.Linear"
};
/**
* Namespace: OpenLayers.Easing.Expo
*/
OpenLayers.Easing.Expo = {
/**
* Function: easeIn
*
* Parameters:
* t - {Float} time
* b - {Float} beginning position
* c - {Float} total change
* d - {Float} duration of the transition
*/
easeIn: function(t, b, c, d) {
return (t==0) ? b : c * Math.pow(2, 10 * (t/d - 1)) + b;
},
/**
* Function: easeOut
*
* Parameters:
* t - {Float} time
* b - {Float} beginning position
* c - {Float} total change
* d - {Float} duration of the transition
*/
easeOut: function(t, b, c, d) {
return (t==d) ? b+c : c * (-Math.pow(2, -10 * t/d) + 1) + b;
},
/**
* Function: easeInOut
*
* Parameters:
* t - {Float} time
* b - {Float} beginning position
* c - {Float} total change
* d - {Float} duration of the transition
*/
easeInOut: function(t, b, c, d) {
if (t==0) return b;
if (t==d) return b+c;
if ((t/=d/2) < 1) return c/2 * Math.pow(2, 10 * (t - 1)) + b;
return c/2 * (-Math.pow(2, -10 * --t) + 2) + b;
},
CLASS_NAME: "OpenLayers.Easing.Expo"
};
/**
* Namespace: OpenLayers.Easing.Quad
*/
OpenLayers.Easing.Quad = {
/**
* Function: easeIn
*
* Parameters:
* t - {Float} time
* b - {Float} beginning position
* c - {Float} total change
* d - {Float} duration of the transition
*/
easeIn: function(t, b, c, d) {
return c*(t/=d)*t + b;
},
/**
* Function: easeOut
*
* Parameters:
* t - {Float} time
* b - {Float} beginning position
* c - {Float} total change
* d - {Float} duration of the transition
*/
easeOut: function(t, b, c, d) {
return -c *(t/=d)*(t-2) + b;
},
/**
* Function: easeInOut
*
* Parameters:
* t - {Float} time
* b - {Float} beginning position
* c - {Float} total change
* d - {Float} duration of the transition
*/
easeInOut: function(t, b, c, d) {
if ((t/=d/2) < 1) return c/2*t*t + b;
return -c/2 * ((--t)*(t-2) - 1) + b;
},
CLASS_NAME: "OpenLayers.Easing.Quad"
};
/*
* This file has been edited substantially from the Rico-released
* version by the OpenLayers development team.
*
*  Copyright 2005 Sabre Airline Solutions
*
*  Licensed under the Apache License, Version 2.0 (the "License");
*  you may not use this file except in compliance with the
*  License. You may obtain a copy of the License at
*
*         http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the * License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, * either express or
* implied. See the License for the specific language governing
* permissions * and limitations under the License.
*
*/
OpenLayers.Rico = new Object();
OpenLayers.Rico.Corner = {
round: function(e, options) {
e = OpenLayers.Util.getElement(e);
this._setOptions(options);
var color = this.options.color;
if ( this.options.color == "fromElement" ) {
color = this._background(e);
}
var bgColor = this.options.bgColor;
if ( this.options.bgColor == "fromParent" ) {
bgColor = this._background(e.offsetParent);
}
this._roundCornersImpl(e, color, bgColor);
},
/**   This is a helper function to change the background
*     color of <div> that has had Rico rounded corners added.
*
*     It seems we cannot just set the background color for the
*     outer <div> so each <span> element used to create the
*     corners must have its background color set individually.
*
* @param {DOM} theDiv - A child of the outer <div> that was
*                        supplied to the `round` method.
*
* @param {String} newColor - The new background color to use.
*/
changeColor: function(theDiv, newColor) {
theDiv.style.backgroundColor = newColor;
var spanElements = theDiv.parentNode.getElementsByTagName("span");
for (var currIdx = 0; currIdx < spanElements.length; currIdx++) {
spanElements[currIdx].style.backgroundColor = newColor;
}
},
/**   This is a helper function to change the background
*     opacity of <div> that has had Rico rounded corners added.
*
*     See changeColor (above) for algorithm explanation
*
* @param {DOM} theDiv A child of the outer <div> that was
*                        supplied to the `round` method.
*
* @param {int} newOpacity The new opacity to use (0-1).
*/
changeOpacity: function(theDiv, newOpacity) {
var mozillaOpacity = newOpacity;
var ieOpacity = 'alpha(opacity=' + newOpacity * 100 + ')';
theDiv.style.opacity = mozillaOpacity;
theDiv.style.filter = ieOpacity;
var spanElements = theDiv.parentNode.getElementsByTagName("span");
for (var currIdx = 0; currIdx < spanElements.length; currIdx++) {
spanElements[currIdx].style.opacity = mozillaOpacity;
spanElements[currIdx].style.filter = ieOpacity;
}
},
/** this function takes care of redoing the rico cornering
*
*    you can't just call updateRicoCorners() again and pass it a
*    new options string. you have to first remove the divs that
*    rico puts on top and below the content div.
*
* @param {DOM} theDiv - A child of the outer <div> that was
*                        supplied to the `round` method.
*
* @param {Object} options - list of options
*/
reRound: function(theDiv, options) {
var topRico = theDiv.parentNode.childNodes[0];
//theDiv would be theDiv.parentNode.childNodes[1]
var bottomRico = theDiv.parentNode.childNodes[2];
theDiv.parentNode.removeChild(topRico);
theDiv.parentNode.removeChild(bottomRico);
this.round(theDiv.parentNode, options);
},
_roundCornersImpl: function(e, color, bgColor) {
if(this.options.border) {
this._renderBorder(e,bgColor);
}
if(this._isTopRounded()) {
this._roundTopCorners(e,color,bgColor);
}
if(this._isBottomRounded()) {
this._roundBottomCorners(e,color,bgColor);
}
},
_renderBorder: function(el,bgColor) {
var borderValue = "1px solid " + this._borderColor(bgColor);
var borderL = "border-left: "  + borderValue;
var borderR = "border-right: " + borderValue;
var style   = "style='" + borderL + ";" + borderR +  "'";
el.innerHTML = "<div " + style + ">" + el.innerHTML + "</div>";
},
_roundTopCorners: function(el, color, bgColor) {
var corner = this._createCorner(bgColor);
for(var i=0 ; i < this.options.numSlices ; i++ ) {
corner.appendChild(this._createCornerSlice(color,bgColor,i,"top"));
}
el.style.paddingTop = 0;
el.insertBefore(corner,el.firstChild);
},
_roundBottomCorners: function(el, color, bgColor) {
var corner = this._createCorner(bgColor);
for(var i=(this.options.numSlices-1) ; i >= 0 ; i-- ) {
corner.appendChild(this._createCornerSlice(color,bgColor,i,"bottom"));
}
el.style.paddingBottom = 0;
el.appendChild(corner);
},
_createCorner: function(bgColor) {
var corner = document.createElement("div");
corner.style.backgroundColor = (this._isTransparent() ? "transparent" : bgColor);
return corner;
},
_createCornerSlice: function(color,bgColor, n, position) {
var slice = document.createElement("span");
var inStyle = slice.style;
inStyle.backgroundColor = color;
inStyle.display  = "block";
inStyle.height   = "1px";
inStyle.overflow = "hidden";
inStyle.fontSize = "1px";
var borderColor = this._borderColor(color,bgColor);
if ( this.options.border && n == 0 ) {
inStyle.borderTopStyle    = "solid";
inStyle.borderTopWidth    = "1px";
inStyle.borderLeftWidth   = "0px";
inStyle.borderRightWidth  = "0px";
inStyle.borderBottomWidth = "0px";
inStyle.height            = "0px"; // assumes css compliant box model
inStyle.borderColor       = borderColor;
}
else if(borderColor) {
inStyle.borderColor = borderColor;
inStyle.borderStyle = "solid";
inStyle.borderWidth = "0px 1px";
}
if ( !this.options.compact && (n == (this.options.numSlices-1)) ) {
inStyle.height = "2px";
}
this._setMargin(slice, n, position);
this._setBorder(slice, n, position);
return slice;
},
_setOptions: function(options) {
this.options = {
corners : "all",
color   : "fromElement",
bgColor : "fromParent",
blend   : true,
border  : false,
compact : false
};
OpenLayers.Util.extend(this.options, options || {});
this.options.numSlices = this.options.compact ? 2 : 4;
if ( this._isTransparent() ) {
this.options.blend = false;
}
},
_whichSideTop: function() {
if ( this._hasString(this.options.corners, "all", "top") ) {
return "";
}
if ( this.options.corners.indexOf("tl") >= 0 && this.options.corners.indexOf("tr") >= 0 ) {
return "";
}
if (this.options.corners.indexOf("tl") >= 0) {
return "left";
} else if (this.options.corners.indexOf("tr") >= 0) {
return "right";
}
return "";
},
_whichSideBottom: function() {
if ( this._hasString(this.options.corners, "all", "bottom") ) {
return "";
}
if ( this.options.corners.indexOf("bl")>=0 && this.options.corners.indexOf("br")>=0 ) {
return "";
}
if(this.options.corners.indexOf("bl") >=0) {
return "left";
} else if(this.options.corners.indexOf("br")>=0) {
return "right";
}
return "";
},
_borderColor : function(color,bgColor) {
if ( color == "transparent" ) {
return bgColor;
} else if ( this.options.border ) {
return this.options.border;
} else if ( this.options.blend ) {
return this._blend( bgColor, color );
} else {
return "";
}
},
_setMargin: function(el, n, corners) {
var marginSize = this._marginSize(n);
var whichSide = corners == "top" ? this._whichSideTop() : this._whichSideBottom();
if ( whichSide == "left" ) {
el.style.marginLeft = marginSize + "px"; el.style.marginRight = "0px";
}
else if ( whichSide == "right" ) {
el.style.marginRight = marginSize + "px"; el.style.marginLeft  = "0px";
}
else {
el.style.marginLeft = marginSize + "px"; el.style.marginRight = marginSize + "px";
}
},
_setBorder: function(el,n,corners) {
var borderSize = this._borderSize(n);
var whichSide = corners == "top" ? this._whichSideTop() : this._whichSideBottom();
if ( whichSide == "left" ) {
el.style.borderLeftWidth = borderSize + "px"; el.style.borderRightWidth = "0px";
}
else if ( whichSide == "right" ) {
el.style.borderRightWidth = borderSize + "px"; el.style.borderLeftWidth  = "0px";
}
else {
el.style.borderLeftWidth = borderSize + "px"; el.style.borderRightWidth = borderSize + "px";
}
if (this.options.border != false) {
el.style.borderLeftWidth = borderSize + "px"; el.style.borderRightWidth = borderSize + "px";
}
},
_marginSize: function(n) {
if ( this._isTransparent() ) {
return 0;
}
var marginSizes          = [ 5, 3, 2, 1 ];
var blendedMarginSizes   = [ 3, 2, 1, 0 ];
var compactMarginSizes   = [ 2, 1 ];
var smBlendedMarginSizes = [ 1, 0 ];
if ( this.options.compact && this.options.blend ) {
return smBlendedMarginSizes[n];
} else if ( this.options.compact ) {
return compactMarginSizes[n];
} else if ( this.options.blend ) {
return blendedMarginSizes[n];
} else {
return marginSizes[n];
}
},
_borderSize: function(n) {
var transparentBorderSizes = [ 5, 3, 2, 1 ];
var blendedBorderSizes     = [ 2, 1, 1, 1 ];
var compactBorderSizes     = [ 1, 0 ];
var actualBorderSizes      = [ 0, 2, 0, 0 ];
if ( this.options.compact && (this.options.blend || this._isTransparent()) ) {
return 1;
} else if ( this.options.compact ) {
return compactBorderSizes[n];
} else if ( this.options.blend ) {
return blendedBorderSizes[n];
} else if ( this.options.border ) {
return actualBorderSizes[n];
} else if ( this._isTransparent() ) {
return transparentBorderSizes[n];
}
return 0;
},
_hasString: function(str) { for(var i=1 ; i<arguments.length ; i++) if (str.indexOf(arguments[i]) >= 0) { return true; } return false; },
_blend: function(c1, c2) { var cc1 = OpenLayers.Rico.Color.createFromHex(c1); cc1.blend(OpenLayers.Rico.Color.createFromHex(c2)); return cc1; },
_background: function(el) { try { return OpenLayers.Rico.Color.createColorFromBackground(el).asHex(); } catch(err) { return "#ffffff"; } },
_isTransparent: function() { return this.options.color == "transparent"; },
_isTopRounded: function() { return this._hasString(this.options.corners, "all", "top", "tl", "tr"); },
_isBottomRounded: function() { return this._hasString(this.options.corners, "all", "bottom", "bl", "br"); },
_hasSingleTextChild: function(el) { return el.childNodes.length == 1 && el.childNodes[0].nodeType == 3; }
};
/*
* This file has been edited substantially from the Rico-released version by
* the OpenLayers development team.
*
* This file is licensed under the Apache License, Version 2.0.
*/
OpenLayers.Rico.Color = OpenLayers.Class({
initialize: function(red, green, blue) {
this.rgb = { r: red, g : green, b : blue };
},
setRed: function(r) {
this.rgb.r = r;
},
setGreen: function(g) {
this.rgb.g = g;
},
setBlue: function(b) {
this.rgb.b = b;
},
setHue: function(h) {
// get an HSB model, and set the new hue...
var hsb = this.asHSB();
hsb.h = h;
// convert back to RGB...
this.rgb = OpenLayers.Rico.Color.HSBtoRGB(hsb.h, hsb.s, hsb.b);
},
setSaturation: function(s) {
// get an HSB model, and set the new hue...
var hsb = this.asHSB();
hsb.s = s;
// convert back to RGB and set values...
this.rgb = OpenLayers.Rico.Color.HSBtoRGB(hsb.h, hsb.s, hsb.b);
},
setBrightness: function(b) {
// get an HSB model, and set the new hue...
var hsb = this.asHSB();
hsb.b = b;
// convert back to RGB and set values...
this.rgb = OpenLayers.Rico.Color.HSBtoRGB( hsb.h, hsb.s, hsb.b );
},
darken: function(percent) {
var hsb  = this.asHSB();
this.rgb = OpenLayers.Rico.Color.HSBtoRGB(hsb.h, hsb.s, Math.max(hsb.b - percent,0));
},
brighten: function(percent) {
var hsb  = this.asHSB();
this.rgb = OpenLayers.Rico.Color.HSBtoRGB(hsb.h, hsb.s, Math.min(hsb.b + percent,1));
},
blend: function(other) {
this.rgb.r = Math.floor((this.rgb.r + other.rgb.r)/2);
this.rgb.g = Math.floor((this.rgb.g + other.rgb.g)/2);
this.rgb.b = Math.floor((this.rgb.b + other.rgb.b)/2);
},
isBright: function() {
var hsb = this.asHSB();
return this.asHSB().b > 0.5;
},
isDark: function() {
return ! this.isBright();
},
asRGB: function() {
return "rgb(" + this.rgb.r + "," + this.rgb.g + "," + this.rgb.b + ")";
},
asHex: function() {
return "#" + this.rgb.r.toColorPart() + this.rgb.g.toColorPart() + this.rgb.b.toColorPart();
},
asHSB: function() {
return OpenLayers.Rico.Color.RGBtoHSB(this.rgb.r, this.rgb.g, this.rgb.b);
},
toString: function() {
return this.asHex();
}
});
OpenLayers.Rico.Color.createFromHex = function(hexCode) {
if(hexCode.length==4) {
var shortHexCode = hexCode;
var hexCode = '#';
for(var i=1;i<4;i++) {
hexCode += (shortHexCode.charAt(i) +
shortHexCode.charAt(i));
}
}
if ( hexCode.indexOf('#') == 0 ) {
hexCode = hexCode.substring(1);
}
var red   = hexCode.substring(0,2);
var green = hexCode.substring(2,4);
var blue  = hexCode.substring(4,6);
return new OpenLayers.Rico.Color( parseInt(red,16), parseInt(green,16), parseInt(blue,16) );
};
/**
* Factory method for creating a color from the background of
* an HTML element.
*/
OpenLayers.Rico.Color.createColorFromBackground = function(elem) {
var actualColor =
RicoUtil.getElementsComputedStyle(OpenLayers.Util.getElement(elem),
"backgroundColor",
"background-color");
if ( actualColor == "transparent" && elem.parentNode ) {
return OpenLayers.Rico.Color.createColorFromBackground(elem.parentNode);
}
if ( actualColor == null ) {
return new OpenLayers.Rico.Color(255,255,255);
}
if ( actualColor.indexOf("rgb(") == 0 ) {
var colors = actualColor.substring(4, actualColor.length - 1 );
var colorArray = colors.split(",");
return new OpenLayers.Rico.Color( parseInt( colorArray[0] ),
parseInt( colorArray[1] ),
parseInt( colorArray[2] )  );
}
else if ( actualColor.indexOf("#") == 0 ) {
return OpenLayers.Rico.Color.createFromHex(actualColor);
}
else {
return new OpenLayers.Rico.Color(255,255,255);
}
};
OpenLayers.Rico.Color.HSBtoRGB = function(hue, saturation, brightness) {
var red   = 0;
var green = 0;
var blue  = 0;
if (saturation == 0) {
red = parseInt(brightness * 255.0 + 0.5);
green = red;
blue = red;
}
else {
var h = (hue - Math.floor(hue)) * 6.0;
var f = h - Math.floor(h);
var p = brightness * (1.0 - saturation);
var q = brightness * (1.0 - saturation * f);
var t = brightness * (1.0 - (saturation * (1.0 - f)));
switch (parseInt(h)) {
case 0:
red   = (brightness * 255.0 + 0.5);
green = (t * 255.0 + 0.5);
blue  = (p * 255.0 + 0.5);
break;
case 1:
red   = (q * 255.0 + 0.5);
green = (brightness * 255.0 + 0.5);
blue  = (p * 255.0 + 0.5);
break;
case 2:
red   = (p * 255.0 + 0.5);
green = (brightness * 255.0 + 0.5);
blue  = (t * 255.0 + 0.5);
break;
case 3:
red   = (p * 255.0 + 0.5);
green = (q * 255.0 + 0.5);
blue  = (brightness * 255.0 + 0.5);
break;
case 4:
red   = (t * 255.0 + 0.5);
green = (p * 255.0 + 0.5);
blue  = (brightness * 255.0 + 0.5);
break;
case 5:
red   = (brightness * 255.0 + 0.5);
green = (p * 255.0 + 0.5);
blue  = (q * 255.0 + 0.5);
break;
}
}
return { r : parseInt(red), g : parseInt(green) , b : parseInt(blue) };
};
OpenLayers.Rico.Color.RGBtoHSB = function(r, g, b) {
var hue;
var saturation;
var brightness;
var cmax = (r > g) ? r : g;
if (b > cmax) {
cmax = b;
}
var cmin = (r < g) ? r : g;
if (b < cmin) {
cmin = b;
}
brightness = cmax / 255.0;
if (cmax != 0) {
saturation = (cmax - cmin)/cmax;
} else {
saturation = 0;
}
if (saturation == 0) {
hue = 0;
} else {
var redc   = (cmax - r)/(cmax - cmin);
var greenc = (cmax - g)/(cmax - cmin);
var bluec  = (cmax - b)/(cmax - cmin);
if (r == cmax) {
hue = bluec - greenc;
} else if (g == cmax) {
hue = 2.0 + redc - bluec;
} else {
hue = 4.0 + greenc - redc;
}
hue = hue / 6.0;
if (hue < 0) {
hue = hue + 1.0;
}
}
return { h : hue, s : saturation, b : brightness };
};