Full read/write support for KML. All KML 2.1 geometries supported. All OL geometries supported (closes #927).
git-svn-id: http://svn.openlayers.org/trunk/openlayers@4219 dc9f47b5-9b13-0410-9fdd-eb0c1a62fdaf
This commit is contained in:
@@ -77,8 +77,8 @@
|
|||||||
formats = {
|
formats = {
|
||||||
wkt: new OpenLayers.Format.WKT(),
|
wkt: new OpenLayers.Format.WKT(),
|
||||||
geojson: new OpenLayers.Format.GeoJSON(),
|
geojson: new OpenLayers.Format.GeoJSON(),
|
||||||
gml: new OpenLayers.Format.GML() //,
|
gml: new OpenLayers.Format.GML(),
|
||||||
//kml: new OpenLayers.Format.KML()
|
kml: new OpenLayers.Format.KML()
|
||||||
};
|
};
|
||||||
|
|
||||||
map.setCenter(new OpenLayers.LonLat(0, 0), 1);
|
map.setCenter(new OpenLayers.LonLat(0, 0), 1);
|
||||||
@@ -146,7 +146,7 @@
|
|||||||
<label for="formatType">Format</label>
|
<label for="formatType">Format</label>
|
||||||
<select name="formatType" id="formatType">
|
<select name="formatType" id="formatType">
|
||||||
<option value="geojson" selected="selected">GeoJSON</option>
|
<option value="geojson" selected="selected">GeoJSON</option>
|
||||||
<!--<option value="kml">KML</option>-->
|
<option value="kml">KML</option>
|
||||||
<option value="gml">GML</option>
|
<option value="gml">GML</option>
|
||||||
<option value="wkt">Well-Known Text (WKT)</option>
|
<option value="wkt">Well-Known Text (WKT)</option>
|
||||||
</select>
|
</select>
|
||||||
|
|||||||
+586
-144
@@ -5,34 +5,63 @@
|
|||||||
/**
|
/**
|
||||||
* @requires OpenLayers/Format.js
|
* @requires OpenLayers/Format.js
|
||||||
* @requires OpenLayers/Feature/Vector.js
|
* @requires OpenLayers/Feature/Vector.js
|
||||||
* @requires OpenLayers/Ajax.js
|
|
||||||
*
|
|
||||||
* Class: OpenLayers.Format.KML
|
|
||||||
* Read only KML. Largely Proof of Concept: does not support advanced Features,
|
|
||||||
* including Polygons. Create a new instance with the
|
|
||||||
* <OpenLayers.Format.KML> constructor.
|
|
||||||
*
|
*
|
||||||
|
* Class: OpenLayers.Format.KML
|
||||||
|
* Read/Wite KML. Create a new instance with the <OpenLayers.Format.KML>
|
||||||
|
* constructor.
|
||||||
|
*
|
||||||
* Inherits from:
|
* Inherits from:
|
||||||
* - <OpenLayers.Format>
|
* - <OpenLayers.Format.XML>
|
||||||
*/
|
*/
|
||||||
OpenLayers.Format.KML = OpenLayers.Class(OpenLayers.Format, {
|
OpenLayers.Format.KML = OpenLayers.Class(OpenLayers.Format.XML, {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* APIProperty: kmlns
|
* APIProperty: kmlns
|
||||||
* KML Namespace to use. Defaults to 2.0 namespace.
|
* {String} KML Namespace to use. Defaults to 2.0 namespace.
|
||||||
*/
|
*/
|
||||||
kmlns: "http://earth.google.com/kml/2.0",
|
kmlns: "http://earth.google.com/kml/2.0",
|
||||||
|
|
||||||
|
/**
|
||||||
|
* APIProperty: placemarksDesc
|
||||||
|
* {String} Name of the placemarks. Default is "No description available."
|
||||||
|
*/
|
||||||
|
placemarksDesc: "No description available",
|
||||||
|
|
||||||
|
/**
|
||||||
|
* APIProperty: foldersName
|
||||||
|
* {String} Name of the folders. Default is "OpenLayers export."
|
||||||
|
*/
|
||||||
|
foldersName: "OpenLayers export",
|
||||||
|
|
||||||
|
/**
|
||||||
|
* APIProperty: foldersDesc
|
||||||
|
* {String} Description of the folders. Default is "Exported on [date]."
|
||||||
|
*/
|
||||||
|
foldersDesc: "Exported on " + new Date(),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* APIProperty: extractAttributes
|
||||||
|
* {Boolean} Extract attributes from KML. Default is true.
|
||||||
|
*/
|
||||||
|
extractAttributes: true,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor: OpenLayers.Format.KML
|
* Constructor: OpenLayers.Format.KML
|
||||||
* Create a new parser for KML
|
* Create a new parser for KML.
|
||||||
*
|
*
|
||||||
* Parameters:
|
* Parameters:
|
||||||
* options - {Object} An optional object whose properties will be set on
|
* options - {Object} An optional object whose properties will be set on
|
||||||
* this instance.
|
* this instance.
|
||||||
*/
|
*/
|
||||||
initialize: function(options) {
|
initialize: function(options) {
|
||||||
OpenLayers.Format.prototype.initialize.apply(this, [options]);
|
// compile regular expressions once instead of every time they are used
|
||||||
|
this.regExes = {
|
||||||
|
trimSpace: (/^\s*|\s*$/g),
|
||||||
|
removeSpace: (/\s*/g),
|
||||||
|
splitSpace: (/\s+/),
|
||||||
|
trimComma: (/\s*,\s*/g)
|
||||||
|
};
|
||||||
|
OpenLayers.Format.XML.prototype.initialize.apply(this, [options]);
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -40,156 +69,569 @@ OpenLayers.Format.KML = OpenLayers.Class(OpenLayers.Format, {
|
|||||||
* Read data from a string, and return a list of features.
|
* Read data from a string, and return a list of features.
|
||||||
*
|
*
|
||||||
* Parameters:
|
* Parameters:
|
||||||
* data - {string} or {XMLNode>} data to read/parse.
|
* data - {String} or {DOMElement} data to read/parse.
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* {Array(<OpenLayers.Feature.Vector>)} List of features.
|
||||||
*/
|
*/
|
||||||
read: function(data) {
|
read: function(data) {
|
||||||
if (typeof data == "string") {
|
if(typeof data == "string") {
|
||||||
data = OpenLayers.parseXMLString(data);
|
data = OpenLayers.Format.XML.prototype.read.apply(this, [data]);
|
||||||
}
|
}
|
||||||
var featureNodes = OpenLayers.Ajax.getElementsByTagNameNS(data, this.kmlns, "", "Placemark");
|
var featureNodes = this.getElementsByTagNameNS(data,
|
||||||
|
this.kmlns,
|
||||||
var features = [];
|
"Placemark");
|
||||||
|
var numFeatures = featureNodes.length;
|
||||||
// Process all the featureMembers
|
var features = new Array(numFeatures);
|
||||||
for (var i = 0; i < featureNodes.length; i++) {
|
for(var i=0; i<numFeatures; i++) {
|
||||||
var feature = this.parseFeature(featureNodes[i]);
|
var feature = this.parseFeature(featureNodes[i]);
|
||||||
|
if(feature) {
|
||||||
if (feature) {
|
features[i] = feature;
|
||||||
features.push(feature);
|
} else {
|
||||||
|
throw "Bad Placemark: " + i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return features;
|
return features;
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method: parseFeature
|
* Method: parseFeature
|
||||||
* This function is the core of the KML parsing code in OpenLayers.
|
* This function is the core of the KML parsing code in OpenLayers.
|
||||||
* It creates the geometries that are then attached to the returned
|
* It creates the geometries that are then attached to the returned
|
||||||
* feature, and calls parseAttributes() to get attribute data out.
|
* feature, and calls parseAttributes() to get attribute data out.
|
||||||
*
|
*
|
||||||
* Parameters:
|
* Parameters:
|
||||||
* xmlNode - {<DOMElement>}
|
* node - {<DOMElement>}
|
||||||
*/
|
*
|
||||||
parseFeature: function(xmlNode) {
|
* Returns:
|
||||||
var geom;
|
* {<OpenLayers.Feature.Vector>} A vector feature.
|
||||||
var p; // [points,bounds]
|
*/
|
||||||
|
parseFeature: function(node) {
|
||||||
var feature = new OpenLayers.Feature.Vector();
|
// only accept one geometry per feature - look for highest "order"
|
||||||
|
var order = ["MultiGeometry", "Polygon", "LineString", "Point"];
|
||||||
// match Point
|
var type, nodeList, geometry, parser;
|
||||||
if (OpenLayers.Ajax.getElementsByTagNameNS(xmlNode,
|
for(var i=0; i<order.length; ++i) {
|
||||||
this.kmlns, "", "Point").length != 0) {
|
type = order[i];
|
||||||
var point = OpenLayers.Ajax.getElementsByTagNameNS(xmlNode,
|
nodeList = this.getElementsByTagNameNS(node, this.kmlns, type);
|
||||||
this.kmlns, "", "Point")[0];
|
if(nodeList.length > 0) {
|
||||||
|
// only deal with first geometry of this type
|
||||||
p = this.parseCoords(point);
|
var parser = this.parseGeometry[type.toLowerCase()];
|
||||||
if (p.points) {
|
if(parser) {
|
||||||
geom = p.points[0];
|
geometry = parser.apply(this, [nodeList[0]]);
|
||||||
// TBD Bounds only set for one of multiple geometries
|
} else {
|
||||||
geom.extendBounds(p.bounds);
|
OpenLayers.Console.error("Unsupported geometry type: " +
|
||||||
}
|
type);
|
||||||
|
}
|
||||||
// match LineString
|
// stop looking for different geometry types
|
||||||
} else if (OpenLayers.Ajax.getElementsByTagNameNS(xmlNode,
|
break;
|
||||||
this.kmlns, "", "LineString").length != 0) {
|
|
||||||
var linestring = OpenLayers.Ajax.getElementsByTagNameNS(xmlNode,
|
|
||||||
this.kmlns, "", "LineString")[0];
|
|
||||||
p = this.parseCoords(linestring);
|
|
||||||
if (p.points) {
|
|
||||||
geom = new OpenLayers.Geometry.LineString(p.points);
|
|
||||||
// TBD Bounds only set for one of multiple geometries
|
|
||||||
geom.extendBounds(p.bounds);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
feature.geometry = geom;
|
// construct feature (optionally with attributes)
|
||||||
feature.attributes = this.parseAttributes(xmlNode);
|
var attributes;
|
||||||
|
if(this.extractAttributes) {
|
||||||
|
attributes = this.parseAttributes(node);
|
||||||
|
}
|
||||||
|
var feature = new OpenLayers.Feature.Vector(geometry, attributes);
|
||||||
|
|
||||||
|
var fid = node.getAttribute("id");
|
||||||
|
if(fid != null) {
|
||||||
|
feature.fid = fid;
|
||||||
|
}
|
||||||
|
|
||||||
return feature;
|
return feature;
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method: parseAttributes
|
* Property: parseGeometry
|
||||||
* recursive function parse the attributes of a KML node.
|
* Properties of this object are the functions that parse geometries based
|
||||||
* Searches for any child nodes which aren't geometries,
|
* on their type.
|
||||||
* and gets their value.
|
|
||||||
*
|
|
||||||
* Parameters:
|
|
||||||
* xmlNode - {<DOMElement>}
|
|
||||||
*/
|
*/
|
||||||
parseAttributes: function(xmlNode) {
|
parseGeometry: {
|
||||||
var nodes = xmlNode.childNodes;
|
|
||||||
var attributes = {};
|
/**
|
||||||
for(var i = 0; i < nodes.length; i++) {
|
* Method: parseGeometry.point
|
||||||
var name = nodes[i].nodeName;
|
* Given a KML node representing a point geometry, create an OpenLayers
|
||||||
var value = OpenLayers.Util.getXmlNodeValue(nodes[i]);
|
* point geometry.
|
||||||
// Ignore Geometry attributes
|
*
|
||||||
// match ".//gml:pos|.//gml:posList|.//gml:coordinates"
|
* Parameters:
|
||||||
if((name.search(":pos")!=-1)
|
* node - {DOMElement} A KML Point node.
|
||||||
||(name.search(":posList")!=-1)
|
*
|
||||||
||(name.search(":coordinates")!=-1)){
|
* Returns:
|
||||||
continue;
|
* {<OpenLayers.Geometry.Point>} A point geometry.
|
||||||
|
*/
|
||||||
|
point: function(node) {
|
||||||
|
var nodeList = this.getElementsByTagNameNS(node, this.kmlns,
|
||||||
|
"coordinates");
|
||||||
|
var coords = [];
|
||||||
|
if(nodeList.length > 0) {
|
||||||
|
var coordString = nodeList[0].firstChild.nodeValue;
|
||||||
|
coordString = coordString.replace(this.regExes.removeSpace, "");
|
||||||
|
coords = coordString.split(",");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for a leaf node
|
|
||||||
if((nodes[i].childNodes.length == 1 && nodes[i].childNodes[0].nodeName == "#text")
|
|
||||||
|| (nodes[i].childNodes.length == 0 && nodes[i].nodeName!="#text")) {
|
|
||||||
attributes[name] = value;
|
|
||||||
}
|
|
||||||
OpenLayers.Util.extend(attributes, this.parseAttributes(nodes[i]))
|
|
||||||
}
|
|
||||||
return attributes;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method: parseCoords
|
|
||||||
* Extract Geographic coordinates from an XML node.
|
|
||||||
*
|
|
||||||
* Parameters:
|
|
||||||
* xmlNode - {<XMLNode>}
|
|
||||||
*
|
|
||||||
* Returns:
|
|
||||||
* An array of <OpenLayers.Geometry.Point> points.
|
|
||||||
*/
|
|
||||||
parseCoords: function(xmlNode) {
|
|
||||||
var p = [];
|
|
||||||
p.points = [];
|
|
||||||
// TBD: Need to handle an array of coordNodes not just coordNodes[0]
|
|
||||||
|
|
||||||
var coordNodes = OpenLayers.Ajax.getElementsByTagNameNS(xmlNode, this.kmlns, "", "coordinates")[0];
|
|
||||||
var coordString = OpenLayers.Util.getXmlNodeValue(coordNodes);
|
|
||||||
|
|
||||||
var firstCoord = coordString.split(" ");
|
|
||||||
|
|
||||||
while (firstCoord[0] == "")
|
|
||||||
firstCoord.shift();
|
|
||||||
|
|
||||||
var dim = firstCoord[0].split(",").length;
|
|
||||||
|
|
||||||
// Extract an array of Numbers from CoordString
|
var point = null;
|
||||||
var nums = (coordString) ? coordString.split(/[, \n\t]+/) : [];
|
if(coords.length > 1) {
|
||||||
|
// preserve third dimension
|
||||||
|
if(coords.length == 2) {
|
||||||
// Remove elements caused by leading and trailing white space
|
coords[2] = null;
|
||||||
while (nums[0] == "")
|
}
|
||||||
nums.shift();
|
point = new OpenLayers.Geometry.Point(coords[0], coords[1],
|
||||||
|
coords[2]);
|
||||||
while (nums[nums.length-1] == "")
|
|
||||||
nums.pop();
|
|
||||||
|
|
||||||
for(i = 0; i < nums.length; i = i + dim) {
|
|
||||||
x = parseFloat(nums[i]);
|
|
||||||
y = parseFloat(nums[i+1]);
|
|
||||||
p.points.push(new OpenLayers.Geometry.Point(x, y));
|
|
||||||
|
|
||||||
if (!p.bounds) {
|
|
||||||
p.bounds = new OpenLayers.Bounds(x, y, x, y);
|
|
||||||
} else {
|
} else {
|
||||||
p.bounds.extend(x, y);
|
throw "Bad coordinate string: " + coordString;
|
||||||
|
}
|
||||||
|
return point;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method: parseGeometry.linestring
|
||||||
|
* Given a KML node representing a linestring geometry, create an
|
||||||
|
* OpenLayers linestring geometry.
|
||||||
|
*
|
||||||
|
* Parameters:
|
||||||
|
* node - {DOMElement} A KML LineString node.
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* {<OpenLayers.Geometry.LineString>} A linestring geometry.
|
||||||
|
*/
|
||||||
|
linestring: function(node, ring) {
|
||||||
|
var nodeList = this.getElementsByTagNameNS(node, this.kmlns,
|
||||||
|
"coordinates");
|
||||||
|
var line = null;
|
||||||
|
if(nodeList.length > 0) {
|
||||||
|
var coordString = nodeList[0].firstChild.nodeValue;
|
||||||
|
coordString = coordString.replace(this.regExes.trimSpace,
|
||||||
|
"");
|
||||||
|
coordString = coordString.replace(this.regExes.trimComma,
|
||||||
|
",");
|
||||||
|
var pointList = coordString.split(this.regExes.splitSpace);
|
||||||
|
var numPoints = pointList.length;
|
||||||
|
var points = new Array(numPoints);
|
||||||
|
var coords, numCoords;
|
||||||
|
for(var i=0; i<numPoints; ++i) {
|
||||||
|
coords = pointList[i].split(",");
|
||||||
|
numCoords = coords.length;
|
||||||
|
if(numCoords > 1) {
|
||||||
|
if(coords.length == 2) {
|
||||||
|
coords[2] = null;
|
||||||
|
}
|
||||||
|
points[i] = new OpenLayers.Geometry.Point(coords[0],
|
||||||
|
coords[1],
|
||||||
|
coords[2]);
|
||||||
|
} else {
|
||||||
|
throw "Bad LineString point coordinates: " +
|
||||||
|
pointList[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(numPoints) {
|
||||||
|
if(ring) {
|
||||||
|
line = new OpenLayers.Geometry.LinearRing(points);
|
||||||
|
} else {
|
||||||
|
line = new OpenLayers.Geometry.LineString(points);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw "Bad LineString coordinates: " + coordString;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return line;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method: parseGeometry.polygon
|
||||||
|
* Given a KML node representing a polygon geometry, create an
|
||||||
|
* OpenLayers polygon geometry.
|
||||||
|
*
|
||||||
|
* Parameters:
|
||||||
|
* node - {DOMElement} A KML Polygon node.
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* {<OpenLayers.Geometry.Polygon>} A polygon geometry.
|
||||||
|
*/
|
||||||
|
polygon: function(node) {
|
||||||
|
var nodeList = this.getElementsByTagNameNS(node, this.kmlns,
|
||||||
|
"LinearRing");
|
||||||
|
var numRings = nodeList.length;
|
||||||
|
var components = new Array(numRings);
|
||||||
|
if(numRings > 0) {
|
||||||
|
// this assumes exterior ring first, inner rings after
|
||||||
|
var ring;
|
||||||
|
for(var i=0; i<nodeList.length; ++i) {
|
||||||
|
ring = this.parseGeometry.linestring.apply(this,
|
||||||
|
[nodeList[i], true]);
|
||||||
|
if(ring) {
|
||||||
|
components[i] = ring;
|
||||||
|
} else {
|
||||||
|
throw "Bad LinearRing geometry: " + i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new OpenLayers.Geometry.Polygon(components);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method: parseGeometry.multigeometry
|
||||||
|
* Given a KML node representing a multigeometry, create an
|
||||||
|
* OpenLayers geometry collection.
|
||||||
|
*
|
||||||
|
* Parameters:
|
||||||
|
* node - {DOMElement} A KML MultiGeometry node.
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* {<OpenLayers.Geometry.Polygon>} A geometry collection.
|
||||||
|
*/
|
||||||
|
multigeometry: function(node) {
|
||||||
|
var child, parser;
|
||||||
|
var parts = [];
|
||||||
|
var children = node.childNodes;
|
||||||
|
for(var i=0; i<children.length; ++i ) {
|
||||||
|
child = children[i];
|
||||||
|
if(child.nodeType == 1) {
|
||||||
|
type = (child.prefix) ?
|
||||||
|
child.nodeName.split(":")[1] :
|
||||||
|
child.nodeName;
|
||||||
|
var parser = this.parseGeometry[type.toLowerCase()];
|
||||||
|
if(parser) {
|
||||||
|
parts.push(parser.apply(this, [child]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new OpenLayers.Geometry.Collection(parts);
|
||||||
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method: parseAttributes
|
||||||
|
*
|
||||||
|
* Parameters:
|
||||||
|
* node - {<DOMElement>}
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* {Object} An attributes object.
|
||||||
|
*/
|
||||||
|
parseAttributes: function(node) {
|
||||||
|
var attributes = {};
|
||||||
|
// assume attribute nodes are type 1 children with a type 3 child
|
||||||
|
var child, grandchildren, grandchild;
|
||||||
|
var children = node.childNodes;
|
||||||
|
for(var i=0; i<children.length; ++i) {
|
||||||
|
child = children[i];
|
||||||
|
if(child.nodeType == 1) {
|
||||||
|
grandchildren = child.childNodes;
|
||||||
|
if(grandchildren.length == 1) {
|
||||||
|
grandchild = grandchildren[0];
|
||||||
|
if(grandchild.nodeType == 3) {
|
||||||
|
name = (child.prefix) ?
|
||||||
|
child.nodeName.split(":")[1] :
|
||||||
|
child.nodeName;
|
||||||
|
value = grandchild.nodeValue.replace(
|
||||||
|
this.regExes.trimSpace, "");
|
||||||
|
attributes[name] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return p;
|
return attributes;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* APIMethod: write
|
||||||
|
* Accept Feature Collection, and return a string.
|
||||||
|
*
|
||||||
|
* Parameters:
|
||||||
|
* features - An array of <OpenLayers.Feature.Vector> features.
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* {String} A KML string.
|
||||||
|
*/
|
||||||
|
write: function(features) {
|
||||||
|
if(!(features instanceof Array)) {
|
||||||
|
features = [features];
|
||||||
|
}
|
||||||
|
var kml = this.createElementNS(this.kmlns, "kml");
|
||||||
|
var folder = this.createFolderXML();
|
||||||
|
for(var i=0; i<features.length; ++i) {
|
||||||
|
folder.appendChild(this.createPlacemarkXML(features[i]));
|
||||||
|
}
|
||||||
|
kml.appendChild(folder);
|
||||||
|
return OpenLayers.Format.XML.prototype.write.apply(this, [kml]);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method: createFolderXML
|
||||||
|
* Creates and returns a KML folder node
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* {DOMElement}
|
||||||
|
*/
|
||||||
|
createFolderXML: function() {
|
||||||
|
// Folder name
|
||||||
|
var folderName = this.createElementNS(this.kmlns, "name");
|
||||||
|
var folderNameText = this.createTextNode(this.foldersName);
|
||||||
|
folderName.appendChild(folderNameText);
|
||||||
|
|
||||||
|
// Folder description
|
||||||
|
var folderDesc = this.createElementNS(this.kmlns, "description");
|
||||||
|
var folderDescText = this.createTextNode(this.foldersDesc);
|
||||||
|
folderDesc.appendChild(folderDescText);
|
||||||
|
|
||||||
|
// Folder
|
||||||
|
var folder = this.createElementNS(this.kmlns, "Folder");
|
||||||
|
folder.appendChild(folderName);
|
||||||
|
folder.appendChild(folderDesc);
|
||||||
|
|
||||||
|
return folder;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method: createPlacemarkXML
|
||||||
|
* Creates and returns a KML placemark node representing the given feature.
|
||||||
|
*
|
||||||
|
* Parameters:
|
||||||
|
* feature - {<OpenLayers.Feature.Vector>}
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* {DOMElement}
|
||||||
|
*/
|
||||||
|
createPlacemarkXML: function(feature) {
|
||||||
|
// Placemark name
|
||||||
|
var placemarkName = this.createElementNS(this.kmlns, "name");
|
||||||
|
var name = (feature.attributes.name) ?
|
||||||
|
feature.attributes.name : feature.id;
|
||||||
|
placemarkName.appendChild(this.createTextNode(name));
|
||||||
|
|
||||||
|
// Placemark description
|
||||||
|
var placemarkDesc = this.createElementNS(this.kmlns, "description");
|
||||||
|
var desc = (feature.attributes.description) ?
|
||||||
|
feature.attributes.description : this.placemarksDesc;
|
||||||
|
placemarkDesc.appendChild(this.createTextNode(desc));
|
||||||
|
|
||||||
|
// Placemark
|
||||||
|
var placemarkNode = this.createElementNS(this.kmlns, "Placemark");
|
||||||
|
if(feature.fid != null) {
|
||||||
|
placemarkNode.setAttribute("id", feature.fid);
|
||||||
|
}
|
||||||
|
placemarkNode.appendChild(placemarkName);
|
||||||
|
placemarkNode.appendChild(placemarkDesc);
|
||||||
|
|
||||||
|
// Geometry node (Point, LineString, etc. nodes)
|
||||||
|
var geometryNode = this.buildGeometryNode(feature.geometry);
|
||||||
|
placemarkNode.appendChild(geometryNode);
|
||||||
|
|
||||||
|
// TBD - deal with remaining (non name/description) attributes.
|
||||||
|
return placemarkNode;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method: buildGeometryNode
|
||||||
|
* Builds and returns a KML geometry node with the given geometry.
|
||||||
|
*
|
||||||
|
* Parameters:
|
||||||
|
* geometry - {<OpenLayers.Geometry>}
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* {DOMElement}
|
||||||
|
*/
|
||||||
|
buildGeometryNode: function(geometry) {
|
||||||
|
var className = geometry.CLASS_NAME;
|
||||||
|
var type = className.substring(className.lastIndexOf(".") + 1);
|
||||||
|
var builder = this.buildGeometry[type.toLowerCase()];
|
||||||
|
var node = null;
|
||||||
|
if(builder) {
|
||||||
|
node = builder.apply(this, [geometry]);
|
||||||
|
}
|
||||||
|
return node;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Property: buildGeometry
|
||||||
|
* Object containing methods to do the actual geometry node building
|
||||||
|
* based on geometry type.
|
||||||
|
*/
|
||||||
|
buildGeometry: {
|
||||||
|
// TBD: Anybody care about namespace aliases here (these nodes have
|
||||||
|
// no prefixes)?
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method: buildGeometry.point
|
||||||
|
* Given an OpenLayers point geometry, create a KML point.
|
||||||
|
*
|
||||||
|
* Parameters:
|
||||||
|
* geometry - {<OpenLayers.Geometry.Point>} A point geometry.
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* {DOMElement} A KML point node.
|
||||||
|
*/
|
||||||
|
point: function(geometry) {
|
||||||
|
var kml = this.createElementNS(this.kmlns, "Point");
|
||||||
|
kml.appendChild(this.buildCoordinatesNode(geometry));
|
||||||
|
return kml;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method: buildGeometry.multipoint
|
||||||
|
* Given an OpenLayers multipoint geometry, create a KML
|
||||||
|
* GeometryCollection.
|
||||||
|
*
|
||||||
|
* Parameters:
|
||||||
|
* geometry - {<OpenLayers.Geometry.Point>} A multipoint geometry.
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* {DOMElement} A KML GeometryCollection node.
|
||||||
|
*/
|
||||||
|
multipoint: function(geometry) {
|
||||||
|
return this.buildGeometry.collection(geometry);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method: buildGeometry.linestring
|
||||||
|
* Given an OpenLayers linestring geometry, create a KML linestring.
|
||||||
|
*
|
||||||
|
* Parameters:
|
||||||
|
* geometry - {<OpenLayers.Geometry.LineString>} A linestring geometry.
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* {DOMElement} A KML linestring node.
|
||||||
|
*/
|
||||||
|
linestring: function(geometry) {
|
||||||
|
var kml = this.createElementNS(this.kmlns, "LineString");
|
||||||
|
kml.appendChild(this.buildCoordinatesNode(geometry));
|
||||||
|
return kml;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method: buildGeometry.multilinestring
|
||||||
|
* Given an OpenLayers multilinestring geometry, create a KML
|
||||||
|
* GeometryCollection.
|
||||||
|
*
|
||||||
|
* Parameters:
|
||||||
|
* geometry - {<OpenLayers.Geometry.Point>} A multilinestring geometry.
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* {DOMElement} A KML GeometryCollection node.
|
||||||
|
*/
|
||||||
|
multilinestring: function(geometry) {
|
||||||
|
return this.buildGeometry.collection(geometry);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method: buildGeometry.linearring
|
||||||
|
* Given an OpenLayers linearring geometry, create a KML linearring.
|
||||||
|
*
|
||||||
|
* Parameters:
|
||||||
|
* geometry - {<OpenLayers.Geometry.LinearRing>} A linearring geometry.
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* {DOMElement} A KML linearring node.
|
||||||
|
*/
|
||||||
|
linearring: function(geometry) {
|
||||||
|
var kml = this.createElementNS(this.kmlns, "LinearRing");
|
||||||
|
kml.appendChild(this.buildCoordinatesNode(geometry));
|
||||||
|
return kml;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method: buildGeometry.polygon
|
||||||
|
* Given an OpenLayers polygon geometry, create a KML polygon.
|
||||||
|
*
|
||||||
|
* Parameters:
|
||||||
|
* geometry - {<OpenLayers.Geometry.Polygon>} A polygon geometry.
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* {DOMElement} A KML polygon node.
|
||||||
|
*/
|
||||||
|
polygon: function(geometry) {
|
||||||
|
var kml = this.createElementNS(this.kmlns, "Polygon");
|
||||||
|
var rings = geometry.components;
|
||||||
|
var ringMember, ringGeom, type;
|
||||||
|
for(var i=0; i<rings.length; ++i) {
|
||||||
|
type = (i==0) ? "outerBoundaryIs" : "innerBoundaryIs";
|
||||||
|
ringMember = this.createElementNS(this.kmlns, type);
|
||||||
|
ringGeom = this.buildGeometry.linearring.apply(this,
|
||||||
|
[rings[i]]);
|
||||||
|
ringMember.appendChild(ringGeom);
|
||||||
|
kml.appendChild(ringMember);
|
||||||
|
}
|
||||||
|
return kml;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method: buildGeometry.multipolygon
|
||||||
|
* Given an OpenLayers multipolygon geometry, create a KML
|
||||||
|
* GeometryCollection.
|
||||||
|
*
|
||||||
|
* Parameters:
|
||||||
|
* geometry - {<OpenLayers.Geometry.Point>} A multipolygon geometry.
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* {DOMElement} A KML GeometryCollection node.
|
||||||
|
*/
|
||||||
|
multipolygon: function(geometry) {
|
||||||
|
return this.buildGeometry.collection(geometry);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method: buildGeometry.collection
|
||||||
|
* Given an OpenLayers geometry collection, create a KML MultiGeometry.
|
||||||
|
*
|
||||||
|
* Parameters:
|
||||||
|
* geometry - {<OpenLayers.Geometry.Collection>} A geometry collection.
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* {DOMElement} A KML MultiGeometry node.
|
||||||
|
*/
|
||||||
|
collection: function(geometry) {
|
||||||
|
var kml = this.createElementNS(this.kmlns, "MultiGeometry");
|
||||||
|
var child;
|
||||||
|
for(var i=0; i<geometry.components.length; ++i) {
|
||||||
|
child = this.buildGeometryNode.apply(this,
|
||||||
|
[geometry.components[i]]);
|
||||||
|
if(child) {
|
||||||
|
kml.appendChild(child);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return kml;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method: buildCoordinatesNode
|
||||||
|
* Builds and returns the KML coordinates node with the given geometry
|
||||||
|
* <coordinates>...</coordinates>
|
||||||
|
*
|
||||||
|
* Parameters:
|
||||||
|
* geometry - {<OpenLayers.Geometry>}
|
||||||
|
*
|
||||||
|
* Return:
|
||||||
|
* {DOMElement}
|
||||||
|
*/
|
||||||
|
buildCoordinatesNode: function(geometry) {
|
||||||
|
var coordinatesNode = this.createElementNS(this.kmlns, "coordinates");
|
||||||
|
|
||||||
|
var path;
|
||||||
|
var points = geometry.components;
|
||||||
|
if(points) {
|
||||||
|
// LineString or LinearRing
|
||||||
|
var point;
|
||||||
|
var numPoints = points.length;
|
||||||
|
var parts = new Array(numPoints);
|
||||||
|
for(var i=0; i<numPoints; ++i) {
|
||||||
|
point = points[i];
|
||||||
|
parts[i] = point.x + "," + point.y;
|
||||||
|
}
|
||||||
|
path = parts.join(" ");
|
||||||
|
} else {
|
||||||
|
// Point
|
||||||
|
path = geometry.x + "," + geometry.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
var txtNode = this.createTextNode(path);
|
||||||
|
coordinatesNode.appendChild(txtNode);
|
||||||
|
|
||||||
|
return coordinatesNode;
|
||||||
|
},
|
||||||
|
|
||||||
CLASS_NAME: "OpenLayers.Format.KML"
|
CLASS_NAME: "OpenLayers.Format.KML"
|
||||||
});
|
});
|
||||||
+19
-10
@@ -3,6 +3,7 @@
|
|||||||
<script src="../../lib/OpenLayers.js"></script>
|
<script src="../../lib/OpenLayers.js"></script>
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
|
|
||||||
|
var test_content = '<kml xmlns="http://earth.google.com/kml/2.0"><Folder><name>OpenLayers export</name><description>Vector geometries from OpenLayers</description><Placemark id="KML.Polygon"><name>OpenLayers.Feature.Vector_344</name><description>A KLM Polygon</description><Polygon><outerBoundaryIs><LinearRing><coordinates>5.001370157823406,49.26855713824488 8.214706453896161,49.630662409673505 8.397385910100951,48.45172350357396 5.001370157823406,49.26855713824488</coordinates></LinearRing></outerBoundaryIs></Polygon></Placemark><Placemark id="KML.LineString"><name>OpenLayers.Feature.Vector_402</name><description>A KML LineString</description><LineString><coordinates>5.838523393080493,49.74814616928052 5.787079558782349,48.410795432216574 8.91427702008381,49.28932499608202</coordinates></LineString></Placemark><Placemark id="KML.Point"><name>OpenLayers.Feature.Vector_451</name><description>A KML Point</description><Point><coordinates>6.985073041685488,49.8682250149058</coordinates></Point></Placemark><Placemark id="KML.MultiGeometry"><name>SF Marina Harbor Master</name><description>KML MultiGeometry</description><MultiGeometry><LineString><coordinates>-122.4425587930444,37.80666418607323 -122.4428379594768,37.80663578323093</coordinates></LineString><LineString><coordinates>-122.4425509770566,37.80662588061205 -122.4428340530617,37.8065999493009</coordinates></LineString></MultiGeometry></Placemark></Folder></kml>';
|
||||||
|
|
||||||
function test_Format_KML_constructor(t) {
|
function test_Format_KML_constructor(t) {
|
||||||
t.plan(4);
|
t.plan(4);
|
||||||
@@ -14,24 +15,32 @@
|
|||||||
t.eq(format.foo, "bar", "constructor sets options correctly");
|
t.eq(format.foo, "bar", "constructor sets options correctly");
|
||||||
t.eq(typeof format.read, "function", "format has a read function");
|
t.eq(typeof format.read, "function", "format has a read function");
|
||||||
t.eq(typeof format.write, "function", "format has a write function");
|
t.eq(typeof format.write, "function", "format has a write function");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function test_Format_KML_read(t) {
|
function test_Format_KML_read(t) {
|
||||||
t.plan(1);
|
t.plan(5);
|
||||||
t.ok(true, "Read tests not done yet.");
|
var features = (new OpenLayers.Format.KML()).read(this.test_content);
|
||||||
|
t.eq(features.length, 4, "Number of features read is correct");
|
||||||
|
t.ok(features[0].geometry.toString() == "POLYGON((5.001370157823406 49.26855713824488,8.214706453896161 49.630662409673505,8.397385910100951 48.45172350357396,5.001370157823406 49.26855713824488))", "polygon feature geometry correctly created");
|
||||||
|
t.ok(features[1].geometry.toString() == "LINESTRING(5.838523393080493 49.74814616928052,5.787079558782349 48.410795432216574,8.91427702008381 49.28932499608202)", "linestring feature geometry correctly created");
|
||||||
|
t.ok(features[2].geometry.toString() == "POINT(6.985073041685488 49.8682250149058)", "point feature geometry correctly created");
|
||||||
|
t.ok(features[3].geometry.CLASS_NAME == "OpenLayers.Geometry.Collection",
|
||||||
|
"read geometry collection");
|
||||||
}
|
}
|
||||||
|
|
||||||
function test_Format_KML_write(t) {
|
function test_Format_KML_write(t) {
|
||||||
|
// make sure id, name, and description are preserved
|
||||||
t.plan(1);
|
t.plan(1);
|
||||||
t.ok(true, "Write tests not done yet.");
|
var kmlExpected = this.test_content;
|
||||||
|
var options = {
|
||||||
|
folderName: "OpenLayers export",
|
||||||
|
foldersDesc: "Vector geometries from OpenLayers"
|
||||||
|
}
|
||||||
|
|
||||||
var format = new OpenLayers.Format.KML();
|
var format = new OpenLayers.Format.KML(options);
|
||||||
//var doc = format.read(text);
|
var features = format.read(kmlExpected);
|
||||||
//var out = format.write(doc);
|
var kmlOut = format.write(features);
|
||||||
//out = out.replace(/[\r\n]/g, '');
|
t.eq(kmlOut, kmlExpected, "correctly writes an KML doc string");
|
||||||
//t.eq(text, out,
|
|
||||||
// "correctly writes an KML DOM doc");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
Reference in New Issue
Block a user