Batch merge for rc2 of 2.7. 'svn merge -r7967:HEAD from trunk (Closes #1733) (Closes #1489) (Closes #1639) (Closes #1718) (Closes #1723) (Closes #1732) (Closes #1616) (Closes #1722)
git-svn-id: http://svn.openlayers.org/branches/openlayers/2.7@8012 dc9f47b5-9b13-0410-9fdd-eb0c1a62fdaf
This commit is contained in:
@@ -168,8 +168,6 @@ OpenLayers.Control.Permalink = OpenLayers.Class(OpenLayers.Control, {
|
||||
*/
|
||||
createParams: function(center, zoom, layers) {
|
||||
center = center || this.map.getCenter();
|
||||
zoom = zoom || this.map.getZoom();
|
||||
layers = layers || this.map.layers;
|
||||
|
||||
var params = OpenLayers.Util.getParameters(this.base);
|
||||
|
||||
@@ -177,8 +175,11 @@ OpenLayers.Control.Permalink = OpenLayers.Class(OpenLayers.Control, {
|
||||
// Break out of this function, and simply return the params from the
|
||||
// base link.
|
||||
if (center) {
|
||||
|
||||
params.zoom = this.map.getZoom();
|
||||
|
||||
//zoom
|
||||
params.zoom = zoom || this.map.getZoom();
|
||||
|
||||
//lon,lat
|
||||
var lat = center.lat;
|
||||
var lon = center.lon;
|
||||
|
||||
@@ -192,10 +193,12 @@ OpenLayers.Control.Permalink = OpenLayers.Class(OpenLayers.Control, {
|
||||
}
|
||||
params.lat = Math.round(lat*100000)/100000;
|
||||
params.lon = Math.round(lon*100000)/100000;
|
||||
|
||||
|
||||
//layers
|
||||
layers = layers || this.map.layers;
|
||||
params.layers = '';
|
||||
for (var i=0, len=this.map.layers.length; i<len; i++) {
|
||||
var layer = this.map.layers[i];
|
||||
for (var i=0, len=layers.length; i<len; i++) {
|
||||
var layer = layers[i];
|
||||
|
||||
if (layer.isBaseLayer) {
|
||||
params.layers += (layer == this.map.baseLayer) ? "B" : "0";
|
||||
|
||||
@@ -13,6 +13,12 @@
|
||||
*/
|
||||
OpenLayers.Format = OpenLayers.Class({
|
||||
|
||||
/**
|
||||
* Property: options
|
||||
* {Object} A reference to options passed to the constructor.
|
||||
*/
|
||||
options: null,
|
||||
|
||||
/**
|
||||
* APIProperty: externalProjection
|
||||
* {<OpenLayers.Projection>} When passed a externalProjection and
|
||||
@@ -54,6 +60,14 @@ OpenLayers.Format = OpenLayers.Class({
|
||||
*/
|
||||
initialize: function(options) {
|
||||
OpenLayers.Util.extend(this, options);
|
||||
this.options = options;
|
||||
},
|
||||
|
||||
/**
|
||||
* APIMethod: destroy
|
||||
* Clean up.
|
||||
*/
|
||||
destroy: function() {
|
||||
},
|
||||
|
||||
/**
|
||||
|
||||
525
lib/OpenLayers/Format/GML/Base.js
Normal file
525
lib/OpenLayers/Format/GML/Base.js
Normal file
@@ -0,0 +1,525 @@
|
||||
/* 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
|
||||
*/
|
||||
|
||||
/**
|
||||
* Eventually, this will require the OpenLayers.Format.GML. For now, since
|
||||
* this parser can be included in a lib without the old GML parser, we
|
||||
* declare the namespace if it doesn't exist.
|
||||
*/
|
||||
if(!OpenLayers.Format.GML) {
|
||||
OpenLayers.Format.GML = {};
|
||||
}
|
||||
|
||||
/**
|
||||
* Class: OpenLayers.Format.GML.Base
|
||||
* Superclass for GML parsers.
|
||||
*
|
||||
* Inherits from:
|
||||
* - <OpenLayers.Format.XML>
|
||||
*/
|
||||
OpenLayers.Format.GML.Base = OpenLayers.Class(OpenLayers.Format.XML, {
|
||||
|
||||
/**
|
||||
* Property: namespaces
|
||||
* {Object} Mapping of namespace aliases to namespace URIs.
|
||||
*/
|
||||
namespaces: {
|
||||
gml: "http://www.opengis.net/gml",
|
||||
xlink: "http://www.w3.org/1999/xlink",
|
||||
xsi: "http://www.w3.org/2001/XMLSchema-instance",
|
||||
wfs: "http://www.opengis.net/wfs" // this is a convenience for reading wfs:FeatureCollection
|
||||
},
|
||||
|
||||
/**
|
||||
* Property: defaultPrefix
|
||||
*/
|
||||
defaultPrefix: "gml",
|
||||
|
||||
/**
|
||||
* Property: schemaLocation
|
||||
* {String} Schema location for a particular minor version.
|
||||
*/
|
||||
schemaLocation: null,
|
||||
|
||||
/**
|
||||
* APIProperty: featureType
|
||||
* {String} The local (without prefix) feature typeName.
|
||||
*/
|
||||
featureType: null,
|
||||
|
||||
/**
|
||||
* APIProperty: featureNS
|
||||
* {String} The feature namespace. Must be set in the options at
|
||||
* construction.
|
||||
*/
|
||||
featureNS: null,
|
||||
|
||||
/**
|
||||
* APIProperty: geometry
|
||||
* {String} Name of geometry element. Defaults to "geometry".
|
||||
*/
|
||||
geometryName: "geometry",
|
||||
|
||||
/**
|
||||
* APIProperty: extractAttributes
|
||||
* {Boolean} Extract attributes from GML. Default is true.
|
||||
*/
|
||||
extractAttributes: true,
|
||||
|
||||
/**
|
||||
* APIProperty: srsName
|
||||
* {String} URI for spatial reference system. This is optional for
|
||||
* single part geometries and mandatory for collections and multis.
|
||||
* If set, the srsName attribute will be written for all geometries.
|
||||
* Default is null.
|
||||
*/
|
||||
srsName: null,
|
||||
|
||||
/**
|
||||
* APIProperty: xy
|
||||
* {Boolean} Order of the GML coordinate true:(x,y) or false:(y,x)
|
||||
* Changing is not recommended, a new Format should be instantiated.
|
||||
*/
|
||||
xy: true,
|
||||
|
||||
/**
|
||||
* Property: regExes
|
||||
* Compiled regular expressions for manipulating strings.
|
||||
*/
|
||||
regExes: {
|
||||
trimSpace: (/^\s*|\s*$/g),
|
||||
removeSpace: (/\s*/g),
|
||||
splitSpace: (/\s+/),
|
||||
trimComma: (/\s*,\s*/g)
|
||||
},
|
||||
|
||||
/**
|
||||
* Constructor: OpenLayers.Format.GML.Base
|
||||
* Instances of this class are not created directly. Use the
|
||||
* <OpenLayers.Format.GML.v2> or <OpenLayers.Format.GML.v3> constructor
|
||||
* instead.
|
||||
*
|
||||
* Parameters:
|
||||
* options - {Object} An optional object whose properties will be set on
|
||||
* this instance.
|
||||
*
|
||||
* Valid options properties:
|
||||
* featureType - {String} Local (without prefix) feature typeName (required).
|
||||
* featureNS - {String} Feature namespace (required).
|
||||
* geometryName - {String} Geometry element name.
|
||||
*/
|
||||
initialize: function(options) {
|
||||
OpenLayers.Format.XML.prototype.initialize.apply(this, [options]);
|
||||
this.setNamespace("feature", options.featureNS);
|
||||
},
|
||||
|
||||
/**
|
||||
* Method: read
|
||||
*
|
||||
* Parameters:
|
||||
* data - {DOMElement} A gml:featureMember element, a gml:featureMembers
|
||||
* element, or an element containing either of the above at any level.
|
||||
*
|
||||
* Returns:
|
||||
* {Array(<OpenLayers.Feature.Vector>)} An array of features.
|
||||
*/
|
||||
read: function(data) {
|
||||
if(typeof data == "string") {
|
||||
data = OpenLayers.Format.XML.prototype.read.apply(this, [data]);
|
||||
}
|
||||
if(data && data.nodeType == 9) {
|
||||
data = data.documentElement;
|
||||
}
|
||||
var features = [];
|
||||
this.readNode(data, {features: features});
|
||||
if(features.length == 0) {
|
||||
// look for gml:featureMember elements
|
||||
var elements = this.getElementsByTagNameNS(
|
||||
data, this.namespaces.gml, "featureMember"
|
||||
);
|
||||
if(elements.length) {
|
||||
for(var i=0, len=elements.length; i<len; ++i) {
|
||||
this.readNode(elements[i], {features: features});
|
||||
}
|
||||
} else {
|
||||
// look for gml:featureMembers elements (this is v3, but does no harm here)
|
||||
var elements = this.getElementsByTagNameNS(
|
||||
data, this.namespaces.gml, "featureMembers"
|
||||
);
|
||||
if(elements.length) {
|
||||
// there can be only one
|
||||
this.readNode(elements[0], {features: features});
|
||||
}
|
||||
}
|
||||
}
|
||||
return features;
|
||||
},
|
||||
|
||||
/**
|
||||
* Property: readers
|
||||
* Contains public functions, grouped by namespace prefix, that will
|
||||
* be applied when a namespaced node is found matching the function
|
||||
* name. The function will be applied in the scope of this parser
|
||||
* with two arguments: the node being read and a context object passed
|
||||
* from the parent.
|
||||
*/
|
||||
readers: {
|
||||
"gml": {
|
||||
"featureMember": function(node, obj) {
|
||||
this.readChildNodes(node, obj);
|
||||
},
|
||||
"featureMembers": function(node, obj) {
|
||||
this.readChildNodes(node, obj);
|
||||
},
|
||||
"Point": function(node, container) {
|
||||
var obj = {points: []};
|
||||
this.readChildNodes(node, obj);
|
||||
if(!container.components) {
|
||||
container.components = [];
|
||||
}
|
||||
container.components.push(obj.points[0]);
|
||||
},
|
||||
"coordinates": function(node, obj) {
|
||||
var str = this.concatChildValues(node).replace(
|
||||
this.regExes.trimSpace, ""
|
||||
);
|
||||
str = str.replace(this.regExes.trimComma, ",");
|
||||
var pointList = str.split(this.regExes.splitSpace);
|
||||
var coords;
|
||||
var numPoints = pointList.length;
|
||||
var points = new Array(numPoints);
|
||||
for(var i=0; i<numPoints; ++i) {
|
||||
coords = pointList[i].split(",");
|
||||
if (this.xy) {
|
||||
points[i] = new OpenLayers.Geometry.Point(
|
||||
coords[0], coords[1], coords[2]
|
||||
);
|
||||
} else {
|
||||
points[i] = new OpenLayers.Geometry.Point(
|
||||
coords[1], coords[0], coords[2]
|
||||
);
|
||||
}
|
||||
}
|
||||
obj.points = points;
|
||||
},
|
||||
"coord": function(node, obj) {
|
||||
var coord = {};
|
||||
this.readChildNodes(node, coord);
|
||||
if(!obj.points) {
|
||||
obj.points = [];
|
||||
}
|
||||
obj.points.push(new OpenLayers.Geometry.Point(
|
||||
coord.x, coord.y, coord.z
|
||||
));
|
||||
},
|
||||
"X": function(node, coord) {
|
||||
coord.x = this.getChildValue(node);
|
||||
},
|
||||
"Y": function(node, coord) {
|
||||
coord.y = this.getChildValue(node);
|
||||
},
|
||||
"Z": function(node, coord) {
|
||||
coord.z = this.getChildValue(node);
|
||||
},
|
||||
"MultiPoint": function(node, container) {
|
||||
var obj = {components: []};
|
||||
this.readChildNodes(node, obj);
|
||||
container.components = [
|
||||
new OpenLayers.Geometry.MultiPoint(obj.components)
|
||||
];
|
||||
},
|
||||
"pointMember": function(node, obj) {
|
||||
this.readChildNodes(node, obj);
|
||||
},
|
||||
"LineString": function(node, container) {
|
||||
var obj = {};
|
||||
this.readChildNodes(node, obj);
|
||||
if(!container.components) {
|
||||
container.components = [];
|
||||
}
|
||||
container.components.push(
|
||||
new OpenLayers.Geometry.LineString(obj.points)
|
||||
);
|
||||
},
|
||||
"MultiLineString": function(node, container) {
|
||||
var obj = {components: []};
|
||||
this.readChildNodes(node, obj);
|
||||
container.components = [
|
||||
new OpenLayers.Geometry.MultiLineString(obj.components)
|
||||
];
|
||||
},
|
||||
"lineStringMember": function(node, obj) {
|
||||
this.readChildNodes(node, obj);
|
||||
},
|
||||
"Polygon": function(node, container) {
|
||||
var obj = {outer: null, inner: []};
|
||||
this.readChildNodes(node, obj);
|
||||
obj.inner.unshift(obj.outer);
|
||||
if(!container.components) {
|
||||
container.components = [];
|
||||
}
|
||||
container.components.push(
|
||||
new OpenLayers.Geometry.Polygon(obj.inner)
|
||||
);
|
||||
},
|
||||
"LinearRing": function(node, obj) {
|
||||
var container = {};
|
||||
this.readChildNodes(node, container);
|
||||
obj.components = [new OpenLayers.Geometry.LinearRing(
|
||||
container.points
|
||||
)];
|
||||
},
|
||||
"MultiPolygon": function(node, container) {
|
||||
var obj = {components: []};
|
||||
this.readChildNodes(node, obj);
|
||||
container.components = [
|
||||
new OpenLayers.Geometry.MultiPolygon(obj.components)
|
||||
];
|
||||
},
|
||||
"polygonMember": function(node, obj) {
|
||||
this.readChildNodes(node, obj);
|
||||
},
|
||||
"GeometryCollection": function(node, container) {
|
||||
var obj = {components: []};
|
||||
this.readChildNodes(node, obj);
|
||||
container.components = [
|
||||
new OpenLayers.Geometry.Collection(obj.components)
|
||||
];
|
||||
},
|
||||
"geometryMember": function(node, obj) {
|
||||
this.readChildNodes(node, obj);
|
||||
}
|
||||
},
|
||||
"feature": {
|
||||
"*": function(node, obj) {
|
||||
// The node can either be named like the featureType, or it
|
||||
// can be a child of the feature:featureType. Children can be
|
||||
// geometry or attributes.
|
||||
var name;
|
||||
var local = node.localName || node.nodeName.split(":").pop();
|
||||
if(local == this.featureType) {
|
||||
name = "_typeName";
|
||||
} else {
|
||||
// Assume attribute elements have one child node and that the child
|
||||
// is a text node. Otherwise assume it is a geometry node.
|
||||
if(node.childNodes.length == 1 && node.firstChild.nodeType == 3) {
|
||||
if(this.extractAttributes) {
|
||||
name = "_attribute";
|
||||
}
|
||||
} else {
|
||||
name = "_geometry";
|
||||
}
|
||||
}
|
||||
if(name) {
|
||||
this.readers.feature[name].apply(this, [node, obj]);
|
||||
}
|
||||
},
|
||||
"_typeName": function(node, obj) {
|
||||
var container = {components: [], attributes: {}};
|
||||
this.readChildNodes(node, container);
|
||||
var feature = new OpenLayers.Feature.Vector(
|
||||
container.components[0], container.attributes
|
||||
);
|
||||
var fid = node.getAttribute("fid") ||
|
||||
this.getAttributeNS(node, this.namespaces["gml"], "id");
|
||||
if(fid) {
|
||||
feature.fid = fid;
|
||||
}
|
||||
if(this.internalProjection && this.externalProjection &&
|
||||
feature.geometry) {
|
||||
feature.geometry.transform(
|
||||
this.externalProjection, this.internalProjection
|
||||
);
|
||||
}
|
||||
obj.features.push(feature);
|
||||
},
|
||||
"_geometry": function(node, obj) {
|
||||
this.readChildNodes(node, obj);
|
||||
},
|
||||
"_attribute": function(node, obj) {
|
||||
var local = node.localName || node.nodeName.split(":").pop();
|
||||
var value = this.getChildValue(node);
|
||||
obj.attributes[local] = value;
|
||||
}
|
||||
},
|
||||
"wfs": {
|
||||
"FeatureCollection": function(node, obj) {
|
||||
this.readChildNodes(node, obj);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Method: write
|
||||
*
|
||||
* Parameters:
|
||||
* features - {Array(<OpenLayers.Feature.Vector>) | OpenLayers.Feature.Vector}
|
||||
* An array of features or a single feature.
|
||||
*
|
||||
* Returns:
|
||||
* {String} Given an array of features, a doc with a gml:featureMembers
|
||||
* element will be returned. Given a single feature, a doc with a
|
||||
* gml:featureMember element will be returned.
|
||||
*/
|
||||
write: function(features) {
|
||||
var name;
|
||||
if(features instanceof Array) {
|
||||
name = "featureMembers";
|
||||
} else {
|
||||
name = "featureMember";
|
||||
}
|
||||
var root = this.writeNode("gml:" + name, features);
|
||||
this.setAttributeNS(
|
||||
root, this.namespaces["xsi"],
|
||||
"xsi:schemaLocation", this.schemaLocation
|
||||
);
|
||||
|
||||
return OpenLayers.Format.XML.prototype.write.apply(this, [root]);
|
||||
},
|
||||
|
||||
/**
|
||||
* Property: writers
|
||||
* As a compliment to the readers property, this structure contains public
|
||||
* writing functions grouped by namespace alias and named like the
|
||||
* node names they produce.
|
||||
*/
|
||||
writers: {
|
||||
"gml": {
|
||||
"featureMember": function(feature) {
|
||||
var node = this.createElementNSPlus("gml:featureMember");
|
||||
this.writeNode("feature:_typeName", feature, node);
|
||||
return node;
|
||||
},
|
||||
"MultiPoint": function(geometry) {
|
||||
var node = this.createElementNSPlus("gml:MultiPoint");
|
||||
for(var i=0; i<geometry.components.length; ++i) {
|
||||
this.writeNode("pointMember", geometry.components[i], node);
|
||||
}
|
||||
return node;
|
||||
},
|
||||
"pointMember": function(geometry) {
|
||||
var node = this.createElementNSPlus("gml:pointMember");
|
||||
this.writeNode("Point", geometry, node);
|
||||
return node;
|
||||
},
|
||||
"MultiLineString": function(geometry) {
|
||||
var node = this.createElementNSPlus("gml:MultiLineString");
|
||||
for(var i=0; i<geometry.components.length; ++i) {
|
||||
this.writeNode("lineStringMember", geometry.components[i], node);
|
||||
}
|
||||
return node;
|
||||
},
|
||||
"lineStringMember": function(geometry) {
|
||||
var node = this.createElementNSPlus("gml:lineStringMember");
|
||||
this.writeNode("LineString", geometry, node);
|
||||
return node;
|
||||
},
|
||||
"MultiPolygon": function(geometry) {
|
||||
var node = this.createElementNSPlus("gml:MultiPolygon");
|
||||
for(var i=0; i<geometry.components.length; ++i) {
|
||||
this.writeNode(
|
||||
"polygonMember", geometry.components[i], node
|
||||
);
|
||||
}
|
||||
return node;
|
||||
},
|
||||
"polygonMember": function(geometry) {
|
||||
var node = this.createElementNSPlus("gml:polygonMember");
|
||||
this.writeNode("Polygon", geometry, node);
|
||||
return node;
|
||||
},
|
||||
"GeometryCollection": function(geometry) {
|
||||
var node = this.createElementNSPlus("gml:GeometryCollection");
|
||||
for(var i=0, len=geometry.components.length; i<len; ++i) {
|
||||
this.writeNode("geometryMember", geometry.components[i], node);
|
||||
}
|
||||
return node;
|
||||
},
|
||||
"geometryMember": function(geometry) {
|
||||
var node = this.createElementNSPlus("gml:geometryMember");
|
||||
var child = this.writeNode("feature:_geometry", geometry);
|
||||
node.appendChild(child.firstChild);
|
||||
return node;
|
||||
}
|
||||
},
|
||||
"feature": {
|
||||
"_typeName": function(feature) {
|
||||
var node = this.createElementNSPlus("feature:" + this.featureType, {
|
||||
attributes: {fid: feature.fid}
|
||||
});
|
||||
if(feature.geometry) {
|
||||
this.writeNode("feature:_geometry", feature.geometry, node);
|
||||
}
|
||||
for(var name in feature.attributes) {
|
||||
var value = feature.attributes[name];
|
||||
if(value != null) {
|
||||
this.writeNode(
|
||||
"feature:_attribute",
|
||||
{name: name, value: value}, node
|
||||
)
|
||||
}
|
||||
}
|
||||
return node;
|
||||
},
|
||||
"_geometry": function(geometry) {
|
||||
if(this.externalProjection && this.internalProjection) {
|
||||
geometry = geometry.clone().transform(
|
||||
this.internalProjection, this.externalProjection
|
||||
);
|
||||
}
|
||||
var node = this.createElementNSPlus(
|
||||
"feature:" + this.geometryName
|
||||
);
|
||||
var type = this.geometryTypes[geometry.CLASS_NAME];
|
||||
var child = this.writeNode("gml:" + type, geometry, node);
|
||||
if(this.srsName) {
|
||||
child.setAttribute("srsName", this.srsName);
|
||||
}
|
||||
return node;
|
||||
},
|
||||
"_attribute": function(obj) {
|
||||
return this.createElementNSPlus("feature:" + obj.name, {
|
||||
value: obj.value
|
||||
});
|
||||
}
|
||||
},
|
||||
"wfs": {
|
||||
"FeatureCollection": function(features) {
|
||||
/**
|
||||
* This is only here because GML2 only describes abstract
|
||||
* feature collections. Typically, you would not be using
|
||||
* the GML format to write wfs elements. This just provides
|
||||
* some way to write out lists of features. GML3 defines the
|
||||
* featureMembers element, so that is used by default instead.
|
||||
*/
|
||||
var node = this.createElementNSPlus("wfs:FeatureCollection");
|
||||
for(var i=0, len=features.length; i<len; ++i) {
|
||||
this.writeNode("gml:featureMember", features[i], node);
|
||||
}
|
||||
return node;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Property: geometryTypes
|
||||
* {Object} Maps OpenLayers geometry class names to GML element names.
|
||||
*/
|
||||
geometryTypes: {
|
||||
"OpenLayers.Geometry.Point": "Point",
|
||||
"OpenLayers.Geometry.MultiPoint": "MultiPoint",
|
||||
"OpenLayers.Geometry.LineString": "LineString",
|
||||
"OpenLayers.Geometry.MultiLineString": "MultiLineString",
|
||||
"OpenLayers.Geometry.Polygon": "Polygon",
|
||||
"OpenLayers.Geometry.MultiPolygon": "MultiPolygon",
|
||||
"OpenLayers.Geometry.Collection": "GeometryCollection"
|
||||
},
|
||||
|
||||
CLASS_NAME: "OpenLayers.Format.GML.Base"
|
||||
|
||||
});
|
||||
192
lib/OpenLayers/Format/GML/v2.js
Normal file
192
lib/OpenLayers/Format/GML/v2.js
Normal file
@@ -0,0 +1,192 @@
|
||||
/* 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/GML/Base.js
|
||||
*/
|
||||
|
||||
/**
|
||||
* Class: OpenLayers.Format.GML.v2
|
||||
* Parses GML version 2.
|
||||
*
|
||||
* Inherits from:
|
||||
* - <OpenLayers.Format.GML.Base>
|
||||
*/
|
||||
OpenLayers.Format.GML.v2 = OpenLayers.Class(OpenLayers.Format.GML.Base, {
|
||||
|
||||
/**
|
||||
* Property: schemaLocation
|
||||
* {String} Schema location for a particular minor version.
|
||||
*/
|
||||
schemaLocation: "http://www.opengis.net/gml http://schemas.opengis.net/gml/2.1.2/feature.xsd",
|
||||
|
||||
/**
|
||||
* Constructor: OpenLayers.Format.GML.v2
|
||||
* Create a parser for GML v2.
|
||||
*
|
||||
* Parameters:
|
||||
* options - {Object} An optional object whose properties will be set on
|
||||
* this instance.
|
||||
*
|
||||
* Valid options properties:
|
||||
* featureType - {String} Local (without prefix) feature typeName (required).
|
||||
* featureNS - {String} Feature namespace (required).
|
||||
* geometryName - {String} Geometry element name.
|
||||
*/
|
||||
initialize: function(options) {
|
||||
OpenLayers.Format.GML.Base.prototype.initialize.apply(this, [options]);
|
||||
},
|
||||
|
||||
/**
|
||||
* Property: readers
|
||||
* Contains public functions, grouped by namespace prefix, that will
|
||||
* be applied when a namespaced node is found matching the function
|
||||
* name. The function will be applied in the scope of this parser
|
||||
* with two arguments: the node being read and a context object passed
|
||||
* from the parent.
|
||||
*/
|
||||
readers: {
|
||||
"gml": OpenLayers.Util.applyDefaults({
|
||||
"outerBoundaryIs": function(node, container) {
|
||||
var obj = {};
|
||||
this.readChildNodes(node, obj);
|
||||
container.outer = obj.components[0];
|
||||
},
|
||||
"innerBoundaryIs": function(node, container) {
|
||||
var obj = {};
|
||||
this.readChildNodes(node, obj);
|
||||
container.inner.push(obj.components[0]);
|
||||
},
|
||||
"Box": function(node, container) {
|
||||
var obj = {};
|
||||
this.readChildNodes(node, obj);
|
||||
if(!container.components) {
|
||||
container.components = [];
|
||||
}
|
||||
var min = obj.points[0];
|
||||
var max = obj.points[1];
|
||||
container.components.push(
|
||||
new OpenLayers.Bounds(min.x, min.y, max.x, max.y)
|
||||
);
|
||||
}
|
||||
}, OpenLayers.Format.GML.Base.prototype.readers["gml"]),
|
||||
"feature": OpenLayers.Format.GML.Base.prototype.readers["feature"],
|
||||
"wfs": OpenLayers.Format.GML.Base.prototype.readers["wfs"]
|
||||
},
|
||||
|
||||
/**
|
||||
* Method: write
|
||||
*
|
||||
* Parameters:
|
||||
* features - {Array(<OpenLayers.Feature.Vector>) | OpenLayers.Feature.Vector}
|
||||
* An array of features or a single feature.
|
||||
*
|
||||
* Returns:
|
||||
* {String} Given an array of features, a doc with a gml:featureMembers
|
||||
* element will be returned. Given a single feature, a doc with a
|
||||
* gml:featureMember element will be returned.
|
||||
*/
|
||||
write: function(features) {
|
||||
var name;
|
||||
if(features instanceof Array) {
|
||||
// GML2 only has abstract feature collections
|
||||
// wfs provides a feature collection from a well-known schema
|
||||
name = "wfs:FeatureCollection";
|
||||
} else {
|
||||
name = "gml:featureMember";
|
||||
}
|
||||
var root = this.writeNode(name, features);
|
||||
this.setAttributeNS(
|
||||
root, this.namespaces["xsi"],
|
||||
"xsi:schemaLocation", this.schemaLocation
|
||||
);
|
||||
|
||||
return OpenLayers.Format.XML.prototype.write.apply(this, [root]);
|
||||
},
|
||||
|
||||
/**
|
||||
* Property: writers
|
||||
* As a compliment to the readers property, this structure contains public
|
||||
* writing functions grouped by namespace alias and named like the
|
||||
* node names they produce.
|
||||
*/
|
||||
writers: {
|
||||
"gml": OpenLayers.Util.applyDefaults({
|
||||
"Point": function(geometry) {
|
||||
var node = this.createElementNSPlus("gml:Point");
|
||||
this.writeNode("coordinates", [geometry], node);
|
||||
return node;
|
||||
},
|
||||
"coordinates": function(points) {
|
||||
var numPoints = points.length;
|
||||
var parts = new Array(numPoints);
|
||||
var point;
|
||||
for(var i=0; i<numPoints; ++i) {
|
||||
point = points[i];
|
||||
if(this.xy) {
|
||||
parts[i] = point.x + "," + point.y;
|
||||
} else {
|
||||
parts[i] = point.y + "," + point.x;
|
||||
}
|
||||
if(point.z != undefined) { // allow null or undefined
|
||||
parts[i] += "," + point.z;
|
||||
}
|
||||
}
|
||||
return this.createElementNSPlus("gml:coordinates", {
|
||||
attributes: {
|
||||
decimal: ".", cs: ",", ts: " "
|
||||
},
|
||||
value: (numPoints == 1) ? parts[0] : parts.join(" ")
|
||||
});
|
||||
},
|
||||
"LineString": function(geometry) {
|
||||
var node = this.createElementNSPlus("gml:LineString");
|
||||
this.writeNode("coordinates", geometry.components, node);
|
||||
return node;
|
||||
},
|
||||
"Polygon": function(geometry) {
|
||||
var node = this.createElementNSPlus("gml:Polygon");
|
||||
this.writeNode("outerBoundaryIs", geometry.components[0], node);
|
||||
for(var i=1; i<geometry.components.length; ++i) {
|
||||
this.writeNode(
|
||||
"innerBoundaryIs", geometry.components[i], node
|
||||
);
|
||||
}
|
||||
return node;
|
||||
},
|
||||
"outerBoundaryIs": function(ring) {
|
||||
var node = this.createElementNSPlus("gml:outerBoundaryIs");
|
||||
this.writeNode("LinearRing", ring, node);
|
||||
return node;
|
||||
},
|
||||
"innerBoundaryIs": function(ring) {
|
||||
var node = this.createElementNSPlus("gml:innerBoundaryIs");
|
||||
this.writeNode("LinearRing", ring, node);
|
||||
return node;
|
||||
},
|
||||
"LinearRing": function(ring) {
|
||||
var node = this.createElementNSPlus("gml:LinearRing");
|
||||
this.writeNode("coordinates", ring.components, node);
|
||||
return node;
|
||||
},
|
||||
"Box": function(bounds) {
|
||||
var node = this.createElementNSPlus("gml:Box");
|
||||
this.writeNode("coordinates", [
|
||||
{x: bounds.left, y: bounds.bottom},
|
||||
{x: bounds.right, y: bounds.top}
|
||||
], node);
|
||||
// srsName attribute is optional for gml:Box
|
||||
if(this.srsName) {
|
||||
node.setAttribute("srsName", this.srsName);
|
||||
}
|
||||
return node;
|
||||
}
|
||||
}, OpenLayers.Format.GML.Base.prototype.writers["gml"]),
|
||||
"feature": OpenLayers.Format.GML.Base.prototype.writers["feature"],
|
||||
"wfs": OpenLayers.Format.GML.Base.prototype.writers["wfs"]
|
||||
},
|
||||
|
||||
CLASS_NAME: "OpenLayers.Format.GML.v2"
|
||||
|
||||
});
|
||||
287
lib/OpenLayers/Format/GML/v3.js
Normal file
287
lib/OpenLayers/Format/GML/v3.js
Normal file
@@ -0,0 +1,287 @@
|
||||
/* 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/GML/Base.js
|
||||
*/
|
||||
|
||||
/**
|
||||
* Class: OpenLayers.Format.GML.v3
|
||||
* Parses GML version 3.
|
||||
*
|
||||
* Inherits from:
|
||||
* - <OpenLayers.Format.GML.Base>
|
||||
*/
|
||||
OpenLayers.Format.GML.v3 = OpenLayers.Class(OpenLayers.Format.GML.Base, {
|
||||
|
||||
/**
|
||||
* Property: schemaLocation
|
||||
* {String} Schema location for a particular minor version. The writers
|
||||
* conform with the Simple Features Profile for GML.
|
||||
*/
|
||||
schemaLocation: "http://www.opengis.net/gml http://schemas.opengis.net/gml/3.1.1/profiles/gmlsfProfile/1.0.0/gmlsf.xsd",
|
||||
|
||||
/**
|
||||
* Constructor: OpenLayers.Format.GML.v3
|
||||
* Create a parser for GML v3.
|
||||
*
|
||||
* Parameters:
|
||||
* options - {Object} An optional object whose properties will be set on
|
||||
* this instance.
|
||||
*
|
||||
* Valid options properties:
|
||||
* featureType - {String} Local (without prefix) feature typeName (required).
|
||||
* featureNS - {String} Feature namespace (required).
|
||||
* geometryName - {String} Geometry element name.
|
||||
*/
|
||||
initialize: function(options) {
|
||||
OpenLayers.Format.GML.Base.prototype.initialize.apply(this, [options]);
|
||||
},
|
||||
|
||||
/**
|
||||
* Property: readers
|
||||
* Contains public functions, grouped by namespace prefix, that will
|
||||
* be applied when a namespaced node is found matching the function
|
||||
* name. The function will be applied in the scope of this parser
|
||||
* with two arguments: the node being read and a context object passed
|
||||
* from the parent.
|
||||
*/
|
||||
readers: {
|
||||
"gml": OpenLayers.Util.applyDefaults({
|
||||
"featureMembers": function(node, obj) {
|
||||
this.readChildNodes(node, obj);
|
||||
},
|
||||
"pos": function(node, obj) {
|
||||
var str = this.getChildValue(node).replace(
|
||||
this.regExes.trimSpace, ""
|
||||
);
|
||||
var coords = str.split(this.regExes.splitSpace);
|
||||
var point;
|
||||
if(this.xy) {
|
||||
point = new OpenLayers.Geometry.Point(
|
||||
coords[0], coords[1], coords[2]
|
||||
);
|
||||
} else {
|
||||
point = new OpenLayers.Geometry.Point(
|
||||
coords[1], coords[0], coords[2]
|
||||
);
|
||||
}
|
||||
obj.points = [point];
|
||||
},
|
||||
"posList": function(node, obj) {
|
||||
var str = this.concatChildValues(node).replace(
|
||||
this.regExes.trimSpace, ""
|
||||
);
|
||||
var coords = str.split(this.regExes.splitSpace);
|
||||
var dim = parseInt(node.getAttribute("dimension")) || 2;
|
||||
var j, x, y, z;
|
||||
var numPoints = coords.length / dim;
|
||||
var points = new Array(numPoints);
|
||||
for(var i=0, len=coords.length; i<len; i += dim) {
|
||||
x = coords[i];
|
||||
y = coords[i+1];
|
||||
z = (dim == 2) ? undefined : coords[i+2];
|
||||
if (this.xy) {
|
||||
points[i/dim] = new OpenLayers.Geometry.Point(x, y, z);
|
||||
} else {
|
||||
points[i/dim] = new OpenLayers.Geometry.Point(y, x, z);
|
||||
}
|
||||
}
|
||||
obj.points = points;
|
||||
},
|
||||
"exterior": function(node, container) {
|
||||
var obj = {};
|
||||
this.readChildNodes(node, obj);
|
||||
container.outer = obj.components[0];
|
||||
},
|
||||
"interior": function(node, container) {
|
||||
var obj = {};
|
||||
this.readChildNodes(node, obj);
|
||||
container.inner.push(obj.components[0]);
|
||||
},
|
||||
"MultiSurface": function(node, container) {
|
||||
var obj = {components: []};
|
||||
this.readChildNodes(node, obj);
|
||||
if(obj.components.length > 0) {
|
||||
container.components = [
|
||||
new OpenLayers.Geometry.MultiPolygon(obj.components)
|
||||
];
|
||||
}
|
||||
},
|
||||
"surfaceMember": function(node, obj) {
|
||||
this.readChildNodes(node, obj);
|
||||
},
|
||||
"surfaceMembers": function(node, obj) {
|
||||
this.readChildNodes(node, obj);
|
||||
},
|
||||
"pointMembers": function(node, obj) {
|
||||
this.readChildNodes(node, obj);
|
||||
},
|
||||
"lineStringMembers": function(node, obj) {
|
||||
this.readChildNodes(node, obj);
|
||||
},
|
||||
"polygonMembers": function(node, obj) {
|
||||
this.readChildNodes(node, obj);
|
||||
},
|
||||
"geometryMembers": function(node, obj) {
|
||||
this.readChildNodes(node, obj);
|
||||
},
|
||||
"Envelope": function(node, container) {
|
||||
var obj = {points: new Array(2)};
|
||||
this.readChildNodes(node, obj);
|
||||
if(!container.components) {
|
||||
container.components = [];
|
||||
}
|
||||
var min = obj.points[0];
|
||||
var max = obj.points[1];
|
||||
container.components.push(
|
||||
new OpenLayers.Bounds(min.x, min.y, max.x, max.y)
|
||||
);
|
||||
},
|
||||
"lowerCorner": function(node, container) {
|
||||
var obj = {};
|
||||
this.readChildNodes(node, obj)
|
||||
container.points[0] = obj.points[0];
|
||||
},
|
||||
"upperCorner": function(node, container) {
|
||||
var obj = {};
|
||||
this.readChildNodes(node, obj)
|
||||
container.points[1] = obj.points[0];
|
||||
}
|
||||
}, OpenLayers.Format.GML.Base.prototype.readers["gml"]),
|
||||
"feature": OpenLayers.Format.GML.Base.prototype.readers["feature"],
|
||||
"wfs": OpenLayers.Format.GML.Base.prototype.readers["wfs"]
|
||||
},
|
||||
|
||||
/**
|
||||
* Method: write
|
||||
*
|
||||
* Parameters:
|
||||
* features - {Array(<OpenLayers.Feature.Vector>) | OpenLayers.Feature.Vector}
|
||||
* An array of features or a single feature.
|
||||
*
|
||||
* Returns:
|
||||
* {String} Given an array of features, a doc with a gml:featureMembers
|
||||
* element will be returned. Given a single feature, a doc with a
|
||||
* gml:featureMember element will be returned.
|
||||
*/
|
||||
write: function(features) {
|
||||
var name;
|
||||
if(features instanceof Array) {
|
||||
name = "featureMembers";
|
||||
} else {
|
||||
name = "featureMember";
|
||||
}
|
||||
var root = this.writeNode("gml:" + name, features);
|
||||
this.setAttributeNS(
|
||||
root, this.namespaces["xsi"],
|
||||
"xsi:schemaLocation", this.schemaLocation
|
||||
);
|
||||
|
||||
return OpenLayers.Format.XML.prototype.write.apply(this, [root]);
|
||||
},
|
||||
|
||||
/**
|
||||
* Property: writers
|
||||
* As a compliment to the readers property, this structure contains public
|
||||
* writing functions grouped by namespace alias and named like the
|
||||
* node names they produce.
|
||||
*/
|
||||
writers: {
|
||||
"gml": OpenLayers.Util.applyDefaults({
|
||||
"featureMembers": function(features) {
|
||||
var node = this.createElementNSPlus("gml:featureMembers");
|
||||
for(var i=0, len=features.length; i<len; ++i) {
|
||||
this.writeNode("feature:_typeName", features[i], node);
|
||||
}
|
||||
return node;
|
||||
},
|
||||
"Point": function(geometry) {
|
||||
var node = this.createElementNSPlus("gml:Point");
|
||||
this.writeNode("pos", geometry, node);
|
||||
return node;
|
||||
},
|
||||
"pos": function(point) {
|
||||
// only 2d for simple features profile
|
||||
var pos = (this.xy) ?
|
||||
(point.x + " " + point.y) : (point.y + " " + point.x);
|
||||
return this.createElementNSPlus("gml:pos", {
|
||||
value: pos
|
||||
});
|
||||
},
|
||||
"LineString": function(geometry) {
|
||||
var node = this.createElementNSPlus("gml:LineString");
|
||||
this.writeNode("posList", geometry.components, node);
|
||||
return node;
|
||||
},
|
||||
"posList": function(points) {
|
||||
// only 2d for simple features profile
|
||||
var len = points.length;
|
||||
var parts = new Array(len);
|
||||
var point;
|
||||
for(var i=0; i<len; ++i) {
|
||||
point = points[i];
|
||||
if(this.xy) {
|
||||
parts[i] = point.x + " " + point.y;
|
||||
} else {
|
||||
parts[i] = point.y + " " + point.x;
|
||||
}
|
||||
}
|
||||
return this.createElementNSPlus("gml:posList", {
|
||||
value: parts.join(" ")
|
||||
});
|
||||
},
|
||||
"Polygon": function(geometry) {
|
||||
var node = this.createElementNSPlus("gml:Polygon");
|
||||
this.writeNode("exterior", geometry.components[0], node);
|
||||
for(var i=1, len=geometry.components.length; i<len; ++i) {
|
||||
this.writeNode(
|
||||
"interior", geometry.components[i], node
|
||||
);
|
||||
}
|
||||
return node;
|
||||
},
|
||||
"exterior": function(ring) {
|
||||
var node = this.createElementNSPlus("gml:exterior");
|
||||
this.writeNode("LinearRing", ring, node);
|
||||
return node;
|
||||
},
|
||||
"interior": function(ring) {
|
||||
var node = this.createElementNSPlus("gml:interior");
|
||||
this.writeNode("LinearRing", ring, node);
|
||||
return node;
|
||||
},
|
||||
"LinearRing": function(ring) {
|
||||
var node = this.createElementNSPlus("gml:LinearRing");
|
||||
this.writeNode("posList", ring.components, node);
|
||||
return node;
|
||||
},
|
||||
"Envelope": function(bounds) {
|
||||
var node = this.createElementNSPlus("gml:Envelope");
|
||||
this.writeNode("lowerCorner", bounds, node);
|
||||
this.writeNode("upperCorner", bounds, node);
|
||||
// srsName attribute is required for gml:Envelope
|
||||
if(this.srsName) {
|
||||
node.setAttribute("srsName", this.srsName);
|
||||
}
|
||||
return node;
|
||||
},
|
||||
"lowerCorner": function(bounds) {
|
||||
var node = this.createElementNSPlus("gml:lowerCorner");
|
||||
this.writeNode("pos", {x: bounds.left, y: bounds.bottom}, node);
|
||||
return node;
|
||||
},
|
||||
"upperCorner": function(bounds) {
|
||||
var node = this.createElementNSPlus("gml:upperCorner");
|
||||
this.writeNode("pos", {x: bounds.right, y: bounds.top}, node);
|
||||
return node;
|
||||
}
|
||||
}, OpenLayers.Format.GML.Base.prototype.writers["gml"]),
|
||||
"feature": OpenLayers.Format.GML.Base.prototype.writers["feature"],
|
||||
"wfs": OpenLayers.Format.GML.Base.prototype.writers["wfs"]
|
||||
},
|
||||
|
||||
CLASS_NAME: "OpenLayers.Format.GML.v3"
|
||||
|
||||
});
|
||||
@@ -19,6 +19,46 @@
|
||||
*/
|
||||
OpenLayers.Format.XML = OpenLayers.Class(OpenLayers.Format, {
|
||||
|
||||
/**
|
||||
* Property: namespaces
|
||||
* {Object} Mapping of namespace aliases to namespace URIs. Properties
|
||||
* of this object should not be set individually. Read-only. All
|
||||
* XML subclasses should have their own namespaces object. Use
|
||||
* <setNamespace> to add or set a namespace alias after construction.
|
||||
*/
|
||||
namespaces: null,
|
||||
|
||||
/**
|
||||
* Property: namespaceAlias
|
||||
* {Object} Mapping of namespace URI to namespace alias. This object
|
||||
* is read-only. Use <setNamespace> to add or set a namespace alias.
|
||||
*/
|
||||
namespaceAlias: null,
|
||||
|
||||
/**
|
||||
* Property: defaultPrefix
|
||||
* {String} The default namespace alias for creating element nodes.
|
||||
*/
|
||||
defaultPrefix: null,
|
||||
|
||||
/**
|
||||
* Property: readers
|
||||
* Contains public functions, grouped by namespace prefix, that will
|
||||
* be applied when a namespaced node is found matching the function
|
||||
* name. The function will be applied in the scope of this parser
|
||||
* with two arguments: the node being read and a context object passed
|
||||
* from the parent.
|
||||
*/
|
||||
readers: {},
|
||||
|
||||
/**
|
||||
* Property: writers
|
||||
* As a compliment to the <readers> property, this structure contains public
|
||||
* writing functions grouped by namespace alias and named like the
|
||||
* node names they produce.
|
||||
*/
|
||||
writers: {},
|
||||
|
||||
/**
|
||||
* Property: xmldom
|
||||
* {XMLDom} If this browser uses ActiveX, this will be set to a XMLDOM
|
||||
@@ -44,6 +84,34 @@ OpenLayers.Format.XML = OpenLayers.Class(OpenLayers.Format, {
|
||||
this.xmldom = new ActiveXObject("Microsoft.XMLDOM");
|
||||
}
|
||||
OpenLayers.Format.prototype.initialize.apply(this, [options]);
|
||||
// clone the namespace object and set all namespace aliases
|
||||
this.namespaces = OpenLayers.Util.extend({}, this.namespaces);
|
||||
this.namespaceAlias = {};
|
||||
for(var alias in this.namespaces) {
|
||||
this.namespaceAlias[this.namespaces[alias]] = alias;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* APIMethod: destroy
|
||||
* Clean up.
|
||||
*/
|
||||
destroy: function() {
|
||||
this.xmldom = null;
|
||||
OpenLayers.Format.prototype.destroy.apply(this, arguments);
|
||||
},
|
||||
|
||||
/**
|
||||
* Method: setNamespace
|
||||
* Set a namespace alias and URI for the format.
|
||||
*
|
||||
* Parameters:
|
||||
* alias - {String} The namespace alias (prefix).
|
||||
* uri - {String} The namespace URI.
|
||||
*/
|
||||
setNamespace: function(alias, uri) {
|
||||
this.namespaces[alias] = uri;
|
||||
this.namespaceAlias[uri] = alias;
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -289,11 +357,12 @@ OpenLayers.Format.XML = OpenLayers.Class(OpenLayers.Format, {
|
||||
* {String} The value of the first child of the given node.
|
||||
*/
|
||||
getChildValue: function(node, def) {
|
||||
var value;
|
||||
if (node && node.firstChild && node.firstChild.nodeValue) {
|
||||
value = node.firstChild.nodeValue;
|
||||
} else {
|
||||
value = (def != undefined) ? def : "";
|
||||
var value = def || "";
|
||||
if(node) {
|
||||
var child = node.firstChild;
|
||||
if(child) {
|
||||
value = child.nodeValue || value;
|
||||
}
|
||||
}
|
||||
return value;
|
||||
},
|
||||
@@ -384,6 +453,172 @@ OpenLayers.Format.XML = OpenLayers.Class(OpenLayers.Format, {
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Method: createElementNSPlus
|
||||
* Shorthand for creating namespaced elements with optional attributes and
|
||||
* child text nodes.
|
||||
*
|
||||
* Parameters:
|
||||
* name - {String} The qualified node name.
|
||||
* options - {Object} Optional object for node configuration.
|
||||
*
|
||||
* Valid options:
|
||||
* uri - {String} Optional namespace uri for the element - supply a prefix
|
||||
* instead if the namespace uri is a property of the format's namespace
|
||||
* object.
|
||||
* attributes - {Object} Optional attributes to be set using the
|
||||
* <setAttributes> method.
|
||||
* value - {String} Optional text to be appended as a text node.
|
||||
*
|
||||
* Returns:
|
||||
* {Element} An element node.
|
||||
*/
|
||||
createElementNSPlus: function(name, options) {
|
||||
options = options || {};
|
||||
var loc = name.indexOf(":");
|
||||
// order of prefix preference
|
||||
// 1. in the uri option
|
||||
// 2. in the prefix option
|
||||
// 3. in the qualified name
|
||||
// 4. from the defaultPrefix
|
||||
var uri = options.uri || this.namespaces[options.prefix];
|
||||
if(!uri) {
|
||||
loc = name.indexOf(":");
|
||||
uri = this.namespaces[name.substring(0, loc)];
|
||||
}
|
||||
if(!uri) {
|
||||
uri = this.namespaces[this.defaultPrefix];
|
||||
}
|
||||
var node = this.createElementNS(uri, name);
|
||||
if(options.attributes) {
|
||||
this.setAttributes(node, options.attributes);
|
||||
}
|
||||
if(options.value) {
|
||||
node.appendChild(this.createTextNode(options.value));
|
||||
}
|
||||
return node;
|
||||
},
|
||||
|
||||
/**
|
||||
* Method: setAttributes
|
||||
* Set multiple attributes given key value pairs from an object.
|
||||
*
|
||||
* Parameters:
|
||||
* node - {Element} An element node.
|
||||
* obj - {Object || Array} An object whose properties represent attribute
|
||||
* names and values represent attribute values. If an attribute name
|
||||
* is a qualified name ("prefix:local"), the prefix will be looked up
|
||||
* in the parsers {namespaces} object. If the prefix is found,
|
||||
* setAttributeNS will be used instead of setAttribute.
|
||||
*/
|
||||
setAttributes: function(node, obj) {
|
||||
var value, loc, alias, uri;
|
||||
for(var name in obj) {
|
||||
if(obj[name] != null && obj[name].toString) {
|
||||
value = obj[name].toString();
|
||||
// check for qualified attribute name ("prefix:local")
|
||||
uri = this.namespaces[name.substring(0, name.indexOf(":"))] || null;
|
||||
this.setAttributeNS(node, uri, name, value);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Method: readNode
|
||||
* Shorthand for applying one of the named readers given the node
|
||||
* namespace and local name. Readers take two args (node, obj) and
|
||||
* generally extend or modify the second.
|
||||
*
|
||||
* Parameters:
|
||||
* node - {DOMElement} The node to be read (required).
|
||||
* obj - {Object} The object to be modified (optional).
|
||||
*
|
||||
* Returns:
|
||||
* {Object} The input object, modified (or a new one if none was provided).
|
||||
*/
|
||||
readNode: function(node, obj) {
|
||||
if(!obj) {
|
||||
obj = {};
|
||||
}
|
||||
var group = this.readers[this.namespaceAlias[node.namespaceURI]];
|
||||
if(group) {
|
||||
var local = node.localName || node.nodeName.split(":").pop();
|
||||
var reader = group[local] || group["*"];
|
||||
if(reader) {
|
||||
reader.apply(this, [node, obj]);
|
||||
}
|
||||
}
|
||||
return obj;
|
||||
},
|
||||
|
||||
/**
|
||||
* Method: readChildNodes
|
||||
* Shorthand for applying the named readers to all children of a node.
|
||||
* For each child of type 1 (element), <readSelf> is called.
|
||||
*
|
||||
* Parameters:
|
||||
* node - {DOMElement} The node to be read (required).
|
||||
* obj - {Object} The object to be modified (optional).
|
||||
*
|
||||
* Returns:
|
||||
* {Object} The input object, modified.
|
||||
*/
|
||||
readChildNodes: function(node, obj) {
|
||||
if(!obj) {
|
||||
obj = {};
|
||||
}
|
||||
var children = node.childNodes;
|
||||
var child;
|
||||
for(var i=0, len=children.length; i<len; ++i) {
|
||||
child = children[i];
|
||||
if(child.nodeType == 1) {
|
||||
this.readNode(child, obj);
|
||||
}
|
||||
}
|
||||
return obj;
|
||||
},
|
||||
|
||||
/**
|
||||
* Method: writeNode
|
||||
* Shorthand for applying one of the named writers and appending the
|
||||
* results to a node. If a qualified name is not provided for the
|
||||
* second argument (and a local name is used instead), the namespace
|
||||
* of the parent node will be assumed.
|
||||
*
|
||||
* Parameters:
|
||||
* name - {String} The name of a node to generate. If a qualified name
|
||||
* (e.g. "pre:Name") is used, the namespace prefix is assumed to be
|
||||
* in the <writers> group. If a local name is used (e.g. "Name") then
|
||||
* the namespace of the parent is assumed. If a local name is used
|
||||
* and no parent is supplied, then the default namespace is assumed.
|
||||
* obj - {Object} Structure containing data for the writer.
|
||||
* parent - {DOMElement} Result will be appended to this node. If no parent
|
||||
* is supplied, the node will not be appended to anything.
|
||||
*
|
||||
* Returns:
|
||||
* {DOMElement} The child node.
|
||||
*/
|
||||
writeNode: function(name, obj, parent) {
|
||||
var prefix, local;
|
||||
var split = name.indexOf(":");
|
||||
if(split > 0) {
|
||||
prefix = name.substring(0, split);
|
||||
local = name.substring(split + 1);
|
||||
} else {
|
||||
if(parent) {
|
||||
prefix = this.namespaceAlias[parent.namespaceURI];
|
||||
} else {
|
||||
prefix = this.defaultPrefix;
|
||||
}
|
||||
local = name;
|
||||
}
|
||||
var child = this.writers[prefix][local].apply(this, [obj]);
|
||||
if(parent) {
|
||||
parent.appendChild(child);
|
||||
}
|
||||
return child;
|
||||
},
|
||||
|
||||
CLASS_NAME: "OpenLayers.Format.XML"
|
||||
|
||||
});
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
/**
|
||||
* @requires OpenLayers/Layer/Grid.js
|
||||
* @requires OpenLayers/Tile/Image.js
|
||||
*/
|
||||
|
||||
/**
|
||||
|
||||
@@ -38,7 +38,12 @@ OpenLayers.Layer.Vector = OpenLayers.Class(OpenLayers.Layer, {
|
||||
* Supported map event types (in addition to those from <OpenLayers.Layer>):
|
||||
* - *beforefeatureadded* Triggered before a feature is added. Listeners
|
||||
* will receive an object with a *feature* property referencing the
|
||||
* feature to be added.
|
||||
* feature to be added. To stop the feature from being added, a
|
||||
* listener should return false.
|
||||
* - *beforefeaturesadded* Triggered before an array of features is added.
|
||||
* Listeners will receive an object with a *features* property
|
||||
* referencing the feature to be added. To stop the features from
|
||||
* being added, a listener should return false.
|
||||
* - *featureadded* Triggered after a feature is added. The event
|
||||
* object passed to listeners will have a *feature* property with a
|
||||
* reference to the added feature.
|
||||
@@ -72,7 +77,8 @@ OpenLayers.Layer.Vector = OpenLayers.Class(OpenLayers.Layer, {
|
||||
* - *refresh* Triggered when something wants a strategy to ask the protocol
|
||||
* for a new set of features.
|
||||
*/
|
||||
EVENT_TYPES: ["beforefeatureadded", "featureadded", "featuresadded",
|
||||
EVENT_TYPES: ["beforefeatureadded", "beforefeaturesadded",
|
||||
"featureadded", "featuresadded",
|
||||
"beforefeatureremoved", "featureremoved", "featuresremoved",
|
||||
"beforefeatureselected", "featureselected", "featureunselected",
|
||||
"beforefeaturemodified", "featuremodified", "afterfeaturemodified",
|
||||
@@ -407,19 +413,14 @@ OpenLayers.Layer.Vector = OpenLayers.Class(OpenLayers.Layer, {
|
||||
}
|
||||
|
||||
if(!zoomChanged && coordSysUnchanged) {
|
||||
var unrenderedFeatures = {};
|
||||
for(var i in this.unrenderedFeatures) {
|
||||
var feature = this.unrenderedFeatures[i];
|
||||
if(!this.drawFeature(feature)) {
|
||||
unrenderedFeatures[i] = feature;
|
||||
}
|
||||
this.drawFeature(feature);
|
||||
}
|
||||
this.unrenderedFeatures = unrenderedFeatures;
|
||||
}
|
||||
}
|
||||
|
||||
if (!this.drawn || zoomChanged || !coordSysUnchanged) {
|
||||
this.unrenderedFeatures = {};
|
||||
this.drawn = true;
|
||||
var feature;
|
||||
for(var i=0, len=this.features.length; i<len; i++) {
|
||||
@@ -429,9 +430,7 @@ OpenLayers.Layer.Vector = OpenLayers.Class(OpenLayers.Layer, {
|
||||
this.renderer.locked = false;
|
||||
}
|
||||
feature = this.features[i];
|
||||
if (!this.drawFeature(feature)) {
|
||||
this.unrenderedFeatures[feature.id] = feature;
|
||||
};
|
||||
this.drawFeature(feature);
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -450,6 +449,15 @@ OpenLayers.Layer.Vector = OpenLayers.Class(OpenLayers.Layer, {
|
||||
}
|
||||
|
||||
var notify = !options || !options.silent;
|
||||
if(notify) {
|
||||
var event = {features: features};
|
||||
var ret = this.events.triggerEvent("beforefeaturesadded", event);
|
||||
if(ret === false) {
|
||||
return;
|
||||
}
|
||||
features = event.features;
|
||||
}
|
||||
|
||||
|
||||
for (var i=0, len=features.length; i<len; i++) {
|
||||
if (i != (features.length - 1)) {
|
||||
@@ -476,16 +484,15 @@ OpenLayers.Layer.Vector = OpenLayers.Class(OpenLayers.Layer, {
|
||||
}
|
||||
|
||||
if (notify) {
|
||||
this.events.triggerEvent("beforefeatureadded", {
|
||||
feature: feature
|
||||
});
|
||||
if(this.events.triggerEvent("beforefeatureadded",
|
||||
{feature: feature}) === false) {
|
||||
continue;
|
||||
};
|
||||
this.preFeatureInsert(feature);
|
||||
}
|
||||
|
||||
if (this.drawn) {
|
||||
if(!this.drawFeature(feature)) {
|
||||
this.unrenderedFeatures[feature.id] = feature;
|
||||
}
|
||||
this.drawFeature(feature);
|
||||
}
|
||||
|
||||
if (notify) {
|
||||
@@ -603,10 +610,6 @@ OpenLayers.Layer.Vector = OpenLayers.Class(OpenLayers.Layer, {
|
||||
* Parameters:
|
||||
* feature - {<OpenLayers.Feature.Vector>}
|
||||
* style - {Object} Symbolizer hash or {String} renderIntent
|
||||
*
|
||||
* Returns:
|
||||
* {Boolean} true if the renderer was able to draw the feature, false
|
||||
* otherwise
|
||||
*/
|
||||
drawFeature: function(feature, style) {
|
||||
if (typeof style != "object") {
|
||||
@@ -618,7 +621,11 @@ OpenLayers.Layer.Vector = OpenLayers.Class(OpenLayers.Layer, {
|
||||
}
|
||||
}
|
||||
|
||||
return this.renderer.drawFeature(feature, style);
|
||||
if (!this.renderer.drawFeature(feature, style)) {
|
||||
this.unrenderedFeatures[feature.id] = feature;
|
||||
} else {
|
||||
delete this.unrenderedFeatures[feature.id];
|
||||
};
|
||||
},
|
||||
|
||||
/**
|
||||
|
||||
@@ -167,7 +167,14 @@ OpenLayers.Map = OpenLayers.Class({
|
||||
|
||||
/**
|
||||
* Property: controls
|
||||
* {Array(<OpenLayers.Control>)} List of controls associated with the map
|
||||
* {Array(<OpenLayers.Control>)} List of controls associated with the map.
|
||||
*
|
||||
* If not provided in the map options at construction, the map will
|
||||
* be given the following controls by default:
|
||||
* - <OpenLayers.Control.Navigation>
|
||||
* - <OpenLayers.Control.PanZoom>
|
||||
* - <OpenLayers.Control.ArgParser>
|
||||
* - <OpenLayers.Control.Attribution>
|
||||
*/
|
||||
controls: null,
|
||||
|
||||
|
||||
@@ -112,6 +112,15 @@ OpenLayers.Protocol.HTTP = OpenLayers.Class(OpenLayers.Protocol, {
|
||||
* options - {Object} Optional object for configuring the request.
|
||||
* This object is modified and should not be reused.
|
||||
*
|
||||
* Valid options:
|
||||
* url - {String} Url for the request.
|
||||
* params - {Object} Parameters to get serialized as a query string.
|
||||
* headers - {Object} Headers to be set on the request.
|
||||
* filter - {<OpenLayers.Filter.BBOX>} If a bbox filter is sent, it will be
|
||||
* serialized according to the OpenSearch Geo extension
|
||||
* (bbox=minx,miny,maxx,maxy). Note that a BBOX filter as the child
|
||||
* of a logical filter will not be serialized.
|
||||
*
|
||||
* Returns:
|
||||
* {<OpenLayers.Protocol.Response>} A response object, whose "priv" property
|
||||
* references the HTTP request, this object is also passed to the
|
||||
@@ -121,6 +130,14 @@ OpenLayers.Protocol.HTTP = OpenLayers.Class(OpenLayers.Protocol, {
|
||||
read: function(options) {
|
||||
options = OpenLayers.Util.applyDefaults(options, this.options);
|
||||
var resp = new OpenLayers.Protocol.Response({requestType: "read"});
|
||||
|
||||
if(options.filter && options.filter instanceof OpenLayers.Filter.Spatial) {
|
||||
if(options.filter.type == OpenLayers.Filter.Spatial.BBOX) {
|
||||
options.params = OpenLayers.Util.extend(options.params, {
|
||||
bbox: options.filter.value.toArray()
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
resp.priv = OpenLayers.Request.GET({
|
||||
url: options.url,
|
||||
|
||||
87
lib/OpenLayers/Protocol/SQL.js
Normal file
87
lib/OpenLayers/Protocol/SQL.js
Normal file
@@ -0,0 +1,87 @@
|
||||
/* 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/Protocol.js
|
||||
*/
|
||||
|
||||
/**
|
||||
* Class: OpenLayers.Protocol.SQL
|
||||
* Abstract SQL protocol class. Not to be instantiated directly. Use
|
||||
* one of the SQL protocol subclasses instead.
|
||||
*
|
||||
* Inherits from:
|
||||
* - <OpenLayers.Protocol>
|
||||
*/
|
||||
OpenLayers.Protocol.SQL = OpenLayers.Class(OpenLayers.Protocol, {
|
||||
|
||||
/**
|
||||
* APIProperty: databaseName
|
||||
* {String}
|
||||
*/
|
||||
databaseName: 'ol',
|
||||
|
||||
/**
|
||||
* APIProperty: tableName
|
||||
* Name of the database table into which Features should be saved.
|
||||
*/
|
||||
tableName: "ol_vector_features",
|
||||
|
||||
/**
|
||||
* Property: postReadFiltering
|
||||
* {Boolean} Whether the filter (if there's one) must be applied after
|
||||
* the features have been read from the database; for example the
|
||||
* BBOX strategy passes the read method a BBOX spatial filter, if
|
||||
* postReadFiltering is true every feature read from the database
|
||||
* will go through the BBOX spatial filter, which can be costly;
|
||||
* defaults to true.
|
||||
*/
|
||||
postReadFiltering: true,
|
||||
|
||||
/**
|
||||
* Constructor: OpenLayers.Protocol.SQL
|
||||
*/
|
||||
initialize: function(options) {
|
||||
OpenLayers.Protocol.prototype.initialize.apply(this, [options]);
|
||||
},
|
||||
|
||||
/**
|
||||
* APIMethod: destroy
|
||||
* Clean up the protocol.
|
||||
*/
|
||||
destroy: function() {
|
||||
OpenLayers.Protocol.prototype.destroy.apply(this);
|
||||
},
|
||||
|
||||
/**
|
||||
* APIMethod: supported
|
||||
* This should be overridden by specific subclasses
|
||||
*
|
||||
* Returns:
|
||||
* {Boolean} Whether or not the browser supports the SQL backend
|
||||
*/
|
||||
supported: function() {
|
||||
return false;
|
||||
},
|
||||
|
||||
/**
|
||||
* Method: evaluateFilter
|
||||
* If postReadFiltering is true evaluate the filter against the feature
|
||||
* and return the result of the evaluation, otherwise return true.
|
||||
*
|
||||
* Parameters:
|
||||
* {<OpenLayers.Feature.Vector>} The feature.
|
||||
* {<OpenLayers.Filter>} The filter.
|
||||
*
|
||||
* Returns:
|
||||
* {Boolean} true if postReadFiltering if false, the result of the
|
||||
* filter evaluation otherwise.
|
||||
*/
|
||||
evaluateFilter: function(feature, filter) {
|
||||
return filter && this.postReadFiltering ?
|
||||
filter.evaluate(feature) : true;
|
||||
},
|
||||
|
||||
CLASS_NAME: "OpenLayers.Protocol.SQL"
|
||||
});
|
||||
559
lib/OpenLayers/Protocol/SQL/Gears.js
Normal file
559
lib/OpenLayers/Protocol/SQL/Gears.js
Normal file
@@ -0,0 +1,559 @@
|
||||
/* 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 Gears/gears_init.js
|
||||
* @requires OpenLayers/Protocol/SQL.js
|
||||
* @requires OpenLayers/Format/JSON.js
|
||||
* @requires OpenLayers/Format/WKT.js
|
||||
*/
|
||||
|
||||
/**
|
||||
* Class: OpenLayers.Protocol.SQL.Gears
|
||||
* This Protocol stores feature in the browser via the Gears Database module
|
||||
* <http://code.google.com/apis/gears/api_database.html>.
|
||||
*
|
||||
* The main advantage is that all the read, create, update and delete operations
|
||||
* can be done offline.
|
||||
*
|
||||
* Inherits from:
|
||||
* - <OpenLayers.Protocol.SQL>
|
||||
*/
|
||||
OpenLayers.Protocol.SQL.Gears = OpenLayers.Class(OpenLayers.Protocol.SQL, {
|
||||
|
||||
/**
|
||||
* Property: FID_PREFIX
|
||||
* {String}
|
||||
*/
|
||||
FID_PREFIX: '__gears_fid__',
|
||||
|
||||
/**
|
||||
* Property: NULL_GEOMETRY
|
||||
* {String}
|
||||
*/
|
||||
NULL_GEOMETRY: '__gears_null_geometry__',
|
||||
|
||||
/**
|
||||
* Property: NULL_FEATURE_STATE
|
||||
* {String}
|
||||
*/
|
||||
NULL_FEATURE_STATE: '__gears_null_feature_state__',
|
||||
|
||||
/**
|
||||
* Property: jsonParser
|
||||
* {<OpenLayers.Format.JSON>}
|
||||
*/
|
||||
jsonParser: null,
|
||||
|
||||
/**
|
||||
* Property: wktParser
|
||||
* {<OpenLayers.Format.WKT>}
|
||||
*/
|
||||
wktParser: null,
|
||||
|
||||
/**
|
||||
* Property: fidRegExp
|
||||
* {RegExp} Regular expression to know whether a feature was
|
||||
* created in offline mode.
|
||||
*/
|
||||
fidRegExp: null,
|
||||
|
||||
/**
|
||||
* Property: saveFeatureState
|
||||
* {Boolean} Whether to save the feature state (<OpenLayers.State>)
|
||||
* into the database, defaults to true.
|
||||
*/
|
||||
saveFeatureState: true,
|
||||
|
||||
/**
|
||||
* Property: typeOfFid
|
||||
* {String} The type of the feature identifier, either "number" or
|
||||
* "string", defaults to "string".
|
||||
*/
|
||||
typeOfFid: "string",
|
||||
|
||||
/**
|
||||
* Property: db
|
||||
* {GearsDatabase}
|
||||
*/
|
||||
db: null,
|
||||
|
||||
/**
|
||||
* Constructor: OpenLayers.Protocol.SQL.Gears
|
||||
*/
|
||||
initialize: function(options) {
|
||||
if (!this.supported()) {
|
||||
return;
|
||||
}
|
||||
OpenLayers.Protocol.SQL.prototype.initialize.apply(this, [options]);
|
||||
this.jsonParser = new OpenLayers.Format.JSON();
|
||||
this.wktParser = new OpenLayers.Format.WKT();
|
||||
|
||||
this.fidRegExp = new RegExp('^' + this.FID_PREFIX);
|
||||
this.initializeDatabase();
|
||||
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* Method: initializeDatabase
|
||||
*/
|
||||
initializeDatabase: function() {
|
||||
this.db = google.gears.factory.create('beta.database');
|
||||
this.db.open(this.databaseName);
|
||||
this.db.execute(
|
||||
"CREATE TABLE IF NOT EXISTS " + this.tableName +
|
||||
" (fid TEXT UNIQUE, geometry TEXT, properties TEXT," +
|
||||
" state TEXT)");
|
||||
},
|
||||
|
||||
/**
|
||||
* APIMethod: destroy
|
||||
* Clean up the protocol.
|
||||
*/
|
||||
destroy: function() {
|
||||
this.db.close();
|
||||
this.db = null;
|
||||
|
||||
this.jsonParser = null;
|
||||
this.wktParser = null;
|
||||
|
||||
OpenLayers.Protocol.SQL.prototype.destroy.apply(this);
|
||||
},
|
||||
|
||||
/**
|
||||
* APIMethod: supported
|
||||
* Determine whether a browser supports Gears
|
||||
*
|
||||
* Returns:
|
||||
* {Boolean} The browser supports Gears
|
||||
*/
|
||||
supported: function() {
|
||||
return !!(window.google && google.gears);
|
||||
},
|
||||
|
||||
/**
|
||||
* Method: read
|
||||
* Read all features from the database and return a
|
||||
* <OpenLayers.Protocol.Response> instance. If the options parameter
|
||||
* contains a callback attribute, the function is called with the response
|
||||
* as a parameter.
|
||||
*
|
||||
* Parameters:
|
||||
* options - {Object} Optional object for configuring the request; it
|
||||
* can have the {Boolean} property "noFeatureStateReset" which
|
||||
* specifies if the state of features read from the Gears
|
||||
* database must be reset to null, if "noFeatureStateReset"
|
||||
* is undefined or false then each feature's state is reset
|
||||
* to null, if "noFeatureStateReset" is true the feature state
|
||||
* is preserved.
|
||||
*
|
||||
* Returns:
|
||||
* {<OpenLayers.Protocol.Response>} An <OpenLayers.Protocol.Response>
|
||||
* object.
|
||||
*/
|
||||
read: function(options) {
|
||||
options = OpenLayers.Util.applyDefaults(options, this.options);
|
||||
|
||||
var feature, features = [];
|
||||
var rs = this.db.execute("SELECT * FROM " + this.tableName);
|
||||
while (rs.isValidRow()) {
|
||||
feature = this.unfreezeFeature(rs);
|
||||
if (this.evaluateFilter(feature, options.filter)) {
|
||||
if (!options.noFeatureStateReset) {
|
||||
feature.state = null;
|
||||
}
|
||||
features.push(feature);
|
||||
}
|
||||
rs.next();
|
||||
}
|
||||
rs.close();
|
||||
|
||||
var resp = new OpenLayers.Protocol.Response({
|
||||
code: OpenLayers.Protocol.Response.SUCCESS,
|
||||
requestType: "read",
|
||||
features: features
|
||||
});
|
||||
|
||||
if (options && options.callback) {
|
||||
options.callback.call(options.scope, resp);
|
||||
}
|
||||
|
||||
return resp;
|
||||
},
|
||||
|
||||
/**
|
||||
* Method: unfreezeFeature
|
||||
*
|
||||
* Parameters:
|
||||
* row - {ResultSet}
|
||||
*
|
||||
* Returns:
|
||||
* {<OpenLayers.Feature.Vector>}
|
||||
*/
|
||||
unfreezeFeature: function(row) {
|
||||
var feature;
|
||||
var wkt = row.fieldByName('geometry');
|
||||
if (wkt == this.NULL_GEOMETRY) {
|
||||
feature = new OpenLayers.Feature.Vector();
|
||||
} else {
|
||||
feature = this.wktParser.read(wkt);
|
||||
}
|
||||
|
||||
feature.attributes = this.jsonParser.read(
|
||||
row.fieldByName('properties'));
|
||||
|
||||
feature.fid = this.extractFidFromField(row.fieldByName('fid'));
|
||||
|
||||
var state = row.fieldByName('state');
|
||||
if (state == this.NULL_FEATURE_STATE) {
|
||||
state = null;
|
||||
}
|
||||
feature.state = state;
|
||||
|
||||
return feature;
|
||||
},
|
||||
|
||||
/**
|
||||
* Method: extractFidFromField
|
||||
*
|
||||
* Parameters:
|
||||
* field - {String}
|
||||
*
|
||||
* Returns
|
||||
* {String} or {Number} The fid.
|
||||
*/
|
||||
extractFidFromField: function(field) {
|
||||
if (!field.match(this.fidRegExp) && this.typeOfFid == "number") {
|
||||
field = parseFloat(field);
|
||||
}
|
||||
return field;
|
||||
},
|
||||
|
||||
/**
|
||||
* Method: create
|
||||
* Create new features into the database.
|
||||
*
|
||||
* Parameters:
|
||||
* features - {Array({<OpenLayers.Feature.Vector>})} or
|
||||
* {<OpenLayers.Feature.Vector>} The features to create in
|
||||
* the database.
|
||||
* options - {Object} Optional object for configuring the request.
|
||||
*
|
||||
* Returns:
|
||||
* {<OpenLayers.Protocol.Response>} An <OpenLayers.Protocol.Response>
|
||||
* object.
|
||||
*/
|
||||
create: function(features, options) {
|
||||
options = OpenLayers.Util.applyDefaults(options, this.options);
|
||||
|
||||
var resp = this.createOrUpdate(features);
|
||||
resp.requestType = "create";
|
||||
|
||||
if (options && options.callback) {
|
||||
options.callback.call(options.scope, resp);
|
||||
}
|
||||
|
||||
return resp;
|
||||
},
|
||||
|
||||
/**
|
||||
* Method: update
|
||||
* Construct a request updating modified feature.
|
||||
*
|
||||
* Parameters:
|
||||
* features - {Array({<OpenLayers.Feature.Vector>})} or
|
||||
* {<OpenLayers.Feature.Vector>} The features to update in
|
||||
* the database.
|
||||
* options - {Object} Optional object for configuring the request.
|
||||
*
|
||||
* Returns:
|
||||
* {<OpenLayers.Protocol.Response>} An <OpenLayers.Protocol.Response>
|
||||
* object.
|
||||
*/
|
||||
update: function(features, options) {
|
||||
options = OpenLayers.Util.applyDefaults(options, this.options);
|
||||
|
||||
var resp = this.createOrUpdate(features);
|
||||
resp.requestType = "update";
|
||||
|
||||
if (options && options.callback) {
|
||||
options.callback.call(options.scope, resp);
|
||||
}
|
||||
|
||||
return resp;
|
||||
},
|
||||
|
||||
/**
|
||||
* Method: createOrUpdate
|
||||
* Construct a request for updating or creating features in the
|
||||
* database.
|
||||
*
|
||||
* Parameters:
|
||||
* features - {Array({<OpenLayers.Feature.Vector>})} or
|
||||
* {<OpenLayers.Feature.Vector>} The feature to create or update
|
||||
* in the database.
|
||||
*
|
||||
* Returns:
|
||||
* {<OpenLayers.Protocol.Response>} An <OpenLayers.Protocol.Response>
|
||||
* object.
|
||||
*/
|
||||
createOrUpdate: function(features) {
|
||||
if (!(features instanceof Array)) {
|
||||
features = [features];
|
||||
}
|
||||
|
||||
var i, len = features.length, feature;
|
||||
var insertedFeatures = new Array(len);
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
feature = features[i];
|
||||
var params = this.freezeFeature(feature);
|
||||
this.db.execute(
|
||||
"REPLACE INTO " + this.tableName +
|
||||
" (fid, geometry, properties, state)" +
|
||||
" VALUES (?, ?, ?, ?)",
|
||||
params);
|
||||
|
||||
var clone = feature.clone();
|
||||
clone.fid = this.extractFidFromField(params[0]);
|
||||
insertedFeatures[i] = clone;
|
||||
}
|
||||
|
||||
return new OpenLayers.Protocol.Response({
|
||||
code: OpenLayers.Protocol.Response.SUCCESS,
|
||||
features: insertedFeatures,
|
||||
reqFeatures: features
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Method: freezeFeature
|
||||
*
|
||||
* Parameters:
|
||||
* feature - {<OpenLayers.Feature.Vector>}
|
||||
* state - {String} The feature state to store in the database.
|
||||
*
|
||||
* Returns:
|
||||
* {Array}
|
||||
*/
|
||||
freezeFeature: function(feature) {
|
||||
// 2 notes:
|
||||
// - fid might not be a string
|
||||
// - getFeatureStateForFreeze needs the feature fid to it's stored
|
||||
// in the feature here
|
||||
feature.fid = feature.fid != null ?
|
||||
"" + feature.fid : OpenLayers.Util.createUniqueID(this.FID_PREFIX);
|
||||
|
||||
var geometry = feature.geometry != null ?
|
||||
feature.geometry.toString() : this.NULL_GEOMETRY;
|
||||
|
||||
var properties = this.jsonParser.write(feature.attributes);
|
||||
|
||||
var state = this.getFeatureStateForFreeze(feature);
|
||||
|
||||
return [feature.fid, geometry, properties, state];
|
||||
},
|
||||
|
||||
/**
|
||||
* Method: getFeatureStateForFreeze
|
||||
* Get the state of the feature to store into the database.
|
||||
*
|
||||
* Parameters:
|
||||
* feature - {<OpenLayers.Feature.Vector>} The feature.
|
||||
*
|
||||
* Returns
|
||||
* {String} The state
|
||||
*/
|
||||
getFeatureStateForFreeze: function(feature) {
|
||||
var state;
|
||||
if (!this.saveFeatureState) {
|
||||
state = this.NULL_FEATURE_STATE;
|
||||
} else if (this.createdOffline(feature)) {
|
||||
// if the feature was created in offline mode, its
|
||||
// state must remain INSERT
|
||||
state = OpenLayers.State.INSERT;
|
||||
} else {
|
||||
state = feature.state;
|
||||
}
|
||||
return state;
|
||||
},
|
||||
|
||||
/**
|
||||
* Method: delete
|
||||
* Delete features from the database.
|
||||
*
|
||||
* Parameters:
|
||||
* features - {Array({<OpenLayers.Feature.Vector>})} or
|
||||
* {<OpenLayers.Feature.Vector>}
|
||||
* options - {Object} Optional object for configuring the request.
|
||||
* This object is modified and should not be reused.
|
||||
*
|
||||
* Returns:
|
||||
* {<OpenLayers.Protocol.Response>} An <OpenLayers.Protocol.Response>
|
||||
* object.
|
||||
*/
|
||||
"delete": function(features, options) {
|
||||
if (!(features instanceof Array)) {
|
||||
features = [features];
|
||||
}
|
||||
|
||||
options = OpenLayers.Util.applyDefaults(options, this.options);
|
||||
|
||||
var i, len, feature;
|
||||
for (i = 0, len = features.length; i < len; i++) {
|
||||
feature = features[i];
|
||||
|
||||
// if saveFeatureState is set to true and if the feature wasn't created
|
||||
// in offline mode we don't delete it in the database but just update
|
||||
// it state column
|
||||
if (this.saveFeatureState && !this.createdOffline(feature)) {
|
||||
var toDelete = feature.clone();
|
||||
toDelete.fid = feature.fid;
|
||||
if (toDelete.geometry) {
|
||||
toDelete.geometry.destroy();
|
||||
toDelete.geometry = null;
|
||||
}
|
||||
toDelete.state = feature.state;
|
||||
this.createOrUpdate(toDelete);
|
||||
} else {
|
||||
this.db.execute(
|
||||
"DELETE FROM " + this.tableName +
|
||||
" WHERE fid = ?", [feature.fid]);
|
||||
}
|
||||
}
|
||||
|
||||
var resp = new OpenLayers.Protocol.Response({
|
||||
code: OpenLayers.Protocol.Response.SUCCESS,
|
||||
requestType: "delete",
|
||||
reqFeatures: features
|
||||
});
|
||||
|
||||
if (options && options.callback) {
|
||||
options.callback.call(options.scope, resp);
|
||||
}
|
||||
|
||||
return resp;
|
||||
},
|
||||
|
||||
/**
|
||||
* Method: createdOffline
|
||||
* Returns true if the feature had a feature id when it was created in
|
||||
* the Gears database, false otherwise; this is determined by
|
||||
* checking the form of the feature's fid value.
|
||||
*
|
||||
* Parameters:
|
||||
* feature - {<OpenLayers.Feature.Vector>}
|
||||
*
|
||||
* Returns:
|
||||
* {Boolean}
|
||||
*/
|
||||
createdOffline: function(feature) {
|
||||
return (typeof feature.fid == "string" &&
|
||||
!!(feature.fid.match(this.fidRegExp)));
|
||||
},
|
||||
|
||||
/**
|
||||
* Method: commit
|
||||
* Go over the features and for each take action
|
||||
* based on the feature state. Possible actions are create,
|
||||
* update and delete.
|
||||
*
|
||||
* Parameters:
|
||||
* features - {Array({<OpenLayers.Feature.Vector>})}
|
||||
* options - {Object} Object whose possible keys are "create", "update",
|
||||
* "delete", "callback" and "scope", the values referenced by the
|
||||
* first three are objects as passed to the "create", "update", and
|
||||
* "delete" methods, the value referenced by the "callback" key is
|
||||
* a function which is called when the commit operation is complete
|
||||
* using the scope referenced by the "scope" key.
|
||||
*
|
||||
* Returns:
|
||||
* {Array({<OpenLayers.Protocol.Response>})} An array of
|
||||
* <OpenLayers.Protocol.Response> objects, one per request made
|
||||
* to the database.
|
||||
*/
|
||||
commit: function(features, options) {
|
||||
var opt, resp = [], nRequests = 0, nResponses = 0;
|
||||
|
||||
function callback(resp) {
|
||||
if (++nResponses < nRequests) {
|
||||
resp.last = false;
|
||||
}
|
||||
this.callUserCallback(options, resp);
|
||||
}
|
||||
|
||||
var feature, toCreate = [], toUpdate = [], toDelete = [];
|
||||
for (var i = features.length - 1; i >= 0; i--) {
|
||||
feature = features[i];
|
||||
switch (feature.state) {
|
||||
case OpenLayers.State.INSERT:
|
||||
toCreate.push(feature);
|
||||
break;
|
||||
case OpenLayers.State.UPDATE:
|
||||
toUpdate.push(feature);
|
||||
break;
|
||||
case OpenLayers.State.DELETE:
|
||||
toDelete.push(feature);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (toCreate.length > 0) {
|
||||
nRequests++;
|
||||
opt = OpenLayers.Util.applyDefaults(
|
||||
{"callback": callback, "scope": this},
|
||||
options.create
|
||||
);
|
||||
resp.push(this.create(toCreate, opt));
|
||||
}
|
||||
if (toUpdate.length > 0) {
|
||||
nRequests++;
|
||||
opt = OpenLayers.Util.applyDefaults(
|
||||
{"callback": callback, "scope": this},
|
||||
options.update
|
||||
);
|
||||
resp.push(this.update(toUpdate, opt));
|
||||
}
|
||||
if (toDelete.length > 0) {
|
||||
nRequests++;
|
||||
opt = OpenLayers.Util.applyDefaults(
|
||||
{"callback": callback, "scope": this},
|
||||
options["delete"]
|
||||
);
|
||||
resp.push(this["delete"](toDelete, opt));
|
||||
}
|
||||
|
||||
return resp;
|
||||
},
|
||||
|
||||
/**
|
||||
* Method: clear
|
||||
* Removes all rows of the table.
|
||||
*/
|
||||
clear: function() {
|
||||
this.db.execute("DELETE FROM " + this.tableName);
|
||||
},
|
||||
|
||||
/**
|
||||
* Method: callUserCallback
|
||||
* This method is called from within commit each time a request is made
|
||||
* to the database, it is responsible for calling the user-supplied
|
||||
* callbacks.
|
||||
*
|
||||
* Parameters:
|
||||
* options - {Object} The map of options passed to the commit call.
|
||||
* resp - {<OpenLayers.Protocol.Response>}
|
||||
*/
|
||||
callUserCallback: function(options, resp) {
|
||||
var opt = options[resp.requestType];
|
||||
if (opt && opt.callback) {
|
||||
opt.callback.call(opt.scope, resp);
|
||||
}
|
||||
if (resp.last && options.callback) {
|
||||
options.callback.call(options.scope);
|
||||
}
|
||||
},
|
||||
|
||||
CLASS_NAME: "OpenLayers.Protocol.SQL.Gears"
|
||||
});
|
||||
@@ -810,7 +810,9 @@ OpenLayers.Renderer.Elements = OpenLayers.Class(OpenLayers.Renderer, {
|
||||
|
||||
if (this.indexer) {
|
||||
this.indexer.remove(element);
|
||||
|
||||
}
|
||||
|
||||
if (element._style.backgroundGraphic) {
|
||||
var backgroundId = geometry.id + this.BACKGROUND_ID_SUFFIX;
|
||||
var bElem = OpenLayers.Util.getElement(backgroundId);
|
||||
if (bElem && bElem.parentNode) {
|
||||
|
||||
@@ -153,7 +153,7 @@ OpenLayers.Renderer.SVG = OpenLayers.Class(OpenLayers.Renderer.Elements, {
|
||||
* y - {Float}
|
||||
*
|
||||
* Returns:
|
||||
* {Boolean} true if the translation parameters ar in the valid coordinates
|
||||
* {Boolean} true if the translation parameters are in the valid coordinates
|
||||
* range, false otherwise.
|
||||
*/
|
||||
translate: function(x, y) {
|
||||
|
||||
@@ -33,6 +33,12 @@ OpenLayers.Renderer.VML = OpenLayers.Class(OpenLayers.Renderer.Elements, {
|
||||
*/
|
||||
symbolCache: {},
|
||||
|
||||
/**
|
||||
* Property: offset
|
||||
* {Object} Hash with "x" and "y" properties
|
||||
*/
|
||||
offset: null,
|
||||
|
||||
/**
|
||||
* Constructor: OpenLayers.Renderer.VML
|
||||
* Create a new VML renderer.
|
||||
@@ -50,8 +56,10 @@ OpenLayers.Renderer.VML = OpenLayers.Class(OpenLayers.Renderer.Elements, {
|
||||
style.addRule('olv\\:*', "behavior: url(#default#VML); " +
|
||||
"position: absolute; display: inline-block;");
|
||||
}
|
||||
|
||||
OpenLayers.Renderer.Elements.prototype.initialize.apply(this,
|
||||
arguments);
|
||||
this.offset = {x: 0, y: 0};
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -90,8 +98,18 @@ OpenLayers.Renderer.VML = OpenLayers.Class(OpenLayers.Renderer.Elements, {
|
||||
arguments);
|
||||
var resolution = this.getResolution();
|
||||
|
||||
var org = extent.left/resolution + " " +
|
||||
(extent.top/resolution - this.size.h);
|
||||
var left = extent.left/resolution;
|
||||
var top = extent.top/resolution - this.size.h;
|
||||
if (resolutionChanged) {
|
||||
this.offset = {x: left, y: top};
|
||||
left = 0;
|
||||
top = 0;
|
||||
} else {
|
||||
left = left - this.offset.x;
|
||||
top = top - this.offset.y;
|
||||
}
|
||||
|
||||
var org = left + " " + top;
|
||||
this.root.setAttribute("coordorigin", org);
|
||||
|
||||
var size = this.size.w + " " + this.size.h;
|
||||
@@ -191,8 +209,8 @@ OpenLayers.Renderer.VML = OpenLayers.Class(OpenLayers.Renderer.Elements, {
|
||||
var yOffset = (style.graphicYOffset != undefined) ?
|
||||
style.graphicYOffset : -(0.5 * height);
|
||||
|
||||
node.style.left = ((geometry.x/resolution)+xOffset).toFixed();
|
||||
node.style.top = ((geometry.y/resolution)-(yOffset+height)).toFixed();
|
||||
node.style.left = ((geometry.x/resolution - this.offset.x)+xOffset).toFixed();
|
||||
node.style.top = ((geometry.y/resolution - this.offset.y)-(yOffset+height)).toFixed();
|
||||
node.style.width = width + "px";
|
||||
node.style.height = height + "px";
|
||||
node.style.flip = "y";
|
||||
@@ -448,10 +466,10 @@ OpenLayers.Renderer.VML = OpenLayers.Class(OpenLayers.Renderer.Elements, {
|
||||
var resolution = this.getResolution();
|
||||
|
||||
var scaledBox =
|
||||
new OpenLayers.Bounds((bbox.left/resolution).toFixed(),
|
||||
(bbox.bottom/resolution).toFixed(),
|
||||
(bbox.right/resolution).toFixed(),
|
||||
(bbox.top/resolution).toFixed());
|
||||
new OpenLayers.Bounds((bbox.left/resolution - this.offset.x).toFixed(),
|
||||
(bbox.bottom/resolution - this.offset.y).toFixed(),
|
||||
(bbox.right/resolution - this.offset.x).toFixed(),
|
||||
(bbox.top/resolution - this.offset.y).toFixed());
|
||||
|
||||
// Set the internal coordinate system to draw the path
|
||||
node.style.left = scaledBox.left + "px";
|
||||
@@ -613,9 +631,9 @@ OpenLayers.Renderer.VML = OpenLayers.Class(OpenLayers.Renderer.Elements, {
|
||||
drawCircle: function(node, geometry, radius) {
|
||||
if(!isNaN(geometry.x)&& !isNaN(geometry.y)) {
|
||||
var resolution = this.getResolution();
|
||||
|
||||
node.style.left = ((geometry.x /resolution).toFixed() - radius) + "px";
|
||||
node.style.top = ((geometry.y /resolution).toFixed() - radius) + "px";
|
||||
|
||||
node.style.left = ((geometry.x /resolution - this.offset.x).toFixed() - radius) + "px";
|
||||
node.style.top = ((geometry.y /resolution - this.offset.y).toFixed() - radius) + "px";
|
||||
|
||||
var diameter = radius * 2;
|
||||
|
||||
@@ -680,8 +698,8 @@ OpenLayers.Renderer.VML = OpenLayers.Class(OpenLayers.Renderer.Elements, {
|
||||
var comp, x, y;
|
||||
for (var i = 0; i < numComponents; i++) {
|
||||
comp = geometry.components[i];
|
||||
x = (comp.x/resolution);
|
||||
y = (comp.y/resolution);
|
||||
x = (comp.x/resolution - this.offset.x);
|
||||
y = (comp.y/resolution - this.offset.y);
|
||||
parts[i] = " " + x.toFixed() + "," + y.toFixed() + " l ";
|
||||
}
|
||||
var end = (closeLine) ? " x e" : " e";
|
||||
@@ -713,8 +731,8 @@ OpenLayers.Renderer.VML = OpenLayers.Class(OpenLayers.Renderer.Elements, {
|
||||
path.push("m");
|
||||
for (i=0, ilen=linearRing.components.length; i<ilen; i++) {
|
||||
comp = linearRing.components[i];
|
||||
x = comp.x / resolution;
|
||||
y = comp.y / resolution;
|
||||
x = comp.x / resolution - this.offset.x;
|
||||
y = comp.y / resolution - this.offset.y;
|
||||
path.push(" " + x.toFixed() + "," + y.toFixed());
|
||||
if (i==0) {
|
||||
path.push(" l");
|
||||
@@ -741,8 +759,8 @@ OpenLayers.Renderer.VML = OpenLayers.Class(OpenLayers.Renderer.Elements, {
|
||||
drawRectangle: function(node, geometry) {
|
||||
var resolution = this.getResolution();
|
||||
|
||||
node.style.left = geometry.x/resolution + "px";
|
||||
node.style.top = geometry.y/resolution + "px";
|
||||
node.style.left = (geometry.x/resolution - this.offset.x) + "px";
|
||||
node.style.top = (geometry.y/resolution - this.offset.y) + "px";
|
||||
node.style.width = geometry.width/resolution + "px";
|
||||
node.style.height = geometry.height/resolution + "px";
|
||||
|
||||
@@ -769,8 +787,8 @@ OpenLayers.Renderer.VML = OpenLayers.Class(OpenLayers.Renderer.Elements, {
|
||||
var comp, x, y;
|
||||
for (var i=0, len=geometry.components.length; i<len; i++) {
|
||||
comp = geometry.components[i];
|
||||
x = comp.x / resolution;
|
||||
y = comp.y / resolution;
|
||||
x = comp.x / resolution - this.offset.x;
|
||||
y = comp.y / resolution - this.offset.y;
|
||||
if ((i%3)==0 && (i/3)==0) {
|
||||
path.push("m");
|
||||
} else if ((i%3)==1) {
|
||||
|
||||
@@ -87,7 +87,11 @@ OpenLayers.Request = {
|
||||
var request = new OpenLayers.Request.XMLHttpRequest();
|
||||
var url = config.url;
|
||||
if(config.params) {
|
||||
url += "?" + OpenLayers.Util.getParameterString(config.params);
|
||||
var paramString = OpenLayers.Util.getParameterString(config.params);
|
||||
if(paramString.length > 0) {
|
||||
var separator = (url.indexOf('?') > -1) ? '&' : '?';
|
||||
url += separator + paramString;
|
||||
}
|
||||
}
|
||||
if(config.proxy && (url.indexOf("http") == 0)) {
|
||||
url = config.proxy + encodeURIComponent(url);
|
||||
@@ -265,4 +269,4 @@ OpenLayers.Request = {
|
||||
return OpenLayers.Request.issue(config);
|
||||
}
|
||||
|
||||
};
|
||||
};
|
||||
|
||||
210
lib/OpenLayers/Strategy/BBOX.js
Normal file
210
lib/OpenLayers/Strategy/BBOX.js
Normal file
@@ -0,0 +1,210 @@
|
||||
/* 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/Strategy.js
|
||||
* @requires OpenLayers/Filter/Spatial.js
|
||||
*/
|
||||
|
||||
/**
|
||||
* Class: OpenLayers.Strategy.BBOX
|
||||
* A simple strategy that reads new features when the viewport invalidates
|
||||
* some bounds.
|
||||
*
|
||||
* Inherits from:
|
||||
* - <OpenLayers.Strategy>
|
||||
*/
|
||||
OpenLayers.Strategy.BBOX = OpenLayers.Class(OpenLayers.Strategy, {
|
||||
|
||||
/**
|
||||
* Property: bounds
|
||||
* {<OpenLayers.Bounds>} The current data bounds.
|
||||
*/
|
||||
bounds: null,
|
||||
|
||||
/**
|
||||
* Property: ratio
|
||||
* {Float} The ratio of the data bounds to the viewport bounds (in each
|
||||
* dimension).
|
||||
*/
|
||||
ratio: 2,
|
||||
|
||||
/**
|
||||
* Property: response
|
||||
* {<OpenLayers.Protocol.Response>} The protocol response object returned
|
||||
* by the layer protocol.
|
||||
*/
|
||||
response: null,
|
||||
|
||||
/**
|
||||
* Constructor: OpenLayers.Strategy.BBOX
|
||||
* Create a new BBOX strategy.
|
||||
*
|
||||
* Parameters:
|
||||
* options - {Object} Optional object whose properties will be set on the
|
||||
* instance.
|
||||
*/
|
||||
initialize: function(options) {
|
||||
OpenLayers.Strategy.prototype.initialize.apply(this, [options]);
|
||||
},
|
||||
|
||||
/**
|
||||
* Method: activate
|
||||
* Set up strategy with regard to reading new batches of remote data.
|
||||
*
|
||||
* Returns:
|
||||
* {Boolean} The strategy was successfully activated.
|
||||
*/
|
||||
activate: function() {
|
||||
var activated = OpenLayers.Strategy.prototype.activate.call(this);
|
||||
if(activated) {
|
||||
this.layer.events.on({
|
||||
"moveend": this.update,
|
||||
scope: this
|
||||
});
|
||||
this.layer.events.on({
|
||||
"refresh": this.update,
|
||||
scope: this
|
||||
});
|
||||
}
|
||||
return activated;
|
||||
},
|
||||
|
||||
/**
|
||||
* Method: deactivate
|
||||
* Tear down strategy with regard to reading new batches of remote data.
|
||||
*
|
||||
* Returns:
|
||||
* {Boolean} The strategy was successfully deactivated.
|
||||
*/
|
||||
deactivate: function() {
|
||||
var deactivated = OpenLayers.Strategy.prototype.deactivate.call(this);
|
||||
if(deactivated) {
|
||||
this.layer.events.un({
|
||||
"moveend": this.update,
|
||||
scope: this
|
||||
});
|
||||
this.layer.events.un({
|
||||
"refresh": this.update,
|
||||
scope: this
|
||||
});
|
||||
}
|
||||
return deactivated;
|
||||
},
|
||||
|
||||
/**
|
||||
* Method: update
|
||||
* Callback function called on "moveend" or "refresh" layer events.
|
||||
*
|
||||
* Parameters:
|
||||
* options - {Object} An object with a property named "force", this
|
||||
* property references a boolean value indicating if new data
|
||||
* must be incondtionally read.
|
||||
*/
|
||||
update: function(options) {
|
||||
var mapBounds = this.layer.map.getExtent();
|
||||
if ((options && options.force) || this.invalidBounds(mapBounds)) {
|
||||
this.calculateBounds(mapBounds);
|
||||
this.triggerRead();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Method: invalidBounds
|
||||
*
|
||||
* Parameters:
|
||||
* mapBounds - {<OpenLayers.Bounds>} the current map extent, will be
|
||||
* retrieved from the map object if not provided
|
||||
*
|
||||
* Returns:
|
||||
* {Boolean}
|
||||
*/
|
||||
invalidBounds: function(mapBounds) {
|
||||
if(!mapBounds) {
|
||||
mapBounds = this.layer.map.getExtent();
|
||||
}
|
||||
return !this.bounds || !this.bounds.containsBounds(mapBounds);
|
||||
},
|
||||
|
||||
/**
|
||||
* Method: calculateBounds
|
||||
*
|
||||
* Parameters:
|
||||
* mapBounds - {<OpenLayers.Bounds>} the current map extent, will be
|
||||
* retrieved from the map object if not provided
|
||||
*/
|
||||
calculateBounds: function(mapBounds) {
|
||||
if(!mapBounds) {
|
||||
mapBounds = this.layer.map.getExtent();
|
||||
}
|
||||
var center = mapBounds.getCenterLonLat();
|
||||
var dataWidth = mapBounds.getWidth() * this.ratio;
|
||||
var dataHeight = mapBounds.getHeight() * this.ratio;
|
||||
this.bounds = new OpenLayers.Bounds(
|
||||
center.lon - (dataWidth / 2),
|
||||
center.lat - (dataHeight / 2),
|
||||
center.lon + (dataWidth / 2),
|
||||
center.lat + (dataHeight / 2)
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
* Method: triggerRead
|
||||
*
|
||||
* Returns:
|
||||
* {<OpenLayers.Protocol.Response>} The protocol response object
|
||||
* returned by the layer protocol.
|
||||
*/
|
||||
triggerRead: function() {
|
||||
var filter = this.createFilter();
|
||||
if (this.response && this.response.priv &&
|
||||
typeof this.response.priv.abort == "function") {
|
||||
this.response.priv.abort();
|
||||
}
|
||||
this.response = this.layer.protocol.read({
|
||||
filter: filter,
|
||||
callback: this.merge,
|
||||
scope: this
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Method: createFilter
|
||||
*
|
||||
* Returns
|
||||
* {<OpenLayers.Filter>} The filter object.
|
||||
*/
|
||||
createFilter: function() {
|
||||
var filter = new OpenLayers.Filter.Spatial({
|
||||
type: OpenLayers.Filter.Spatial.BBOX,
|
||||
value: this.bounds,
|
||||
projection: this.layer.projection
|
||||
});
|
||||
if (this.layer.filter) {
|
||||
filter = new OpenLayers.Filter.Logical({
|
||||
type: OpenLayers.Filter.Logical.AND,
|
||||
filters: [this.layer.filter, filter]
|
||||
});
|
||||
}
|
||||
return filter;
|
||||
},
|
||||
|
||||
/**
|
||||
* Method: merge
|
||||
* Given a list of features, determine which ones to add to the layer.
|
||||
*
|
||||
* Parameters:
|
||||
* resp - {<OpenLayers.Protocol.Response>} The response object passed
|
||||
* by the protocol.
|
||||
*/
|
||||
merge: function(resp) {
|
||||
this.layer.destroyFeatures();
|
||||
var features = resp.features;
|
||||
if(features && features.length > 0) {
|
||||
this.layer.addFeatures(features);
|
||||
}
|
||||
},
|
||||
|
||||
CLASS_NAME: "OpenLayers.Strategy.BBOX"
|
||||
});
|
||||
261
lib/OpenLayers/Strategy/Cluster.js
Normal file
261
lib/OpenLayers/Strategy/Cluster.js
Normal file
@@ -0,0 +1,261 @@
|
||||
/* 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/Strategy.js
|
||||
*/
|
||||
|
||||
/**
|
||||
* Class: OpenLayers.Strategy.Cluster
|
||||
* Strategy for vector feature clustering.
|
||||
*
|
||||
* Inherits from:
|
||||
* - <OpenLayers.Strategy>
|
||||
*/
|
||||
OpenLayers.Strategy.Cluster = OpenLayers.Class(OpenLayers.Strategy, {
|
||||
|
||||
/**
|
||||
* Property: layer
|
||||
* {<OpenLayers.Layer.Vector>} The layer that this strategy is assigned to.
|
||||
*/
|
||||
layer: null,
|
||||
|
||||
/**
|
||||
* APIProperty: distance
|
||||
* {Integer} Pixel distance between features that should be considered a
|
||||
* single cluster. Default is 20 pixels.
|
||||
*/
|
||||
distance: 20,
|
||||
|
||||
/**
|
||||
* Property: features
|
||||
* {Array(<OpenLayers.Feature.Vector>)} Cached features.
|
||||
*/
|
||||
features: null,
|
||||
|
||||
/**
|
||||
* Property: clusters
|
||||
* {Array(<OpenLayers.Feature.Vector>)} Calculated clusters.
|
||||
*/
|
||||
clusters: null,
|
||||
|
||||
/**
|
||||
* Property: clustering
|
||||
* {Boolean} The strategy is currently clustering features.
|
||||
*/
|
||||
clustering: false,
|
||||
|
||||
/**
|
||||
* Property: resolution
|
||||
* {Float} The resolution (map units per pixel) of the current cluster set.
|
||||
*/
|
||||
resolution: null,
|
||||
|
||||
/**
|
||||
* Constructor: OpenLayers.Strategy.Cluster
|
||||
* Create a new clustering strategy.
|
||||
*
|
||||
* Parameters:
|
||||
* options - {Object} Optional object whose properties will be set on the
|
||||
* instance.
|
||||
*/
|
||||
initialize: function(options) {
|
||||
OpenLayers.Strategy.prototype.initialize.apply(this, [options]);
|
||||
},
|
||||
|
||||
/**
|
||||
* APIMethod: activate
|
||||
* Activate the strategy. Register any listeners, do appropriate setup.
|
||||
*
|
||||
* Returns:
|
||||
* {Boolean} The strategy was successfully activated.
|
||||
*/
|
||||
activate: function() {
|
||||
var activated = OpenLayers.Strategy.prototype.activate.call(this);
|
||||
if(activated) {
|
||||
this.layer.events.on({
|
||||
"beforefeaturesadded": this.cacheFeatures,
|
||||
scope: this
|
||||
});
|
||||
this.layer.map.events.on({"zoomend": this.cluster, scope: this});
|
||||
}
|
||||
return activated;
|
||||
},
|
||||
|
||||
/**
|
||||
* APIMethod: deactivate
|
||||
* Deactivate the strategy. Unregister any listeners, do appropriate
|
||||
* tear-down.
|
||||
*
|
||||
* Returns:
|
||||
* {Boolean} The strategy was successfully deactivated.
|
||||
*/
|
||||
deactivate: function() {
|
||||
var deactivated = OpenLayers.Strategy.prototype.deactivate.call(this);
|
||||
if(deactivated) {
|
||||
this.clearCache();
|
||||
this.layer.events.un({
|
||||
"beforefeaturesadded": this.cacheFeatures,
|
||||
scope: this
|
||||
});
|
||||
this.layer.map.events.un({"zoomend": this.cluster, scope: this});
|
||||
}
|
||||
return deactivated;
|
||||
},
|
||||
|
||||
/**
|
||||
* Method: cacheFeatures
|
||||
* Cache features before they are added to the layer.
|
||||
*
|
||||
* Parameters:
|
||||
* event - {Object} The event that this was listening for. This will come
|
||||
* with a batch of features to be clustered.
|
||||
*
|
||||
* Returns:
|
||||
* {Boolean} False to stop layer from being added to the layer.
|
||||
*/
|
||||
cacheFeatures: function(event) {
|
||||
var propagate = true;
|
||||
if(!this.clustering) {
|
||||
this.clearCache();
|
||||
this.features = event.features;
|
||||
this.cluster();
|
||||
propagate = false;
|
||||
}
|
||||
return propagate;
|
||||
},
|
||||
|
||||
/**
|
||||
* Method: clearCache
|
||||
* Clear out the cached features. This destroys features, assuming
|
||||
* nothing else has a reference.
|
||||
*/
|
||||
clearCache: function() {
|
||||
if(this.features) {
|
||||
for(var i=0; i<this.features.length; ++i) {
|
||||
this.features[i].destroy();
|
||||
}
|
||||
}
|
||||
this.features = null;
|
||||
},
|
||||
|
||||
/**
|
||||
* Method: cluster
|
||||
* Cluster features based on some threshold distance.
|
||||
*/
|
||||
cluster: function() {
|
||||
if(this.features) {
|
||||
var resolution = this.layer.getResolution();
|
||||
if(resolution != this.resolution || !this.clustersExist()) {
|
||||
this.resolution = resolution;
|
||||
var clusters = [];
|
||||
var feature, clustered, cluster;
|
||||
for(var i=0; i<this.features.length; ++i) {
|
||||
feature = this.features[i];
|
||||
clustered = false;
|
||||
for(var j=0; j<clusters.length; ++j) {
|
||||
cluster = clusters[j];
|
||||
if(this.shouldCluster(cluster, feature)) {
|
||||
this.addToCluster(cluster, feature);
|
||||
clustered = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!clustered) {
|
||||
clusters.push(this.createCluster(this.features[i]));
|
||||
}
|
||||
}
|
||||
this.layer.destroyFeatures();
|
||||
if(clusters.length > 0) {
|
||||
this.clustering = true;
|
||||
// A legitimate feature addition could occur during this
|
||||
// addFeatures call. For clustering to behave well, features
|
||||
// should be removed from a layer before requesting a new batch.
|
||||
this.layer.addFeatures(clusters);
|
||||
this.clustering = false;
|
||||
}
|
||||
this.clusters = clusters;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Method: clustersExist
|
||||
* Determine whether calculated clusters are already on the layer.
|
||||
*
|
||||
* Returns:
|
||||
* {Boolean} The calculated clusters are already on the layer.
|
||||
*/
|
||||
clustersExist: function() {
|
||||
var exist = false;
|
||||
if(this.clusters && this.clusters.length > 0 &&
|
||||
this.clusters.length == this.layer.features.length) {
|
||||
exist = true;
|
||||
for(var i=0; i<this.clusters.length; ++i) {
|
||||
if(this.clusters[i] != this.layer.features[i]) {
|
||||
exist = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return exist;
|
||||
},
|
||||
|
||||
/**
|
||||
* Method: shouldCluster
|
||||
* Determine whether to include a feature in a given cluster.
|
||||
*
|
||||
* Parameters:
|
||||
* cluster - {<OpenLayers.Feature.Vector>} A cluster.
|
||||
* feature - {<OpenLayers.Feature.Vector>} A feature.
|
||||
*
|
||||
* Returns:
|
||||
* {Boolean} The feature should be included in the cluster.
|
||||
*/
|
||||
shouldCluster: function(cluster, feature) {
|
||||
var cc = cluster.geometry.getBounds().getCenterLonLat();
|
||||
var fc = feature.geometry.getBounds().getCenterLonLat();
|
||||
var distance = (
|
||||
Math.sqrt(
|
||||
Math.pow((cc.lon - fc.lon), 2) + Math.pow((cc.lat - fc.lat), 2)
|
||||
) / this.resolution
|
||||
);
|
||||
return (distance <= this.distance);
|
||||
},
|
||||
|
||||
/**
|
||||
* Method: addToCluster
|
||||
* Add a feature to a cluster.
|
||||
*
|
||||
* Parameters:
|
||||
* cluster - {<OpenLayers.Feature.Vector>} A cluster.
|
||||
* feature - {<OpenLayers.Feature.Vector>} A feature.
|
||||
*/
|
||||
addToCluster: function(cluster, feature) {
|
||||
cluster.cluster.push(feature);
|
||||
cluster.attributes.count += 1;
|
||||
},
|
||||
|
||||
/**
|
||||
* Method: createCluster
|
||||
* Given a feature, create a cluster.
|
||||
*
|
||||
* Parameters:
|
||||
* feature - {<OpenLayers.Feature.Vector>}
|
||||
*
|
||||
* Returns:
|
||||
* {<OpenLayers.Feature.Vector>} A cluster.
|
||||
*/
|
||||
createCluster: function(feature) {
|
||||
var center = feature.geometry.getBounds().getCenterLonLat();
|
||||
var cluster = new OpenLayers.Feature.Vector(
|
||||
new OpenLayers.Geometry.Point(center.lon, center.lat),
|
||||
{count: 1}
|
||||
);
|
||||
cluster.cluster = [feature];
|
||||
return cluster;
|
||||
},
|
||||
|
||||
CLASS_NAME: "OpenLayers.Strategy.Cluster"
|
||||
});
|
||||
241
lib/OpenLayers/Strategy/Paging.js
Normal file
241
lib/OpenLayers/Strategy/Paging.js
Normal file
@@ -0,0 +1,241 @@
|
||||
/* 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/Strategy.js
|
||||
*/
|
||||
|
||||
/**
|
||||
* Class: OpenLayers.Strategy.Paging
|
||||
* Strategy for vector feature paging
|
||||
*
|
||||
* Inherits from:
|
||||
* - <OpenLayers.Strategy>
|
||||
*/
|
||||
OpenLayers.Strategy.Paging = OpenLayers.Class(OpenLayers.Strategy, {
|
||||
|
||||
/**
|
||||
* Property: layer
|
||||
* {<OpenLayers.Layer.Vector>} The layer that this strategy is assigned to.
|
||||
*/
|
||||
layer: null,
|
||||
|
||||
/**
|
||||
* Property: features
|
||||
* {Array(<OpenLayers.Feature.Vector>)} Cached features.
|
||||
*/
|
||||
features: null,
|
||||
|
||||
/**
|
||||
* Property: length
|
||||
* {Integer} Number of features per page. Default is 10.
|
||||
*/
|
||||
length: 10,
|
||||
|
||||
/**
|
||||
* Property: num
|
||||
* {Integer} The currently displayed page number.
|
||||
*/
|
||||
num: null,
|
||||
|
||||
/**
|
||||
* Property: paging
|
||||
* {Boolean} The strategy is currently changing pages.
|
||||
*/
|
||||
paging: false,
|
||||
|
||||
/**
|
||||
* Constructor: OpenLayers.Strategy.Paging
|
||||
* Create a new paging strategy.
|
||||
*
|
||||
* Parameters:
|
||||
* options - {Object} Optional object whose properties will be set on the
|
||||
* instance.
|
||||
*/
|
||||
initialize: function(options) {
|
||||
OpenLayers.Strategy.prototype.initialize.apply(this, [options]);
|
||||
},
|
||||
|
||||
/**
|
||||
* APIMethod: activate
|
||||
* Activate the strategy. Register any listeners, do appropriate setup.
|
||||
*
|
||||
* Returns:
|
||||
* {Boolean} The strategy was successfully activated.
|
||||
*/
|
||||
activate: function() {
|
||||
var activated = OpenLayers.Strategy.prototype.activate.call(this);
|
||||
if(activated) {
|
||||
this.layer.events.on({
|
||||
"beforefeaturesadded": this.cacheFeatures,
|
||||
scope: this
|
||||
});
|
||||
}
|
||||
return activated;
|
||||
},
|
||||
|
||||
/**
|
||||
* APIMethod: deactivate
|
||||
* Deactivate the strategy. Unregister any listeners, do appropriate
|
||||
* tear-down.
|
||||
*
|
||||
* Returns:
|
||||
* {Boolean} The strategy was successfully deactivated.
|
||||
*/
|
||||
deactivate: function() {
|
||||
var deactivated = OpenLayers.Strategy.prototype.deactivate.call(this);
|
||||
if(deactivated) {
|
||||
this.clearCache();
|
||||
this.layer.events.un({
|
||||
"beforefeaturesadded": this.cacheFeatures,
|
||||
scope: this
|
||||
});
|
||||
}
|
||||
return deactivated;
|
||||
},
|
||||
|
||||
/**
|
||||
* Method: cacheFeatures
|
||||
* Cache features before they are added to the layer.
|
||||
*
|
||||
* Parameters:
|
||||
* event - {Object} The event that this was listening for. This will come
|
||||
* with a batch of features to be paged.
|
||||
*/
|
||||
cacheFeatures: function(event) {
|
||||
if(!this.paging) {
|
||||
this.clearCache();
|
||||
this.features = event.features;
|
||||
this.pageNext(event);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Method: clearCache
|
||||
* Clear out the cached features. This destroys features, assuming
|
||||
* nothing else has a reference.
|
||||
*/
|
||||
clearCache: function() {
|
||||
if(this.features) {
|
||||
for(var i=0; i<this.features.length; ++i) {
|
||||
this.features[i].destroy();
|
||||
}
|
||||
}
|
||||
this.features = null;
|
||||
this.num = null;
|
||||
},
|
||||
|
||||
/**
|
||||
* APIMethod: pageCount
|
||||
* Get the total count of pages given the current cache of features.
|
||||
*
|
||||
* Returns:
|
||||
* {Integer} The page count.
|
||||
*/
|
||||
pageCount: function() {
|
||||
var numFeatures = this.features ? this.features.length : 0;
|
||||
return Math.ceil(numFeatures / this.length);
|
||||
},
|
||||
|
||||
/**
|
||||
* APIMethod: pageNum
|
||||
* Get the zero based page number.
|
||||
*
|
||||
* Returns:
|
||||
* {Integer} The current page number being displayed.
|
||||
*/
|
||||
pageNum: function() {
|
||||
return this.num;
|
||||
},
|
||||
|
||||
/**
|
||||
* APIMethod: pageLength
|
||||
* Gets or sets page length.
|
||||
*
|
||||
* Parameters:
|
||||
* newLength: {Integer} Optional length to be set.
|
||||
*
|
||||
* Returns:
|
||||
* {Integer} The length of a page (number of features per page).
|
||||
*/
|
||||
pageLength: function(newLength) {
|
||||
if(newLength && newLength > 0) {
|
||||
this.length = newLength;
|
||||
}
|
||||
return this.length;
|
||||
},
|
||||
|
||||
/**
|
||||
* APIMethod: pageNext
|
||||
* Display the next page of features.
|
||||
*
|
||||
* Returns:
|
||||
* {Boolean} A new page was displayed.
|
||||
*/
|
||||
pageNext: function(event) {
|
||||
var changed = false;
|
||||
if(this.features) {
|
||||
if(this.num === null) {
|
||||
this.num = -1;
|
||||
}
|
||||
var start = (this.num + 1) * this.length;
|
||||
changed = this.page(start, event);
|
||||
}
|
||||
return changed;
|
||||
},
|
||||
|
||||
/**
|
||||
* APIMethod: pagePrevious
|
||||
* Display the previous page of features.
|
||||
*
|
||||
* Returns:
|
||||
* {Boolean} A new page was displayed.
|
||||
*/
|
||||
pagePrevious: function() {
|
||||
var changed = false;
|
||||
if(this.features) {
|
||||
if(this.num === null) {
|
||||
this.num = this.pageCount();
|
||||
}
|
||||
var start = (this.num - 1) * this.length;
|
||||
changed = this.page(start);
|
||||
}
|
||||
return changed;
|
||||
},
|
||||
|
||||
/**
|
||||
* Method: page
|
||||
* Display the page starting at the given index from the cache.
|
||||
*
|
||||
* Returns:
|
||||
* {Boolean} A new page was displayed.
|
||||
*/
|
||||
page: function(start, event) {
|
||||
var changed = false;
|
||||
if(this.features) {
|
||||
if(start >= 0 && start < this.features.length) {
|
||||
var num = Math.floor(start / this.length);
|
||||
if(num != this.num) {
|
||||
this.paging = true;
|
||||
var features = this.features.slice(start, start + this.length);
|
||||
this.layer.removeFeatures(this.layer.features);
|
||||
this.num = num;
|
||||
// modify the event if any
|
||||
if(event && event.features) {
|
||||
// this.was called by an event listener
|
||||
event.features = features;
|
||||
} else {
|
||||
// this was called directly on the strategy
|
||||
this.layer.addFeatures(features);
|
||||
}
|
||||
this.paging = false;
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return changed;
|
||||
},
|
||||
|
||||
CLASS_NAME: "OpenLayers.Strategy.Paging"
|
||||
});
|
||||
@@ -796,13 +796,18 @@ OpenLayers.Util.rad = function(x) {return x*Math.PI/180;};
|
||||
|
||||
/**
|
||||
* Function: distVincenty
|
||||
* Given two objects representing points with geographic coordinates, this
|
||||
* calculates the distance between those points on the surface of an
|
||||
* ellipsoid.
|
||||
*
|
||||
* Parameters:
|
||||
* p1 - {<OpenLayers.LonLat>} (or any object with both .lat, .lon properties)
|
||||
* p2 - {<OpenLayers.LonLat>} (or any object with both .lat, .lon properties)
|
||||
*
|
||||
* Returns:
|
||||
* {Float}
|
||||
* {Float} The distance (in km) between the two input points as measured on an
|
||||
* ellipsoid. Note that the input point objects must be in geographic
|
||||
* coordinates (decimal degrees) and the return distance is in kilometers.
|
||||
*/
|
||||
OpenLayers.Util.distVincenty=function(p1, p2) {
|
||||
var a = 6378137, b = 6356752.3142, f = 1/298.257223563;
|
||||
|
||||
Reference in New Issue
Block a user