/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
* license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
* full text of the license. */
/**
* @requires OpenLayers/Format/WKT.js
* @requires OpenLayers/Feature/Vector.js
*/
/**
* Class: OpenLayers.Geometry
* A Geometry is a description of a geographic object.  Create an instance of
* this class with the <OpenLayers.Geometry> constructor.  This is a base class,
* typical geometry types are described by subclasses of this class.
*/
OpenLayers.Geometry = OpenLayers.Class({
/**
* Property: id
* {String} A unique identifier for this geometry.
*/
id: null,
/**
* Property: parent
* {<OpenLayers.Geometry>}This is set when a Geometry is added as component
* of another geometry
*/
parent: null,
/**
* Property: bounds
* {<OpenLayers.Bounds>} The bounds of this geometry
*/
bounds: null,
/**
* Constructor: OpenLayers.Geometry
* Creates a geometry object.
*/
initialize: function() {
this.id = OpenLayers.Util.createUniqueID(this.CLASS_NAME+ "_");
},
/**
* Method: destroy
* Destroy this geometry.
*/
destroy: function() {
this.id = null;
this.bounds = null;
},
/**
* APIMethod: clone
* Create a clone of this geometry.  Does not set any non-standard
*     properties of the cloned geometry.
*
* Returns:
* {<OpenLayers.Geometry>} An exact clone of this geometry.
*/
clone: function() {
return new OpenLayers.Geometry();
},
/**
* Set the bounds for this Geometry.
*
* Parameters:
* object - {<OpenLayers.Bounds>}
*/
setBounds: function(bounds) {
if (bounds) {
this.bounds = bounds.clone();
}
},
/**
* Method: clearBounds
* Nullify this components bounds and that of its parent as well.
*/
clearBounds: function() {
this.bounds = null;
if (this.parent) {
this.parent.clearBounds();
}
},
/**
* Method: extendBounds
* Extend the existing bounds to include the new bounds.
* If geometry's bounds is not yet set, then set a new Bounds.
*
* Parameters:
* newBounds - {<OpenLayers.Bounds>}
*/
extendBounds: function(newBounds){
var bounds = this.getBounds();
if (!bounds) {
this.setBounds(newBounds);
} else {
this.bounds.extend(newBounds);
}
},
/**
* APIMethod: getBounds
* Get the bounds for this Geometry. If bounds is not set, it
* is calculated again, this makes queries faster.
*
* Returns:
* {<OpenLayers.Bounds>}
*/
getBounds: function() {
if (this.bounds == null) {
this.calculateBounds();
}
return this.bounds;
},
/**
* APIMethod: calculateBounds
* Recalculate the bounds for the geometry.
*/
calculateBounds: function() {
//
// This should be overridden by subclasses.
//
},
/**
* Method: atPoint
* Note - This is only an approximation based on the bounds of the
* geometry.
*
* Parameters:
* lonlat - {<OpenLayers.LonLat>}
* toleranceLon - {float} Optional tolerance in Geometric Coords
* toleranceLat - {float} Optional tolerance in Geographic Coords
*
* Returns:
* {Boolean} Whether or not the geometry is at the specified location
*/
atPoint: function(lonlat, toleranceLon, toleranceLat) {
var atPoint = false;
var bounds = this.getBounds();
if ((bounds != null) && (lonlat != null)) {
var dX = (toleranceLon != null) ? toleranceLon : 0;
var dY = (toleranceLat != null) ? toleranceLat : 0;
var toleranceBounds =
new OpenLayers.Bounds(this.bounds.left - dX,
this.bounds.bottom - dY,
this.bounds.right + dX,
this.bounds.top + dY);
atPoint = toleranceBounds.containsLonLat(lonlat);
}
return atPoint;
},
/**
* Method: getLength
* Calculate the length of this geometry. This method is defined in
* subclasses.
*
* Returns:
* {Float} The length of the collection by summing its parts
*/
getLength: function() {
//to be overridden by geometries that actually have a length
//
return 0.0;
},
/**
* Method: getArea
* Calculate the area of this geometry. This method is defined in subclasses.
*
* Returns:
* {Float} The area of the collection by summing its parts
*/
getArea: function() {
//to be overridden by geometries that actually have an area
//
return 0.0;
},
/**
* Method: toString
* Returns the Well-Known Text representation of a geometry
*
* Returns:
* {String} Well-Known Text
*/
toString: function() {
return OpenLayers.Format.WKT.prototype.write(
new OpenLayers.Feature.Vector(this)
);
},
CLASS_NAME: "OpenLayers.Geometry"
});
/**
* Method: OpenLayers.Geometry.segmentsIntersect
* Determine whether two line segments intersect.  Optionally calculates
*     and returns the intersection point.  This function is optimized for
*     cases where seg1.x2 >= seg2.x1 || seg2.x2 >= seg1.x1.  In those
*     obvious cases where there is no intersection, the function should
*     not be called.
*
* Parameters:
* seg1 - {Object} Object representing a segment with properties x1, y1, x2,
*     and y2.  The start point is represented by x1 and y1.  The end point
*     is represented by x2 and y2.  Start and end are ordered so that x1 < x2.
* seg2 - {Object} Object representing a segment with properties x1, y1, x2,
*     and y2.  The start point is represented by x1 and y1.  The end point
*     is represented by x2 and y2.  Start and end are ordered so that x1 < x2.
* point - {Boolean} Return the intersection point.  If false, the actual
*     intersection point will not be calculated.  If true and the segments
*     intersect, the intersection point will be returned.  If true and
*     the segments do not intersect, false will be returned.  If true and
*     the segments are coincident, true will be returned.
*
* Returns:
* {Boolean | <OpenLayers.Geometry.Point>}  The two segments intersect.
*     If the point argument is true, the return will be the intersection
*     point or false if none exists.  If point is true and the segments
*     are coincident, return will be true (and the instersection is equal
*     to the shorter segment).
*/
OpenLayers.Geometry.segmentsIntersect = function(seg1, seg2, point) {
var intersection = false;
var x11_21 = seg1.x1 - seg2.x1;
var y11_21 = seg1.y1 - seg2.y1;
var x12_11 = seg1.x2 - seg1.x1;
var y12_11 = seg1.y2 - seg1.y1;
var y22_21 = seg2.y2 - seg2.y1;
var x22_21 = seg2.x2 - seg2.x1;
var d = (y22_21 * x12_11) - (x22_21 * y12_11);
var n1 = (x22_21 * y11_21) - (y22_21 * x11_21);
var n2 = (x12_11 * y11_21) - (y12_11 * x11_21);
if(d == 0) {
// parallel
if(n1 == 0 && n2 == 0) {
// coincident
intersection = true;
}
} else {
var along1 = n1 / d;
var along2 = n2 / d;
if(along1 >= 0 && along1 <= 1 && along2 >=0 && along2 <= 1) {
// intersect
if(!point) {
intersection = true;
} else {
// calculate the intersection point
var x = seg1.x1 + (along1 * x12_11);
var y = seg1.y1 + (along1 * y12_11);
intersection = new OpenLayers.Geometry.Point(x, y);
}
}
}
return intersection;
};
/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
* license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
* full text of the license. */
/**
* @requires OpenLayers/Geometry.js
*/
/**
* Class: OpenLayers.Geometry.Point
* Point geometry class.
*
* Inherits from:
*  - <OpenLayers.Geometry>
*/
OpenLayers.Geometry.Point = OpenLayers.Class(OpenLayers.Geometry, {
/**
* APIProperty: x
* {float}
*/
x: null,
/**
* APIProperty: y
* {float}
*/
y: null,
/**
* Constructor: OpenLayers.Geometry.Point
* Construct a point geometry.
*
* Parameters:
* x - {float}
* y - {float}
*
*/
initialize: function(x, y) {
OpenLayers.Geometry.prototype.initialize.apply(this, arguments);
this.x = parseFloat(x);
this.y = parseFloat(y);
},
/**
* APIMethod: clone
*
* Returns:
* {<OpenLayers.Geometry.Point>} An exact clone of this OpenLayers.Geometry.Point
*/
clone: function(obj) {
if (obj == null) {
obj = new OpenLayers.Geometry.Point(this.x, this.y);
}
// catch any randomly tagged-on properties
OpenLayers.Util.applyDefaults(obj, this);
return obj;
},
/**
* Method: calculateBounds
* Create a new Bounds based on the lon/lat
*/
calculateBounds: function () {
this.bounds = new OpenLayers.Bounds(this.x, this.y,
this.x, this.y);
},
/**
* APIMethod: distanceTo
*
* Parameters:
* point - {<OpenLayers.Geometry.Point>}
*/
distanceTo: function(point) {
var distance = 0.0;
if ( (this.x != null) && (this.y != null) &&
(point != null) && (point.x != null) && (point.y != null) ) {
var dx2 = Math.pow(this.x - point.x, 2);
var dy2 = Math.pow(this.y - point.y, 2);
distance = Math.sqrt( dx2 + dy2 );
}
return distance;
},
/**
* APIMethod: equals
*
* Parameters:
* xy - {<OpenLayers.Geometry>}
*
* Returns:
* {Boolean} Boolean value indicating whether the passed-in
*          {<OpenLayers.Geometry>} object has the same  components as this
*          note that if ll passed in is null, returns false
*
*/
equals:function(geom) {
var equals = false;
if (geom != null) {
equals = ((this.x == geom.x && this.y == geom.y) ||
(isNaN(this.x) && isNaN(this.y) && isNaN(geom.x) && isNaN(geom.y)));
}
return equals;
},
/**
* Method: toShortString
*
* Returns:
* {String} Shortened String representation of Point object.
*         (ex. <i>"5, 42"</i>)
*/
toShortString: function() {
return (this.x + ", " + this.y);
},
/**
* APIMethod: move
* Moves a point in place
*
* Parameters:
* x - {Float}
* y - {Float}
*/
move: function(x, y) {
this.x = this.x + x;
this.y = this.y + y;
this.clearBounds();
},
/**
* APIMethod: rotate
* Rotate a point around another.
*
* Parameters:
* angle - {Float} Rotation angle in degrees (measured counterclockwise
*                 from the positive x-axis)
* origin - {<OpenLayers.Geometry.Point>} Center point for the rotation
*/
rotate: function(angle, origin) {
angle *= Math.PI / 180;
var radius = this.distanceTo(origin);
var theta = angle + Math.atan2(this.y - origin.y, this.x - origin.x);
this.x = origin.x + (radius * Math.cos(theta));
this.y = origin.y + (radius * Math.sin(theta));
this.clearBounds();
},
/**
* APIMethod: resize
* Resize a point relative to some origin.  For points, this has the effect
*     of scaling a vector (from the origin to the point).  This method is
*     more useful on geometry collection subclasses.
*
* Parameters:
* scale - {Float} Ratio of the new distance from the origin to the old
*                 distance from the origin.  A scale of 2 doubles the
*                 distance between the point and origin.
* origin - {<OpenLayers.Geometry.Point>} Point of origin for resizing
* ratio - {Float} Optional x:y ratio for resizing.  Default ratio is 1.
*/
resize: function(scale, origin, ratio) {
ratio = (ratio == undefined) ? 1 : ratio;
this.x = origin.x + (scale * ratio * (this.x - origin.x));
this.y = origin.y + (scale * (this.y - origin.y));
this.clearBounds();
},
/**
* APIMethod: intersects
* Determine if the input geometry intersects this one.
*
* Parameters:
* geometry - {<OpenLayers.Geometry>} Any type of geometry.
*
* Returns:
* {Boolean} The input geometry intersects this one.
*/
intersects: function(geometry) {
var intersect = false;
if(geometry.CLASS_NAME == "OpenLayers.Geometry.Point") {
intersect = this.equals(geometry);
} else {
intersect = geometry.intersects(this);
}
return intersect;
},
/**
* APIMethod: transform
* Translate the x,y properties of the point from source to dest.
*
* Parameters:
* source - {<OpenLayers.Projection>}
* dest - {<OpenLayers.Projection>}
*
* Returns:
* {<OpenLayers.Geometry>}
*/
transform: function(source, dest) {
if ((source && dest)) {
OpenLayers.Projection.transform(
this, source, dest);
}
return this;
},
CLASS_NAME: "OpenLayers.Geometry.Point"
});
/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
* license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
* full text of the license. */
/**
* Class: OpenLayers.Renderer
* This is the base class for all renderers.
*
* This is based on a merger code written by Paul Spencer and Bertil Chapuis.
* It is largely composed of virtual functions that are to be implemented
* in technology-specific subclasses, but there is some generic code too.
*
* The functions that *are* implemented here merely deal with the maintenance
*  of the size and extent variables, as well as the cached 'resolution'
*  value.
*
* A note to the user that all subclasses should use getResolution() instead
*  of directly accessing this.resolution in order to correctly use the
*  cacheing system.
*
*/
OpenLayers.Renderer = OpenLayers.Class({
/**
* Property: container
* {DOMElement}
*/
container: null,
/**
* Property: extent
* {<OpenLayers.Bounds>}
*/
extent: null,
/**
* Property: size
* {<OpenLayers.Size>}
*/
size: null,
/**
* Property: resolution
* {Float} cache of current map resolution
*/
resolution: null,
/**
* Property: map
* {<OpenLayers.Map>} Reference to the map -- this is set in Vector's setMap()
*/
map: null,
/**
* Constructor: OpenLayers.Renderer
*
* Parameters:
* containerID - {<String>}
*/
initialize: function(containerID) {
this.container = OpenLayers.Util.getElement(containerID);
},
/**
* APIMethod: destroy
*/
destroy: function() {
this.container = null;
this.extent = null;
this.size =  null;
this.resolution = null;
this.map = null;
},
/**
* APIMethod: supported
* This should be overridden by specific subclasses
*
* Returns:
* {Boolean} Whether or not the browser supports the renderer class
*/
supported: function() {
return false;
},
/**
* Method: setExtent
* Set the visible part of the layer.
*
* Resolution has probably changed, so we nullify the resolution
* cache (this.resolution) -- this way it will be re-computed when
* next it is needed.
*
* Parameters:
* extent - {<OpenLayers.Bounds>}
*/
setExtent: function(extent) {
this.extent = extent.clone();
this.resolution = null;
},
/**
* Method: setSize
* Sets the size of the drawing surface.
*
* Resolution has probably changed, so we nullify the resolution
* cache (this.resolution) -- this way it will be re-computed when
* next it is needed.
*
* Parameters:
* size - {<OpenLayers.Size>}
*/
setSize: function(size) {
this.size = size.clone();
this.resolution = null;
},
/**
* Method: getResolution
* Uses cached copy of resolution if available to minimize computing
*
* Returns:
* The current map's resolution
*/
getResolution: function() {
this.resolution = this.resolution || this.map.getResolution();
return this.resolution;
},
/**
* Method: drawFeature
* Draw the feature.  The optional style argument can be used
* to override the feature's own style.  This method should only
* be called from layer.drawFeature().
*
* Parameters:
* feature - {<OpenLayers.Feature.Vector>}
* style - {<Object>}
*/
drawFeature: function(feature, style) {
if(style == null) {
style = feature.style;
}
if (feature.geometry) {
this.drawGeometry(feature.geometry, style, feature.id);
}
},
/**
* Method: drawGeometry
*
* Draw a geometry.  This should only be called from the renderer itself.
* Use layer.drawFeature() from outside the renderer.
* virtual function
*
* Parameters:
* geometry - {<OpenLayers.Geometry>}
* style - {Object}
* featureId - {<String>}
*/
drawGeometry: function(geometry, style, featureId) {},
/**
* Method: clear
* Clear all vectors from the renderer.
* virtual function.
*/
clear: function() {},
/**
* Method: getFeatureIdFromEvent
* Returns a feature id from an event on the renderer.
* How this happens is specific to the renderer.  This should be
* called from layer.getFeatureFromEvent().
* Virtual function.
*
* Parameters:
* evt - {<OpenLayers.Event>}
*
* Returns:
* {String} A feature id or null.
*/
getFeatureIdFromEvent: function(evt) {},
/**
* Method: eraseFeatures
* This is called by the layer to erase features
*
* Parameters:
* features - {Array(<OpenLayers.Feature.Vector>)}
*/
eraseFeatures: function(features) {
if(!(features instanceof Array)) {
features = [features];
}
for(var i=0; i<features.length; ++i) {
this.eraseGeometry(features[i].geometry);
}
},
/**
* Method: eraseGeometry
* Remove a geometry from the renderer (by id).
* virtual function.
*
* Parameters:
* geometry - {<OpenLayers.Geometry>}
*/
eraseGeometry: function(geometry) {},
CLASS_NAME: "OpenLayers.Renderer"
});
/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
* license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
* full text of the license. */
/**
* @requires OpenLayers/Renderer.js
*/
/**
* Class: OpenLayers.Renderer.Elements
* This is another virtual class in that it should never be instantiated by
*  itself as a Renderer. It exists because there is *tons* of shared
*  functionality between different vector libraries which use nodes/elements
*  as a base for rendering vectors.
*
* The highlevel bits of code that are implemented here are the adding and
*  removing of geometries, which is essentially the same for any
*  element-based renderer. The details of creating each node and drawing the
*  paths are of course different, but the machinery is the same.
*
* Inherits:
*  - <OpenLayers.Renderer>
*/
OpenLayers.Renderer.Elements = OpenLayers.Class(OpenLayers.Renderer, {
/**
* Property: rendererRoot
* {DOMElement}
*/
rendererRoot: null,
/**
* Property: root
* {DOMElement}
*/
root: null,
/**
* Property: xmlns
* {String}
*/
xmlns: null,
/**
* Property: minimumSymbolizer
* {Object}
*/
minimumSymbolizer: {
strokeLinecap: "round",
strokeOpacity: 1,
fillOpacity: 1,
pointRadius: 0
},
/**
* Constructor: OpenLayers.Renderer.Elements
*
* Parameters:
* containerID - {String}
*/
initialize: function(containerID) {
OpenLayers.Renderer.prototype.initialize.apply(this, arguments);
this.rendererRoot = this.createRenderRoot();
this.root = this.createRoot();
this.rendererRoot.appendChild(this.root);
this.container.appendChild(this.rendererRoot);
},
/**
* Method: destroy
*/
destroy: function() {
this.clear();
this.rendererRoot = null;
this.root = null;
this.xmlns = null;
OpenLayers.Renderer.prototype.destroy.apply(this, arguments);
},
/**
* Method: clear
* Remove all the elements from the root
*/
clear: function() {
if (this.root) {
while (this.root.childNodes.length > 0) {
this.root.removeChild(this.root.firstChild);
}
}
},
/**
* Method: getNodeType
* This function is in charge of asking the specific renderer which type
*     of node to create for the given geometry and style. All geometries
*     in an Elements-based renderer consist of one node and some
*     attributes. We have the nodeFactory() function which creates a node
*     for us, but it takes a 'type' as input, and that is precisely what
*     this function tells us.
*
* Parameters:
* geometry - {<OpenLayers.Geometry>}
* style - {Object}
*
* Returns:
* {String} The corresponding node type for the specified geometry
*/
getNodeType: function(geometry, style) { },
/**
* Method: drawGeometry
* Draw the geometry, creating new nodes, setting paths, setting style,
*     setting featureId on the node.  This method should only be called
*     by the renderer itself.
*
* Parameters:
* geometry - {<OpenLayers.Geometry>}
* style - {Object}
* featureId - {String}
*/
drawGeometry: function(geometry, style, featureId) {
var className = geometry.CLASS_NAME;
if ((className == "OpenLayers.Geometry.Collection") ||
(className == "OpenLayers.Geometry.MultiPoint") ||
(className == "OpenLayers.Geometry.MultiLineString") ||
(className == "OpenLayers.Geometry.MultiPolygon")) {
for (var i = 0; i < geometry.components.length; i++) {
this.drawGeometry(geometry.components[i], style, featureId);
}
return;
};
if (style.display != "none") {
//first we create the basic node and add it to the root
var nodeType = this.getNodeType(geometry, style);
var node = this.nodeFactory(geometry.id, nodeType);
node._featureId = featureId;
node._geometryClass = geometry.CLASS_NAME;
node._style = style;
//now actually draw the node, and style it
node = this.drawGeometryNode(node, geometry);
// append the node to root (but only if it's new)
if (node.parentNode != this.root) {
this.root.appendChild(node);
}
this.postDraw(node);
} else {
node = OpenLayers.Util.getElement(geometry.id);
if (node) {
node.parentNode.removeChild(node);
}
}
},
/**
* Method: drawGeometryNode
* Given a node, draw a geometry on the specified layer.
*     node and geometry are required arguments, style is optional.
*     This method is only called by the render itself.
*
* Parameters:
* node - {DOMElement}
* geometry - {<OpenLayers.Geometry>}
* style - {Object}
*/
drawGeometryNode: function(node, geometry, style) {
style = style || node._style;
OpenLayers.Util.applyDefaults(style, this.minimumSymbolizer);
var options = {
'isFilled': true,
'isStroked': !!style.strokeWidth
};
switch (geometry.CLASS_NAME) {
case "OpenLayers.Geometry.Point":
this.drawPoint(node, geometry);
break;
case "OpenLayers.Geometry.LineString":
options.isFilled = false;
this.drawLineString(node, geometry);
break;
case "OpenLayers.Geometry.LinearRing":
this.drawLinearRing(node, geometry);
break;
case "OpenLayers.Geometry.Polygon":
this.drawPolygon(node, geometry);
break;
case "OpenLayers.Geometry.Surface":
this.drawSurface(node, geometry);
break;
case "OpenLayers.Geometry.Rectangle":
this.drawRectangle(node, geometry);
break;
default:
break;
}
node._style = style;
node._options = options;
//set style
//TBD simplify this
return this.setStyle(node, style, options, geometry);
},
/**
* Method: postDraw
* Things that have do be done after the geometry node is appended
* to its parent node. To be overridden by subclasses.
*
* Parameters:
* node - {DOMElement}
*/
postDraw: function(node) {},
/**
* Method: drawPoint
* Virtual function for drawing Point Geometry.
* Should be implemented by subclasses.
* This method is only called by the renderer itself.
*
* Parameters:
* node - {DOMElement}
* geometry - {<OpenLayers.Geometry>}
*/
drawPoint: function(node, geometry) {},
/**
* Method: drawLineString
* Virtual function for drawing LineString Geometry.
* Should be implemented by subclasses.
* This method is only called by the renderer itself.
*
* Parameters:
* node - {DOMElement}
* geometry - {<OpenLayers.Geometry>}
*/
drawLineString: function(node, geometry) {},
/**
* Method: drawLinearRing
* Virtual function for drawing LinearRing Geometry.
* Should be implemented by subclasses.
* This method is only called by the renderer itself.
*
* Parameters:
* node - {DOMElement}
* geometry - {<OpenLayers.Geometry>}
*/
drawLinearRing: function(node, geometry) {},
/**
* Method: drawPolygon
* Virtual function for drawing Polygon Geometry.
* Should be implemented by subclasses.
* This method is only called by the renderer itself.
*
* Parameters:
* node - {DOMElement}
* geometry - {<OpenLayers.Geometry>}
*/
drawPolygon: function(node, geometry) {},
/**
* Method: drawRectangle
* Virtual function for drawing Rectangle Geometry.
* Should be implemented by subclasses.
* This method is only called by the renderer itself.
*
* Parameters:
* node - {DOMElement}
* geometry - {<OpenLayers.Geometry>}
*/
drawRectangle: function(node, geometry) {},
/**
* Method: drawCircle
* Virtual function for drawing Circle Geometry.
* Should be implemented by subclasses.
* This method is only called by the renderer itself.
*
* Parameters:
* node - {DOMElement}
* geometry - {<OpenLayers.Geometry>}
*/
drawCircle: function(node, geometry) {},
/**
* Method: drawSurface
* Virtual function for drawing Surface Geometry.
* Should be implemented by subclasses.
* This method is only called by the renderer itself.
*
* Parameters:
* node - {DOMElement}
* geometry - {<OpenLayers.Geometry>}
*/
drawSurface: function(node, geometry) {},
/**
* Method: getFeatureIdFromEvent
*
* Parameters:
* evt - {Object} An <OpenLayers.Event> object
*
* Returns:
* {<OpenLayers.Geometry>} A geometry from an event that
*                         happened on a layer
*/
getFeatureIdFromEvent: function(evt) {
var node = evt.target || evt.srcElement;
return node._featureId;
},
/**
* Method: eraseGeometry
* Erase a geometry from the renderer. In the case of a multi-geometry,
*     we cycle through and recurse on ourselves. Otherwise, we look for a
*     node with the geometry.id, destroy its geometry, and remove it from
*     the DOM.
*
* Parameters:
* geometry - {<OpenLayers.Geometry>}
*/
eraseGeometry: function(geometry) {
if ((geometry.CLASS_NAME == "OpenLayers.Geometry.MultiPoint") ||
(geometry.CLASS_NAME == "OpenLayers.Geometry.MultiLineString") ||
(geometry.CLASS_NAME == "OpenLayers.Geometry.MultiPolygon")) {
for (var i = 0; i < geometry.components.length; i++) {
this.eraseGeometry(geometry.components[i]);
}
} else {
var element = OpenLayers.Util.getElement(geometry.id);
if (element && element.parentNode) {
element.parentNode.removeChild(element);
}
}
},
/**
* Method: nodeFactory
* Create new node of the specified type, with the (optional) specified id.
*
* If node already exists with same ID and type, we remove it and then
*  call ourselves again to recreate it.
*
* Parameters:
* id - {String}
* type - {String} type Kind of node to draw
*
* Returns:
* {DOMElement} A new node of the given type and id
*/
nodeFactory: function(id, type) {
var node = OpenLayers.Util.getElement(id);
if (node) {
if (!this.nodeTypeCompare(node, type)) {
node.parentNode.removeChild(node);
node = this.nodeFactory(id, type);
}
} else {
node = this.createNode(type, id);
}
return node;
},
CLASS_NAME: "OpenLayers.Renderer.Elements"
});
/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
* license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
* full text of the license. */
/**
* @requires OpenLayers/Util.js
* @requires OpenLayers/Feature/Vector.js
*/
/**
* Class: OpenLayers.Style
* This class represents a UserStyle obtained
*     from a SLD, containing styling rules.
*/
OpenLayers.Style = OpenLayers.Class({
/**
* APIProperty: name
* {String}
*/
name: null,
/**
* Property: title
* {String} Title of this style (set if included in SLD)
*/
title: null,
/**
* Property: description
* {String} Description of this style (set if abstract is included in SLD)
*/
description: null,
/**
* APIProperty: layerName
* {<String>} name of the layer that this style belongs to, usually
* according to the NamedLayer attribute of an SLD document.
*/
layerName: null,
/**
* APIProperty: isDefault
* {Boolean}
*/
isDefault: false,
/**
* Property: rules
* {Array(<OpenLayers.Rule>)}
*/
rules: null,
/**
* Property: context
* {Object} An optional object with properties that symbolizers' property
* values should be evaluatad against. If no context is specified,
* feature.attributes will be used
*/
context: null,
/**
* Property: defaultStyle
* {Object} hash of style properties to use as default for merging
* rule-based style symbolizers onto. If no rules are defined,
* createSymbolizer will return this style.
*/
defaultStyle: null,
/**
* Property: propertyStyles
* {Hash of Boolean} cache of style properties that need to be parsed for
* propertyNames. Property names are keys, values won't be used.
*/
propertyStyles: null,
/**
* Constructor: OpenLayers.Style
* Creates a UserStyle.
*
* Parameters:
* style        - {Object} Optional hash of style properties that will be
*                used as default style for this style object. This style
*                applies if no rules are specified. Symbolizers defined in
*                rules will extend this default style.
* options      - {Object} An optional object with properties to set on the
*                userStyle
*
* Return:
* {<OpenLayers.Style>}
*/
initialize: function(style, options) {
this.rules = [];
// use the default style from OpenLayers.Feature.Vector if no style
// was given in the constructor
this.setDefaultStyle(style ||
OpenLayers.Feature.Vector.style["default"]);
OpenLayers.Util.extend(this, options);
},
/**
* APIMethod: destroy
* nullify references to prevent circular references and memory leaks
*/
destroy: function() {
for (var i=0; i<this.rules.length; i++) {
this.rules[i].destroy();
this.rules[i] = null;
}
this.rules = null;
this.defaultStyle = null;
},
/**
* Method: createSymbolizer
* creates a style by applying all feature-dependent rules to the base
* style.
*
* Parameters:
* feature - {<OpenLayers.Feature>} feature to evaluate rules for
*
* Returns:
* {Object} symbolizer hash
*/
createSymbolizer: function(feature) {
var style = this.createLiterals(
OpenLayers.Util.extend({}, this.defaultStyle), feature);
var rules = this.rules;
var rule, context;
var elseRules = [];
var appliedRules = false;
for(var i=0; i<rules.length; i++) {
rule = rules[i];
// does the rule apply?
var applies = rule.evaluate(feature);
if(applies) {
if(rule instanceof OpenLayers.Rule && rule.elseFilter) {
elseRules.push(rule);
} else {
appliedRules = true;
this.applySymbolizer(rule, style, feature);
}
}
}
// if no other rules apply, apply the rules with else filters
if(appliedRules == false && elseRules.length > 0) {
appliedRules = true;
for(var i=0; i<elseRules.length; i++) {
this.applySymbolizer(elseRules[i], style, feature);
}
}
// don't display if there were rules but none applied
if(rules.length > 0 && appliedRules == false) {
style.display = "none";
} else {
style.display = "";
}
return style;
},
/**
* Method: applySymbolizer
*
* Parameters:
* rule - {OpenLayers.Rule}
* style - {Object}
* feature - {<OpenLayer.Feature.Vector>}
*
* Returns:
* {Object} A style with new symbolizer applied.
*/
applySymbolizer: function(rule, style, feature) {
var symbolizerPrefix = feature.geometry ?
this.getSymbolizerPrefix(feature.geometry) :
OpenLayers.Style.SYMBOLIZER_PREFIXES[0];
var symbolizer = rule.symbolizer[symbolizerPrefix] || rule.symbolizer;
// merge the style with the current style
return this.createLiterals(
OpenLayers.Util.extend(style, symbolizer), feature);
},
/**
* Method: createLiterals
* creates literals for all style properties that have an entry in
* <this.propertyStyles>.
*
* Parameters:
* style   - {Object} style to create literals for. Will be modified
*           inline.
* feature - {Object}
*
* Returns:
* {Object} the modified style
*/
createLiterals: function(style, feature) {
var context = this.context || feature.attributes || feature.data;
for (var i in this.propertyStyles) {
style[i] = OpenLayers.Style.createLiteral(style[i], context, feature);
}
return style;
},
/**
* Method: findPropertyStyles
* Looks into all rules for this style and the defaultStyle to collect
* all the style hash property names containing ${...} strings that have
* to be replaced using the createLiteral method before returning them.
*
* Returns:
* {Object} hash of property names that need createLiteral parsing. The
* name of the property is the key, and the value is true;
*/
findPropertyStyles: function() {
var propertyStyles = {};
// check the default style
var style = this.defaultStyle;
this.addPropertyStyles(propertyStyles, style);
// walk through all rules to check for properties in their symbolizer
var rules = this.rules;
var symbolizer, value;
for (var i=0; i<rules.length; i++) {
var symbolizer = rules[i].symbolizer;
for (var key in symbolizer) {
value = symbolizer[key];
if (typeof value == "object") {
// symbolizer key is "Point", "Line" or "Polygon"
this.addPropertyStyles(propertyStyles, value);
} else {
// symbolizer is a hash of style properties
this.addPropertyStyles(propertyStyles, symbolizer);
break;
}
}
}
return propertyStyles;
},
/**
* Method: addPropertyStyles
*
* Parameters:
* propertyStyles - {Object} hash to add new property styles to. Will be
*                  modified inline
* symbolizer     - {Object} search this symbolizer for property styles
*
* Returns:
* {Object} propertyStyles hash
*/
addPropertyStyles: function(propertyStyles, symbolizer) {
var property;
for (var key in symbolizer) {
property = symbolizer[key];
if (typeof property == "string" &&
property.match(/\$\{\w+\}/)) {
propertyStyles[key] = true;
}
}
return propertyStyles;
},
/**
* APIMethod: addRules
* Adds rules to this style.
*
* Parameters:
* rules - {Array(<OpenLayers.Rule>)}
*/
addRules: function(rules) {
this.rules = this.rules.concat(rules);
this.propertyStyles = this.findPropertyStyles();
},
/**
* APIMethod: setDefaultStyle
* Sets the default style for this style object.
*
* Parameters:
* style - {Object} Hash of style properties
*/
setDefaultStyle: function(style) {
this.defaultStyle = style;
this.propertyStyles = this.findPropertyStyles();
},
/**
* Method: getSymbolizerPrefix
* Returns the correct symbolizer prefix according to the
* geometry type of the passed geometry
*
* Parameters:
* geometry {<OpenLayers.Geometry>}
*
* Returns:
* {String} key of the according symbolizer
*/
getSymbolizerPrefix: function(geometry) {
var prefixes = OpenLayers.Style.SYMBOLIZER_PREFIXES;
for (var i=0; i<prefixes.length; i++) {
if (geometry.CLASS_NAME.indexOf(prefixes[i]) != -1) {
return prefixes[i];
}
}
},
CLASS_NAME: "OpenLayers.Style"
});
/**
* Function: createLiteral
* converts a style value holding a combination of PropertyName and Literal
* into a Literal, taking the property values from the passed features.
*
* Parameters:
* value - {String} value to parse. If this string contains a construct like
*         "foo ${bar}", then "foo " will be taken as literal, and "${bar}"
*         will be replaced by the value of the "bar" attribute of the passed
*         feature.
* context - {Object} context to take attribute values from
* feature - {OpenLayers.Feature.Vector} The feature that will be passed
*     to <OpenLayers.String.format> for evaluating functions in the context.
*
* Returns:
* {String} the parsed value. In the example of the value parameter above, the
* result would be "foo valueOfBar", assuming that the passed feature has an
* attribute named "bar" with the value "valueOfBar".
*/
OpenLayers.Style.createLiteral = function(value, context, feature) {
if (typeof value == "string" && value.indexOf("${") != -1) {
value = OpenLayers.String.format(value, context, [feature]);
value = (isNaN(value) || !value) ? value : parseFloat(value);
}
return value;
};
/**
* Constant: OpenLayers.Style.SYMBOLIZER_PREFIXES
* {Array} prefixes of the sld symbolizers. These are the
* same as the main geometry types
*/
OpenLayers.Style.SYMBOLIZER_PREFIXES = ['Point', 'Line', 'Polygon'];
/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
* license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
* full text of the license. */
/**
* @requires OpenLayers/Style.js
* @requires OpenLayers/Feature/Vector.js
*/
/**
* Class: OpenLayers.StyleMap
*/
OpenLayers.StyleMap = OpenLayers.Class({
/**
* Property: styles
* Hash of {<OpenLayers.Style>}, keyed by names of well known
* rendering intents (e.g. "default", "temporary", "select").
*/
styles: null,
/**
* Property: extendDefault
* {Boolean} if true, every render intent will extend the symbolizers
* specified for the "default" intent at rendering time. Otherwise, every
* rendering intent will be treated as a completely independent style.
*/
extendDefault: true,
/**
* Constructor: OpenLayers.StyleMap
*
* Parameters:
* style   - {Object} Optional. Either a style hash, or a style object, or
*           a hash of style objects (style hashes) keyed by rendering
*           intent. If just one style hash or style object is passed,
*           this will be used for all known render intents (default,
*           select, temporary)
* options - {Object} optional hash of additional options for this
*           instance
*/
initialize: function (style, options) {
this.styles = {
"default": new OpenLayers.Style(
OpenLayers.Feature.Vector.style["default"]),
"select": new OpenLayers.Style(
OpenLayers.Feature.Vector.style["select"]),
"temporary": new OpenLayers.Style(
OpenLayers.Feature.Vector.style["temporary"])
};
// take whatever the user passed as style parameter and convert it
// into parts of stylemap.
if(style instanceof OpenLayers.Style) {
// user passed a style object
this.styles["default"] = style;
this.styles["select"] = style;
this.styles["temporary"] = style;
} else if(typeof style == "object") {
for(var key in style) {
if(style[key] instanceof OpenLayers.Style) {
// user passed a hash of style objects
this.styles[key] = style[key];
} else if(typeof style[key] == "object") {
// user passsed a hash of style hashes
this.styles[key] = new OpenLayers.Style(style[key]);
} else {
// user passed a style hash (i.e. symbolizer)
this.styles["default"] = new OpenLayers.Style(style);
this.styles["select"] = new OpenLayers.Style(style);
this.styles["temporary"] = new OpenLayers.Style(style);
break;
}
}
}
OpenLayers.Util.extend(this, options);
},
/**
* Method: destroy
*/
destroy: function() {
for(var key in this.styles) {
this.styles[key].destroy();
}
this.styles = null;
},
/**
* Method: createSymbolizer
* Creates the symbolizer for a feature for a render intent.
*
* Parameters:
* feature - {<OpenLayers.Feature>} The feature to evaluate the rules
*           of the intended style against.
* intent  - {String} The intent determines the symbolizer that will be
*           used to draw the feature. Well known intents are "default"
*           (for just drawing the features), "select" (for selected
*           features) and "temporary" (for drawing features).
*
* Returns:
* {Object} symbolizer hash
*/
createSymbolizer: function(feature, intent) {
if(!feature) {
feature = new OpenLayers.Feature.Vector();
}
if(!this.styles[intent]) {
intent = "default";
}
feature.renderIntent = intent;
var defaultSymbolizer = {};
if(this.extendDefault && intent != "default") {
defaultSymbolizer = this.styles["default"].createSymbolizer(feature);
}
return OpenLayers.Util.extend(defaultSymbolizer,
this.styles[intent].createSymbolizer(feature));
},
/**
* Method: addUniqueValueRules
* Convenience method to create comparison rules for unique values of a
* property. The rules will be added to the style object for a specified
* rendering intent. This method is a shortcut for creating something like
* the "unique value legends" familiar from well known desktop GIS systems
*
* Parameters:
* renderIntent - {String} rendering intent to add the rules to
* property     - {String} values of feature attributes to create the
*                rules for
* symbolizers  - {Object} Hash of symbolizers, keyed by the desired
*                property values
*/
addUniqueValueRules: function(renderIntent, property, symbolizers) {
var rules = [];
for (var value in symbolizers) {
rules.push(new OpenLayers.Rule({
symbolizer: symbolizers[value],
filter: new OpenLayers.Filter.Comparison({
type: OpenLayers.Filter.Comparison.EQUAL_TO,
property: property,
value: value
})
}));
}
this.styles[renderIntent].addRules(rules);
},
CLASS_NAME: "OpenLayers.StyleMap"
});
/* Copyright (c) 2006 MetaCarta, Inc., published under a modified BSD license.
* See http://svn.openlayers.org/trunk/openlayers/repository-license.txt
* for the full text of the license. */
/**
* @requires OpenLayers/Util.js
* @requires OpenLayers/Style.js
*/
/**
* Class: OpenLayers.Rule
* This class represents an SLD Rule, as being used for rule-based SLD styling.
*/
OpenLayers.Rule = OpenLayers.Class({
/**
* Property: id
* {String} A unique id for this session.
*/
id: null,
/**
* APIProperty: name
* {String} name of this rule
*/
name: 'default',
/**
* Property: title
* {String} Title of this rule (set if included in SLD)
*/
title: null,
/**
* Property: description
* {String} Description of this rule (set if abstract is included in SLD)
*/
description: null,
/**
* Property: context
* {Object} An optional object with properties that the rule should be
* evaluatad against. If no context is specified, feature.attributes will
* be used.
*/
context: null,
/**
* Property: filter
* {<OpenLayers.Filter>} Optional filter for the rule.
*/
filter: null,
/**
* Property: elseFilter
* {Boolean} Determines whether this rule is only to be applied only if
* no other rules match (ElseFilter according to the SLD specification).
* Default is false.  For instances of OpenLayers.Rule, if elseFilter is
* false, the rule will always apply.  For subclasses, the else property is
* ignored.
*/
elseFilter: false,
/**
* Property: symbolizer
* {Object} Symbolizer or hash of symbolizers for this rule. If hash of
* symbolizers, keys are one or more of ["Point", "Line", "Polygon"]
*/
symbolizer: null,
/**
* APIProperty: minScaleDenominator
* {Number} or {String} minimum scale at which to draw the feature.
* In the case of a String, this can be a combination of text and
* propertyNames in the form "literal ${propertyName}"
*/
minScaleDenominator: null,
/**
* APIProperty: maxScaleDenominator
* {Number} or {String} maximum scale at which to draw the feature.
* In the case of a String, this can be a combination of text and
* propertyNames in the form "literal ${propertyName}"
*/
maxScaleDenominator: null,
/**
* Constructor: OpenLayers.Rule
* Creates a Rule.
*
* Parameters:
* options - {Object} An optional object with properties to set on the
*           rule
*
* Returns:
* {<OpenLayers.Rule>}
*/
initialize: function(options) {
this.id = OpenLayers.Util.createUniqueID(this.CLASS_NAME + "_");
this.symbolizer = {};
OpenLayers.Util.extend(this, options);
},
/**
* APIMethod: destroy
* nullify references to prevent circular references and memory leaks
*/
destroy: function() {
for (var i in this.symbolizer) {
this.symbolizer[i] = null;
}
this.symbolizer = null;
},
/**
* APIMethod: evaluate
* evaluates this rule for a specific feature
*
* Parameters:
* feature - {<OpenLayers.Feature>} feature to apply the rule to.
*
* Returns:
* {Boolean} true if the rule applies, false if it does not.
* This rule is the default rule and always returns true.
*/
evaluate: function(feature) {
var context = this.getContext(feature);
var applies = true;
if (this.minScaleDenominator || this.maxScaleDenominator) {
var scale = feature.layer.map.getScale();
}
// check if within minScale/maxScale bounds
if (this.minScaleDenominator) {
applies = scale >= OpenLayers.Style.createLiteral(
this.minScaleDenominator, context);
}
if (applies && this.maxScaleDenominator) {
applies = scale < OpenLayers.Style.createLiteral(
this.maxScaleDenominator, context);
}
// check if optional filter applies
if(applies && this.filter) {
// feature id filters get the feature, others get the context
if(this.filter.CLASS_NAME == "OpenLayers.Filter.FeatureId") {
applies = this.filter.evaluate(feature);
} else {
applies = this.filter.evaluate(context);
}
}
return applies;
},
/**
* Method: getContext
* Gets the context for evaluating this rule
*
* Paramters:
* feature - {<OpenLayers.Feature>} feature to take the context from if
*           none is specified.
*/
getContext: function(feature) {
var context = this.context;
if (!context) {
context = feature.attributes || feature.data;
}
return context;
},
CLASS_NAME: "OpenLayers.Rule"
});
/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
* license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
* full text of the license. */
/**
* @requires OpenLayers/Util.js
*/
/**
* Class: OpenLayers.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({
/**
* APIProperty: externalProjection
* {<OpenLayers.Projection>} 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
*     {<OpenLayers.Projection.addTransform>} for more information on
*     custom transformations.
*/
externalProjection: null,
/**
* APIProperty: internalProjection
* {<OpenLayers.Projection>} 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
*     {<OpenLayers.Projection.addTransform>} for more information on
*     custom transformations.
*/
internalProjection: null,
/**
* 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
*
* Returns:
* An instance of OpenLayers.Format
*/
initialize: function(options) {
OpenLayers.Util.extend(this, options);
},
/**
* 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) {
alert(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) {
alert(OpenLayers.i18n("writeNotImplemented"));
},
CLASS_NAME: "OpenLayers.Format"
});
/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
* license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
* full text of the license. */
/**
* @requires OpenLayers/Format.js
*/
/**
* Class: OpenLayers.Format.XML
* Read and write XML.  For cross-browser XML generation, use methods on an
*     instance of the XML format class instead of on <code>document<end>.
*     The DOM creation and traversing methods exposed here all mimic the
*     W3C XML DOM methods.  Create a new parser with the
*     <OpenLayers.Format.XML> constructor.
*
* Inherits from:
*  - <OpenLayers.Format>
*/
OpenLayers.Format.XML = OpenLayers.Class(OpenLayers.Format, {
/**
* Property: xmldom
* {XMLDom} If this browser uses ActiveX, this will be set to a XMLDOM
*     object.  It is not intended to be a browser sniffing property.
*     Instead, the xmldom property is used instead of <code>document<end>
*     where namespaced node creation methods are not supported. In all
*     other browsers, this remains null.
*/
xmldom: null,
/**
* Constructor: OpenLayers.Format.XML
* Construct an XML parser.  The parser is used to read and write XML.
*     Reading XML from a string returns a DOM element.  Writing XML from
*     a DOM element returns a string.
*
* Parameters:
* options - {Object} Optional object whose properties will be set on
*     the object.
*/
initialize: function(options) {
if(window.ActiveXObject) {
this.xmldom = new ActiveXObject("Microsoft.XMLDOM");
}
OpenLayers.Format.prototype.initialize.apply(this, [options]);
},
/**
* APIMethod: read
* Deserialize a XML string and return a DOM node.
*
* Parameters:
* text - {String} A XML string
* Returns:
* {DOMElement} A DOM node
*/
read: function(text) {
var index = text.indexOf('<');
if(index > 0) {
text = text.substring(index);
}
var node = OpenLayers.Util.Try(
OpenLayers.Function.bind((
function() {
var xmldom;
/**
* Since we want to be able to call this method on the prototype
* itself, this.xmldom may not exist even if in IE.
*/
if(window.ActiveXObject && !this.xmldom) {
xmldom = new ActiveXObject("Microsoft.XMLDOM");
} else {
xmldom = this.xmldom;
}
xmldom.loadXML(text);
return xmldom;
}
), this),
function() {
return new DOMParser().parseFromString(text, 'text/xml');
},
function() {
var req = new XMLHttpRequest();
req.open("GET", "data:" + "text/xml" +
";charset=utf-8," + encodeURIComponent(text), false);
if(req.overrideMimeType) {
req.overrideMimeType("text/xml");
}
req.send(null);
return req.responseXML;
}
);
return node;
},
/**
* APIMethod: write
* Serialize a DOM node into a XML string.
*
* Parameters:
* node - {DOMElement} A DOM node.
*
* Returns:
* {String} The XML string representation of the input node.
*/
write: function(node) {
var data;
if(this.xmldom) {
data = node.xml;
} else {
var serializer = new XMLSerializer();
if (node.nodeType == 1) {
// Add nodes to a document before serializing. Everything else
// is serialized as is. This may need more work. See #1218 .
var doc = document.implementation.createDocument("", "", null);
if (doc.importNode) {
node = doc.importNode(node, true);
}
doc.appendChild(node);
data = serializer.serializeToString(doc);
} else {
data = serializer.serializeToString(node);
}
}
return data;
},
/**
* APIMethod: createElementNS
* Create a new element with namespace.  This node can be appended to
*     another node with the standard node.appendChild method.  For
*     cross-browser support, this method must be used instead of
*     document.createElementNS.
*
* Parameters:
* uri - {String} Namespace URI for the element.
* name - {String} The qualified name of the element (prefix:localname).
*
* Returns:
* {Element} A DOM element with namespace.
*/
createElementNS: function(uri, name) {
var element;
if(this.xmldom) {
if(typeof uri == "string") {
element = this.xmldom.createNode(1, name, uri);
} else {
element = this.xmldom.createNode(1, name, "");
}
} else {
element = document.createElementNS(uri, name);
}
return element;
},
/**
* APIMethod: createTextNode
* Create a text node.  This node can be appended to another node with
*     the standard node.appendChild method.  For cross-browser support,
*     this method must be used instead of document.createTextNode.
*
* Parameters:
* text - {String} The text of the node.
*
* Returns:
* {DOMElement} A DOM text node.
*/
createTextNode: function(text) {
var node;
if(this.xmldom) {
node = this.xmldom.createTextNode(text);
} else {
node = document.createTextNode(text);
}
return node;
},
/**
* APIMethod: getElementsByTagNameNS
* Get a list of elements on a node given the namespace URI and local name.
*     To return all nodes in a given namespace, use '*' for the name
*     argument.  To return all nodes of a given (local) name, regardless
*     of namespace, use '*' for the uri argument.
*
* Parameters:
* node - {Element} Node on which to search for other nodes.
* uri - {String} Namespace URI.
* name - {String} Local name of the tag (without the prefix).
*
* Returns:
* {NodeList} A node list or array of elements.
*/
getElementsByTagNameNS: function(node, uri, name) {
var elements = [];
if(node.getElementsByTagNameNS) {
elements = node.getElementsByTagNameNS(uri, name);
} else {
// brute force method
var allNodes = node.getElementsByTagName("*");
var potentialNode, fullName;
for(var i=0; i<allNodes.length; ++i) {
potentialNode = allNodes[i];
fullName = (potentialNode.prefix) ?
(potentialNode.prefix + ":" + name) : name;
if((name == "*") || (fullName == potentialNode.nodeName)) {
if((uri == "*") || (uri == potentialNode.namespaceURI)) {
elements.push(potentialNode);
}
}
}
}
return elements;
},
/**
* APIMethod: getAttributeNodeNS
* Get an attribute node given the namespace URI and local name.
*
* Parameters:
* node - {Element} Node on which to search for attribute nodes.
* uri - {String} Namespace URI.
* name - {String} Local name of the attribute (without the prefix).
*
* Returns:
* {DOMElement} An attribute node or null if none found.
*/
getAttributeNodeNS: function(node, uri, name) {
var attributeNode = null;
if(node.getAttributeNodeNS) {
attributeNode = node.getAttributeNodeNS(uri, name);
} else {
var attributes = node.attributes;
var potentialNode, fullName;
for(var i=0; i<attributes.length; ++i) {
potentialNode = attributes[i];
if(potentialNode.namespaceURI == uri) {
fullName = (potentialNode.prefix) ?
(potentialNode.prefix + ":" + name) : name;
if(fullName == potentialNode.nodeName) {
attributeNode = potentialNode;
break;
}
}
}
}
return attributeNode;
},
/**
* APIMethod: getAttributeNS
* Get an attribute value given the namespace URI and local name.
*
* Parameters:
* node - {Element} Node on which to search for an attribute.
* uri - {String} Namespace URI.
* name - {String} Local name of the attribute (without the prefix).
*
* Returns:
* {String} An attribute value or and empty string if none found.
*/
getAttributeNS: function(node, uri, name) {
var attributeValue = "";
if(node.getAttributeNS) {
attributeValue = node.getAttributeNS(uri, name) || "";
} else {
var attributeNode = this.getAttributeNodeNS(node, uri, name);
if(attributeNode) {
attributeValue = attributeNode.nodeValue;
}
}
return attributeValue;
},
/**
* APIMethod: getChildValue
* Get the value of the first child node if it exists, or return an
*     optional default string.  Returns an empty string if no first child
*     exists and no default value is supplied.
*
* Parameters:
* node - {DOMElement} The element used to look for a first child value.
* def - {String} Optional string to return in the event that no
*     first child value exists.
*
* Returns:
* {String} The value of the first child of the given node.
*/
getChildValue: function(node, def) {
var value;
try {
value = node.firstChild.nodeValue;
} catch(e) {
value = (def != undefined) ? def : "";
}
return value;
},
/**
* APIMethod: concatChildValues
* Concatenate the value of all child nodes if any exist, or return an
*     optional default string.  Returns an empty string if no children
*     exist and no default value is supplied.  Not optimized for large
*     numbers of child nodes.
*
* Parameters:
* node - {DOMElement} The element used to look for child values.
* def - {String} Optional string to return in the event that no
*     child exist.
*
* Returns:
* {String} The concatenated value of all child nodes of the given node.
*/
concatChildValues: function(node, def) {
var value = "";
var child = node.firstChild;
var childValue;
while(child) {
childValue = child.nodeValue;
if(childValue) {
value += childValue;
}
child = child.nextSibling;
}
if(value == "" && def != undefined) {
value = def;
}
return value;
},
/**
* APIMethod: hasAttributeNS
* Determine whether a node has a particular attribute matching the given
*     name and namespace.
*
* Parameters:
* node - {Element} Node on which to search for an attribute.
* uri - {String} Namespace URI.
* name - {String} Local name of the attribute (without the prefix).
*
* Returns:
* {Boolean} The node has an attribute matching the name and namespace.
*/
hasAttributeNS: function(node, uri, name) {
var found = false;
if(node.hasAttributeNS) {
found = node.hasAttributeNS(uri, name);
} else {
found = !!this.getAttributeNodeNS(node, uri, name);
}
return found;
},
/**
* APIMethod: setAttributeNS
* Adds a new attribute or changes the value of an attribute with the given
*     namespace and name.
*
* Parameters:
* node - {Element} Element node on which to set the attribute.
* uri - {String} Namespace URI for the attribute.
* name - {String} Qualified name (prefix:localname) for the attribute.
* value - {String} Attribute value.
*/
setAttributeNS: function(node, uri, name, value) {
if(node.setAttributeNS) {
node.setAttributeNS(uri, name, value);
} else {
if(this.xmldom) {
if(uri) {
var attribute = node.ownerDocument.createNode(
2, name, uri
);
attribute.nodeValue = value;
node.setAttributeNode(attribute);
} else {
node.setAttribute(name, value);
}
} else {
throw "setAttributeNS not implemented";
}
}
},
CLASS_NAME: "OpenLayers.Format.XML"
});
/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
* license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
* full text of the license. */
/**
* @requires OpenLayers/Format/XML.js
* @requires OpenLayers/Feature/Vector.js
* @requires OpenLayers/Geometry/Point.js
* @requires OpenLayers/Geometry/LineString.js
* @requires OpenLayers/Geometry/Polygon.js
*/
/**
* Class: OpenLayers.Format.GeoRSS
* Read/write GeoRSS parser. Create a new instance with the
*     <OpenLayers.Format.GeoRSS> constructor.
*
* Inherits from:
*  - <OpenLayers.Format.XML>
*/
OpenLayers.Format.GeoRSS = OpenLayers.Class(OpenLayers.Format.XML, {
/**
* APIProperty: rssns
* {String} RSS namespace to use. Defaults to
*   "http://backend.userland.com/rss2"
*/
rssns: "http://backend.userland.com/rss2",
/**
* APIProperty: featurens
* {String} Feature Attributes namespace.  Defaults to
*    "http://mapserver.gis.umn.edu/mapserver"
*/
featureNS: "http://mapserver.gis.umn.edu/mapserver",
/**
* APIProperty: georssns
* {String} GeoRSS namespace to use.  Defaults to
*     "http://www.georss.org/georss"
*/
georssns: "http://www.georss.org/georss",
/**
* APIProperty: geons
* {String} W3C Geo namespace to use.  Defaults to
*     "http://www.w3.org/2003/01/geo/wgs84_pos#"
*/
geons: "http://www.w3.org/2003/01/geo/wgs84_pos#",
/**
* APIProperty: featureTitle
* {String} Default title for features.  Defaults to "Untitled"
*/
featureTitle: "Untitled",
/**
* APIProperty: featureDescription
* {String} Default description for features.  Defaults to "No Description"
*/
featureDescription: "No Description",
/**
* Property: gmlParse
* {Object} GML Format object for parsing features
* Non-API and only created if necessary
*/
gmlParser: null,
/**
* APIProperty: xy
* {Boolean} Order of the GML coordinate: true:(x,y) or false:(y,x)
* For GeoRSS the default is (y,x), therefore: false
*/
xy: false,
/**
* Constructor: OpenLayers.Format.GeoRSS
* Create a new parser for GeoRSS.
*
* Parameters:
* options - {Object} An optional object whose properties will be set on
*     this instance.
*/
initialize: function(options) {
OpenLayers.Format.XML.prototype.initialize.apply(this, [options]);
},
/**
* Method: createGeometryFromItem
* Return a geometry from a GeoRSS Item.
*
* Parameters:
* item - {DOMElement} A GeoRSS item node.
*
* Returns:
* {<OpenLayers.Geometry>} A geometry representing the node.
*/
createGeometryFromItem: function(item) {
var point = this.getElementsByTagNameNS(item, this.georssns, "point");
var lat = this.getElementsByTagNameNS(item, this.geons, 'lat');
var lon = this.getElementsByTagNameNS(item, this.geons, 'long');
var line = this.getElementsByTagNameNS(item,
this.georssns,
"line");
var polygon = this.getElementsByTagNameNS(item,
this.georssns,
"polygon");
var where = this.getElementsByTagNameNS(item,
this.georssns,
"where");
if (point.length > 0 || (lat.length > 0 && lon.length > 0)) {
var location;
if (point.length > 0) {
location = OpenLayers.String.trim(
point[0].firstChild.nodeValue).split(/\s+/);
if (location.length !=2) {
location = OpenLayers.String.trim(
point[0].firstChild.nodeValue).split(/\s*,\s*/);
}
} else {
location = [parseFloat(lat[0].firstChild.nodeValue),
parseFloat(lon[0].firstChild.nodeValue)];
}
var geometry = new OpenLayers.Geometry.Point(parseFloat(location[1]),
parseFloat(location[0]));
} else if (line.length > 0) {
var coords = OpenLayers.String.trim(line[0].firstChild.nodeValue).split(/\s+/);
var components = [];
var point;
for (var i=0; i < coords.length; i+=2) {
point = new OpenLayers.Geometry.Point(parseFloat(coords[i+1]),
parseFloat(coords[i]));
components.push(point);
}
geometry = new OpenLayers.Geometry.LineString(components);
} else if (polygon.length > 0) {
var coords = OpenLayers.String.trim(polygon[0].firstChild.nodeValue).split(/\s+/);
var components = [];
var point;
for (var i=0; i < coords.length; i+=2) {
point = new OpenLayers.Geometry.Point(parseFloat(coords[i+1]),
parseFloat(coords[i]));
components.push(point);
}
geometry = new OpenLayers.Geometry.Polygon([new OpenLayers.Geometry.LinearRing(components)]);
} else if (where.length > 0) {
if (!this.gmlParser) {
this.gmlParser = new OpenLayers.Format.GML({'xy': this.xy});
}
var feature = this.gmlParser.parseFeature(where[0]);
geometry = feature.geometry;
}
if (geometry && this.internalProjection && this.externalProjection) {
geometry.transform(this.externalProjection,
this.internalProjection);
}
return geometry;
},
/**
* Method: createFeatureFromItem
* Return a feature from a GeoRSS Item.
*
* Parameters:
* item - {DOMElement} A GeoRSS item node.
*
* Returns:
* {<OpenLayers.Feature.Vector>} A feature representing the item.
*/
createFeatureFromItem: function(item) {
var geometry = this.createGeometryFromItem(item);
/* Provide defaults for title and description */
var title = this.getChildValue(item, "*", "title", this.featureTitle);
/* First try RSS descriptions, then Atom summaries */
var description = this.getChildValue(
item, "*", "description",
this.getChildValue(item, "*", "content", this.featureDescription)
);
/* If no link URL is found in the first child node, try the
href attribute */
var link = this.getChildValue(item, "*", "link");
if(!link) {
try {
link = this.getElementsByTagNameNS(item, "*", "link")[0].getAttribute("href");
} catch(e) {
link = null;
}
}
var id = this.getChildValue(item, "*", "id", null);
var data = {
"title": title,
"description": description,
"link": link
};
var feature = new OpenLayers.Feature.Vector(geometry, data);
feature.fid = id;
return feature;
},
/**
* Method: getChildValue
*
* Parameters:
* node - {DOMElement}
* nsuri - {String} Child node namespace uri ("*" for any).
* name - {String} Child node name.
* def - {String} Optional string default to return if no child found.
*
* Returns:
* {String} The value of the first child with the given tag name.  Returns
*     default value or empty string if none found.
*/
getChildValue: function(node, nsuri, name, def) {
var value;
try {
value = this.getElementsByTagNameNS(node, nsuri, name)[0].firstChild.nodeValue;
} catch(e) {
value = (def == undefined) ? "" : def;
}
return value;
},
/**
* APIMethod: read
* Return a list of features from a GeoRSS doc
* Parameters:
* data - {Element}
*
* Returns:
* An Array of <OpenLayers.Feature.Vector>s
*/
read: function(doc) {
if (typeof doc == "string") {
doc = OpenLayers.Format.XML.prototype.read.apply(this, [doc]);
}
/* Try RSS items first, then Atom entries */
var itemlist = null;
itemlist = this.getElementsByTagNameNS(doc, '*', 'item');
if (itemlist.length == 0) {
itemlist = this.getElementsByTagNameNS(doc, '*', 'entry');
}
var numItems = itemlist.length;
var features = new Array(numItems);
for(var i=0; i<numItems; i++) {
features[i] = this.createFeatureFromItem(itemlist[i]);
}
return features;
},
/**
* APIMethod: write
* Accept Feature Collection, and return a string.
*
* Parameters:
* features - {Array(<OpenLayers.Feature.Vector>)} List of features to serialize into a string.
*/
write: function(features) {
var georss;
if(features instanceof Array) {
georss = this.createElementNS(this.rssns, "rss");
for(var i=0; i < features.length; i++) {
georss.appendChild(this.createFeatureXML(features[i]));
}
} else {
georss = this.createFeatureXML(features);
}
return OpenLayers.Format.XML.prototype.write.apply(this, [georss]);
},
/**
* Method: createFeatureXML
* Accept an <OpenLayers.Feature.Vector>, and build a geometry for it.
*
* Parameters:
* feature - {<OpenLayers.Feature.Vector>}
*
* Returns:
* {DOMElement}
*/
createFeatureXML: function(feature) {
var geometryNode = this.buildGeometryNode(feature.geometry);
var featureNode = this.createElementNS(this.rssns, "item");
var titleNode = this.createElementNS(this.rssns, "title");
titleNode.appendChild(this.createTextNode(feature.attributes.title ? feature.attributes.title : ""));
var descNode = this.createElementNS(this.rssns, "description");
descNode.appendChild(this.createTextNode(feature.attributes.description ? feature.attributes.description : ""));
featureNode.appendChild(titleNode);
featureNode.appendChild(descNode);
if (feature.attributes.link) {
var linkNode = this.createElementNS(this.rssns, "link");
linkNode.appendChild(this.createTextNode(feature.attributes.link));
featureNode.appendChild(linkNode);
}
for(var attr in feature.attributes) {
if (attr == "link" || attr == "title" || attr == "description") { continue; }
var attrText = this.createTextNode(feature.attributes[attr]);
var nodename = attr;
if (attr.search(":") != -1) {
nodename = attr.split(":")[1];
}
var attrContainer = this.createElementNS(this.featureNS, "feature:"+nodename);
attrContainer.appendChild(attrText);
featureNode.appendChild(attrContainer);
}
featureNode.appendChild(geometryNode);
return featureNode;
},
/**
* Method: buildGeometryNode
* builds a GeoRSS node with a given geometry
*
* Parameters:
* geometry - {<OpenLayers.Geometry>}
*
* Returns:
* {DOMElement} A gml node.
*/
buildGeometryNode: function(geometry) {
if (this.internalProjection && this.externalProjection) {
geometry = geometry.clone();
geometry.transform(this.internalProjection,
this.externalProjection);
}
var node;
// match Polygon
if (geometry.CLASS_NAME == "OpenLayers.Geometry.Polygon") {
node = this.createElementNS(this.georssns, 'georss:polygon');
node.appendChild(this.buildCoordinatesNode(geometry.components[0]));
}
// match LineString
else if (geometry.CLASS_NAME == "OpenLayers.Geometry.LineString") {
node = this.createElementNS(this.georssns, 'georss:line');
node.appendChild(this.buildCoordinatesNode(geometry));
}
// match Point
else if (geometry.CLASS_NAME == "OpenLayers.Geometry.Point") {
node = this.createElementNS(this.georssns, 'georss:point');
node.appendChild(this.buildCoordinatesNode(geometry));
} else {
throw "Couldn't parse " + geometry.CLASS_NAME;
}
return node;
},
/**
* Method: buildCoordinatesNode
*
* Parameters:
* geometry - {<OpenLayers.Geometry>}
*/
buildCoordinatesNode: function(geometry) {
var points = null;
if (geometry.components) {
points = geometry.components;
}
var path;
if (points) {
var numPoints = points.length;
var parts = new Array(numPoints);
for (var i = 0; i < numPoints; i++) {
parts[i] = points[i].y + " " + points[i].x;
}
path = parts.join(" ");
} else {
path = geometry.y + " " + geometry.x;
}
return this.createTextNode(path);
},
CLASS_NAME: "OpenLayers.Format.GeoRSS"
});
/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
* license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
* full text of the license. */
/**
* Namespace: OpenLayers.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
*     <setCode> method to set this value and the <getCode> 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 <OpenLayers.Lang.translate> 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 <OpenLayers.Lang>
*     dictionary exists for the code, the <OpenLayers.String.defaultLang>
*     will be used.
*/
setCode: function(code) {
var lang;
if(!code) {
code = (OpenLayers.Util.getBrowserName() == "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 <getCode> will be used to determine the appropriate
*     dictionary.  Dictionaries are stored in <OpenLayers.Lang>.
*
* Parameters:
* key - {String} The key for an i18n string value in the dictionary.
* context - {Object} Optional context to be used with
*     <OpenLayers.String.format>.
*
* Returns:
* {String} A internationalized string.
*/
translate: function(key, context) {
var dictionary = OpenLayers.Lang[OpenLayers.Lang.getCode()];
var message = 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 <OpenLayers.Lang.translate>.  Looks up a key from a dictionary
*     based on the current language string. The value of
*     <OpenLayers.Lang.getCode> will be used to determine the appropriate
*     dictionary.  Dictionaries are stored in <OpenLayers.Lang>.
*
* Parameters:
* key - {String} The key for an i18n string value in the dictionary.
* context - {Object} Optional context to be used with
*     <OpenLayers.String.format>.
*
* Returns:
* {String} A internationalized string.
*/
OpenLayers.i18n = OpenLayers.Lang.translate;
/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
* license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
* full text of the license. */
/**
* @requires OpenLayers/Lang.js
*/
/**
* Namespace: OpenLayers.Lang["en"]
* Dictionary for English.  Keys for entries are used in calls to
*     <OpenLayers.Lang.translate>.  Entry bodies are normal strings or
*     strings formatted for use with <OpenLayers.String.format> calls.
*/
OpenLayers.Lang.en = {
'unhandledRequest': "Unhandled request return ${statusText}",
'permalink': "Permalink",
'overlays': "Overlays",
'baseLayer': "Base Layer",
'sameProjection':
"The overview map only works when it is in the same projection as the main map",
'readNotImplemented': "Read not implemented.",
'writeNotImplemented': "Write not implemented.",
'noFID': "Can't update a feature for which there is no FID.",
'errorLoadingGML': "Error in loading GML file ${url}",
'browserNotSupported':
"Your browser does not support vector rendering. Currently supported renderers are:\n${renderers}",
'componentShouldBe': "addFeatures : component should be an ${geomType}",
// console message
'getFeatureError':
"getFeatureFromEvent called on layer with no renderer. This usually means you " +
"destroyed a layer, but not some handler which is associated with it.",
// console message
'minZoomLevelError':
"The minZoomLevel property is only intended for use " +
"with the FixedZoomLevels-descendent layers. That this " +
"wfs layer checks for minZoomLevel is a relic of the" +
"past. We cannot, however, remove it without possibly " +
"breaking OL based applications that may depend on it." +
" Therefore we are deprecating it -- the minZoomLevel " +
"check below will be removed at 3.0. Please instead " +
"use min/max resolution setting as described here: " +
"http://trac.openlayers.org/wiki/SettingZoomLevels",
'commitSuccess': "WFS Transaction: SUCCESS ${response}",
'commitFailed': "WFS Transaction: FAILED ${response}",
'googleWarning':
"The Google Layer was unable to load correctly.<br><br>" +
"To get rid of this message, select a new BaseLayer " +
"in the layer switcher in the upper-right corner.<br><br>" +
"Most likely, this is because the Google Maps library " +
"script was either not included, or does not contain the " +
"correct API key for your site.<br><br>" +
"Developers: For help getting this working correctly, " +
"<a href='http://trac.openlayers.org/wiki/Google' " +
"target='_blank'>click here</a>",
'getLayerWarning':
"The ${layerType} Layer was unable to load correctly.<br><br>" +
"To get rid of this message, select a new BaseLayer " +
"in the layer switcher in the upper-right corner.<br><br>" +
"Most likely, this is because the ${layerLib} library " +
"script was either not correctly included.<br><br>" +
"Developers: For help getting this working correctly, " +
"<a href='http://trac.openlayers.org/wiki/${layerLib}' " +
"target='_blank'>click here</a>",
'scale': "Scale = 1 : ${scaleDenom}",
// console message
'layerAlreadyAdded':
"You tried to add the layer: ${layerName} to the map, but it has already been added",
// console message
'reprojectDeprecated':
"You are using the 'reproject' option " +
"on the ${layerName} layer. This option is deprecated: " +
"its use was designed to support displaying data over commercial " +
"basemaps, but that functionality should now be achieved by using " +
"Spherical Mercator support. More information is available from " +
"http://trac.openlayers.org/wiki/SphericalMercator.",
// console message
'methodDeprecated':
"This method has been deprecated and will be removed in 3.0. " +
"Please use ${newMethod} instead.",
// console message
'boundsAddError': "You must pass both x and y values to the add function.",
// console message
'lonlatAddError': "You must pass both lon and lat values to the add function.",
// console message
'pixelAddError': "You must pass both x and y values to the add function.",
// console message
'unsupportedGeometryType': "Unsupported geometry type: ${geomType}",
// console message
'pagePositionFailed':
"OpenLayers.Util.pagePosition failed: element with id ${elemId} may be misplaced.",
'end': ''
};