summaryrefslogtreecommitdiff
path: root/misc/openlayers/lib/OpenLayers/Format/KML.js
diff options
context:
space:
mode:
Diffstat (limited to 'misc/openlayers/lib/OpenLayers/Format/KML.js')
-rw-r--r--misc/openlayers/lib/OpenLayers/Format/KML.js1517
1 files changed, 0 insertions, 1517 deletions
diff --git a/misc/openlayers/lib/OpenLayers/Format/KML.js b/misc/openlayers/lib/OpenLayers/Format/KML.js
deleted file mode 100644
index e10bce7..0000000
--- a/misc/openlayers/lib/OpenLayers/Format/KML.js
+++ /dev/null
@@ -1,1517 +0,0 @@
-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the 2-clause BSD license.
- * See license.txt in the OpenLayers distribution or repository for the
- * full text of the license. */
-
-/**
- * @requires OpenLayers/BaseTypes/Date.js
- * @requires OpenLayers/Format/XML.js
- * @requires OpenLayers/Feature/Vector.js
- * @requires OpenLayers/Geometry/Point.js
- * @requires OpenLayers/Geometry/LineString.js
- * @requires OpenLayers/Geometry/Polygon.js
- * @requires OpenLayers/Geometry/Collection.js
- * @requires OpenLayers/Request/XMLHttpRequest.js
- * @requires OpenLayers/Projection.js
- */
-
-/**
- * Class: OpenLayers.Format.KML
- * Read/Write KML. Create a new instance with the <OpenLayers.Format.KML>
- * constructor.
- *
- * Inherits from:
- * - <OpenLayers.Format.XML>
- */
-OpenLayers.Format.KML = OpenLayers.Class(OpenLayers.Format.XML, {
-
- /**
- * Property: namespaces
- * {Object} Mapping of namespace aliases to namespace URIs.
- */
- namespaces: {
- kml: "http://www.opengis.net/kml/2.2",
- gx: "http://www.google.com/kml/ext/2.2"
- },
-
- /**
- * APIProperty: kmlns
- * {String} KML Namespace to use. Defaults to 2.0 namespace.
- */
- 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".
- * If set to null, no name element will be created.
- */
- foldersName: "OpenLayers export",
-
- /**
- * APIProperty: foldersDesc
- * {String} Description of the folders. Default is "Exported on [date]."
- * If set to null, no description element will be created.
- */
- foldersDesc: "Exported on " + new Date(),
-
- /**
- * APIProperty: extractAttributes
- * {Boolean} Extract attributes from KML. Default is true.
- * Extracting styleUrls requires this to be set to true
- * Note that currently only Data and SimpleData
- * elements are handled.
- */
- extractAttributes: true,
-
- /**
- * APIProperty: kvpAttributes
- * {Boolean} Only used if extractAttributes is true.
- * If set to true, attributes will be simple
- * key-value pairs, compatible with other formats,
- * Any displayName elements will be ignored.
- * If set to false, attributes will be objects,
- * retaining any displayName elements, but not
- * compatible with other formats. Any CDATA in
- * displayName will be read in as a string value.
- * Default is false.
- */
- kvpAttributes: false,
-
- /**
- * Property: extractStyles
- * {Boolean} Extract styles from KML. Default is false.
- * Extracting styleUrls also requires extractAttributes to be
- * set to true
- */
- extractStyles: false,
-
- /**
- * APIProperty: extractTracks
- * {Boolean} Extract gx:Track elements from Placemark elements. Default
- * is false. If true, features will be generated for all points in
- * all gx:Track elements. Features will have a when (Date) attribute
- * based on when elements in the track. If tracks include angle
- * elements, features will have heading, tilt, and roll attributes.
- * If track point coordinates have three values, features will have
- * an altitude attribute with the third coordinate value.
- */
- extractTracks: false,
-
- /**
- * APIProperty: trackAttributes
- * {Array} If <extractTracks> is true, points within gx:Track elements will
- * be parsed as features with when, heading, tilt, and roll attributes.
- * Any additional attribute names can be provided in <trackAttributes>.
- */
- trackAttributes: null,
-
- /**
- * Property: internalns
- * {String} KML Namespace to use -- defaults to the namespace of the
- * Placemark node being parsed, but falls back to kmlns.
- */
- internalns: null,
-
- /**
- * Property: features
- * {Array} Array of features
- *
- */
- features: null,
-
- /**
- * Property: styles
- * {Object} Storage of style objects
- *
- */
- styles: null,
-
- /**
- * Property: styleBaseUrl
- * {String}
- */
- styleBaseUrl: "",
-
- /**
- * Property: fetched
- * {Object} Storage of KML URLs that have been fetched before
- * in order to prevent reloading them.
- */
- fetched: null,
-
- /**
- * APIProperty: maxDepth
- * {Integer} Maximum depth for recursive loading external KML URLs
- * Defaults to 0: do no external fetching
- */
- maxDepth: 0,
-
- /**
- * Constructor: OpenLayers.Format.KML
- * Create a new parser for KML.
- *
- * Parameters:
- * options - {Object} An optional object whose properties will be set on
- * this instance.
- */
- initialize: function(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),
- kmlColor: (/(\w{2})(\w{2})(\w{2})(\w{2})/),
- kmlIconPalette: (/root:\/\/icons\/palette-(\d+)(\.\w+)/),
- straightBracket: (/\$\[(.*?)\]/g)
- };
- // KML coordinates are always in longlat WGS84
- this.externalProjection = new OpenLayers.Projection("EPSG:4326");
-
- OpenLayers.Format.XML.prototype.initialize.apply(this, [options]);
- },
-
- /**
- * APIMethod: read
- * Read data from a string, and return a list of features.
- *
- * Parameters:
- * data - {String} or {DOMElement} data to read/parse.
- *
- * Returns:
- * {Array(<OpenLayers.Feature.Vector>)} List of features.
- */
- read: function(data) {
- this.features = [];
- this.styles = {};
- this.fetched = {};
-
- // Set default options
- var options = {
- depth: 0,
- styleBaseUrl: this.styleBaseUrl
- };
-
- return this.parseData(data, options);
- },
-
- /**
- * Method: parseData
- * Read data from a string, and return a list of features.
- *
- * Parameters:
- * data - {String} or {DOMElement} data to read/parse.
- * options - {Object} Hash of options
- *
- * Returns:
- * {Array(<OpenLayers.Feature.Vector>)} List of features.
- */
- parseData: function(data, options) {
- if(typeof data == "string") {
- data = OpenLayers.Format.XML.prototype.read.apply(this, [data]);
- }
-
- // Loop throught the following node types in this order and
- // process the nodes found
- var types = ["Link", "NetworkLink", "Style", "StyleMap", "Placemark"];
- for(var i=0, len=types.length; i<len; ++i) {
- var type = types[i];
-
- var nodes = this.getElementsByTagNameNS(data, "*", type);
-
- // skip to next type if no nodes are found
- if(nodes.length == 0) {
- continue;
- }
-
- switch (type.toLowerCase()) {
-
- // Fetch external links
- case "link":
- case "networklink":
- this.parseLinks(nodes, options);
- break;
-
- // parse style information
- case "style":
- if (this.extractStyles) {
- this.parseStyles(nodes, options);
- }
- break;
- case "stylemap":
- if (this.extractStyles) {
- this.parseStyleMaps(nodes, options);
- }
- break;
-
- // parse features
- case "placemark":
- this.parseFeatures(nodes, options);
- break;
- }
- }
-
- return this.features;
- },
-
- /**
- * Method: parseLinks
- * Finds URLs of linked KML documents and fetches them
- *
- * Parameters:
- * nodes - {Array} of {DOMElement} data to read/parse.
- * options - {Object} Hash of options
- *
- */
- parseLinks: function(nodes, options) {
-
- // Fetch external links <NetworkLink> and <Link>
- // Don't do anything if we have reached our maximum depth for recursion
- if (options.depth >= this.maxDepth) {
- return false;
- }
-
- // increase depth
- var newOptions = OpenLayers.Util.extend({}, options);
- newOptions.depth++;
-
- for(var i=0, len=nodes.length; i<len; i++) {
- var href = this.parseProperty(nodes[i], "*", "href");
- if(href && !this.fetched[href]) {
- this.fetched[href] = true; // prevent reloading the same urls
- var data = this.fetchLink(href);
- if (data) {
- this.parseData(data, newOptions);
- }
- }
- }
-
- },
-
- /**
- * Method: fetchLink
- * Fetches a URL and returns the result
- *
- * Parameters:
- * href - {String} url to be fetched
- *
- */
- fetchLink: function(href) {
- var request = OpenLayers.Request.GET({url: href, async: false});
- if (request) {
- return request.responseText;
- }
- },
-
- /**
- * Method: parseStyles
- * Parses <Style> nodes
- *
- * Parameters:
- * nodes - {Array} of {DOMElement} data to read/parse.
- * options - {Object} Hash of options
- *
- */
- parseStyles: function(nodes, options) {
- for(var i=0, len=nodes.length; i<len; i++) {
- var style = this.parseStyle(nodes[i]);
- if(style) {
- var styleName = (options.styleBaseUrl || "") + "#" + style.id;
-
- this.styles[styleName] = style;
- }
- }
- },
-
- /**
- * Method: parseKmlColor
- * Parses a kml color (in 'aabbggrr' format) and returns the corresponding
- * color and opacity or null if the color is invalid.
- *
- * Parameters:
- * kmlColor - {String} a kml formated color
- *
- * Returns:
- * {Object}
- */
- parseKmlColor: function(kmlColor) {
- var color = null;
- if (kmlColor) {
- var matches = kmlColor.match(this.regExes.kmlColor);
- if (matches) {
- color = {
- color: '#' + matches[4] + matches[3] + matches[2],
- opacity: parseInt(matches[1], 16) / 255
- };
- }
- }
- return color;
- },
-
- /**
- * Method: parseStyle
- * Parses the children of a <Style> node and builds the style hash
- * accordingly
- *
- * Parameters:
- * node - {DOMElement} <Style> node
- *
- */
- parseStyle: function(node) {
- var style = {};
-
- var types = ["LineStyle", "PolyStyle", "IconStyle", "BalloonStyle",
- "LabelStyle"];
- var type, styleTypeNode, nodeList, geometry, parser;
- for(var i=0, len=types.length; i<len; ++i) {
- type = types[i];
- styleTypeNode = this.getElementsByTagNameNS(node, "*", type)[0];
- if(!styleTypeNode) {
- continue;
- }
-
- // only deal with first geometry of this type
- switch (type.toLowerCase()) {
- case "linestyle":
- var kmlColor = this.parseProperty(styleTypeNode, "*", "color");
- var color = this.parseKmlColor(kmlColor);
- if (color) {
- style["strokeColor"] = color.color;
- style["strokeOpacity"] = color.opacity;
- }
-
- var width = this.parseProperty(styleTypeNode, "*", "width");
- if (width) {
- style["strokeWidth"] = width;
- }
- break;
-
- case "polystyle":
- var kmlColor = this.parseProperty(styleTypeNode, "*", "color");
- var color = this.parseKmlColor(kmlColor);
- if (color) {
- style["fillOpacity"] = color.opacity;
- style["fillColor"] = color.color;
- }
- // Check if fill is disabled
- var fill = this.parseProperty(styleTypeNode, "*", "fill");
- if (fill == "0") {
- style["fillColor"] = "none";
- }
- // Check if outline is disabled
- var outline = this.parseProperty(styleTypeNode, "*", "outline");
- if (outline == "0") {
- style["strokeWidth"] = "0";
- }
-
- break;
-
- case "iconstyle":
- // set scale
- var scale = parseFloat(this.parseProperty(styleTypeNode,
- "*", "scale") || 1);
-
- // set default width and height of icon
- var width = 32 * scale;
- var height = 32 * scale;
-
- var iconNode = this.getElementsByTagNameNS(styleTypeNode,
- "*",
- "Icon")[0];
- if (iconNode) {
- var href = this.parseProperty(iconNode, "*", "href");
- if (href) {
-
- var w = this.parseProperty(iconNode, "*", "w");
- var h = this.parseProperty(iconNode, "*", "h");
-
- // Settings for Google specific icons that are 64x64
- // We set the width and height to 64 and halve the
- // scale to prevent icons from being too big
- var google = "http://maps.google.com/mapfiles/kml";
- if (OpenLayers.String.startsWith(
- href, google) && !w && !h) {
- w = 64;
- h = 64;
- scale = scale / 2;
- }
-
- // if only dimension is defined, make sure the
- // other one has the same value
- w = w || h;
- h = h || w;
-
- if (w) {
- width = parseInt(w) * scale;
- }
-
- if (h) {
- height = parseInt(h) * scale;
- }
-
- // support for internal icons
- // (/root://icons/palette-x.png)
- // x and y tell the position on the palette:
- // - in pixels
- // - starting from the left bottom
- // We translate that to a position in the list
- // and request the appropriate icon from the
- // google maps website
- var matches = href.match(this.regExes.kmlIconPalette);
- if (matches) {
- var palette = matches[1];
- var file_extension = matches[2];
-
- var x = this.parseProperty(iconNode, "*", "x");
- var y = this.parseProperty(iconNode, "*", "y");
-
- var posX = x ? x/32 : 0;
- var posY = y ? (7 - y/32) : 7;
-
- var pos = posY * 8 + posX;
- href = "http://maps.google.com/mapfiles/kml/pal"
- + palette + "/icon" + pos + file_extension;
- }
-
- style["graphicOpacity"] = 1; // fully opaque
- style["externalGraphic"] = href;
- }
-
- }
-
-
- // hotSpots define the offset for an Icon
- var hotSpotNode = this.getElementsByTagNameNS(styleTypeNode,
- "*",
- "hotSpot")[0];
- if (hotSpotNode) {
- var x = parseFloat(hotSpotNode.getAttribute("x"));
- var y = parseFloat(hotSpotNode.getAttribute("y"));
-
- var xUnits = hotSpotNode.getAttribute("xunits");
- if (xUnits == "pixels") {
- style["graphicXOffset"] = -x * scale;
- }
- else if (xUnits == "insetPixels") {
- style["graphicXOffset"] = -width + (x * scale);
- }
- else if (xUnits == "fraction") {
- style["graphicXOffset"] = -width * x;
- }
-
- var yUnits = hotSpotNode.getAttribute("yunits");
- if (yUnits == "pixels") {
- style["graphicYOffset"] = -height + (y * scale) + 1;
- }
- else if (yUnits == "insetPixels") {
- style["graphicYOffset"] = -(y * scale) + 1;
- }
- else if (yUnits == "fraction") {
- style["graphicYOffset"] = -height * (1 - y) + 1;
- }
- }
-
- style["graphicWidth"] = width;
- style["graphicHeight"] = height;
- break;
-
- case "balloonstyle":
- var balloonStyle = OpenLayers.Util.getXmlNodeValue(
- styleTypeNode);
- if (balloonStyle) {
- style["balloonStyle"] = balloonStyle.replace(
- this.regExes.straightBracket, "${$1}");
- }
- break;
- case "labelstyle":
- var kmlColor = this.parseProperty(styleTypeNode, "*", "color");
- var color = this.parseKmlColor(kmlColor);
- if (color) {
- style["fontColor"] = color.color;
- style["fontOpacity"] = color.opacity;
- }
- break;
-
- default:
- }
- }
-
- // Some polygons have no line color, so we use the fillColor for that
- if (!style["strokeColor"] && style["fillColor"]) {
- style["strokeColor"] = style["fillColor"];
- }
-
- var id = node.getAttribute("id");
- if (id && style) {
- style.id = id;
- }
-
- return style;
- },
-
- /**
- * Method: parseStyleMaps
- * Parses <StyleMap> nodes, but only uses the 'normal' key
- *
- * Parameters:
- * nodes - {Array} of {DOMElement} data to read/parse.
- * options - {Object} Hash of options
- *
- */
- parseStyleMaps: function(nodes, options) {
- // Only the default or "normal" part of the StyleMap is processed now
- // To do the select or "highlight" bit, we'd need to change lots more
-
- for(var i=0, len=nodes.length; i<len; i++) {
- var node = nodes[i];
- var pairs = this.getElementsByTagNameNS(node, "*",
- "Pair");
-
- var id = node.getAttribute("id");
- for (var j=0, jlen=pairs.length; j<jlen; j++) {
- var pair = pairs[j];
- // Use the shortcut in the SLD format to quickly retrieve the
- // value of a node. Maybe it's good to have a method in
- // Format.XML to do this
- var key = this.parseProperty(pair, "*", "key");
- var styleUrl = this.parseProperty(pair, "*", "styleUrl");
-
- if (styleUrl && key == "normal") {
- this.styles[(options.styleBaseUrl || "") + "#" + id] =
- this.styles[(options.styleBaseUrl || "") + styleUrl];
- }
-
- // TODO: implement the "select" part
- //if (styleUrl && key == "highlight") {
- //}
-
- }
- }
-
- },
-
-
- /**
- * Method: parseFeatures
- * Loop through all Placemark nodes and parse them.
- * Will create a list of features
- *
- * Parameters:
- * nodes - {Array} of {DOMElement} data to read/parse.
- * options - {Object} Hash of options
- *
- */
- parseFeatures: function(nodes, options) {
- var features = [];
- for(var i=0, len=nodes.length; i<len; i++) {
- var featureNode = nodes[i];
- var feature = this.parseFeature.apply(this,[featureNode]) ;
- if(feature) {
-
- // Create reference to styleUrl
- if (this.extractStyles && feature.attributes &&
- feature.attributes.styleUrl) {
- feature.style = this.getStyle(feature.attributes.styleUrl, options);
- }
-
- if (this.extractStyles) {
- // Make sure that <Style> nodes within a placemark are
- // processed as well
- var inlineStyleNode = this.getElementsByTagNameNS(featureNode,
- "*",
- "Style")[0];
- if (inlineStyleNode) {
- var inlineStyle= this.parseStyle(inlineStyleNode);
- if (inlineStyle) {
- feature.style = OpenLayers.Util.extend(
- feature.style, inlineStyle
- );
- }
- }
- }
-
- // check if gx:Track elements should be parsed
- if (this.extractTracks) {
- var tracks = this.getElementsByTagNameNS(
- featureNode, this.namespaces.gx, "Track"
- );
- if (tracks && tracks.length > 0) {
- var track = tracks[0];
- var container = {
- features: [],
- feature: feature
- };
- this.readNode(track, container);
- if (container.features.length > 0) {
- features.push.apply(features, container.features);
- }
- }
- } else {
- // add feature to list of features
- features.push(feature);
- }
- } else {
- throw "Bad Placemark: " + i;
- }
- }
-
- // add new features to existing feature list
- this.features = this.features.concat(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: {
- "kml": {
- "when": function(node, container) {
- container.whens.push(OpenLayers.Date.parse(
- this.getChildValue(node)
- ));
- },
- "_trackPointAttribute": function(node, container) {
- var name = node.nodeName.split(":").pop();
- container.attributes[name].push(this.getChildValue(node));
- }
- },
- "gx": {
- "Track": function(node, container) {
- var obj = {
- whens: [],
- points: [],
- angles: []
- };
- if (this.trackAttributes) {
- var name;
- obj.attributes = {};
- for (var i=0, ii=this.trackAttributes.length; i<ii; ++i) {
- name = this.trackAttributes[i];
- obj.attributes[name] = [];
- if (!(name in this.readers.kml)) {
- this.readers.kml[name] = this.readers.kml._trackPointAttribute;
- }
- }
- }
- this.readChildNodes(node, obj);
- if (obj.whens.length !== obj.points.length) {
- throw new Error("gx:Track with unequal number of when (" +
- obj.whens.length + ") and gx:coord (" +
- obj.points.length + ") elements.");
- }
- var hasAngles = obj.angles.length > 0;
- if (hasAngles && obj.whens.length !== obj.angles.length) {
- throw new Error("gx:Track with unequal number of when (" +
- obj.whens.length + ") and gx:angles (" +
- obj.angles.length + ") elements.");
- }
- var feature, point, angles;
- for (var i=0, ii=obj.whens.length; i<ii; ++i) {
- feature = container.feature.clone();
- feature.fid = container.feature.fid || container.feature.id;
- point = obj.points[i];
- feature.geometry = point;
- if ("z" in point) {
- feature.attributes.altitude = point.z;
- }
- if (this.internalProjection && this.externalProjection) {
- feature.geometry.transform(
- this.externalProjection, this.internalProjection
- );
- }
- if (this.trackAttributes) {
- for (var j=0, jj=this.trackAttributes.length; j<jj; ++j) {
- var name = this.trackAttributes[j];
- feature.attributes[name] = obj.attributes[name][i];
- }
- }
- feature.attributes.when = obj.whens[i];
- feature.attributes.trackId = container.feature.id;
- if (hasAngles) {
- angles = obj.angles[i];
- feature.attributes.heading = parseFloat(angles[0]);
- feature.attributes.tilt = parseFloat(angles[1]);
- feature.attributes.roll = parseFloat(angles[2]);
- }
- container.features.push(feature);
- }
- },
- "coord": function(node, container) {
- var str = this.getChildValue(node);
- var coords = str.replace(this.regExes.trimSpace, "").split(/\s+/);
- var point = new OpenLayers.Geometry.Point(coords[0], coords[1]);
- if (coords.length > 2) {
- point.z = parseFloat(coords[2]);
- }
- container.points.push(point);
- },
- "angles": function(node, container) {
- var str = this.getChildValue(node);
- var parts = str.replace(this.regExes.trimSpace, "").split(/\s+/);
- container.angles.push(parts);
- }
- }
- },
-
- /**
- * Method: parseFeature
- * This function is the core of the KML parsing code in OpenLayers.
- * It creates the geometries that are then attached to the returned
- * feature, and calls parseAttributes() to get attribute data out.
- *
- * Parameters:
- * node - {DOMElement}
- *
- * Returns:
- * {<OpenLayers.Feature.Vector>} A vector feature.
- */
- parseFeature: function(node) {
- // only accept one geometry per feature - look for highest "order"
- var order = ["MultiGeometry", "Polygon", "LineString", "Point"];
- var type, nodeList, geometry, parser;
- for(var i=0, len=order.length; i<len; ++i) {
- type = order[i];
- this.internalns = node.namespaceURI ?
- node.namespaceURI : this.kmlns;
- nodeList = this.getElementsByTagNameNS(node,
- this.internalns, type);
- if(nodeList.length > 0) {
- // only deal with first geometry of this type
- var parser = this.parseGeometry[type.toLowerCase()];
- if(parser) {
- geometry = parser.apply(this, [nodeList[0]]);
- if (this.internalProjection && this.externalProjection) {
- geometry.transform(this.externalProjection,
- this.internalProjection);
- }
- } else {
- throw new TypeError("Unsupported geometry type: " + type);
- }
- // stop looking for different geometry types
- break;
- }
- }
-
- // construct feature (optionally with attributes)
- var attributes;
- if(this.extractAttributes) {
- attributes = this.parseAttributes(node);
- }
- var feature = new OpenLayers.Feature.Vector(geometry, attributes);
-
- var fid = node.getAttribute("id") || node.getAttribute("name");
- if(fid != null) {
- feature.fid = fid;
- }
-
- return feature;
- },
-
- /**
- * Method: getStyle
- * Retrieves a style from a style hash using styleUrl as the key
- * If the styleUrl doesn't exist yet, we try to fetch it
- * Internet
- *
- * Parameters:
- * styleUrl - {String} URL of style
- * options - {Object} Hash of options
- *
- * Returns:
- * {Object} - (reference to) Style hash
- */
- getStyle: function(styleUrl, options) {
-
- var styleBaseUrl = OpenLayers.Util.removeTail(styleUrl);
-
- var newOptions = OpenLayers.Util.extend({}, options);
- newOptions.depth++;
- newOptions.styleBaseUrl = styleBaseUrl;
-
- // Fetch remote Style URLs (if not fetched before)
- if (!this.styles[styleUrl]
- && !OpenLayers.String.startsWith(styleUrl, "#")
- && newOptions.depth <= this.maxDepth
- && !this.fetched[styleBaseUrl] ) {
-
- var data = this.fetchLink(styleBaseUrl);
- if (data) {
- this.parseData(data, newOptions);
- }
-
- }
-
- // return requested style
- var style = OpenLayers.Util.extend({}, this.styles[styleUrl]);
- return style;
- },
-
- /**
- * Property: parseGeometry
- * Properties of this object are the functions that parse geometries based
- * on their type.
- */
- parseGeometry: {
-
- /**
- * Method: parseGeometry.point
- * Given a KML node representing a point geometry, create an OpenLayers
- * point geometry.
- *
- * Parameters:
- * node - {DOMElement} A KML Point node.
- *
- * Returns:
- * {<OpenLayers.Geometry.Point>} A point geometry.
- */
- point: function(node) {
- var nodeList = this.getElementsByTagNameNS(node, this.internalns,
- "coordinates");
- var coords = [];
- if(nodeList.length > 0) {
- var coordString = nodeList[0].firstChild.nodeValue;
- coordString = coordString.replace(this.regExes.removeSpace, "");
- coords = coordString.split(",");
- }
-
- var point = null;
- if(coords.length > 1) {
- // preserve third dimension
- if(coords.length == 2) {
- coords[2] = null;
- }
- point = new OpenLayers.Geometry.Point(coords[0], coords[1],
- coords[2]);
- } else {
- 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.internalns,
- "coordinates");
- var line = null;
- if(nodeList.length > 0) {
- var coordString = this.getChildValue(nodeList[0]);
-
- 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.internalns,
- "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, len=nodeList.length; i<len; ++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.Collection>} A geometry collection.
- */
- multigeometry: function(node) {
- var child, parser;
- var parts = [];
- var children = node.childNodes;
- for(var i=0, len=children.length; i<len; ++i ) {
- child = children[i];
- if(child.nodeType == 1) {
- var 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 = {};
-
- // Extended Data is parsed first.
- var edNodes = node.getElementsByTagName("ExtendedData");
- if (edNodes.length) {
- attributes = this.parseExtendedData(edNodes[0]);
- }
-
- // assume attribute nodes are type 1 children with a type 3 or 4 child
- var child, grandchildren, grandchild;
- var children = node.childNodes;
-
- for(var i=0, len=children.length; i<len; ++i) {
- child = children[i];
- if(child.nodeType == 1) {
- grandchildren = child.childNodes;
- if(grandchildren.length >= 1 && grandchildren.length <= 3) {
- var grandchild;
- switch (grandchildren.length) {
- case 1:
- grandchild = grandchildren[0];
- break;
- case 2:
- var c1 = grandchildren[0];
- var c2 = grandchildren[1];
- grandchild = (c1.nodeType == 3 || c1.nodeType == 4) ?
- c1 : c2;
- break;
- case 3:
- default:
- grandchild = grandchildren[1];
- break;
- }
- if(grandchild.nodeType == 3 || grandchild.nodeType == 4) {
- var name = (child.prefix) ?
- child.nodeName.split(":")[1] :
- child.nodeName;
- var value = OpenLayers.Util.getXmlNodeValue(grandchild);
- if (value) {
- value = value.replace(this.regExes.trimSpace, "");
- attributes[name] = value;
- }
- }
- }
- }
- }
- return attributes;
- },
-
- /**
- * Method: parseExtendedData
- * Parse ExtendedData from KML. Limited support for schemas/datatypes.
- * See http://code.google.com/apis/kml/documentation/kmlreference.html#extendeddata
- * for more information on extendeddata.
- */
- parseExtendedData: function(node) {
- var attributes = {};
- var i, len, data, key;
- var dataNodes = node.getElementsByTagName("Data");
- for (i = 0, len = dataNodes.length; i < len; i++) {
- data = dataNodes[i];
- key = data.getAttribute("name");
- var ed = {};
- var valueNode = data.getElementsByTagName("value");
- if (valueNode.length) {
- ed['value'] = this.getChildValue(valueNode[0]);
- }
- if (this.kvpAttributes) {
- attributes[key] = ed['value'];
- } else {
- var nameNode = data.getElementsByTagName("displayName");
- if (nameNode.length) {
- ed['displayName'] = this.getChildValue(nameNode[0]);
- }
- attributes[key] = ed;
- }
- }
- var simpleDataNodes = node.getElementsByTagName("SimpleData");
- for (i = 0, len = simpleDataNodes.length; i < len; i++) {
- var ed = {};
- data = simpleDataNodes[i];
- key = data.getAttribute("name");
- ed['value'] = this.getChildValue(data);
- if (this.kvpAttributes) {
- attributes[key] = ed['value'];
- } else {
- ed['displayName'] = key;
- attributes[key] = ed;
- }
- }
-
- return attributes;
- },
-
- /**
- * Method: parseProperty
- * Convenience method to find a node and return its value
- *
- * Parameters:
- * xmlNode - {<DOMElement>}
- * namespace - {String} namespace of the node to find
- * tagName - {String} name of the property to parse
- *
- * Returns:
- * {String} The value for the requested property (defaults to null)
- */
- parseProperty: function(xmlNode, namespace, tagName) {
- var value;
- var nodeList = this.getElementsByTagNameNS(xmlNode, namespace, tagName);
- try {
- value = OpenLayers.Util.getXmlNodeValue(nodeList[0]);
- } catch(e) {
- value = null;
- }
-
- return value;
- },
-
- /**
- * APIMethod: write
- * Accept Feature Collection, and return a string.
- *
- * Parameters:
- * features - {Array(<OpenLayers.Feature.Vector>)} An array of features.
- *
- * Returns:
- * {String} A KML string.
- */
- write: function(features) {
- if(!(OpenLayers.Util.isArray(features))) {
- features = [features];
- }
- var kml = this.createElementNS(this.kmlns, "kml");
- var folder = this.createFolderXML();
- for(var i=0, len=features.length; i<len; ++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
- var folder = this.createElementNS(this.kmlns, "Folder");
-
- // Folder name
- if (this.foldersName) {
- var folderName = this.createElementNS(this.kmlns, "name");
- var folderNameText = this.createTextNode(this.foldersName);
- folderName.appendChild(folderNameText);
- folder.appendChild(folderName);
- }
-
- // Folder description
- if (this.foldersDesc) {
- var folderDesc = this.createElementNS(this.kmlns, "description");
- var folderDescText = this.createTextNode(this.foldersDesc);
- folderDesc.appendChild(folderDescText);
- 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 label = (feature.style && feature.style.label) ? feature.style.label : feature.id;
- var name = feature.attributes.name || label;
- placemarkName.appendChild(this.createTextNode(name));
-
- // Placemark description
- var placemarkDesc = this.createElementNS(this.kmlns, "description");
- var desc = 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);
-
- // output attributes as extendedData
- if (feature.attributes) {
- var edNode = this.buildExtendedData(feature.attributes);
- if (edNode) {
- placemarkNode.appendChild(edNode);
- }
- }
-
- 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.apply(this, [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.apply(this, [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, len=rings.length; i<len; ++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.apply(this, [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, len=geometry.components.length; i<len; ++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>}
- *
- * Returns:
- * {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] = this.buildCoordinates(point);
- }
- path = parts.join(" ");
- } else {
- // Point
- path = this.buildCoordinates(geometry);
- }
-
- var txtNode = this.createTextNode(path);
- coordinatesNode.appendChild(txtNode);
-
- return coordinatesNode;
- },
-
- /**
- * Method: buildCoordinates
- *
- * Parameters:
- * point - {<OpenLayers.Geometry.Point>}
- *
- * Returns
- * {String} a coordinate pair
- */
- buildCoordinates: function(point) {
- if (this.internalProjection && this.externalProjection) {
- point = point.clone();
- point.transform(this.internalProjection,
- this.externalProjection);
- }
- return point.x + "," + point.y;
- },
-
- /**
- * Method: buildExtendedData
- *
- * Parameters:
- * attributes - {Object}
- *
- * Returns
- * {DOMElement} A KML ExtendedData node or {null} if no attributes.
- */
- buildExtendedData: function(attributes) {
- var extendedData = this.createElementNS(this.kmlns, "ExtendedData");
- for (var attributeName in attributes) {
- // empty, name, description, styleUrl attributes ignored
- if (attributes[attributeName] && attributeName != "name" && attributeName != "description" && attributeName != "styleUrl") {
- var data = this.createElementNS(this.kmlns, "Data");
- data.setAttribute("name", attributeName);
- var value = this.createElementNS(this.kmlns, "value");
- if (typeof attributes[attributeName] == "object") {
- // cater for object attributes with 'value' properties
- // other object properties will output an empty node
- if (attributes[attributeName].value) {
- value.appendChild(this.createTextNode(attributes[attributeName].value));
- }
- if (attributes[attributeName].displayName) {
- var displayName = this.createElementNS(this.kmlns, "displayName");
- // displayName always written as CDATA
- displayName.appendChild(this.getXMLDoc().createCDATASection(attributes[attributeName].displayName));
- data.appendChild(displayName);
- }
- } else {
- value.appendChild(this.createTextNode(attributes[attributeName]));
- }
- data.appendChild(value);
- extendedData.appendChild(data);
- }
- }
- if (this.isSimpleContent(extendedData)) {
- return null;
- } else {
- return extendedData;
- }
- },
-
- CLASS_NAME: "OpenLayers.Format.KML"
-});