Add KML Styling support. Thanks rdewit for this great contribution. r=crschmidt,me (closes #1259)
git-svn-id: http://svn.openlayers.org/trunk/openlayers@6179 dc9f47b5-9b13-0410-9fdd-eb0c1a62fdaf
This commit is contained in:
@@ -4,14 +4,19 @@
|
|||||||
<script src="../lib/OpenLayers.js"></script>
|
<script src="../lib/OpenLayers.js"></script>
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
function parseData(req) {
|
function parseData(req) {
|
||||||
g = new OpenLayers.Format.KML();
|
g = new OpenLayers.Format.KML({extractStyles: true});
|
||||||
html = ""
|
html = ""
|
||||||
features = g.read(req.responseText);
|
features = g.read(req.responseText);
|
||||||
for(var feat in features) {
|
for(var feat in features) {
|
||||||
html += "Feature: Geometry: "+ features[feat].geometry+",";
|
html += "Feature: Geometry: "+ features[feat].geometry+",";
|
||||||
html += "<ul>";
|
html += "<ul>";
|
||||||
for (var j in features[feat].attributes) {
|
for (var j in features[feat].attributes) {
|
||||||
html += "<li>"+j+":"+features[feat].attributes[j]+"</li>";
|
html += "<li>Attribute "+j+":"+features[feat].attributes[j]+"</li>";
|
||||||
|
}
|
||||||
|
html += "</ul>"
|
||||||
|
html += "<ul>";
|
||||||
|
for (var j in features[feat].style) {
|
||||||
|
html += "<li>Style "+j+":"+features[feat].style[j]+"</li>";
|
||||||
}
|
}
|
||||||
html += "</ul>"
|
html += "</ul>"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,7 +20,14 @@
|
|||||||
layer = new OpenLayers.Layer.WMS( "OpenLayers WMS",
|
layer = new OpenLayers.Layer.WMS( "OpenLayers WMS",
|
||||||
"http://labs.metacarta.com/wms/vmap0", {layers: 'basic'} );
|
"http://labs.metacarta.com/wms/vmap0", {layers: 'basic'} );
|
||||||
map.addLayer(layer);
|
map.addLayer(layer);
|
||||||
map.addLayer(new OpenLayers.Layer.GML("KML", "kml/lines.kml", {format: OpenLayers.Format.KML}));
|
map.addLayer(new OpenLayers.Layer.GML("KML", "kml/lines.kml",
|
||||||
|
{
|
||||||
|
format: OpenLayers.Format.KML,
|
||||||
|
formatOptions: {
|
||||||
|
extractStyles: true,
|
||||||
|
extractAttributes: true
|
||||||
|
}
|
||||||
|
}));
|
||||||
map.zoomToExtent(new OpenLayers.Bounds(-112.306698,36.017792,-112.03204,36.18087));
|
map.zoomToExtent(new OpenLayers.Bounds(-112.306698,36.017792,-112.03204,36.18087));
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -48,9 +48,18 @@ OpenLayers.Format.KML = OpenLayers.Class(OpenLayers.Format.XML, {
|
|||||||
/**
|
/**
|
||||||
* APIProperty: extractAttributes
|
* APIProperty: extractAttributes
|
||||||
* {Boolean} Extract attributes from KML. Default is true.
|
* {Boolean} Extract attributes from KML. Default is true.
|
||||||
|
* Extracting styleUrls requires this to be set to true
|
||||||
*/
|
*/
|
||||||
extractAttributes: true,
|
extractAttributes: true,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Property: extractStyles
|
||||||
|
* {Boolean} Extract styles from KML. Default is false.
|
||||||
|
* Extracting styleUrls also requires extractAttributes to be
|
||||||
|
* set to true
|
||||||
|
*/
|
||||||
|
extractStyles: false,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Property: internalns
|
* Property: internalns
|
||||||
* {String} KML Namespace to use -- defaults to the namespace of the
|
* {String} KML Namespace to use -- defaults to the namespace of the
|
||||||
@@ -58,6 +67,40 @@ OpenLayers.Format.KML = OpenLayers.Class(OpenLayers.Format.XML, {
|
|||||||
*/
|
*/
|
||||||
internalns: null,
|
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
|
* Constructor: OpenLayers.Format.KML
|
||||||
* Create a new parser for KML.
|
* Create a new parser for KML.
|
||||||
@@ -72,7 +115,10 @@ OpenLayers.Format.KML = OpenLayers.Class(OpenLayers.Format.XML, {
|
|||||||
trimSpace: (/^\s*|\s*$/g),
|
trimSpace: (/^\s*|\s*$/g),
|
||||||
removeSpace: (/\s*/g),
|
removeSpace: (/\s*/g),
|
||||||
splitSpace: (/\s+/),
|
splitSpace: (/\s+/),
|
||||||
trimComma: (/\s*,\s*/g)
|
trimComma: (/\s*,\s*/g),
|
||||||
|
kmlColor: (/(\w{2})(\w{2})(\w{2})(\w{2})/),
|
||||||
|
kmlIconPalette: (/root:\/\/icons\/palette-(\d+)(\.\w+)/),
|
||||||
|
straightBracket: (/\$\[(.*?)\]/g)
|
||||||
};
|
};
|
||||||
OpenLayers.Format.XML.prototype.initialize.apply(this, [options]);
|
OpenLayers.Format.XML.prototype.initialize.apply(this, [options]);
|
||||||
},
|
},
|
||||||
@@ -88,23 +134,425 @@ OpenLayers.Format.KML = OpenLayers.Class(OpenLayers.Format.XML, {
|
|||||||
* {Array(<OpenLayers.Feature.Vector>)} List of features.
|
* {Array(<OpenLayers.Feature.Vector>)} List of features.
|
||||||
*/
|
*/
|
||||||
read: function(data) {
|
read: function(data) {
|
||||||
|
this.features = [];
|
||||||
|
this.styles = {};
|
||||||
|
this.fetched = {};
|
||||||
|
|
||||||
|
// Set default options
|
||||||
|
var options = {
|
||||||
|
depth: this.maxDepth,
|
||||||
|
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") {
|
if(typeof data == "string") {
|
||||||
data = OpenLayers.Format.XML.prototype.read.apply(this, [data]);
|
data = OpenLayers.Format.XML.prototype.read.apply(this, [data]);
|
||||||
}
|
}
|
||||||
var featureNodes = this.getElementsByTagNameNS(data,
|
|
||||||
'*',
|
// Loop throught the following node types in this order and
|
||||||
"Placemark");
|
// process the nodes found
|
||||||
var numFeatures = featureNodes.length;
|
var types = ["Link", "NetworkLink", "Style", "StyleMap", "Placemark"];
|
||||||
var features = new Array(numFeatures);
|
for(var i=0; i<types.length; ++i) {
|
||||||
for(var i=0; i<numFeatures; i++) {
|
var type = types[i];
|
||||||
var feature = this.parseFeature(featureNodes[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; i < nodes.length; 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) {
|
||||||
|
|
||||||
|
if (OpenLayers.ProxyHost
|
||||||
|
&& OpenLayers.String.startsWith(href, "http")) {
|
||||||
|
href = OpenLayers.ProxyHost + escape(href);
|
||||||
|
}
|
||||||
|
|
||||||
|
var request = new OpenLayers.Ajax.Request(href,
|
||||||
|
{method: 'get', asynchronous: false });
|
||||||
|
|
||||||
|
if (request && request.transport) {
|
||||||
|
return request.transport.responseText;
|
||||||
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method: parseStyles
|
||||||
|
* Looks for <Style> nodes in the data and parses them
|
||||||
|
* Also parses <StyleMap> nodes, but only uses the 'normal' key
|
||||||
|
*
|
||||||
|
* Parameters:
|
||||||
|
* nodes - {Array} of {DOMElement} data to read/parse.
|
||||||
|
* options - {Object} Hash of options
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
parseStyles: function(nodes, options) {
|
||||||
|
for(var i=0; i < nodes.length; i++) {
|
||||||
|
var style = this.parseStyle(nodes[i]);
|
||||||
|
if(style) {
|
||||||
|
styleName = (options.styleBaseUrl || "") + "#" + style.id;
|
||||||
|
|
||||||
|
this.styles[styleName] = style;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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"];
|
||||||
|
var type, nodeList, geometry, parser;
|
||||||
|
for(var i=0; i<types.length; ++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 color = this.parseProperty(styleTypeNode, "*", "color");
|
||||||
|
if (color) {
|
||||||
|
var matches = (color.toString()).match(
|
||||||
|
this.regExes.kmlColor);
|
||||||
|
|
||||||
|
// transparency
|
||||||
|
var alpha = matches[1];
|
||||||
|
style["strokeOpacity"] = parseInt(alpha, 16) / 255;
|
||||||
|
|
||||||
|
// rgb colors (google uses bgr)
|
||||||
|
var b = matches[2];
|
||||||
|
var g = matches[3];
|
||||||
|
var r = matches[4];
|
||||||
|
style["strokeColor"] = "#" + r + g + b;
|
||||||
|
}
|
||||||
|
|
||||||
|
var width = this.parseProperty(styleTypeNode, "*", "width");
|
||||||
|
if (width) {
|
||||||
|
style["strokeWidth"] = width;
|
||||||
|
}
|
||||||
|
|
||||||
|
case "polystyle":
|
||||||
|
var color = this.parseProperty(styleTypeNode, "*", "color");
|
||||||
|
if (color) {
|
||||||
|
var matches = (color.toString()).match(
|
||||||
|
this.regExes.kmlColor);
|
||||||
|
|
||||||
|
// transparency
|
||||||
|
var alpha = matches[1];
|
||||||
|
style["fillOpacity"] = parseInt(alpha, 16) / 255;
|
||||||
|
|
||||||
|
// rgb colors (google uses bgr)
|
||||||
|
var b = matches[2];
|
||||||
|
var g = matches[3];
|
||||||
|
var r = matches[4];
|
||||||
|
style["fillColor"] = "#" + r + g + b;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
case "iconstyle":
|
||||||
|
var iconNode = this.getElementsByTagNameNS(styleTypeNode,
|
||||||
|
"*",
|
||||||
|
"Icon")[0];
|
||||||
|
|
||||||
|
// set default width and height of icon
|
||||||
|
style["graphicWidth"] = 32;
|
||||||
|
style["graphicHeight"] = 32;
|
||||||
|
|
||||||
|
if (iconNode) {
|
||||||
|
var href = this.parseProperty(iconNode, "*", "href");
|
||||||
|
if (href) {
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
var w = this.parseProperty(iconNode, "*", "w");
|
||||||
|
if (w) {
|
||||||
|
style["graphicWidth"] = parseInt(w);
|
||||||
|
}
|
||||||
|
|
||||||
|
var h = this.parseProperty(iconNode, "*", "h");
|
||||||
|
if (h) {
|
||||||
|
style["graphicHeight"] = parseInt(h);
|
||||||
|
}
|
||||||
|
|
||||||
|
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 = hotSpotNode.getAttribute("x");
|
||||||
|
var y = hotSpotNode.getAttribute("y");
|
||||||
|
|
||||||
|
var xUnits = hotSpotNode.getAttribute("xunits");
|
||||||
|
if (xUnits == "pixels") {
|
||||||
|
style["graphicXOffset"] = parseInt(x);
|
||||||
|
}
|
||||||
|
else if (xUnits == "insetPixels") {
|
||||||
|
style["graphicXOffset"] = style["graphicWidth"]
|
||||||
|
- parseInt(x);
|
||||||
|
}
|
||||||
|
else if (xUnits == "fraction") {
|
||||||
|
style["graphicXOffset"] = style["graphicWidth"]
|
||||||
|
* parseFloat(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
var yUnits = hotSpotNode.getAttribute("yunits");
|
||||||
|
if (yUnits == "pixels") {
|
||||||
|
style["graphicYOffset"] = parseInt(y);
|
||||||
|
}
|
||||||
|
else if (yUnits == "insetPixels") {
|
||||||
|
style["graphicYOffset"] = style["graphicHeight"]
|
||||||
|
- parseInt(y);
|
||||||
|
}
|
||||||
|
else if (yUnits == "fraction") {
|
||||||
|
style["graphicYOffset"] = style["graphicHeight"]
|
||||||
|
* parseFloat(y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "balloonstyle":
|
||||||
|
var balloonStyle = OpenLayers.Util.getXmlNodeValue(
|
||||||
|
styleTypeNode);
|
||||||
|
if (balloonStyle) {
|
||||||
|
style["balloonStyle"] = balloonStyle.replace(
|
||||||
|
this.regExes.straightBracket, "${$1}");
|
||||||
|
}
|
||||||
|
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
|
||||||
|
* Looks for <Style> nodes in the data and parses them
|
||||||
|
* Also 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; i < nodes.length; i++) {
|
||||||
|
var node = nodes[i];
|
||||||
|
var pairs = this.getElementsByTagNameNS(node, "*",
|
||||||
|
"Pair");
|
||||||
|
|
||||||
|
var id = node.getAttribute("id");
|
||||||
|
for (var j=0; j<pairs.length; 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];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (styleUrl && key == "highlight") {
|
||||||
|
// TODO: implement the "select" part
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 = new Array(nodes.length);
|
||||||
|
for(var i=0; i < nodes.length; i++) {
|
||||||
|
var featureNode = nodes[i];
|
||||||
|
var feature = this.parseFeature.apply(this,[featureNode]) ;
|
||||||
if(feature) {
|
if(feature) {
|
||||||
|
|
||||||
|
// Create reference to styleUrl
|
||||||
|
if (this.extractStyles && feature.attributes &&
|
||||||
|
feature.attributes.styleUrl) {
|
||||||
|
feature.style = this.getStyle(feature.attributes.styleUrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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(styleNode);
|
||||||
|
if (inlineStyle) {
|
||||||
|
feature.style = OpenLayers.Util.extend({},
|
||||||
|
feature.style);
|
||||||
|
OpenLayers.Util.extend(feature.style, inlineStyle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// add feature to list of features
|
||||||
features[i] = feature;
|
features[i] = feature;
|
||||||
} else {
|
} else {
|
||||||
throw "Bad Placemark: " + i;
|
throw "Bad Placemark: " + i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return features;
|
|
||||||
|
// add new features to existing feature list
|
||||||
|
this.features = this.features.concat(features);
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -154,7 +602,7 @@ OpenLayers.Format.KML = OpenLayers.Class(OpenLayers.Format.XML, {
|
|||||||
}
|
}
|
||||||
var feature = new OpenLayers.Feature.Vector(geometry, attributes);
|
var feature = new OpenLayers.Feature.Vector(geometry, attributes);
|
||||||
|
|
||||||
var fid = node.getAttribute("id");
|
var fid = node.getAttribute("id") || node.getAttribute("name");
|
||||||
if(fid != null) {
|
if(fid != null) {
|
||||||
feature.fid = fid;
|
feature.fid = fid;
|
||||||
}
|
}
|
||||||
@@ -162,6 +610,45 @@ OpenLayers.Format.KML = OpenLayers.Class(OpenLayers.Format.XML, {
|
|||||||
return feature;
|
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 = this.styles[styleUrl];
|
||||||
|
return style;
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Property: parseGeometry
|
* Property: parseGeometry
|
||||||
* Properties of this object are the functions that parse geometries based
|
* Properties of this object are the functions that parse geometries based
|
||||||
@@ -334,29 +821,65 @@ OpenLayers.Format.KML = OpenLayers.Class(OpenLayers.Format.XML, {
|
|||||||
*/
|
*/
|
||||||
parseAttributes: function(node) {
|
parseAttributes: function(node) {
|
||||||
var attributes = {};
|
var attributes = {};
|
||||||
// assume attribute nodes are type 1 children with a type 3 child
|
// assume attribute nodes are type 1 children with a type 3 or 4 child
|
||||||
var child, grandchildren, grandchild;
|
var child, grandchildren, grandchild;
|
||||||
var children = node.childNodes;
|
var children = node.childNodes;
|
||||||
for(var i=0; i<children.length; ++i) {
|
for(var i=0; i<children.length; ++i) {
|
||||||
child = children[i];
|
child = children[i];
|
||||||
if(child.nodeType == 1) {
|
if(child.nodeType == 1) {
|
||||||
grandchildren = child.childNodes;
|
grandchildren = child.childNodes;
|
||||||
if(grandchildren.length == 1) {
|
if(grandchildren.length == 1 || grandchildren.length == 3) {
|
||||||
|
var grandchild;
|
||||||
|
switch (grandchildren.length) {
|
||||||
|
case 1:
|
||||||
grandchild = grandchildren[0];
|
grandchild = grandchildren[0];
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
default:
|
||||||
|
grandchild = grandchildren[1];
|
||||||
|
break;
|
||||||
|
}
|
||||||
if(grandchild.nodeType == 3 || grandchild.nodeType == 4) {
|
if(grandchild.nodeType == 3 || grandchild.nodeType == 4) {
|
||||||
var name = (child.prefix) ?
|
var name = (child.prefix) ?
|
||||||
child.nodeName.split(":")[1] :
|
child.nodeName.split(":")[1] :
|
||||||
child.nodeName;
|
child.nodeName;
|
||||||
var value = grandchild.nodeValue.replace(
|
var value = OpenLayers.Util.getXmlNodeValue(grandchild)
|
||||||
this.regExes.trimSpace, "");
|
if (value) {
|
||||||
|
value = value.replace(this.regExes.trimSpace, "");
|
||||||
attributes[name] = value;
|
attributes[name] = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return attributes;
|
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
|
* APIMethod: write
|
||||||
* Accept Feature Collection, and return a string.
|
* Accept Feature Collection, and return a string.
|
||||||
|
|||||||
Reference in New Issue
Block a user