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
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 = "
" + el.innerHTML + "
";
},
_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
= 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; }
};
/* ======================================================================
OpenLayers/Console.js
====================================================================== */
/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
* full list of contributors). Published under the Clear BSD license.
* See http://svn.openlayers.org/trunk/openlayers/license.txt for the
* full text of the license. */
/**
* @requires OpenLayers/BaseTypes/Class.js
*/
/**
* 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: userError
* A single interface for showing error messages to the user. The default
* behavior is a Javascript alert, though this can be overridden by
* reassigning OpenLayers.Console.userError to a different function.
*
* Expects a single error message
*
* Parameters:
* error - {Object}
*/
userError: function(error) {
alert(error);
},
/**
* 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.
*/
var scripts = document.getElementsByTagName("script");
for(var i=0, len=scripts.length; i var map = new OpenLayers.Map('map', { controls: [] });
* >
* > map.addControl(new OpenLayers.Control.PanZoomBar());
* > map.addControl(new OpenLayers.Control.MouseToolbar());
* > map.addControl(new OpenLayers.Control.LayerSwitcher({'ascending':false}));
* > map.addControl(new OpenLayers.Control.Permalink());
* > map.addControl(new OpenLayers.Control.Permalink('permalink'));
* > map.addControl(new OpenLayers.Control.MousePosition());
* > map.addControl(new OpenLayers.Control.OverviewMap());
* > map.addControl(new OpenLayers.Control.KeyboardDefaults());
*
* The next code fragment is a quick example of how to intercept
* shift-mouse click to display the extent of the bounding box
* dragged out by the user. Usually controls are not created
* in exactly this manner. See the source for a more complete
* example:
*
* > var control = new OpenLayers.Control();
* > OpenLayers.Util.extend(control, {
* > draw: function () {
* > // this Handler.Box will intercept the shift-mousedown
* > // before Control.MouseDefault gets to see it
* > this.box = new OpenLayers.Handler.Box( control,
* > {"done": this.notice},
* > {keyMask: OpenLayers.Handler.MOD_SHIFT});
* > this.box.activate();
* > },
* >
* > notice: function (bounds) {
* > OpenLayers.Console.userError(bounds);
* > }
* > });
* > map.addControl(control);
*
*/
OpenLayers.Control = OpenLayers.Class({
/**
* Property: id
* {String}
*/
id: null,
/**
* Property: map
* {} this gets set in the addControl() function in
* OpenLayers.Map
*/
map: null,
/**
* APIProperty: div
* {DOMElement} The element that contains the control, if not present the
* control is placed inside the map.
*/
div: null,
/**
* APIProperty: type
* {Number} Controls can have a 'type'. The type determines the type of
* interactions which are possible with them when they are placed in an
* .
*/
type: null,
/**
* Property: allowSelection
* {Boolean} By deafault, controls do not allow selection, because
* it may interfere with map dragging. If this is true, OpenLayers
* will not prevent selection of the control.
* Default is false.
*/
allowSelection: false,
/**
* Property: displayClass
* {string} This property is used for CSS related to the drawing of the
* Control.
*/
displayClass: "",
/**
* APIProperty: title
* {string} This property is used for showing a tooltip over the
* Control.
*/
title: "",
/**
* APIProperty: autoActivate
* {Boolean} Activate the control when it is added to a map. Default is
* false.
*/
autoActivate: false,
/**
* APIProperty: active
* {Boolean} The control is active (read-only). Use and
* to change control state.
*/
active: null,
/**
* Property: handler
* {} null
*/
handler: null,
/**
* APIProperty: eventListeners
* {Object} If set as an option at construction, the eventListeners
* object will be registered with . Object
* structure must be a listeners object as shown in the example for
* the events.on method.
*/
eventListeners: null,
/**
* APIProperty: events
* {} Events instance for listeners and triggering
* control specific events.
*/
events: null,
/**
* Constant: EVENT_TYPES
* {Array(String)} Supported application event types. Register a listener
* for a particular event with the following syntax:
* (code)
* control.events.register(type, obj, listener);
* (end)
*
* Listeners will be called with a reference to an event object. The
* properties of this event depends on exactly what happened.
*
* All event objects have at least the following properties:
* object - {Object} A reference to control.events.object (a reference
* to the control).
* element - {DOMElement} A reference to control.events.element (which
* will be null unless documented otherwise).
*
* Supported map event types:
* activate - Triggered when activated.
* deactivate - Triggered when deactivated.
*/
EVENT_TYPES: ["activate", "deactivate"],
/**
* Constructor: OpenLayers.Control
* Create an OpenLayers Control. The options passed as a parameter
* directly extend the control. For example passing the following:
*
* > var control = new OpenLayers.Control({div: myDiv});
*
* Overrides the default div attribute value of null.
*
* Parameters:
* options - {Object}
*/
initialize: function (options) {
// We do this before the extend so that instances can override
// className in options.
this.displayClass =
this.CLASS_NAME.replace("OpenLayers.", "ol").replace(/\./g, "");
OpenLayers.Util.extend(this, options);
this.events = new OpenLayers.Events(this, null, this.EVENT_TYPES);
if(this.eventListeners instanceof Object) {
this.events.on(this.eventListeners);
}
if (this.id == null) {
this.id = OpenLayers.Util.createUniqueID(this.CLASS_NAME + "_");
}
},
/**
* Method: destroy
* The destroy method is used to perform any clean up before the control
* is dereferenced. Typically this is where event listeners are removed
* to prevent memory leaks.
*/
destroy: function () {
if(this.events) {
if(this.eventListeners) {
this.events.un(this.eventListeners);
}
this.events.destroy();
this.events = null;
}
this.eventListeners = null;
// eliminate circular references
if (this.handler) {
this.handler.destroy();
this.handler = null;
}
if(this.handlers) {
for(var key in this.handlers) {
if(this.handlers.hasOwnProperty(key) &&
typeof this.handlers[key].destroy == "function") {
this.handlers[key].destroy();
}
}
this.handlers = null;
}
if (this.map) {
this.map.removeControl(this);
this.map = null;
}
this.div = null;
},
/**
* Method: setMap
* Set the map property for the control. This is done through an accessor
* so that subclasses can override this and take special action once
* they have their map variable set.
*
* Parameters:
* map - {}
*/
setMap: function(map) {
this.map = map;
if (this.handler) {
this.handler.setMap(map);
}
},
/**
* Method: draw
* The draw method is called when the control is ready to be displayed
* on the page. If a div has not been created one is created. Controls
* with a visual component will almost always want to override this method
* to customize the look of control.
*
* Parameters:
* px - {} The top-left pixel position of the control
* or null.
*
* Returns:
* {DOMElement} A reference to the DIV DOMElement containing the control
*/
draw: function (px) {
if (this.div == null) {
this.div = OpenLayers.Util.createDiv(this.id);
this.div.className = this.displayClass;
if (!this.allowSelection) {
this.div.className += " olControlNoSelect";
this.div.setAttribute("unselectable", "on", 0);
this.div.onselectstart = OpenLayers.Function.False;
}
if (this.title != "") {
this.div.title = this.title;
}
}
if (px != null) {
this.position = px.clone();
}
this.moveTo(this.position);
return this.div;
},
/**
* Method: moveTo
* Sets the left and top style attributes to the passed in pixel
* coordinates.
*
* Parameters:
* px - {}
*/
moveTo: function (px) {
if ((px != null) && (this.div != null)) {
this.div.style.left = px.x + "px";
this.div.style.top = px.y + "px";
}
},
/**
* APIMethod: activate
* Explicitly activates a control and it's associated
* handler if one has been set. Controls can be
* deactivated by calling the deactivate() method.
*
* Returns:
* {Boolean} True if the control was successfully activated or
* false if the control was already active.
*/
activate: function () {
if (this.active) {
return false;
}
if (this.handler) {
this.handler.activate();
}
this.active = true;
if(this.map) {
OpenLayers.Element.addClass(
this.map.viewPortDiv,
this.displayClass.replace(/ /g, "") + "Active"
);
}
this.events.triggerEvent("activate");
return true;
},
/**
* APIMethod: deactivate
* Deactivates a control and it's associated handler if any. The exact
* effect of this depends on the control itself.
*
* Returns:
* {Boolean} True if the control was effectively deactivated or false
* if the control was already inactive.
*/
deactivate: function () {
if (this.active) {
if (this.handler) {
this.handler.deactivate();
}
this.active = false;
if(this.map) {
OpenLayers.Element.removeClass(
this.map.viewPortDiv,
this.displayClass.replace(/ /g, "") + "Active"
);
}
this.events.triggerEvent("deactivate");
return true;
}
return false;
},
CLASS_NAME: "OpenLayers.Control"
});
/**
* Constant: OpenLayers.Control.TYPE_BUTTON
*/
OpenLayers.Control.TYPE_BUTTON = 1;
/**
* Constant: OpenLayers.Control.TYPE_TOGGLE
*/
OpenLayers.Control.TYPE_TOGGLE = 2;
/**
* Constant: OpenLayers.Control.TYPE_TOOL
*/
OpenLayers.Control.TYPE_TOOL = 3;
/* ======================================================================
OpenLayers/Lang.js
====================================================================== */
/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
* full list of contributors). Published under the Clear BSD license.
* See http://svn.openlayers.org/trunk/openlayers/license.txt for the
* full text of the license. */
/**
* @requires OpenLayers/BaseTypes.js
* @requires OpenLayers/Console.js
*/
/**
* Namespace: OpenLayers.Lang
* Internationalization namespace. Contains dictionaries in various languages
* and methods to set and get the current language.
*/
OpenLayers.Lang = {
/**
* Property: code
* {String} Current language code to use in OpenLayers. Use the
* method to set this value and the method to
* retrieve it.
*/
code: null,
/**
* APIProperty: defaultCode
* {String} Default language to use when a specific language can't be
* found. Default is "en".
*/
defaultCode: "en",
/**
* APIFunction: getCode
* Get the current language code.
*
* Returns:
* The current language code.
*/
getCode: function() {
if(!OpenLayers.Lang.code) {
OpenLayers.Lang.setCode();
}
return OpenLayers.Lang.code;
},
/**
* APIFunction: setCode
* Set the language code for string translation. This code is used by
* the method.
*
* Parameters-
* code - {String} These codes follow the IETF recommendations at
* http://www.ietf.org/rfc/rfc3066.txt. If no value is set, the
* browser's language setting will be tested. If no
* dictionary exists for the code, the
* will be used.
*/
setCode: function(code) {
var lang;
if(!code) {
code = (OpenLayers.BROWSER_NAME == "msie") ?
navigator.userLanguage : navigator.language;
}
var parts = code.split('-');
parts[0] = parts[0].toLowerCase();
if(typeof OpenLayers.Lang[parts[0]] == "object") {
lang = parts[0];
}
// check for regional extensions
if(parts[1]) {
var testLang = parts[0] + '-' + parts[1].toUpperCase();
if(typeof OpenLayers.Lang[testLang] == "object") {
lang = testLang;
}
}
if(!lang) {
OpenLayers.Console.warn(
'Failed to find OpenLayers.Lang.' + parts.join("-") +
' dictionary, falling back to default language'
);
lang = OpenLayers.Lang.defaultCode;
}
OpenLayers.Lang.code = lang;
},
/**
* APIMethod: translate
* Looks up a key from a dictionary based on the current language string.
* The value of will be used to determine the appropriate
* dictionary. Dictionaries are stored in .
*
* Parameters:
* key - {String} The key for an i18n string value in the dictionary.
* context - {Object} Optional context to be used with
* .
*
* Returns:
* {String} A internationalized string.
*/
translate: function(key, context) {
var dictionary = OpenLayers.Lang[OpenLayers.Lang.getCode()];
var message = dictionary && dictionary[key];
if(!message) {
// Message not found, fall back to message key
message = key;
}
if(context) {
message = OpenLayers.String.format(message, context);
}
return message;
}
};
/**
* APIMethod: OpenLayers.i18n
* Alias for . Looks up a key from a dictionary
* based on the current language string. The value of
* will be used to determine the appropriate
* dictionary. Dictionaries are stored in .
*
* Parameters:
* key - {String} The key for an i18n string value in the dictionary.
* context - {Object} Optional context to be used with
* .
*
* Returns:
* {String} A internationalized string.
*/
OpenLayers.i18n = OpenLayers.Lang.translate;
/* ======================================================================
OpenLayers/BaseTypes/Bounds.js
====================================================================== */
/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
* full list of contributors). Published under the Clear BSD license.
* See http://svn.openlayers.org/trunk/openlayers/license.txt for the
* full text of the license. */
/**
* @requires OpenLayers/BaseTypes/Class.js
* @requires OpenLayers/Console.js
* @requires OpenLayers/Lang.js
*/
/**
* 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:
* (code)
* 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
* (end)
*/
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,
/**
* Property: centerLonLat
* {} A cached center location. This should not be
* accessed directly. Use instead.
*/
centerLonLat: 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 = OpenLayers.Util.toFloat(left);
}
if (bottom != null) {
this.bottom = OpenLayers.Util.toFloat(bottom);
}
if (right != null) {
this.right = OpenLayers.Util.toFloat(right);
}
if (top != null) {
this.top = OpenLayers.Util.toFloat(top);
}
},
/**
* Method: clone
* Create a cloned instance of this bounds.
*
* Returns:
* {} 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 - {}
*
* 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.
*/
toString:function() {
return [this.left, this.bottom, this.right, this.top].join(",");
},
/**
* APIMethod: toArray
*
* Parameters:
* reverseAxisOrder - {Boolean} Should we reverse the axis order?
*
* Returns:
* {Array} array of left, bottom, right, top
*/
toArray: function(reverseAxisOrder) {
if (reverseAxisOrder === true) {
return [this.bottom, this.left, this.top, this.right];
} else {
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
* reverseAxisOrder - {Boolean} Should we reverse the axis order?
*
* Returns:
* {String} Simple String representation of bounds object.
* (e.g. "5,42,10,45")
*/
toBBOX:function(decimal, reverseAxisOrder) {
if (decimal== null) {
decimal = 6;
}
var mult = Math.pow(10, decimal);
var xmin = Math.round(this.left * mult) / mult;
var ymin = Math.round(this.bottom * mult) / mult;
var xmax = Math.round(this.right * mult) / mult;
var ymax = Math.round(this.top * mult) / mult;
if (reverseAxisOrder === true) {
return ymin + "," + xmin + "," + ymax + "," + xmax;
} else {
return xmin + "," + ymin + "," + xmax + "," + ymax;
}
},
/**
* APIMethod: toGeometry
* Create a new polygon geometry based on this bounds.
*
* Returns:
* {} 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:
* {} The size of the box.
*/
getSize:function() {
return new OpenLayers.Size(this.getWidth(), this.getHeight());
},
/**
* APIMethod: getCenterPixel
*
* Returns:
* {} 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:
* {} The center of the bounds in map space.
*/
getCenterLonLat:function() {
if(!this.centerLonLat) {
this.centerLonLat = new OpenLayers.LonLat(
(this.left + this.right) / 2, (this.bottom + this.top) / 2
);
}
return this.centerLonLat;
},
/**
* APIMethod: scale
* Scales the bounds around a pixel or lonlat. Note that the new
* bounds may return non-integer properties, even if a pixel
* is passed.
*
* Parameters:
* ratio - {Float}
* origin - { or }
* Default is center.
*
* Returns:
* {} A new bounds that is scaled by ratio
* from origin.
*/
scale: function(ratio, origin){
if(origin == null){
origin = this.getCenterLonLat();
}
var origx,origy;
// get origin coordinates
if(origin.CLASS_NAME == "OpenLayers.LonLat"){
origx = origin.lon;
origy = origin.lat;
} else {
origx = origin.x;
origy = origin.y;
}
var left = (this.left - origx) * ratio + origx;
var bottom = (this.bottom - origy) * ratio + origy;
var right = (this.right - origx) * ratio + origx;
var top = (this.top - origy) * ratio + origy;
return new OpenLayers.Bounds(left, bottom, right, top);
},
/**
* APIMethod: add
*
* Parameters:
* x - {Float}
* y - {Float}
*
* Returns:
* {} 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) {
// clear cached center location
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) {
this.centerLonLat = null;
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 - {}
* 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 - {}
* 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;
}
if (x == null || y == null) {
return false;
}
x = OpenLayers.Util.toFloat(x);
y = OpenLayers.Util.toFloat(y);
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
* Determine whether the target bounds intersects this bounds. Bounds are
* considered intersecting if any of their edges intersect or if one
* bounds contains the other.
*
* Parameters:
* bounds - {} The target bounds.
* inclusive - {Boolean} Treat coincident borders as intersecting. Default
* is true. If false, bounds that do not overlap but only touch at the
* border will not be considered as intersecting.
*
* Returns:
* {Boolean} The passed-in bounds object intersects this bounds.
*/
intersectsBounds:function(bounds, inclusive) {
if (inclusive == null) {
inclusive = true;
}
var intersects = false;
var mightTouch = (
this.left == bounds.right ||
this.right == bounds.left ||
this.top == bounds.bottom ||
this.bottom == bounds.top
);
// if the two bounds only touch at an edge, and inclusive is false,
// then the bounds don't *really* intersect.
if (inclusive || !mightTouch) {
// otherwise, if one of the boundaries even partially contains another,
// inclusive of the edges, then they do intersect.
var inBottom = (
((bounds.bottom >= this.bottom) && (bounds.bottom <= this.top)) ||
((this.bottom >= bounds.bottom) && (this.bottom <= bounds.top))
);
var inTop = (
((bounds.top >= this.bottom) && (bounds.top <= this.top)) ||
((this.top > bounds.bottom) && (this.top < bounds.top))
);
var inLeft = (
((bounds.left >= this.left) && (bounds.left <= this.right)) ||
((this.left >= bounds.left) && (this.left <= bounds.right))
);
var inRight = (
((bounds.right >= this.left) && (bounds.right <= this.right)) ||
((this.right >= bounds.left) && (this.right <= bounds.right))
);
intersects = ((inBottom || inTop) && (inLeft || inRight));
}
return intersects;
},
/**
* APIMethod: containsBounds
* Determine whether the target bounds is contained within this bounds.
*
* bounds - {} The target bounds.
* partial - {Boolean} If any of the target corners is within this bounds
* consider the bounds contained. Default is false. If false, the
* entire target bounds must be contained within this bounds.
* inclusive - {Boolean} Treat shared edges as contained. Default is
* true.
*
* Returns:
* {Boolean} The passed-in bounds object is contained within this bounds.
*/
containsBounds:function(bounds, partial, inclusive) {
if (partial == null) {
partial = false;
}
if (inclusive == null) {
inclusive = true;
}
var bottomLeft = this.contains(bounds.left, bounds.bottom, inclusive);
var bottomRight = this.contains(bounds.right, bounds.bottom, inclusive);
var topLeft = this.contains(bounds.left, bounds.top, inclusive);
var topRight = this.contains(bounds.right, bounds.top, inclusive);
return (partial) ? (bottomLeft || bottomRight || topLeft || topRight)
: (bottomLeft && bottomRight && topLeft && topRight);
},
/**
* APIMethod: determineQuadrant
*
* Parameters:
* 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 - {} Source projection.
* dest - {} Destination projection.
*
* Returns:
* {} Itself, for use in chaining operations.
*/
transform: function(source, dest) {
// clear cached center location
this.centerLonLat = null;
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 - {}
* options - {Object} Some possible options are:
*
* Allowed Options:
* 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:
* {} 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. (e.g. "5,42,10,45")
* reverseAxisOrder - {Boolean} Does the string use reverse axis order?
*
* Returns:
* {} New bounds object built from the
* passed-in String.
*/
OpenLayers.Bounds.fromString = function(str, reverseAxisOrder) {
var bounds = str.split(",");
return OpenLayers.Bounds.fromArray(bounds, reverseAxisOrder);
};
/**
* APIFunction: fromArray
* Alternative constructor that builds a new OpenLayers.Bounds
* from an array
*
* Parameters:
* bbox - {Array(Float)} Array of bounds values (e.g. [5,42,10,45])
* reverseAxisOrder - {Boolean} Does the array use reverse axis order?
*
* Returns:
* {} New bounds object built from the passed-in Array.
*/
OpenLayers.Bounds.fromArray = function(bbox, reverseAxisOrder) {
return reverseAxisOrder === true ?
new OpenLayers.Bounds(parseFloat(bbox[1]),
parseFloat(bbox[0]),
parseFloat(bbox[3]),
parseFloat(bbox[2])) :
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 - {}
*
* Returns:
* {} 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;
};
/* ======================================================================
OpenLayers/BaseTypes/Element.js
====================================================================== */
/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
* full list of contributors). Published under the Clear BSD license.
* See http://svn.openlayers.org/trunk/openlayers/license.txt for the
* full text of the license. */
/**
* @requires OpenLayers/Util.js
* @requires OpenLayers/BaseTypes.js
*/
/**
* 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, len=arguments.length; i"lon=5,lat=42")
*/
toString:function() {
return ("lon=" + this.lon + ",lat=" + this.lat);
},
/**
* APIMethod: toShortString
*
* Returns:
* {String} Shortened String representation of OpenLayers.LonLat object.
* (e.g. "5, 42")
*/
toShortString:function() {
return (this.lon + ", " + this.lat);
},
/**
* APIMethod: clone
*
* Returns:
* {} 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:
* {} 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 + OpenLayers.Util.toFloat(lon),
this.lat + OpenLayers.Util.toFloat(lat));
},
/**
* APIMethod: equals
*
* Parameters:
* ll - {}
*
* Returns:
* {Boolean} Boolean value indicating whether the passed-in
* 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. This transformation is
* *in place*: if you want a *new* lonlat, use .clone() first.
*
* Parameters:
* source - {} Source projection.
* dest - {} Destination projection.
*
* Returns:
* {} 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 - {}
*
* Returns:
* {} 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 from a
* parameter string
*
* Parameters:
* str - {String} Comma-separated Lon,Lat coordinate string.
* (e.g. "5,40")
*
* Returns:
* {} New object built from the
* passed-in String.
*/
OpenLayers.LonLat.fromString = function(str) {
var pair = str.split(",");
return new OpenLayers.LonLat(pair[0], pair[1]);
};
/**
* Function: fromArray
* Alternative constructor that builds a new from an
* array of two numbers that represent lon- and lat-values.
*
* Parameters:
* arr - {Array(Float)} Array of lon/lat values (e.g. [5,-42])
*
* Returns:
* {} New object built from the
* passed-in array.
*/
OpenLayers.LonLat.fromArray = function(arr) {
var gotArr = OpenLayers.Util.isArray(arr),
lon = gotArr && arr[0],
lat = gotArr && arr[1];
return new OpenLayers.LonLat(lon, lat);
};
/* ======================================================================
OpenLayers/BaseTypes/Pixel.js
====================================================================== */
/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
* full list of contributors). Published under the Clear BSD license.
* See http://svn.openlayers.org/trunk/openlayers/license.txt for the
* full text of the license. */
/**
* @requires OpenLayers/BaseTypes/Class.js
* @requires OpenLayers/Console.js
* @requires OpenLayers/Lang.js
*/
/**
* 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:
* {} 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 - {}
*
* 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: distanceTo
* Returns the distance to the pixel point passed in as a parameter.
*
* Parameters:
* px - {}
*
* Returns:
* {Float} The pixel point passed in as parameter to calculate the
* distance to.
*/
distanceTo:function(px) {
return Math.sqrt(
Math.pow(this.x - px.x, 2) +
Math.pow(this.y - px.y, 2)
);
},
/**
* APIMethod: add
*
* Parameters:
* x - {Integer}
* y - {Integer}
*
* Returns:
* {} 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 - {}
*
* Returns:
* {} 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"
});
/* ======================================================================
OpenLayers/BaseTypes/Size.js
====================================================================== */
/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
* full list of contributors). Published under the Clear BSD license.
* See http://svn.openlayers.org/trunk/openlayers/license.txt for the
* full text of the license. */
/**
* @requires OpenLayers/BaseTypes/Class.js
*/
/**
* 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.
* (e.g. "w=55,h=66")
*/
toString:function() {
return ("w=" + this.w + ",h=" + this.h);
},
/**
* APIMethod: clone
* Create a clone of this size object
*
* Returns:
* {} 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 - {}
*
* 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"
});
/* ======================================================================
OpenLayers/Events.js
====================================================================== */
/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
* full list of contributors). Published under the Clear BSD license.
* See http://svn.openlayers.org/trunk/openlayers/license.txt for the
* full text of the license. */
/**
* @requires OpenLayers/Util.js
*/
/**
* Namespace: OpenLayers.Event
* Utility functions for event handling.
*/
OpenLayers.Event = {
/**
* Property: observers
* {Object} A hashtable cache of the event observers. Keyed by
* element._eventCacheID
*/
observers: false,
/**
* Constant: KEY_BACKSPACE
* {int}
*/
KEY_BACKSPACE: 8,
/**
* Constant: KEY_TAB
* {int}
*/
KEY_TAB: 9,
/**
* Constant: KEY_RETURN
* {int}
*/
KEY_RETURN: 13,
/**
* Constant: KEY_ESC
* {int}
*/
KEY_ESC: 27,
/**
* Constant: KEY_LEFT
* {int}
*/
KEY_LEFT: 37,
/**
* Constant: KEY_UP
* {int}
*/
KEY_UP: 38,
/**
* Constant: KEY_RIGHT
* {int}
*/
KEY_RIGHT: 39,
/**
* Constant: KEY_DOWN
* {int}
*/
KEY_DOWN: 40,
/**
* Constant: KEY_DELETE
* {int}
*/
KEY_DELETE: 46,
/**
* Method: element
* Cross browser event element detection.
*
* Parameters:
* event - {Event}
*
* Returns:
* {DOMElement} The element that caused the event
*/
element: function(event) {
return event.target || event.srcElement;
},
/**
* Method: isSingleTouch
* Determine whether event was caused by a single touch
*
* Parameters:
* event - {Event}
*
* Returns:
* {Boolean}
*/
isSingleTouch: function(event) {
return event.touches && event.touches.length == 1;
},
/**
* Method: isMultiTouch
* Determine whether event was caused by a multi touch
*
* Parameters:
* event - {Event}
*
* Returns:
* {Boolean}
*/
isMultiTouch: function(event) {
return event.touches && event.touches.length > 1;
},
/**
* Method: isLeftClick
* Determine whether event was caused by a left click.
*
* Parameters:
* event - {Event}
*
* Returns:
* {Boolean}
*/
isLeftClick: function(event) {
return (((event.which) && (event.which == 1)) ||
((event.button) && (event.button == 1)));
},
/**
* Method: isRightClick
* Determine whether event was caused by a right mouse click.
*
* Parameters:
* event - {Event}
*
* Returns:
* {Boolean}
*/
isRightClick: function(event) {
return (((event.which) && (event.which == 3)) ||
((event.button) && (event.button == 2)));
},
/**
* Method: stop
* Stops an event from propagating.
*
* Parameters:
* event - {Event}
* allowDefault - {Boolean} If true, we stop the event chain but
* still allow the default browser
* behaviour (text selection, radio-button
* clicking, etc)
* Default false
*/
stop: function(event, allowDefault) {
if (!allowDefault) {
if (event.preventDefault) {
event.preventDefault();
} else {
event.returnValue = false;
}
}
if (event.stopPropagation) {
event.stopPropagation();
} else {
event.cancelBubble = true;
}
},
/**
* Method: findElement
*
* Parameters:
* event - {Event}
* tagName - {String}
*
* Returns:
* {DOMElement} The first node with the given tagName, starting from the
* node the event was triggered on and traversing the DOM upwards
*/
findElement: function(event, tagName) {
var element = OpenLayers.Event.element(event);
while (element.parentNode && (!element.tagName ||
(element.tagName.toUpperCase() != tagName.toUpperCase()))){
element = element.parentNode;
}
return element;
},
/**
* Method: observe
*
* Parameters:
* elementParam - {DOMElement || String}
* name - {String}
* observer - {function}
* useCapture - {Boolean}
*/
observe: function(elementParam, name, observer, useCapture) {
var element = OpenLayers.Util.getElement(elementParam);
useCapture = useCapture || false;
if (name == 'keypress' &&
(navigator.appVersion.match(/Konqueror|Safari|KHTML/)
|| element.attachEvent)) {
name = 'keydown';
}
//if observers cache has not yet been created, create it
if (!this.observers) {
this.observers = {};
}
//if not already assigned, make a new unique cache ID
if (!element._eventCacheID) {
var idPrefix = "eventCacheID_";
if (element.id) {
idPrefix = element.id + "_" + idPrefix;
}
element._eventCacheID = OpenLayers.Util.createUniqueID(idPrefix);
}
var cacheID = element._eventCacheID;
//if there is not yet a hash entry for this element, add one
if (!this.observers[cacheID]) {
this.observers[cacheID] = [];
}
//add a new observer to this element's list
this.observers[cacheID].push({
'element': element,
'name': name,
'observer': observer,
'useCapture': useCapture
});
//add the actual browser event listener
if (element.addEventListener) {
element.addEventListener(name, observer, useCapture);
} else if (element.attachEvent) {
element.attachEvent('on' + name, observer);
}
},
/**
* Method: stopObservingElement
* Given the id of an element to stop observing, cycle through the
* element's cached observers, calling stopObserving on each one,
* skipping those entries which can no longer be removed.
*
* parameters:
* elementParam - {DOMElement || String}
*/
stopObservingElement: function(elementParam) {
var element = OpenLayers.Util.getElement(elementParam);
var cacheID = element._eventCacheID;
this._removeElementObservers(OpenLayers.Event.observers[cacheID]);
},
/**
* Method: _removeElementObservers
*
* Parameters:
* elementObservers - {Array(Object)} Array of (element, name,
* observer, usecapture) objects,
* taken directly from hashtable
*/
_removeElementObservers: function(elementObservers) {
if (elementObservers) {
for(var i = elementObservers.length-1; i >= 0; i--) {
var entry = elementObservers[i];
var args = new Array(entry.element,
entry.name,
entry.observer,
entry.useCapture);
var removed = OpenLayers.Event.stopObserving.apply(this, args);
}
}
},
/**
* Method: stopObserving
*
* Parameters:
* elementParam - {DOMElement || String}
* name - {String}
* observer - {function}
* useCapture - {Boolean}
*
* Returns:
* {Boolean} Whether or not the event observer was removed
*/
stopObserving: function(elementParam, name, observer, useCapture) {
useCapture = useCapture || false;
var element = OpenLayers.Util.getElement(elementParam);
var cacheID = element._eventCacheID;
if (name == 'keypress') {
if ( navigator.appVersion.match(/Konqueror|Safari|KHTML/) ||
element.detachEvent) {
name = 'keydown';
}
}
// find element's entry in this.observers cache and remove it
var foundEntry = false;
var elementObservers = OpenLayers.Event.observers[cacheID];
if (elementObservers) {
// find the specific event type in the element's list
var i=0;
while(!foundEntry && i < elementObservers.length) {
var cacheEntry = elementObservers[i];
if ((cacheEntry.name == name) &&
(cacheEntry.observer == observer) &&
(cacheEntry.useCapture == useCapture)) {
elementObservers.splice(i, 1);
if (elementObservers.length == 0) {
delete OpenLayers.Event.observers[cacheID];
}
foundEntry = true;
break;
}
i++;
}
}
//actually remove the event listener from browser
if (foundEntry) {
if (element.removeEventListener) {
element.removeEventListener(name, observer, useCapture);
} else if (element && element.detachEvent) {
element.detachEvent('on' + name, observer);
}
}
return foundEntry;
},
/**
* Method: unloadCache
* Cycle through all the element entries in the events cache and call
* stopObservingElement on each.
*/
unloadCache: function() {
// check for OpenLayers.Event before checking for observers, because
// OpenLayers.Event may be undefined in IE if no map instance was
// created
if (OpenLayers.Event && OpenLayers.Event.observers) {
for (var cacheID in OpenLayers.Event.observers) {
var elementObservers = OpenLayers.Event.observers[cacheID];
OpenLayers.Event._removeElementObservers.apply(this,
[elementObservers]);
}
OpenLayers.Event.observers = false;
}
},
CLASS_NAME: "OpenLayers.Event"
};
/* prevent memory leaks in IE */
OpenLayers.Event.observe(window, 'unload', OpenLayers.Event.unloadCache, false);
/**
* Class: OpenLayers.Events
*/
OpenLayers.Events = OpenLayers.Class({
/**
* Constant: BROWSER_EVENTS
* {Array(String)} supported events
*/
BROWSER_EVENTS: [
"mouseover", "mouseout",
"mousedown", "mouseup", "mousemove",
"click", "dblclick", "rightclick", "dblrightclick",
"resize", "focus", "blur",
"touchstart", "touchmove", "touchend"
],
/**
* Property: listeners
* {Object} Hashtable of Array(Function): events listener functions
*/
listeners: null,
/**
* Property: object
* {Object} the code object issuing application events
*/
object: null,
/**
* Property: element
* {DOMElement} the DOM element receiving browser events
*/
element: null,
/**
* Property: eventTypes
* {Array(String)} list of support application events
*/
eventTypes: null,
/**
* Property: eventHandler
* {Function} bound event handler attached to elements
*/
eventHandler: null,
/**
* APIProperty: fallThrough
* {Boolean}
*/
fallThrough: null,
/**
* APIProperty: includeXY
* {Boolean} Should the .xy property automatically be created for browser
* mouse events? In general, this should be false. If it is true, then
* mouse events will automatically generate a '.xy' property on the
* event object that is passed. (Prior to OpenLayers 2.7, this was true
* by default.) Otherwise, you can call the getMousePosition on the
* relevant events handler on the object available via the 'evt.object'
* property of the evt object. So, for most events, you can call:
* function named(evt) {
* this.xy = this.object.events.getMousePosition(evt)
* }
*
* This option typically defaults to false for performance reasons:
* when creating an events object whose primary purpose is to manage
* relatively positioned mouse events within a div, it may make
* sense to set it to true.
*
* This option is also used to control whether the events object caches
* offsets. If this is false, it will not: the reason for this is that
* it is only expected to be called many times if the includeXY property
* is set to true. If you set this to true, you are expected to clear
* the offset cache manually (using this.clearMouseCache()) if:
* the border of the element changes
* the location of the element in the page changes
*/
includeXY: false,
/**
* Method: clearMouseListener
* A version of that is bound to this instance so that
* it can be used with and
* .
*/
clearMouseListener: null,
/**
* Constructor: OpenLayers.Events
* Construct an OpenLayers.Events object.
*
* Parameters:
* object - {Object} The js object to which this Events object is being added
* element - {DOMElement} A dom element to respond to browser events
* eventTypes - {Array(String)} Array of custom application events
* fallThrough - {Boolean} Allow events to fall through after these have
* been handled?
* options - {Object} Options for the events object.
*/
initialize: function (object, element, eventTypes, fallThrough, options) {
OpenLayers.Util.extend(this, options);
this.object = object;
this.fallThrough = fallThrough;
this.listeners = {};
// keep a bound copy of handleBrowserEvent() so that we can
// pass the same function to both Event.observe() and .stopObserving()
this.eventHandler = OpenLayers.Function.bindAsEventListener(
this.handleBrowserEvent, this
);
// to be used with observe and stopObserving
this.clearMouseListener = OpenLayers.Function.bind(
this.clearMouseCache, this
);
// if eventTypes is specified, create a listeners list for each
// custom application event.
this.eventTypes = [];
if (eventTypes != null) {
for (var i=0, len=eventTypes.length; i as shown in the examples
* below.
*
* Example use:
* (code)
* // register a single listener for the "loadstart" event
* events.on({"loadstart": loadStartListener});
*
* // this is equivalent to the following
* events.register("loadstart", undefined, loadStartListener);
*
* // register multiple listeners to be called with the same `this` object
* events.on({
* "loadstart": loadStartListener,
* "loadend": loadEndListener,
* scope: object
* });
*
* // this is equivalent to the following
* events.register("loadstart", object, loadStartListener);
* events.register("loadend", object, loadEndListener);
* (end)
*
* Parameters:
* object - {Object}
*/
on: function(object) {
for(var type in object) {
if(type != "scope") {
this.register(type, object.scope, object[type]);
}
}
},
/**
* APIMethod: register
* Register an event on the events object.
*
* When the event is triggered, the 'func' function will be called, in the
* context of 'obj'. Imagine we were to register an event, specifying an
* OpenLayers.Bounds Object as 'obj'. When the event is triggered, the
* context in the callback function will be our Bounds object. This means
* that within our callback function, we can access the properties and
* methods of the Bounds object through the "this" variable. So our
* callback could execute something like:
* : leftStr = "Left: " + this.left;
*
* or
*
* : centerStr = "Center: " + this.getCenterLonLat();
*
* Parameters:
* type - {String} Name of the event to register
* obj - {Object} The object to bind the context to for the callback#.
* If no object is specified, default is the Events's
* 'object' property.
* func - {Function} The callback function. If no callback is
* specified, this function does nothing.
*
*
*/
register: function (type, obj, func) {
if ( (func != null) &&
(OpenLayers.Util.indexOf(this.eventTypes, type) != -1) ) {
if (obj == null) {
obj = this.object;
}
var listeners = this.listeners[type];
listeners.push( {obj: obj, func: func} );
}
},
/**
* APIMethod: registerPriority
* Same as register() but adds the new listener to the *front* of the
* events queue instead of to the end.
*
* TODO: get rid of this in 3.0 - Decide whether listeners should be
* called in the order they were registered or in reverse order.
*
*
* Parameters:
* type - {String} Name of the event to register
* obj - {Object} The object to bind the context to for the callback#.
* If no object is specified, default is the Events's
* 'object' property.
* func - {Function} The callback function. If no callback is
* specified, this function does nothing.
*/
registerPriority: function (type, obj, func) {
if (func != null) {
if (obj == null) {
obj = this.object;
}
var listeners = this.listeners[type];
if (listeners != null) {
listeners.unshift( {obj: obj, func: func} );
}
}
},
/**
* APIMethod: un
* Convenience method for unregistering listeners with a common scope.
* Internally, this method calls as shown in the examples
* below.
*
* Example use:
* (code)
* // unregister a single listener for the "loadstart" event
* events.un({"loadstart": loadStartListener});
*
* // this is equivalent to the following
* events.unregister("loadstart", undefined, loadStartListener);
*
* // unregister multiple listeners with the same `this` object
* events.un({
* "loadstart": loadStartListener,
* "loadend": loadEndListener,
* scope: object
* });
*
* // this is equivalent to the following
* events.unregister("loadstart", object, loadStartListener);
* events.unregister("loadend", object, loadEndListener);
* (end)
*/
un: function(object) {
for(var type in object) {
if(type != "scope") {
this.unregister(type, object.scope, object[type]);
}
}
},
/**
* APIMethod: unregister
*
* Parameters:
* type - {String}
* obj - {Object} If none specified, defaults to this.object
* func - {Function}
*/
unregister: function (type, obj, func) {
if (obj == null) {
obj = this.object;
}
var listeners = this.listeners[type];
if (listeners != null) {
for (var i=0, len=listeners.length; i} The current xy coordinate of the mouse, adjusted
* for offsets
*/
getMousePosition: function (evt) {
if (!this.includeXY) {
this.clearMouseCache();
} else if (!this.element.hasScrollEvent) {
OpenLayers.Event.observe(window, "scroll", this.clearMouseListener);
this.element.hasScrollEvent = true;
}
if (!this.element.scrolls) {
var viewportElement = OpenLayers.Util.getViewportElement();
this.element.scrolls = [
viewportElement.scrollLeft,
viewportElement.scrollTop
];
}
if (!this.element.lefttop) {
this.element.lefttop = [
(document.documentElement.clientLeft || 0),
(document.documentElement.clientTop || 0)
];
}
if (!this.element.offsets) {
this.element.offsets = OpenLayers.Util.pagePosition(this.element);
}
return new OpenLayers.Pixel(
(evt.clientX + this.element.scrolls[0]) - this.element.offsets[0]
- this.element.lefttop[0],
(evt.clientY + this.element.scrolls[1]) - this.element.offsets[1]
- this.element.lefttop[1]
);
},
CLASS_NAME: "OpenLayers.Events"
});
/* ======================================================================
OpenLayers/Control/OverviewMap.js
====================================================================== */
/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
* full list of contributors). Published under the Clear BSD license.
* See http://svn.openlayers.org/trunk/openlayers/license.txt for the
* full text of the license. */
/**
* @requires OpenLayers/Control.js
* @requires OpenLayers/BaseTypes.js
* @requires OpenLayers/Events.js
*/
/**
* Class: OpenLayers.Control.OverviewMap
* The OverMap control creates a small overview map, useful to display the
* extent of a zoomed map and your main map and provide additional
* navigation options to the User. By default the overview map is drawn in
* the lower right corner of the main map. Create a new overview map with the
* constructor.
*
* Inerits from:
* -
*/
OpenLayers.Control.OverviewMap = OpenLayers.Class(OpenLayers.Control, {
/**
* Property: element
* {DOMElement} The DOM element that contains the overview map
*/
element: null,
/**
* APIProperty: ovmap
* {} A reference to the overview map itself.
*/
ovmap: null,
/**
* APIProperty: size
* {} The overvew map size in pixels. Note that this is
* the size of the map itself - the element that contains the map (default
* class name olControlOverviewMapElement) may have padding or other style
* attributes added via CSS.
*/
size: new OpenLayers.Size(180, 90),
/**
* APIProperty: layers
* {Array()} Ordered list of layers in the overview map.
* If none are sent at construction, the base layer for the main map is used.
*/
layers: null,
/**
* APIProperty: minRectSize
* {Integer} The minimum width or height (in pixels) of the extent
* rectangle on the overview map. When the extent rectangle reaches
* this size, it will be replaced depending on the value of the
* property. Default is 15 pixels.
*/
minRectSize: 15,
/**
* APIProperty: minRectDisplayClass
* {String} Replacement style class name for the extent rectangle when
* is reached. This string will be suffixed on to the
* displayClass. Default is "RectReplacement".
*
* Example CSS declaration:
* (code)
* .olControlOverviewMapRectReplacement {
* overflow: hidden;
* cursor: move;
* background-image: url("img/overview_replacement.gif");
* background-repeat: no-repeat;
* background-position: center;
* }
* (end)
*/
minRectDisplayClass: "RectReplacement",
/**
* APIProperty: minRatio
* {Float} The ratio of the overview map resolution to the main map
* resolution at which to zoom farther out on the overview map.
*/
minRatio: 8,
/**
* APIProperty: maxRatio
* {Float} The ratio of the overview map resolution to the main map
* resolution at which to zoom farther in on the overview map.
*/
maxRatio: 32,
/**
* APIProperty: mapOptions
* {Object} An object containing any non-default properties to be sent to
* the overview map's map constructor. These should include any
* non-default options that the main map was constructed with.
*/
mapOptions: null,
/**
* APIProperty: autoPan
* {Boolean} Always pan the overview map, so the extent marker remains in
* the center. Default is false. If true, when you drag the extent
* marker, the overview map will update itself so the marker returns
* to the center.
*/
autoPan: false,
/**
* Property: handlers
* {Object}
*/
handlers: null,
/**
* Property: resolutionFactor
* {Object}
*/
resolutionFactor: 1,
/**
* APIProperty: maximized
* {Boolean} Start as maximized (visible). Defaults to false.
*/
maximized: false,
/**
* Constructor: OpenLayers.Control.OverviewMap
* Create a new overview map
*
* Parameters:
* object - {Object} Properties of this object will be set on the overview
* map object. Note, to set options on the map object contained in this
* control, set as one of the options properties.
*/
initialize: function(options) {
this.layers = [];
this.handlers = {};
OpenLayers.Control.prototype.initialize.apply(this, [options]);
},
/**
* APIMethod: destroy
* Deconstruct the control
*/
destroy: function() {
if (!this.mapDiv) { // we've already been destroyed
return;
}
if (this.handlers.click) {
this.handlers.click.destroy();
}
if (this.handlers.drag) {
this.handlers.drag.destroy();
}
this.ovmap && this.ovmap.eventsDiv.removeChild(this.extentRectangle);
this.extentRectangle = null;
if (this.rectEvents) {
this.rectEvents.destroy();
this.rectEvents = null;
}
if (this.ovmap) {
this.ovmap.destroy();
this.ovmap = null;
}
this.element.removeChild(this.mapDiv);
this.mapDiv = null;
this.div.removeChild(this.element);
this.element = null;
if (this.maximizeDiv) {
OpenLayers.Event.stopObservingElement(this.maximizeDiv);
this.div.removeChild(this.maximizeDiv);
this.maximizeDiv = null;
}
if (this.minimizeDiv) {
OpenLayers.Event.stopObservingElement(this.minimizeDiv);
this.div.removeChild(this.minimizeDiv);
this.minimizeDiv = null;
}
this.map.events.un({
"moveend": this.update,
"changebaselayer": this.baseLayerDraw,
scope: this
});
OpenLayers.Control.prototype.destroy.apply(this, arguments);
},
/**
* Method: draw
* Render the control in the browser.
*/
draw: function() {
OpenLayers.Control.prototype.draw.apply(this, arguments);
if(!(this.layers.length > 0)) {
if (this.map.baseLayer) {
var layer = this.map.baseLayer.clone();
this.layers = [layer];
} else {
this.map.events.register("changebaselayer", this, this.baseLayerDraw);
return this.div;
}
}
// create overview map DOM elements
this.element = document.createElement('div');
this.element.className = this.displayClass + 'Element';
this.element.style.display = 'none';
this.mapDiv = document.createElement('div');
this.mapDiv.style.width = this.size.w + 'px';
this.mapDiv.style.height = this.size.h + 'px';
this.mapDiv.style.position = 'relative';
this.mapDiv.style.overflow = 'hidden';
this.mapDiv.id = OpenLayers.Util.createUniqueID('overviewMap');
this.extentRectangle = document.createElement('div');
this.extentRectangle.style.position = 'absolute';
this.extentRectangle.style.zIndex = 1000; //HACK
this.extentRectangle.className = this.displayClass+'ExtentRectangle';
this.element.appendChild(this.mapDiv);
this.div.appendChild(this.element);
// Optionally add min/max buttons if the control will go in the
// map viewport.
if(!this.outsideViewport) {
this.div.className += " " + this.displayClass + 'Container';
var imgLocation = OpenLayers.Util.getImagesLocation();
// maximize button div
var img = imgLocation + 'layer-switcher-maximize.png';
this.maximizeDiv = OpenLayers.Util.createAlphaImageDiv(
this.displayClass + 'MaximizeButton',
null,
new OpenLayers.Size(18,18),
img,
'absolute');
this.maximizeDiv.style.display = 'none';
this.maximizeDiv.className = this.displayClass + 'MaximizeButton';
OpenLayers.Event.observe(this.maximizeDiv, 'click',
OpenLayers.Function.bindAsEventListener(this.maximizeControl,
this)
);
this.div.appendChild(this.maximizeDiv);
// minimize button div
var img = imgLocation + 'layer-switcher-minimize.png';
this.minimizeDiv = OpenLayers.Util.createAlphaImageDiv(
'OpenLayers_Control_minimizeDiv',
null,
new OpenLayers.Size(18,18),
img,
'absolute');
this.minimizeDiv.style.display = 'none';
this.minimizeDiv.className = this.displayClass + 'MinimizeButton';
OpenLayers.Event.observe(this.minimizeDiv, 'click',
OpenLayers.Function.bindAsEventListener(this.minimizeControl,
this)
);
this.div.appendChild(this.minimizeDiv);
var eventsToStop = ['dblclick','mousedown'];
for (var i=0, len=eventsToStop.length; i} The pixel location of the drag.
*/
rectDrag: function(px) {
var deltaX = this.handlers.drag.last.x - px.x;
var deltaY = this.handlers.drag.last.y - px.y;
if(deltaX != 0 || deltaY != 0) {
var rectTop = this.rectPxBounds.top;
var rectLeft = this.rectPxBounds.left;
var rectHeight = Math.abs(this.rectPxBounds.getHeight());
var rectWidth = this.rectPxBounds.getWidth();
// don't allow dragging off of parent element
var newTop = Math.max(0, (rectTop - deltaY));
newTop = Math.min(newTop,
this.ovmap.size.h - this.hComp - rectHeight);
var newLeft = Math.max(0, (rectLeft - deltaX));
newLeft = Math.min(newLeft,
this.ovmap.size.w - this.wComp - rectWidth);
this.setRectPxBounds(new OpenLayers.Bounds(newLeft,
newTop + rectHeight,
newLeft + rectWidth,
newTop));
}
},
/**
* Method: mapDivClick
* Handle browser events
*
* Parameters:
* evt - {} evt
*/
mapDivClick: function(evt) {
var pxCenter = this.rectPxBounds.getCenterPixel();
var deltaX = evt.xy.x - pxCenter.x;
var deltaY = evt.xy.y - pxCenter.y;
var top = this.rectPxBounds.top;
var left = this.rectPxBounds.left;
var height = Math.abs(this.rectPxBounds.getHeight());
var width = this.rectPxBounds.getWidth();
var newTop = Math.max(0, (top + deltaY));
newTop = Math.min(newTop, this.ovmap.size.h - height);
var newLeft = Math.max(0, (left + deltaX));
newLeft = Math.min(newLeft, this.ovmap.size.w - width);
this.setRectPxBounds(new OpenLayers.Bounds(newLeft,
newTop + height,
newLeft + width,
newTop));
this.updateMapToRect();
},
/**
* Method: maximizeControl
* Unhide the control. Called when the control is in the map viewport.
*
* Parameters:
* e - {}
*/
maximizeControl: function(e) {
this.element.style.display = '';
this.showToggle(false);
if (e != null) {
OpenLayers.Event.stop(e);
}
},
/**
* Method: minimizeControl
* Hide all the contents of the control, shrink the size,
* add the maximize icon
*
* Parameters:
* e - {}
*/
minimizeControl: function(e) {
this.element.style.display = 'none';
this.showToggle(true);
if (e != null) {
OpenLayers.Event.stop(e);
}
},
/**
* Method: showToggle
* Hide/Show the toggle depending on whether the control is minimized
*
* Parameters:
* minimize - {Boolean}
*/
showToggle: function(minimize) {
this.maximizeDiv.style.display = minimize ? '' : 'none';
this.minimizeDiv.style.display = minimize ? 'none' : '';
},
/**
* Method: update
* Update the overview map after layers move.
*/
update: function() {
if(this.ovmap == null) {
this.createMap();
}
if(this.autoPan || !this.isSuitableOverview()) {
this.updateOverview();
}
// update extent rectangle
this.updateRectToMap();
},
/**
* Method: isSuitableOverview
* Determines if the overview map is suitable given the extent and
* resolution of the main map.
*/
isSuitableOverview: function() {
var mapExtent = this.map.getExtent();
var maxExtent = this.map.maxExtent;
var testExtent = new OpenLayers.Bounds(
Math.max(mapExtent.left, maxExtent.left),
Math.max(mapExtent.bottom, maxExtent.bottom),
Math.min(mapExtent.right, maxExtent.right),
Math.min(mapExtent.top, maxExtent.top));
if (this.ovmap.getProjection() != this.map.getProjection()) {
testExtent = testExtent.transform(
this.map.getProjectionObject(),
this.ovmap.getProjectionObject() );
}
var resRatio = this.ovmap.getResolution() / this.map.getResolution();
return ((resRatio > this.minRatio) &&
(resRatio <= this.maxRatio) &&
(this.ovmap.getExtent().containsBounds(testExtent)));
},
/**
* Method updateOverview
* Called by if returns true
*/
updateOverview: function() {
var mapRes = this.map.getResolution();
var targetRes = this.ovmap.getResolution();
var resRatio = targetRes / mapRes;
if(resRatio > this.maxRatio) {
// zoom in overview map
targetRes = this.minRatio * mapRes;
} else if(resRatio <= this.minRatio) {
// zoom out overview map
targetRes = this.maxRatio * mapRes;
}
var center;
if (this.ovmap.getProjection() != this.map.getProjection()) {
center = this.map.center.clone();
center.transform(this.map.getProjectionObject(),
this.ovmap.getProjectionObject() );
} else {
center = this.map.center;
}
this.ovmap.setCenter(center, this.ovmap.getZoomForResolution(
targetRes * this.resolutionFactor));
this.updateRectToMap();
},
/**
* Method: createMap
* Construct the map that this control contains
*/
createMap: function() {
// create the overview map
var options = OpenLayers.Util.extend(
{controls: [], maxResolution: 'auto',
fallThrough: false}, this.mapOptions);
this.ovmap = new OpenLayers.Map(this.mapDiv, options);
this.ovmap.eventsDiv.appendChild(this.extentRectangle);
// prevent ovmap from being destroyed when the page unloads, because
// the OverviewMap control has to do this (and does it).
OpenLayers.Event.stopObserving(window, 'unload', this.ovmap.unloadDestroy);
this.ovmap.addLayers(this.layers);
this.ovmap.zoomToMaxExtent();
// check extent rectangle border width
this.wComp = parseInt(OpenLayers.Element.getStyle(this.extentRectangle,
'border-left-width')) +
parseInt(OpenLayers.Element.getStyle(this.extentRectangle,
'border-right-width'));
this.wComp = (this.wComp) ? this.wComp : 2;
this.hComp = parseInt(OpenLayers.Element.getStyle(this.extentRectangle,
'border-top-width')) +
parseInt(OpenLayers.Element.getStyle(this.extentRectangle,
'border-bottom-width'));
this.hComp = (this.hComp) ? this.hComp : 2;
this.handlers.drag = new OpenLayers.Handler.Drag(
this, {move: this.rectDrag, done: this.updateMapToRect},
{map: this.ovmap}
);
this.handlers.click = new OpenLayers.Handler.Click(
this, {
"click": this.mapDivClick
},{
"single": true, "double": false,
"stopSingle": true, "stopDouble": true,
"pixelTolerance": 1,
map: this.ovmap
}
);
this.handlers.click.activate();
this.rectEvents = new OpenLayers.Events(this, this.extentRectangle,
null, true);
this.rectEvents.register("mouseover", this, function(e) {
if(!this.handlers.drag.active && !this.map.dragging) {
this.handlers.drag.activate();
}
});
this.rectEvents.register("mouseout", this, function(e) {
if(!this.handlers.drag.dragging) {
this.handlers.drag.deactivate();
}
});
if (this.ovmap.getProjection() != this.map.getProjection()) {
var sourceUnits = this.map.getProjectionObject().getUnits() ||
this.map.units || this.map.baseLayer.units;
var targetUnits = this.ovmap.getProjectionObject().getUnits() ||
this.ovmap.units || this.ovmap.baseLayer.units;
this.resolutionFactor = sourceUnits && targetUnits ?
OpenLayers.INCHES_PER_UNIT[sourceUnits] /
OpenLayers.INCHES_PER_UNIT[targetUnits] : 1;
}
},
/**
* Method: updateRectToMap
* Updates the extent rectangle position and size to match the map extent
*/
updateRectToMap: function() {
// If the projections differ we need to reproject
var bounds;
if (this.ovmap.getProjection() != this.map.getProjection()) {
bounds = this.map.getExtent().transform(
this.map.getProjectionObject(),
this.ovmap.getProjectionObject() );
} else {
bounds = this.map.getExtent();
}
var pxBounds = this.getRectBoundsFromMapBounds(bounds);
if (pxBounds) {
this.setRectPxBounds(pxBounds);
}
},
/**
* Method: updateMapToRect
* Updates the map extent to match the extent rectangle position and size
*/
updateMapToRect: function() {
var lonLatBounds = this.getMapBoundsFromRectBounds(this.rectPxBounds);
if (this.ovmap.getProjection() != this.map.getProjection()) {
lonLatBounds = lonLatBounds.transform(
this.ovmap.getProjectionObject(),
this.map.getProjectionObject() );
}
this.map.panTo(lonLatBounds.getCenterLonLat());
},
/**
* Method: setRectPxBounds
* Set extent rectangle pixel bounds.
*
* Parameters:
* pxBounds - {}
*/
setRectPxBounds: function(pxBounds) {
var top = Math.max(pxBounds.top, 0);
var left = Math.max(pxBounds.left, 0);
var bottom = Math.min(pxBounds.top + Math.abs(pxBounds.getHeight()),
this.ovmap.size.h - this.hComp);
var right = Math.min(pxBounds.left + pxBounds.getWidth(),
this.ovmap.size.w - this.wComp);
var width = Math.max(right - left, 0);
var height = Math.max(bottom - top, 0);
if(width < this.minRectSize || height < this.minRectSize) {
this.extentRectangle.className = this.displayClass +
this.minRectDisplayClass;
var rLeft = left + (width / 2) - (this.minRectSize / 2);
var rTop = top + (height / 2) - (this.minRectSize / 2);
this.extentRectangle.style.top = Math.round(rTop) + 'px';
this.extentRectangle.style.left = Math.round(rLeft) + 'px';
this.extentRectangle.style.height = this.minRectSize + 'px';
this.extentRectangle.style.width = this.minRectSize + 'px';
} else {
this.extentRectangle.className = this.displayClass +
'ExtentRectangle';
this.extentRectangle.style.top = Math.round(top) + 'px';
this.extentRectangle.style.left = Math.round(left) + 'px';
this.extentRectangle.style.height = Math.round(height) + 'px';
this.extentRectangle.style.width = Math.round(width) + 'px';
}
this.rectPxBounds = new OpenLayers.Bounds(
Math.round(left), Math.round(bottom),
Math.round(right), Math.round(top)
);
},
/**
* Method: getRectBoundsFromMapBounds
* Get the rect bounds from the map bounds.
*
* Parameters:
* lonLatBounds - {}
*
* Returns:
* {}A bounds which is the passed-in map lon/lat extent
* translated into pixel bounds for the overview map
*/
getRectBoundsFromMapBounds: function(lonLatBounds) {
var leftBottomLonLat = new OpenLayers.LonLat(lonLatBounds.left,
lonLatBounds.bottom);
var rightTopLonLat = new OpenLayers.LonLat(lonLatBounds.right,
lonLatBounds.top);
var leftBottomPx = this.getOverviewPxFromLonLat(leftBottomLonLat);
var rightTopPx = this.getOverviewPxFromLonLat(rightTopLonLat);
var bounds = null;
if (leftBottomPx && rightTopPx) {
bounds = new OpenLayers.Bounds(leftBottomPx.x, leftBottomPx.y,
rightTopPx.x, rightTopPx.y);
}
return bounds;
},
/**
* Method: getMapBoundsFromRectBounds
* Get the map bounds from the rect bounds.
*
* Parameters:
* pxBounds - {}
*
* Returns:
* {} Bounds which is the passed-in overview rect bounds
* translated into lon/lat bounds for the overview map
*/
getMapBoundsFromRectBounds: function(pxBounds) {
var leftBottomPx = new OpenLayers.Pixel(pxBounds.left,
pxBounds.bottom);
var rightTopPx = new OpenLayers.Pixel(pxBounds.right,
pxBounds.top);
var leftBottomLonLat = this.getLonLatFromOverviewPx(leftBottomPx);
var rightTopLonLat = this.getLonLatFromOverviewPx(rightTopPx);
return new OpenLayers.Bounds(leftBottomLonLat.lon, leftBottomLonLat.lat,
rightTopLonLat.lon, rightTopLonLat.lat);
},
/**
* Method: getLonLatFromOverviewPx
* Get a map location from a pixel location
*
* Parameters:
* overviewMapPx - {}
*
* Returns:
* {} Location which is the passed-in overview map
* OpenLayers.Pixel, translated into lon/lat by the overview map
*/
getLonLatFromOverviewPx: function(overviewMapPx) {
var size = this.ovmap.size;
var res = this.ovmap.getResolution();
var center = this.ovmap.getExtent().getCenterLonLat();
var delta_x = overviewMapPx.x - (size.w / 2);
var delta_y = overviewMapPx.y - (size.h / 2);
return new OpenLayers.LonLat(center.lon + delta_x * res ,
center.lat - delta_y * res);
},
/**
* Method: getOverviewPxFromLonLat
* Get a pixel location from a map location
*
* Parameters:
* lonlat - {}
*
* Returns:
* {} Location which is the passed-in OpenLayers.LonLat,
* translated into overview map pixels
*/
getOverviewPxFromLonLat: function(lonlat) {
var res = this.ovmap.getResolution();
var extent = this.ovmap.getExtent();
var px = null;
if (extent) {
px = new OpenLayers.Pixel(
Math.round(1/res * (lonlat.lon - extent.left)),
Math.round(1/res * (extent.top - lonlat.lat)));
}
return px;
},
CLASS_NAME: 'OpenLayers.Control.OverviewMap'
});
/* ======================================================================
OpenLayers/Control/Panel.js
====================================================================== */
/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
* full list of contributors). Published under the Clear BSD license.
* See http://svn.openlayers.org/trunk/openlayers/license.txt for the
* full text of the license. */
/**
* @requires OpenLayers/Control.js
*/
/**
* Class: OpenLayers.Control.Panel
* The Panel control is a container for other controls. With it toolbars
* may be composed.
*
* Inherits from:
* -
*/
OpenLayers.Control.Panel = OpenLayers.Class(OpenLayers.Control, {
/**
* Property: controls
* {Array()}
*/
controls: null,
/**
* APIProperty: autoActivate
* {Boolean} Activate the control when it is added to a map. Default is
* true.
*/
autoActivate: true,
/**
* APIProperty: defaultControl
* {} The control which is activated when the control is
* activated (turned on), which also happens at instantiation.
* If is true, will be nullified after the
* first activation of the panel.
*/
defaultControl: null,
/**
* APIProperty: saveState
* {Boolean} If set to true, the active state of this panel's controls will
* be stored on panel deactivation, and restored on reactivation. Default
* is false.
*/
saveState: false,
/**
* APIProperty: allowDepress
* {Boolean} If is true the controls can
* be deactivated by clicking the icon that represents them. Default
* is false.
*/
allowDepress: false,
/**
* Property: activeState
* {Object} stores the active state of this panel's controls.
*/
activeState: null,
/**
* Constructor: OpenLayers.Control.Panel
* Create a new control panel.
*
* Each control in the panel is represented by an icon. When clicking
* on an icon, the method is called.
*
* Specific properties for controls on a panel:
* type - {Number} One of ,
* , .
* If not provided, is assumed.
* title - {string} Text displayed when mouse is over the icon that
* represents the control.
*
* The of a control determines the behavior when
* clicking its icon:
* - The control is activated and other
* controls of this type in the same panel are deactivated. This is
* the default type.
* - The active state of the control is
* toggled.
* - The
* method of the control is called,
* but its active state is not changed.
*
* If a control is , it will be drawn with the
* olControl[Name]ItemActive class, otherwise with the
* olControl[Name]ItemInactive class.
*
* Parameters:
* options - {Object} An optional object whose properties will be used
* to extend the control.
*/
initialize: function(options) {
OpenLayers.Control.prototype.initialize.apply(this, [options]);
this.controls = [];
this.activeState = {};
},
/**
* APIMethod: destroy
*/
destroy: function() {
OpenLayers.Control.prototype.destroy.apply(this, arguments);
for (var ctl, i = this.controls.length - 1; i >= 0; i--) {
ctl = this.controls[i];
if (ctl.events) {
ctl.events.un({
activate: this.iconOn,
deactivate: this.iconOff
});
}
OpenLayers.Event.stopObservingElement(ctl.panel_div);
ctl.panel_div = null;
}
this.activeState = null;
},
/**
* APIMethod: activate
*/
activate: function() {
if (OpenLayers.Control.prototype.activate.apply(this, arguments)) {
var control;
for (var i=0, len=this.controls.length; i=0; i--) {
this.div.removeChild(this.div.childNodes[i]);
}
this.div.innerHTML = "";
if (this.active) {
for (var i=0, len=this.controls.length; i}
*/
activateControl: function (control) {
if (!this.active) { return false; }
if (control.type == OpenLayers.Control.TYPE_BUTTON) {
control.trigger();
return;
}
if (control.type == OpenLayers.Control.TYPE_TOGGLE) {
if (control.active) {
control.deactivate();
} else {
control.activate();
}
return;
}
if (this.allowDepress && control.active) {
control.deactivate();
} else {
var c;
for (var i=0, len=this.controls.length; i} Controls to add in the panel.
*/
addControls: function(controls) {
if (!(OpenLayers.Util.isArray(controls))) {
controls = [controls];
}
this.controls = this.controls.concat(controls);
// Give each control a panel_div which will be used later.
// Access to this div is via the panel_div attribute of the
// control added to the panel.
// Also, stop mousedowns and clicks, but don't stop mouseup,
// since they need to pass through.
for (var i=0, len=controls.length; i)} Controls to add into map.
*/
addControlsToMap: function (controls) {
var control;
for (var i=0, len=controls.length; i)} A list of controls matching the given criteria.
* An empty array is returned if no matches are found.
*/
getControlsBy: function(property, match) {
var test = (typeof match.test == "function");
var found = OpenLayers.Array.filter(this.controls, function(item) {
return item[property] == match || (test && match.test(item[property]));
});
return found;
},
/**
* APIMethod: getControlsByName
* Get a list of contorls with names matching the given name.
*
* Parameter:
* match - {String | Object} A control name. The name can also be a regular
* expression literal or object. In addition, it can be any object
* with a method named test. For reqular expressions or other, if
* name.test(control.name) evaluates to true, the control will be included
* in the list of controls returned. If no controls are found, an empty
* array is returned.
*
* Returns:
* {Array()} A list of controls matching the given name.
* An empty array is returned if no matches are found.
*/
getControlsByName: function(match) {
return this.getControlsBy("name", match);
},
/**
* APIMethod: getControlsByClass
* Get a list of controls of a given type (CLASS_NAME).
*
* Parameter:
* match - {String | Object} A control class name. The type can also be a
* regular expression literal or object. In addition, it can be any
* object with a method named test. For reqular expressions or other,
* if type.test(control.CLASS_NAME) evaluates to true, the control will
* be included in the list of controls returned. If no controls are
* found, an empty array is returned.
*
* Returns:
* {Array()} A list of controls matching the given type.
* An empty array is returned if no matches are found.
*/
getControlsByClass: function(match) {
return this.getControlsBy("CLASS_NAME", match);
},
CLASS_NAME: "OpenLayers.Control.Panel"
});
/* ======================================================================
OpenLayers/Control/ZoomIn.js
====================================================================== */
/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
* full list of contributors). Published under the Clear BSD license.
* See http://svn.openlayers.org/trunk/openlayers/license.txt for the
* full text of the license. */
/**
* @requires OpenLayers/Control.js
*/
/**
* Class: OpenLayers.Control.ZoomIn
* The ZoomIn control is a button to increase the zoom level of a map.
*
* Inherits from:
* -
*/
OpenLayers.Control.ZoomIn = OpenLayers.Class(OpenLayers.Control, {
/**
* Property: type
* {String} The type of -- When added to a
* , 'type' is used by the panel to determine how to
* handle our events.
*/
type: OpenLayers.Control.TYPE_BUTTON,
/**
* Method: trigger
*/
trigger: function(){
this.map.zoomIn();
},
CLASS_NAME: "OpenLayers.Control.ZoomIn"
});
/* ======================================================================
OpenLayers/Control/ZoomOut.js
====================================================================== */
/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
* full list of contributors). Published under the Clear BSD license.
* See http://svn.openlayers.org/trunk/openlayers/license.txt for the
* full text of the license. */
/**
* @requires OpenLayers/Control.js
*/
/**
* Class: OpenLayers.Control.ZoomOut
* The ZoomOut control is a button to decrease the zoom level of a map.
*
* Inherits from:
* -
*/
OpenLayers.Control.ZoomOut = OpenLayers.Class(OpenLayers.Control, {
/**
* Property: type
* {String} The type of -- When added to a
* , 'type' is used by the panel to determine how to
* handle our events.
*/
type: OpenLayers.Control.TYPE_BUTTON,
/**
* Method: trigger
*/
trigger: function(){
this.map.zoomOut();
},
CLASS_NAME: "OpenLayers.Control.ZoomOut"
});
/* ======================================================================
OpenLayers/Control/ZoomToMaxExtent.js
====================================================================== */
/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
* full list of contributors). Published under the Clear BSD license.
* See http://svn.openlayers.org/trunk/openlayers/license.txt for the
* full text of the license. */
/**
* @requires OpenLayers/Control.js
*/
/**
* Class: OpenLayers.Control.ZoomToMaxExtent
* The ZoomToMaxExtent control is a button that zooms out to the maximum
* extent of the map. It is designed to be used with a
* .
*
* Inherits from:
* -
*/
OpenLayers.Control.ZoomToMaxExtent = OpenLayers.Class(OpenLayers.Control, {
/**
* Property: type
* {String} The type of -- When added to a
* , 'type' is used by the panel to determine how to
* handle our events.
*/
type: OpenLayers.Control.TYPE_BUTTON,
/*
* Method: trigger
* Do the zoom.
*/
trigger: function() {
if (this.map) {
this.map.zoomToMaxExtent();
}
},
CLASS_NAME: "OpenLayers.Control.ZoomToMaxExtent"
});
/* ======================================================================
OpenLayers/Control/ZoomPanel.js
====================================================================== */
/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
* full list of contributors). Published under the Clear BSD license.
* See http://svn.openlayers.org/trunk/openlayers/license.txt for the
* full text of the license. */
/**
* @requires OpenLayers/Control/Panel.js
* @requires OpenLayers/Control/ZoomIn.js
* @requires OpenLayers/Control/ZoomOut.js
* @requires OpenLayers/Control/ZoomToMaxExtent.js
*/
/**
* Class: OpenLayers.Control.ZoomPanel
* The ZoomPanel control is a compact collecton of 3 zoom controls: a
* , a , and a
* . By default it is drawn in the upper left
* corner of the map.
*
* Note:
* If you wish to use this class with the default images and you want
* it to look nice in ie6, you should add the following, conditionally
* added css stylesheet to your HTML file:
*
* (code)
*
* (end)
*
* Inherits from:
* -
*/
OpenLayers.Control.ZoomPanel = OpenLayers.Class(OpenLayers.Control.Panel, {
/**
* Constructor: OpenLayers.Control.ZoomPanel
* Add the three zooming controls.
*
* Parameters:
* options - {Object} An optional object whose properties will be used
* to extend the control.
*/
initialize: function(options) {
OpenLayers.Control.Panel.prototype.initialize.apply(this, [options]);
this.addControls([
new OpenLayers.Control.ZoomIn(),
new OpenLayers.Control.ZoomToMaxExtent(),
new OpenLayers.Control.ZoomOut()
]);
},
CLASS_NAME: "OpenLayers.Control.ZoomPanel"
});
/* ======================================================================
OpenLayers/Control/PanZoom.js
====================================================================== */
/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
* full list of contributors). Published under the Clear BSD license.
* See http://svn.openlayers.org/trunk/openlayers/license.txt for the
* full text of the license. */
/**
* @requires OpenLayers/Control.js
*/
/**
* Class: OpenLayers.Control.PanZoom
* The PanZoom is a visible control, composed of a
* and a . By
* default it is drawn in the upper left corner of the map.
*
* Inherits from:
* -
*/
OpenLayers.Control.PanZoom = OpenLayers.Class(OpenLayers.Control, {
/**
* APIProperty: slideFactor
* {Integer} Number of pixels by which we'll pan the map in any direction
* on clicking the arrow buttons. If you want to pan by some ratio
* of the map dimensions, use instead.
*/
slideFactor: 50,
/**
* APIProperty: slideRatio
* {Number} The fraction of map width/height by which we'll pan the map
* on clicking the arrow buttons. Default is null. If set, will
* override . E.g. if slideRatio is .5, then the Pan Up
* button will pan up half the map height.
*/
slideRatio: null,
/**
* Property: buttons
* {Array(DOMElement)} Array of Button Divs
*/
buttons: null,
/**
* Property: position
* {}
*/
position: null,
/**
* Constructor: OpenLayers.Control.PanZoom
*
* Parameters:
* options - {Object}
*/
initialize: function(options) {
this.position = new OpenLayers.Pixel(OpenLayers.Control.PanZoom.X,
OpenLayers.Control.PanZoom.Y);
OpenLayers.Control.prototype.initialize.apply(this, arguments);
},
/**
* APIMethod: destroy
*/
destroy: function() {
this.removeButtons();
this.buttons = null;
this.position = null;
OpenLayers.Control.prototype.destroy.apply(this, arguments);
},
/**
* Method: draw
*
* Parameters:
* px - {}
*
* Returns:
* {DOMElement} A reference to the container div for the PanZoom control.
*/
draw: function(px) {
// initialize our internal div
OpenLayers.Control.prototype.draw.apply(this, arguments);
px = this.position;
// place the controls
this.buttons = [];
var sz = new OpenLayers.Size(18,18);
var centered = new OpenLayers.Pixel(px.x+sz.w/2, px.y);
this._addButton("panup", "north-mini.png", centered, sz);
px.y = centered.y+sz.h;
this._addButton("panleft", "west-mini.png", px, sz);
this._addButton("panright", "east-mini.png", px.add(sz.w, 0), sz);
this._addButton("pandown", "south-mini.png",
centered.add(0, sz.h*2), sz);
this._addButton("zoomin", "zoom-plus-mini.png",
centered.add(0, sz.h*3+5), sz);
this._addButton("zoomworld", "zoom-world-mini.png",
centered.add(0, sz.h*4+5), sz);
this._addButton("zoomout", "zoom-minus-mini.png",
centered.add(0, sz.h*5+5), sz);
return this.div;
},
/**
* Method: _addButton
*
* Parameters:
* id - {String}
* img - {String}
* xy - {}
* sz - {}
*
* Returns:
* {DOMElement} A Div (an alphaImageDiv, to be precise) that contains the
* image of the button, and has all the proper event handlers set.
*/
_addButton:function(id, img, xy, sz) {
var imgLocation = OpenLayers.Util.getImagesLocation() + img;
var btn = OpenLayers.Util.createAlphaImageDiv(
this.id + "_" + id,
xy, sz, imgLocation, "absolute");
btn.style.cursor = "pointer";
//we want to add the outer div
this.div.appendChild(btn);
OpenLayers.Event.observe(btn, "mousedown",
OpenLayers.Function.bindAsEventListener(this.buttonDown, btn));
OpenLayers.Event.observe(btn, "dblclick",
OpenLayers.Function.bindAsEventListener(this.doubleClick, btn));
OpenLayers.Event.observe(btn, "click",
OpenLayers.Function.bindAsEventListener(this.doubleClick, btn));
btn.action = id;
btn.map = this.map;
if(!this.slideRatio){
var slideFactorPixels = this.slideFactor;
var getSlideFactor = function() {
return slideFactorPixels;
};
} else {
var slideRatio = this.slideRatio;
var getSlideFactor = function(dim) {
return this.map.getSize()[dim] * slideRatio;
};
}
btn.getSlideFactor = getSlideFactor;
//we want to remember/reference the outer div
this.buttons.push(btn);
return btn;
},
/**
* Method: _removeButton
*
* Parameters:
* btn - {Object}
*/
_removeButton: function(btn) {
OpenLayers.Event.stopObservingElement(btn);
btn.map = null;
btn.getSlideFactor = null;
this.div.removeChild(btn);
OpenLayers.Util.removeItem(this.buttons, btn);
},
/**
* Method: removeButtons
*/
removeButtons: function() {
for(var i=this.buttons.length-1; i>=0; --i) {
this._removeButton(this.buttons[i]);
}
},
/**
* Method: doubleClick
*
* Parameters:
* evt - {Event}
*
* Returns:
* {Boolean}
*/
doubleClick: function (evt) {
OpenLayers.Event.stop(evt);
return false;
},
/**
* Method: buttonDown
*
* Parameters:
* evt - {Event}
*/
buttonDown: function (evt) {
if (!OpenLayers.Event.isLeftClick(evt)) {
return;
}
switch (this.action) {
case "panup":
this.map.pan(0, -this.getSlideFactor("h"));
break;
case "pandown":
this.map.pan(0, this.getSlideFactor("h"));
break;
case "panleft":
this.map.pan(-this.getSlideFactor("w"), 0);
break;
case "panright":
this.map.pan(this.getSlideFactor("w"), 0);
break;
case "zoomin":
this.map.zoomIn();
break;
case "zoomout":
this.map.zoomOut();
break;
case "zoomworld":
this.map.zoomToMaxExtent();
break;
}
OpenLayers.Event.stop(evt);
},
CLASS_NAME: "OpenLayers.Control.PanZoom"
});
/**
* Constant: X
* {Integer}
*/
OpenLayers.Control.PanZoom.X = 4;
/**
* Constant: Y
* {Integer}
*/
OpenLayers.Control.PanZoom.Y = 4;
/* ======================================================================
OpenLayers/Control/PanZoomBar.js
====================================================================== */
/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
* full list of contributors). Published under the Clear BSD license.
* See http://svn.openlayers.org/trunk/openlayers/license.txt for the
* full text of the license. */
/**
* @requires OpenLayers/Control/PanZoom.js
*/
/**
* Class: OpenLayers.Control.PanZoomBar
* The PanZoomBar is a visible control composed of a
* and a .
* By default it is displayed in the upper left corner of the map as 4
* directional arrows above a vertical slider.
*
* Inherits from:
* -
*/
OpenLayers.Control.PanZoomBar = OpenLayers.Class(OpenLayers.Control.PanZoom, {
/**
* APIProperty: zoomStopWidth
*/
zoomStopWidth: 18,
/**
* APIProperty: zoomStopHeight
*/
zoomStopHeight: 11,
/**
* Property: slider
*/
slider: null,
/**
* Property: sliderEvents
* {}
*/
sliderEvents: null,
/**
* Property: zoombarDiv
* {DOMElement}
*/
zoombarDiv: null,
/**
* Property: divEvents
* {}
*/
divEvents: null,
/**
* APIProperty: zoomWorldIcon
* {Boolean}
*/
zoomWorldIcon: false,
/**
* APIProperty: panIcons
* {Boolean} Set this property to false not to display the pan icons. If
* false the zoom world icon is placed under the zoom bar. Defaults to
* true.
*/
panIcons: true,
/**
* APIProperty: forceFixedZoomLevel
* {Boolean} Force a fixed zoom level even though the map has
* fractionalZoom
*/
forceFixedZoomLevel: false,
/**
* Property: mouseDragStart
* {}
*/
mouseDragStart: null,
/**
* Property: deltaY
* {Number} The cumulative vertical pixel offset during a zoom bar drag.
*/
deltaY: null,
/**
* Property: zoomStart
* {}
*/
zoomStart: null,
/**
* Constructor: OpenLayers.Control.PanZoomBar
*/
/**
* APIMethod: destroy
*/
destroy: function() {
this._removeZoomBar();
this.map.events.un({
"changebaselayer": this.redraw,
scope: this
});
OpenLayers.Control.PanZoom.prototype.destroy.apply(this, arguments);
delete this.mouseDragStart;
delete this.zoomStart;
},
/**
* Method: setMap
*
* Parameters:
* map - {}
*/
setMap: function(map) {
OpenLayers.Control.PanZoom.prototype.setMap.apply(this, arguments);
this.map.events.register("changebaselayer", this, this.redraw);
},
/**
* Method: redraw
* clear the div and start over.
*/
redraw: function() {
if (this.div != null) {
this.removeButtons();
this._removeZoomBar();
}
this.draw();
},
/**
* Method: draw
*
* Parameters:
* px - {}
*/
draw: function(px) {
// initialize our internal div
OpenLayers.Control.prototype.draw.apply(this, arguments);
px = this.position.clone();
// place the controls
this.buttons = [];
var sz = new OpenLayers.Size(18,18);
if (this.panIcons) {
var centered = new OpenLayers.Pixel(px.x+sz.w/2, px.y);
var wposition = sz.w;
if (this.zoomWorldIcon) {
centered = new OpenLayers.Pixel(px.x+sz.w, px.y);
}
this._addButton("panup", "north-mini.png", centered, sz);
px.y = centered.y+sz.h;
this._addButton("panleft", "west-mini.png", px, sz);
if (this.zoomWorldIcon) {
this._addButton("zoomworld", "zoom-world-mini.png", px.add(sz.w, 0), sz);
wposition *= 2;
}
this._addButton("panright", "east-mini.png", px.add(wposition, 0), sz);
this._addButton("pandown", "south-mini.png", centered.add(0, sz.h*2), sz);
this._addButton("zoomin", "zoom-plus-mini.png", centered.add(0, sz.h*3+5), sz);
centered = this._addZoomBar(centered.add(0, sz.h*4 + 5));
this._addButton("zoomout", "zoom-minus-mini.png", centered, sz);
}
else {
this._addButton("zoomin", "zoom-plus-mini.png", px, sz);
centered = this._addZoomBar(px.add(0, sz.h));
this._addButton("zoomout", "zoom-minus-mini.png", centered, sz);
if (this.zoomWorldIcon) {
centered = centered.add(0, sz.h+3);
this._addButton("zoomworld", "zoom-world-mini.png", centered, sz);
}
}
return this.div;
},
/**
* Method: _addZoomBar
*
* Parameters:
* location - {} where zoombar drawing is to start.
*/
_addZoomBar:function(centered) {
var imgLocation = OpenLayers.Util.getImagesLocation();
var id = this.id + "_" + this.map.id;
var zoomsToEnd = this.map.getNumZoomLevels() - 1 - this.map.getZoom();
var slider = OpenLayers.Util.createAlphaImageDiv(id,
centered.add(-1, zoomsToEnd * this.zoomStopHeight),
new OpenLayers.Size(20,9),
imgLocation+"slider.png",
"absolute");
slider.style.cursor = "move";
this.slider = slider;
this.sliderEvents = new OpenLayers.Events(this, slider, null, true,
{includeXY: true});
this.sliderEvents.on({
"touchstart": this.zoomBarDown,
"touchmove": this.zoomBarDrag,
"touchend": this.zoomBarUp,
"mousedown": this.zoomBarDown,
"mousemove": this.zoomBarDrag,
"mouseup": this.zoomBarUp,
"dblclick": this.doubleClick,
"click": this.doubleClick
});
var sz = new OpenLayers.Size();
sz.h = this.zoomStopHeight * this.map.getNumZoomLevels();
sz.w = this.zoomStopWidth;
var div = null;
if (OpenLayers.Util.alphaHack()) {
var id = this.id + "_" + this.map.id;
div = OpenLayers.Util.createAlphaImageDiv(id, centered,
new OpenLayers.Size(sz.w,
this.zoomStopHeight),
imgLocation + "zoombar.png",
"absolute", null, "crop");
div.style.height = sz.h + "px";
} else {
div = OpenLayers.Util.createDiv(
'OpenLayers_Control_PanZoomBar_Zoombar' + this.map.id,
centered,
sz,
imgLocation+"zoombar.png");
}
div.style.cursor = "pointer";
this.zoombarDiv = div;
this.divEvents = new OpenLayers.Events(this, div, null, true,
{includeXY: true});
this.divEvents.on({
"touchmove": this.passEventToSlider,
"mousedown": this.divClick,
"mousemove": this.passEventToSlider,
"dblclick": this.doubleClick,
"click": this.doubleClick
});
this.div.appendChild(div);
this.startTop = parseInt(div.style.top);
this.div.appendChild(slider);
this.map.events.register("zoomend", this, this.moveZoomBar);
centered = centered.add(0,
this.zoomStopHeight * this.map.getNumZoomLevels());
return centered;
},
/**
* Method: _removeZoomBar
*/
_removeZoomBar: function() {
this.sliderEvents.un({
"touchmove": this.zoomBarDrag,
"mousedown": this.zoomBarDown,
"mousemove": this.zoomBarDrag,
"mouseup": this.zoomBarUp,
"dblclick": this.doubleClick,
"click": this.doubleClick
});
this.sliderEvents.destroy();
this.divEvents.un({
"touchmove": this.passEventToSlider,
"mousedown": this.divClick,
"mousemove": this.passEventToSlider,
"dblclick": this.doubleClick,
"click": this.doubleClick
});
this.divEvents.destroy();
this.div.removeChild(this.zoombarDiv);
this.zoombarDiv = null;
this.div.removeChild(this.slider);
this.slider = null;
this.map.events.unregister("zoomend", this, this.moveZoomBar);
},
/**
* Method: passEventToSlider
* This function is used to pass events that happen on the div, or the map,
* through to the slider, which then does its moving thing.
*
* Parameters:
* evt - {}
*/
passEventToSlider:function(evt) {
this.sliderEvents.handleBrowserEvent(evt);
},
/**
* Method: divClick
* Picks up on clicks directly on the zoombar div
* and sets the zoom level appropriately.
*/
divClick: function (evt) {
if (!OpenLayers.Event.isLeftClick(evt)) {
return;
}
var levels = evt.xy.y / this.zoomStopHeight;
if(this.forceFixedZoomLevel || !this.map.fractionalZoom) {
levels = Math.floor(levels);
}
var zoom = (this.map.getNumZoomLevels() - 1) - levels;
zoom = Math.min(Math.max(zoom, 0), this.map.getNumZoomLevels() - 1);
this.map.zoomTo(zoom);
OpenLayers.Event.stop(evt);
},
/*
* Method: zoomBarDown
* event listener for clicks on the slider
*
* Parameters:
* evt - {}
*/
zoomBarDown:function(evt) {
if (!OpenLayers.Event.isLeftClick(evt) && !OpenLayers.Event.isSingleTouch(evt)) {
return;
}
this.map.events.on({
"touchmove": this.passEventToSlider,
"mousemove": this.passEventToSlider,
"mouseup": this.passEventToSlider,
scope: this
});
this.mouseDragStart = evt.xy.clone();
this.zoomStart = evt.xy.clone();
this.div.style.cursor = "move";
// reset the div offsets just in case the div moved
this.zoombarDiv.offsets = null;
OpenLayers.Event.stop(evt);
},
/*
* Method: zoomBarDrag
* This is what happens when a click has occurred, and the client is
* dragging. Here we must ensure that the slider doesn't go beyond the
* bottom/top of the zoombar div, as well as moving the slider to its new
* visual location
*
* Parameters:
* evt - {}
*/
zoomBarDrag:function(evt) {
if (this.mouseDragStart != null) {
var deltaY = this.mouseDragStart.y - evt.xy.y;
var offsets = OpenLayers.Util.pagePosition(this.zoombarDiv);
if ((evt.clientY - offsets[1]) > 0 &&
(evt.clientY - offsets[1]) < parseInt(this.zoombarDiv.style.height) - 2) {
var newTop = parseInt(this.slider.style.top) - deltaY;
this.slider.style.top = newTop+"px";
this.mouseDragStart = evt.xy.clone();
}
// set cumulative displacement
this.deltaY = this.zoomStart.y - evt.xy.y;
OpenLayers.Event.stop(evt);
}
},
/*
* Method: zoomBarUp
* Perform cleanup when a mouseup event is received -- discover new zoom
* level and switch to it.
*
* Parameters:
* evt - {}
*/
zoomBarUp:function(evt) {
if (!OpenLayers.Event.isLeftClick(evt) && evt.type !== "touchend") {
return;
}
if (this.mouseDragStart) {
this.div.style.cursor="";
this.map.events.un({
"touchmove": this.passEventToSlider,
"mouseup": this.passEventToSlider,
"mousemove": this.passEventToSlider,
scope: this
});
var zoomLevel = this.map.zoom;
if (!this.forceFixedZoomLevel && this.map.fractionalZoom) {
zoomLevel += this.deltaY/this.zoomStopHeight;
zoomLevel = Math.min(Math.max(zoomLevel, 0),
this.map.getNumZoomLevels() - 1);
} else {
zoomLevel += this.deltaY/this.zoomStopHeight;
zoomLevel = Math.max(Math.round(zoomLevel), 0);
}
this.map.zoomTo(zoomLevel);
this.mouseDragStart = null;
this.zoomStart = null;
this.deltaY = 0;
OpenLayers.Event.stop(evt);
}
},
/*
* Method: moveZoomBar
* Change the location of the slider to match the current zoom level.
*/
moveZoomBar:function() {
var newTop =
((this.map.getNumZoomLevels()-1) - this.map.getZoom()) *
this.zoomStopHeight + this.startTop + 1;
this.slider.style.top = newTop + "px";
},
CLASS_NAME: "OpenLayers.Control.PanZoomBar"
});
/* ======================================================================
OpenLayers/Format.js
====================================================================== */
/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
* full list of contributors). Published under the Clear BSD license.
* See http://svn.openlayers.org/trunk/openlayers/license.txt for the
* full text of the license. */
/**
* @requires OpenLayers/BaseTypes/Class.js
* @requires OpenLayers/Util.js
* @requires OpenLayers/Console.js
* @requires OpenLayers/Lang.js
*/
/**
* Class: OpenLayers.Format
* Base class for format reading/writing a variety of formats. Subclasses
* of OpenLayers.Format are expected to have read and write methods.
*/
OpenLayers.Format = OpenLayers.Class({
/**
* Property: options
* {Object} A reference to options passed to the constructor.
*/
options: null,
/**
* APIProperty: externalProjection
* {} When passed a externalProjection and
* internalProjection, the format will reproject the geometries it
* reads or writes. The externalProjection is the projection used by
* the content which is passed into read or which comes out of write.
* In order to reproject, a projection transformation function for the
* specified projections must be available. This support may be
* provided via proj4js or via a custom transformation function. See
* {} for more information on
* custom transformations.
*/
externalProjection: null,
/**
* APIProperty: internalProjection
* {} When passed a externalProjection and
* internalProjection, the format will reproject the geometries it
* reads or writes. The internalProjection is the projection used by
* the geometries which are returned by read or which are passed into
* write. In order to reproject, a projection transformation function
* for the specified projections must be available. This support may be
* provided via proj4js or via a custom transformation function. See
* {} for more information on
* custom transformations.
*/
internalProjection: null,
/**
* APIProperty: data
* {Object} When is true, this is the parsed string sent to
* .
*/
data: null,
/**
* APIProperty: keepData
* {Object} Maintain a reference () to the most recently read data.
* Default is false.
*/
keepData: false,
/**
* Constructor: OpenLayers.Format
* Instances of this class are not useful. See one of the subclasses.
*
* Parameters:
* options - {Object} An optional object with properties to set on the
* format
*
* Valid options:
* keepData - {Boolean} If true, upon , the data property will be
* set to the parsed object (e.g. the json or xml object).
*
* Returns:
* An instance of OpenLayers.Format
*/
initialize: function(options) {
OpenLayers.Util.extend(this, options);
this.options = options;
},
/**
* APIMethod: destroy
* Clean up.
*/
destroy: function() {
},
/**
* Method: read
* Read data from a string, and return an object whose type depends on the
* subclass.
*
* Parameters:
* data - {string} Data to read/parse.
*
* Returns:
* Depends on the subclass
*/
read: function(data) {
OpenLayers.Console.userError(OpenLayers.i18n("readNotImplemented"));
},
/**
* Method: write
* Accept an object, and return a string.
*
* Parameters:
* object - {Object} Object to be serialized
*
* Returns:
* {String} A string representation of the object.
*/
write: function(object) {
OpenLayers.Console.userError(OpenLayers.i18n("writeNotImplemented"));
},
CLASS_NAME: "OpenLayers.Format"
});
/* ======================================================================
OpenLayers/Feature.js
====================================================================== */
/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
* full list of contributors). Published under the Clear BSD license.
* See http://svn.openlayers.org/trunk/openlayers/license.txt for the
* full text of the license. */
/**
* @requires OpenLayers/BaseTypes/Class.js
* @requires OpenLayers/Util.js
*/
/**
* Class: OpenLayers.Feature
* Features are combinations of geography and attributes. The OpenLayers.Feature
* class specifically combines a marker and a lonlat.
*/
OpenLayers.Feature = OpenLayers.Class({
/**
* Property: layer
* {}
*/
layer: null,
/**
* Property: id
* {String}
*/
id: null,
/**
* Property: lonlat
* {}
*/
lonlat: null,
/**
* Property: data
* {Object}
*/
data: null,
/**
* Property: marker
* {}
*/
marker: null,
/**
* APIProperty: popupClass
* {} The class which will be used to instantiate
* a new Popup. Default is .
*/
popupClass: null,
/**
* Property: popup
* {}
*/
popup: null,
/**
* Constructor: OpenLayers.Feature
* Constructor for features.
*
* Parameters:
* layer - {}
* lonlat - {}
* data - {Object}
*
* Returns:
* {}
*/
initialize: function(layer, lonlat, data) {
this.layer = layer;
this.lonlat = lonlat;
this.data = (data != null) ? data : {};
this.id = OpenLayers.Util.createUniqueID(this.CLASS_NAME + "_");
},
/**
* Method: destroy
* nullify references to prevent circular references and memory leaks
*/
destroy: function() {
//remove the popup from the map
if ((this.layer != null) && (this.layer.map != null)) {
if (this.popup != null) {
this.layer.map.removePopup(this.popup);
}
}
// remove the marker from the layer
if (this.layer != null && this.marker != null) {
this.layer.removeMarker(this.marker);
}
this.layer = null;
this.id = null;
this.lonlat = null;
this.data = null;
if (this.marker != null) {
this.destroyMarker(this.marker);
this.marker = null;
}
if (this.popup != null) {
this.destroyPopup(this.popup);
this.popup = null;
}
},
/**
* Method: onScreen
*
* Returns:
* {Boolean} Whether or not the feature is currently visible on screen
* (based on its 'lonlat' property)
*/
onScreen:function() {
var onScreen = false;
if ((this.layer != null) && (this.layer.map != null)) {
var screenBounds = this.layer.map.getExtent();
onScreen = screenBounds.containsLonLat(this.lonlat);
}
return onScreen;
},
/**
* Method: createMarker
* Based on the data associated with the Feature, create and return a marker object.
*
* Returns:
* {} A Marker Object created from the 'lonlat' and 'icon' properties
* set in this.data. If no 'lonlat' is set, returns null. If no
* 'icon' is set, OpenLayers.Marker() will load the default image.
*
* Note - this.marker is set to return value
*
*/
createMarker: function() {
if (this.lonlat != null) {
this.marker = new OpenLayers.Marker(this.lonlat, this.data.icon);
}
return this.marker;
},
/**
* Method: destroyMarker
* Destroys marker.
* If user overrides the createMarker() function, s/he should be able
* to also specify an alternative function for destroying it
*/
destroyMarker: function() {
this.marker.destroy();
},
/**
* Method: createPopup
* Creates a popup object created from the 'lonlat', 'popupSize',
* and 'popupContentHTML' properties set in this.data. It uses
* this.marker.icon as default anchor.
*
* If no 'lonlat' is set, returns null.
* If no this.marker has been created, no anchor is sent.
*
* Note - the returned popup object is 'owned' by the feature, so you
* cannot use the popup's destroy method to discard the popup.
* Instead, you must use the feature's destroyPopup
*
* Note - this.popup is set to return value
*
* Parameters:
* closeBox - {Boolean} create popup with closebox or not
*
* Returns:
* {} Returns the created popup, which is also set
* as 'popup' property of this feature. Will be of whatever type
* specified by this feature's 'popupClass' property, but must be
* of type .
*
*/
createPopup: function(closeBox) {
if (this.lonlat != null) {
if (!this.popup) {
var anchor = (this.marker) ? this.marker.icon : null;
var popupClass = this.popupClass ?
this.popupClass : OpenLayers.Popup.AnchoredBubble;
this.popup = new popupClass(this.id + "_popup",
this.lonlat,
this.data.popupSize,
this.data.popupContentHTML,
anchor,
closeBox);
}
if (this.data.overflow != null) {
this.popup.contentDiv.style.overflow = this.data.overflow;
}
this.popup.feature = this;
}
return this.popup;
},
/**
* Method: destroyPopup
* Destroys the popup created via createPopup.
*
* As with the marker, if user overrides the createPopup() function, s/he
* should also be able to override the destruction
*/
destroyPopup: function() {
if (this.popup) {
this.popup.feature = null;
this.popup.destroy();
this.popup = null;
}
},
CLASS_NAME: "OpenLayers.Feature"
});
/* ======================================================================
OpenLayers/Feature/Vector.js
====================================================================== */
/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
* full list of contributors). Published under the Clear BSD license.
* See http://svn.openlayers.org/trunk/openlayers/license.txt for the
* full text of the license. */
// TRASH THIS
OpenLayers.State = {
/** states */
UNKNOWN: 'Unknown',
INSERT: 'Insert',
UPDATE: 'Update',
DELETE: 'Delete'
};
/**
* @requires OpenLayers/Feature.js
* @requires OpenLayers/Util.js
*/
/**
* Class: OpenLayers.Feature.Vector
* Vector features use the OpenLayers.Geometry classes as geometry description.
* They have an 'attributes' property, which is the data object, and a 'style'
* property, the default values of which are defined in the
* objects.
*
* Inherits from:
* -
*/
OpenLayers.Feature.Vector = OpenLayers.Class(OpenLayers.Feature, {
/**
* Property: fid
* {String}
*/
fid: null,
/**
* APIProperty: geometry
* {}
*/
geometry: null,
/**
* APIProperty: attributes
* {Object} This object holds arbitrary, serializable properties that
* describe the feature.
*/
attributes: null,
/**
* Property: bounds
* {} The box bounding that feature's geometry, that
* property can be set by an object when
* deserializing the feature, so in most cases it represents an
* information set by the server.
*/
bounds: null,
/**
* Property: state
* {String}
*/
state: null,
/**
* APIProperty: style
* {Object}
*/
style: null,
/**
* APIProperty: url
* {String} If this property is set it will be taken into account by
* {} when upadting or deleting the feature.
*/
url: null,
/**
* Property: renderIntent
* {String} rendering intent currently being used
*/
renderIntent: "default",
/**
* APIProperty: modified
* {Object} An object with the originals of the geometry and attributes of
* the feature, if they were changed. Currently this property is only read
* by , and written by
* , which sets the geometry property.
* Applications can set the originals of modified attributes in the
* attributes property. Note that applications have to check if this
* object and the attributes property is already created before using it.
* After a change made with ModifyFeature, this object could look like
*
* (code)
* {
* geometry: >Object
* }
* (end)
*
* When an application has made changes to feature attributes, it could
* have set the attributes to something like this:
*
* (code)
* {
* attributes: {
* myAttribute: "original"
* }
* }
* (end)
*
* Note that only checks for truthy values in
* *modified.geometry* and the attribute names in *modified.attributes*,
* but it is recommended to set the original values (and not just true) as
* attribute value, so applications could use this information to undo
* changes.
*/
modified: null,
/**
* Constructor: OpenLayers.Feature.Vector
* Create a vector feature.
*
* Parameters:
* geometry - {} The geometry that this feature
* represents.
* attributes - {Object} An optional object that will be mapped to the
* property.
* style - {Object} An optional style object.
*/
initialize: function(geometry, attributes, style) {
OpenLayers.Feature.prototype.initialize.apply(this,
[null, null, attributes]);
this.lonlat = null;
this.geometry = geometry ? geometry : null;
this.state = null;
this.attributes = {};
if (attributes) {
this.attributes = OpenLayers.Util.extend(this.attributes,
attributes);
}
this.style = style ? style : null;
},
/**
* Method: destroy
* nullify references to prevent circular references and memory leaks
*/
destroy: function() {
if (this.layer) {
this.layer.removeFeatures(this);
this.layer = null;
}
this.geometry = null;
this.modified = null;
OpenLayers.Feature.prototype.destroy.apply(this, arguments);
},
/**
* Method: clone
* Create a clone of this vector feature. Does not set any non-standard
* properties.
*
* Returns:
* {} An exact clone of this vector feature.
*/
clone: function () {
return new OpenLayers.Feature.Vector(
this.geometry ? this.geometry.clone() : null,
this.attributes,
this.style);
},
/**
* Method: onScreen
* Determine whether the feature is within the map viewport. This method
* tests for an intersection between the geometry and the viewport
* bounds. If a more effecient but less precise geometry bounds
* intersection is desired, call the method with the boundsOnly
* parameter true.
*
* Parameters:
* boundsOnly - {Boolean} Only test whether a feature's bounds intersects
* the viewport bounds. Default is false. If false, the feature's
* geometry must intersect the viewport for onScreen to return true.
*
* Returns:
* {Boolean} The feature is currently visible on screen (optionally
* based on its bounds if boundsOnly is true).
*/
onScreen:function(boundsOnly) {
var onScreen = false;
if(this.layer && this.layer.map) {
var screenBounds = this.layer.map.getExtent();
if(boundsOnly) {
var featureBounds = this.geometry.getBounds();
onScreen = screenBounds.intersectsBounds(featureBounds);
} else {
var screenPoly = screenBounds.toGeometry();
onScreen = screenPoly.intersects(this.geometry);
}
}
return onScreen;
},
/**
* Method: getVisibility
* Determine whether the feature is displayed or not. It may not displayed
* because:
* - its style display property is set to 'none',
* - it doesn't belong to any layer,
* - the styleMap creates a symbolizer with display property set to 'none'
* for it,
* - the layer which it belongs to is not visible.
*
* Returns:
* {Boolean} The feature is currently displayed.
*/
getVisibility: function() {
return !(this.style && this.style.display == 'none' ||
!this.layer ||
this.layer && this.layer.styleMap &&
this.layer.styleMap.createSymbolizer(this, this.renderIntent).display == 'none' ||
this.layer && !this.layer.getVisibility());
},
/**
* Method: createMarker
* HACK - we need to decide if all vector features should be able to
* create markers
*
* Returns:
* {} For now just returns null
*/
createMarker: function() {
return null;
},
/**
* Method: destroyMarker
* HACK - we need to decide if all vector features should be able to
* delete markers
*
* If user overrides the createMarker() function, s/he should be able
* to also specify an alternative function for destroying it
*/
destroyMarker: function() {
// pass
},
/**
* Method: createPopup
* HACK - we need to decide if all vector features should be able to
* create popups
*
* Returns:
* {} For now just returns null
*/
createPopup: function() {
return null;
},
/**
* Method: atPoint
* Determins whether the feature intersects with the specified location.
*
* Parameters:
* lonlat - {}
* toleranceLon - {float} Optional tolerance in Geometric Coords
* toleranceLat - {float} Optional tolerance in Geographic Coords
*
* Returns:
* {Boolean} Whether or not the feature is at the specified location
*/
atPoint: function(lonlat, toleranceLon, toleranceLat) {
var atPoint = false;
if(this.geometry) {
atPoint = this.geometry.atPoint(lonlat, toleranceLon,
toleranceLat);
}
return atPoint;
},
/**
* Method: destroyPopup
* HACK - we need to decide if all vector features should be able to
* delete popups
*/
destroyPopup: function() {
// pass
},
/**
* Method: move
* Moves the feature and redraws it at its new location
*
* Parameters:
* state - {OpenLayers.LonLat or OpenLayers.Pixel} the
* location to which to move the feature.
*/
move: function(location) {
if(!this.layer || !this.geometry.move){
//do nothing if no layer or immoveable geometry
return undefined;
}
var pixel;
if (location.CLASS_NAME == "OpenLayers.LonLat") {
pixel = this.layer.getViewPortPxFromLonLat(location);
} else {
pixel = location;
}
var lastPixel = this.layer.getViewPortPxFromLonLat(this.geometry.getBounds().getCenterLonLat());
var res = this.layer.map.getResolution();
this.geometry.move(res * (pixel.x - lastPixel.x),
res * (lastPixel.y - pixel.y));
this.layer.drawFeature(this);
return lastPixel;
},
/**
* Method: toState
* Sets the new state
*
* Parameters:
* state - {String}
*/
toState: function(state) {
if (state == OpenLayers.State.UPDATE) {
switch (this.state) {
case OpenLayers.State.UNKNOWN:
case OpenLayers.State.DELETE:
this.state = state;
break;
case OpenLayers.State.UPDATE:
case OpenLayers.State.INSERT:
break;
}
} else if (state == OpenLayers.State.INSERT) {
switch (this.state) {
case OpenLayers.State.UNKNOWN:
break;
default:
this.state = state;
break;
}
} else if (state == OpenLayers.State.DELETE) {
switch (this.state) {
case OpenLayers.State.INSERT:
// the feature should be destroyed
break;
case OpenLayers.State.DELETE:
break;
case OpenLayers.State.UNKNOWN:
case OpenLayers.State.UPDATE:
this.state = state;
break;
}
} else if (state == OpenLayers.State.UNKNOWN) {
this.state = state;
}
},
CLASS_NAME: "OpenLayers.Feature.Vector"
});
/**
* Constant: OpenLayers.Feature.Vector.style
* OpenLayers features can have a number of style attributes. The 'default'
* style will typically be used if no other style is specified. These
* styles correspond for the most part, to the styling properties defined
* by the SVG standard.
* Information on fill properties: http://www.w3.org/TR/SVG/painting.html#FillProperties
* Information on stroke properties: http://www.w3.org/TR/SVG/painting.html#StrokeProperties
*
* Symbolizer properties:
* fill - {Boolean} Set to false if no fill is desired.
* fillColor - {String} Hex fill color. Default is "#ee9900".
* fillOpacity - {Number} Fill opacity (0-1). Default is 0.4
* stroke - {Boolean} Set to false if no stroke is desired.
* strokeColor - {String} Hex stroke color. Default is "#ee9900".
* strokeOpacity - {Number} Stroke opacity (0-1). Default is 1.
* strokeWidth - {Number} Pixel stroke width. Default is 1.
* strokeLinecap - {String} Stroke cap type. Default is "round". [butt | round | square]
* strokeDashstyle - {String} Stroke dash style. Default is "solid". [dot | dash | dashdot | longdash | longdashdot | solid]
* graphic - {Boolean} Set to false if no graphic is desired.
* pointRadius - {Number} Pixel point radius. Default is 6.
* pointerEvents - {String} Default is "visiblePainted".
* cursor - {String} Default is "".
* externalGraphic - {String} Url to an external graphic that will be used for rendering points.
* graphicWidth - {Number} Pixel width for sizing an external graphic.
* graphicHeight - {Number} Pixel height for sizing an external graphic.
* graphicOpacity - {Number} Opacity (0-1) for an external graphic.
* graphicXOffset - {Number} Pixel offset along the positive x axis for displacing an external graphic.
* graphicYOffset - {Number} Pixel offset along the positive y axis for displacing an external graphic.
* rotation - {Number} For point symbolizers, this is the rotation of a graphic in the clockwise direction about its center point (or any point off center as specified by graphicXOffset and graphicYOffset).
* graphicZIndex - {Number} The integer z-index value to use in rendering.
* graphicName - {String} Named graphic to use when rendering points. Supported values include "circle" (default),
* "square", "star", "x", "cross", "triangle".
* graphicTitle - {String} Tooltip for an external graphic.
* backgroundGraphic - {String} Url to a graphic to be used as the background under an externalGraphic.
* backgroundGraphicZIndex - {Number} The integer z-index value to use in rendering the background graphic.
* backgroundXOffset - {Number} The x offset (in pixels) for the background graphic.
* backgroundYOffset - {Number} The y offset (in pixels) for the background graphic.
* backgroundHeight - {Number} The height of the background graphic. If not provided, the graphicHeight will be used.
* backgroundWidth - {Number} The width of the background width. If not provided, the graphicWidth will be used.
* label - {String} The text for an optional label. For browsers that use the canvas renderer, this requires either
* fillText or mozDrawText to be available.
* labelAlign - {String} Label alignment. This specifies the insertion point relative to the text. It is a string
* composed of two characters. The first character is for the horizontal alignment, the second for the vertical
* alignment. Valid values for horizontal alignment: "l"=left, "c"=center, "r"=right. Valid values for vertical
* alignment: "t"=top, "m"=middle, "b"=bottom. Example values: "lt", "cm", "rb".
* labelXOffset - {Number} Pixel offset along the positive x axis for displacing the label. Not supported by the canvas renderer.
* labelYOffset - {Number} Pixel offset along the positive y axis for displacing the label. Not supported by the canvas renderer.
* labelSelect - {Boolean} If set to true, labels will be selectable using SelectFeature or similar controls.
* Default is false.
* fontColor - {String} The font color for the label, to be provided like CSS.
* fontOpacity - {Number} Opacity (0-1) for the label
* fontFamily - {String} The font family for the label, to be provided like in CSS.
* fontSize - {String} The font size for the label, to be provided like in CSS.
* fontStyle - {String} The font style for the label, to be provided like in CSS.
* fontWeight - {String} The font weight for the label, to be provided like in CSS.
* display - {String} Symbolizers will have no effect if display is set to "none". All other values have no effect.
*/
OpenLayers.Feature.Vector.style = {
'default': {
fillColor: "#ee9900",
fillOpacity: 0.4,
hoverFillColor: "white",
hoverFillOpacity: 0.8,
strokeColor: "#ee9900",
strokeOpacity: 1,
strokeWidth: 1,
strokeLinecap: "round",
strokeDashstyle: "solid",
hoverStrokeColor: "red",
hoverStrokeOpacity: 1,
hoverStrokeWidth: 0.2,
pointRadius: 6,
hoverPointRadius: 1,
hoverPointUnit: "%",
pointerEvents: "visiblePainted",
cursor: "inherit"
},
'select': {
fillColor: "blue",
fillOpacity: 0.4,
hoverFillColor: "white",
hoverFillOpacity: 0.8,
strokeColor: "blue",
strokeOpacity: 1,
strokeWidth: 2,
strokeLinecap: "round",
strokeDashstyle: "solid",
hoverStrokeColor: "red",
hoverStrokeOpacity: 1,
hoverStrokeWidth: 0.2,
pointRadius: 6,
hoverPointRadius: 1,
hoverPointUnit: "%",
pointerEvents: "visiblePainted",
cursor: "pointer"
},
'temporary': {
fillColor: "#66cccc",
fillOpacity: 0.2,
hoverFillColor: "white",
hoverFillOpacity: 0.8,
strokeColor: "#66cccc",
strokeOpacity: 1,
strokeLinecap: "round",
strokeWidth: 2,
strokeDashstyle: "solid",
hoverStrokeColor: "red",
hoverStrokeOpacity: 1,
hoverStrokeWidth: 0.2,
pointRadius: 6,
hoverPointRadius: 1,
hoverPointUnit: "%",
pointerEvents: "visiblePainted",
cursor: "inherit"
},
'delete': {
display: "none"
}
};
/* ======================================================================
OpenLayers/Format/WKT.js
====================================================================== */
/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
* full list of contributors). Published under the Clear BSD license.
* See http://svn.openlayers.org/trunk/openlayers/license.txt for the
* full text of the license. */
/**
* @requires OpenLayers/Format.js
* @requires OpenLayers/Feature/Vector.js
*/
/**
* Class: OpenLayers.Format.WKT
* Class for reading and writing Well-Known Text. Create a new instance
* with the constructor.
*
* Inherits from:
* -
*/
OpenLayers.Format.WKT = OpenLayers.Class(OpenLayers.Format, {
/**
* Constructor: OpenLayers.Format.WKT
* Create a new parser for WKT
*
* Parameters:
* options - {Object} An optional object whose properties will be set on
* this instance
*
* Returns:
* {} A new WKT parser.
*/
initialize: function(options) {
this.regExes = {
'typeStr': /^\s*(\w+)\s*\(\s*(.*)\s*\)\s*$/,
'spaces': /\s+/,
'parenComma': /\)\s*,\s*\(/,
'doubleParenComma': /\)\s*\)\s*,\s*\(\s*\(/, // can't use {2} here
'trimParens': /^\s*\(?(.*?)\)?\s*$/
};
OpenLayers.Format.prototype.initialize.apply(this, [options]);
},
/**
* Method: read
* Deserialize a WKT string and return a vector feature or an
* array of vector features. Supports WKT for POINT, MULTIPOINT,
* LINESTRING, MULTILINESTRING, POLYGON, MULTIPOLYGON, and
* GEOMETRYCOLLECTION.
*
* Parameters:
* wkt - {String} A WKT string
*
* Returns:
* {|Array} A feature or array of features for
* GEOMETRYCOLLECTION WKT.
*/
read: function(wkt) {
var features, type, str;
wkt = wkt.replace(/[\n\r]/g, " ");
var matches = this.regExes.typeStr.exec(wkt);
if(matches) {
type = matches[1].toLowerCase();
str = matches[2];
if(this.parse[type]) {
features = this.parse[type].apply(this, [str]);
}
if (this.internalProjection && this.externalProjection) {
if (features &&
features.CLASS_NAME == "OpenLayers.Feature.Vector") {
features.geometry.transform(this.externalProjection,
this.internalProjection);
} else if (features &&
type != "geometrycollection" &&
typeof features == "object") {
for (var i=0, len=features.length; i|Array} A feature or array of
* features
*
* Returns:
* {String} The WKT string representation of the input geometries
*/
write: function(features) {
var collection, geometry, type, data, isCollection;
if (features.constructor == Array) {
collection = features;
isCollection = true;
} else {
collection = [features];
isCollection = false;
}
var pieces = [];
if (isCollection) {
pieces.push('GEOMETRYCOLLECTION(');
}
for (var i=0, len=collection.length; i0) {
pieces.push(',');
}
geometry = collection[i].geometry;
pieces.push(this.extractGeometry(geometry));
}
if (isCollection) {
pieces.push(')');
}
return pieces.join('');
},
/**
* Method: extractGeometry
* Entry point to construct the WKT for a single Geometry object.
*
* Parameters:
* geometry - {}
*
* Returns:
* {String} A WKT string of representing the geometry
*/
extractGeometry: function(geometry) {
var type = geometry.CLASS_NAME.split('.')[2].toLowerCase();
if (!this.extract[type]) {
return null;
}
if (this.internalProjection && this.externalProjection) {
geometry = geometry.clone();
geometry.transform(this.internalProjection, this.externalProjection);
}
var wktType = type == 'collection' ? 'GEOMETRYCOLLECTION' : type.toUpperCase();
var data = wktType + '(' + this.extract[type].apply(this, [geometry]) + ')';
return data;
},
/**
* Object with properties corresponding to the geometry types.
* Property values are functions that do the actual data extraction.
*/
extract: {
/**
* Return a space delimited string of point coordinates.
* @param {} point
* @returns {String} A string of coordinates representing the point
*/
'point': function(point) {
return point.x + ' ' + point.y;
},
/**
* Return a comma delimited string of point coordinates from a multipoint.
* @param {} multipoint
* @returns {String} A string of point coordinate strings representing
* the multipoint
*/
'multipoint': function(multipoint) {
var array = [];
for(var i=0, len=multipoint.components.length; i} linestring
* @returns {String} A string of point coordinate strings representing
* the linestring
*/
'linestring': function(linestring) {
var array = [];
for(var i=0, len=linestring.components.length; i} multilinestring
* @returns {String} A string of of linestring strings representing
* the multilinestring
*/
'multilinestring': function(multilinestring) {
var array = [];
for(var i=0, len=multilinestring.components.length; i} polygon
* @returns {String} An array of linear ring arrays representing the polygon
*/
'polygon': function(polygon) {
var array = [];
for(var i=0, len=polygon.components.length; i} multipolygon
* @returns {String} An array of polygon arrays representing
* the multipolygon
*/
'multipolygon': function(multipolygon) {
var array = [];
for(var i=0, len=multipolygon.components.length; i
* @param {} collection
* @returns {String} internal WKT representation of the collection
*/
'collection': function(collection) {
var array = [];
for(var i=0, len=collection.components.length; i} A point feature
* @private
*/
'point': function(str) {
var coords = OpenLayers.String.trim(str).split(this.regExes.spaces);
return new OpenLayers.Feature.Vector(
new OpenLayers.Geometry.Point(coords[0], coords[1])
);
},
/**
* Return a multipoint feature given a multipoint WKT fragment.
* @param {String} A WKT fragment representing the multipoint
* @returns {} A multipoint feature
* @private
*/
'multipoint': function(str) {
var point;
var points = OpenLayers.String.trim(str).split(',');
var components = [];
for(var i=0, len=points.length; i} A linestring feature
* @private
*/
'linestring': function(str) {
var points = OpenLayers.String.trim(str).split(',');
var components = [];
for(var i=0, len=points.length; i