diff --git a/examples/data/kml/lines.kml b/examples/data/kml/lines.kml
index adc8db6c55..cea9668e7a 100644
--- a/examples/data/kml/lines.kml
+++ b/examples/data/kml/lines.kml
@@ -262,14 +262,22 @@
-112.2626894973474,36.10149062823369,630
-
- Blue Icon
- Just another blue icon.
- data/kml/styles.kml#blueIcons
-
- -112.292238941097,36.09520916122063,630
-
-
+
+ Blue Icon
+ Just another blue icon.
+ data/kml/styles.kml#blueIcons
+
+ -112.292238941097,36.09520916122063,630
+
+
+
+ Sun Icon
+ Just another sun icon.
+ data/kml/styles.kml#sunIconMap
+
+ -112.292238941097,36.15520916122063,630
+
+
diff --git a/examples/data/kml/styles.kml b/examples/data/kml/styles.kml
index 24350ade44..b362878195 100644
--- a/examples/data/kml/styles.kml
+++ b/examples/data/kml/styles.kml
@@ -17,5 +17,16 @@ http://kml-samples.googlecode.com/svn/trunk/kml/Style/styles.kml
+
+
+ normal
+ #blueIcons
+
+
+ highlight
+ #blueIcons
+
+
+
diff --git a/src/ol/parser/kmlparser.js b/src/ol/parser/kmlparser.js
index 66e426ed0d..cc9fdbbf1a 100644
--- a/src/ol/parser/kmlparser.js
+++ b/src/ol/parser/kmlparser.js
@@ -135,12 +135,8 @@ ol.parser.KML = function(opt_options) {
obj.features.push(feature);
}
} else if (goog.isDef(container.geometry)) {
- var styleUrl = container.properties['styleUrl'];
- if (goog.isDef(styleUrl)) {
- if (!goog.string.startsWith(styleUrl, '#')) {
- obj.links.push({href: styleUrl});
- }
- }
+ this.parseStyleUrl(obj, container.properties['styleUrl']);
+
feature = new ol.Feature(container.properties);
if (!goog.isNull(id)) {
feature.setId(id);
@@ -152,10 +148,26 @@ ol.parser.KML = function(opt_options) {
}
}
var symbolizers = undefined;
- if (goog.isDef(container.styles)) {
- symbolizers = container.styles[0].symbolizers;
+ if (goog.isDef(container['styles'])) {
+ symbolizers = container['styles'][0]['symbolizers'];
+
+ } else if (goog.isDef(container['styleMaps'])) {
+ var styleMap = container['styleMaps'][0];
+ for (var i = 0, ii = styleMap['pairs'].length; i < ii; i++) {
+ var pair = styleMap['pairs'][i];
+ if (pair.key === 'normal') {
+ if (goog.isDef(pair['styleUrl'])) {
+ this.parseStyleUrl(obj, pair['styleUrl']);
+ feature.set('styleUrl', pair['styleUrl']);
+ } else if (goog.isDef(pair['styles'])) {
+ symbolizers = pair['styles'][0]['symbolizers'];
+ }
+ }
+ }
}
- this.applyStyle_(feature, obj['styles'], symbolizers);
+
+ this.applyStyle_(feature, obj['styles'], obj['styleMaps'],
+ symbolizers);
obj.features.push(feature);
}
},
@@ -312,6 +324,29 @@ ol.parser.KML = function(opt_options) {
var name = node.nodeName.split(':').pop();
container.attributes[name].push(this.getChildValue(node));
},
+ 'StyleMap': function(node, obj) {
+ if (this.extractStyles === true) {
+ if (!obj['styleMaps']) {
+ obj['styleMaps'] = [];
+ }
+ var styleMap = {'pairs': []};
+ var id = node.getAttribute('id');
+ if (!goog.isNull(id)) {
+ styleMap['id'] = id;
+ }
+ this.readChildNodes(node, styleMap);
+ obj['styleMaps'].push(styleMap);
+ }
+ },
+ 'Pair': function(node, obj) {
+ var pair = {};
+ var id = node.getAttribute('id');
+ if (!goog.isNull(id)) {
+ pair['id'] = id;
+ }
+ this.readChildNodes(node, pair);
+ obj['pairs'].push(pair);
+ },
'Style': function(node, obj) {
if (this.extractStyles === true) {
if (!obj['styles']) {
@@ -579,6 +614,11 @@ ol.parser.KML = function(opt_options) {
this.writeNode('_style', options.styles[i], null, node);
}
}
+ if (goog.isDef(options.styleMaps)) {
+ for (i = 0, ii = options.styleMaps.length; i < ii; ++i) {
+ this.writeNode('_styleMap', options.styleMaps[i], null, node);
+ }
+ }
for (i = 0, ii = options.features.length; i < ii; ++i) {
this.writeNode('_feature', options.features[i], null, node);
}
@@ -597,6 +637,16 @@ ol.parser.KML = function(opt_options) {
}
return node;
},
+ '_styleMap': function(styleMap) {
+ var node = this.createElementNS('StyleMap');
+ if (goog.isDef(styleMap.id)) {
+ this.setAttributeNS(node, null, 'id', styleMap.id);
+ }
+ for (var i = 0, ii = styleMap.pairs.length; i < ii; ++i) {
+ this.writeNode('Pair', styleMap.pairs[i], null, node);
+ }
+ return node;
+ },
'_symbolizer': function(obj) {
var symbolizer = obj.symbolizer;
if (symbolizer instanceof ol.style.Icon) {
@@ -607,6 +657,28 @@ ol.parser.KML = function(opt_options) {
return this.writeNode('PolyStyle', obj);
}
},
+ 'Pair': function(pair) {
+ var node = this.createElementNS('Pair');
+ if (goog.isDef(pair.id)) {
+ this.setAttributeNS(node, null, 'id', pair.id);
+ }
+ if (goog.isDef(pair.key)) {
+ this.writeNode('key', pair.key, null, node);
+ }
+ if (goog.isDef(pair.styleUrl)) {
+ this.writeNode('styleUrl', pair.styleUrl, null, node);
+ } else if (goog.isDef(pair.styles)) {
+ for (var i = 0, ii = pair.styles.length; i < ii; ++i) {
+ this.writeNode('_style', pair.styles[i], null, node);
+ }
+ }
+ return node;
+ },
+ 'key': function(key) {
+ var node = this.createElementNS('key');
+ node.appendChild(this.createTextNode(key));
+ return node;
+ },
'PolyStyle': function(obj) {
/**
* In KML, if a PolyStyle has 1
@@ -706,7 +778,7 @@ ol.parser.KML = function(opt_options) {
this.writeNode('name', feature, null, node);
this.writeNode('description', feature, null, node);
if (goog.isDef(feature.get('styleUrl'))) {
- this.writeNode('styleUrl', feature, null, node);
+ this.writeNode('styleUrl', feature.get('styleUrl'), null, node);
} else {
// inline style
var symbolizers = feature.getSymbolizers();
@@ -733,8 +805,7 @@ ol.parser.KML = function(opt_options) {
return node;
}
},
- 'styleUrl': function(feature) {
- var styleUrl = feature.get('styleUrl');
+ 'styleUrl': function(styleUrl) {
var node = this.createElementNS('styleUrl');
node.appendChild(this.createTextNode(styleUrl));
return node;
@@ -874,6 +945,20 @@ ol.parser.KML.prototype.readFeaturesFromObject = function(obj) {
};
+/**
+ * Parse the link contained in styleUrl, if it exists.
+ * @param {Object} obj The returned object from the parser.
+ * @param {string} styleUrl The style url to parse.
+ */
+ol.parser.KML.prototype.parseStyleUrl = function(obj, styleUrl) {
+ if (goog.isDef(styleUrl)) {
+ if (!goog.string.startsWith(styleUrl, '#')) {
+ obj.links.push({href: styleUrl});
+ }
+ }
+};
+
+
/**
* @param {Array} deferreds List of deferred instances.
* @param {Object} obj The returned object from the parser.
@@ -947,7 +1032,7 @@ ol.parser.KML.prototype.read = function(data, opt_callback) {
function(datas) {
for (var i = 0, ii = obj.features.length; i < ii; ++i) {
var feature = obj.features[i];
- this.applyStyle_(feature, obj['styles']);
+ this.applyStyle_(feature, obj['styles'], obj['styleMaps']);
}
opt_callback.call(null, obj);
}, function() {
@@ -964,17 +1049,40 @@ ol.parser.KML.prototype.read = function(data, opt_callback) {
* @private
* @param {ol.Feature} feature The feature to apply the style to.
* @param {Array} styles The style list to search in.
+ * @param {Array} styleMaps The styleMap list to search in.
* @param {Array.
=} opt_symbolizers Optional symbolizers.
*/
-ol.parser.KML.prototype.applyStyle_ = function(feature, styles,
+ol.parser.KML.prototype.applyStyle_ = function(feature, styles, styleMaps,
opt_symbolizers) {
var symbolizers = opt_symbolizers;
var i, ii;
if (feature.get('styleUrl') && feature.getSymbolizers() === null) {
var styleUrl = feature.get('styleUrl');
styleUrl = styleUrl.substring(styleUrl.indexOf('#') + 1);
+
+ // look for the styleMap and set in the feature
+ if (goog.isDef(styleMaps)) {
+ for (i = 0, ii = styleMaps.length; i < ii; ++i) {
+ var styleMap = styleMaps[i];
+ if (styleMap['id'] === styleUrl) {
+ for (var j = 0, jj = styleMap['pairs'].length; j < jj; j++) {
+ var pair = styleMap['pairs'][j];
+ if (pair.key === 'normal') {
+ if (goog.isDef(pair['styleUrl'])) {
+ styleUrl = pair['styleUrl'];
+ styleUrl = styleUrl.substring(styleUrl.indexOf('#') + 1);
+ } else if (goog.isDef(pair['styles'])) {
+ symbolizers = pair['styles'][0]['symbolizers'];
+ }
+ }
+ }
+ break;
+ }
+ }
+ }
+
// look for the style and set in the feature
- if (goog.isDef(styles)) {
+ if (!goog.isDef(symbolizers) && goog.isDef(styles)) {
for (i = 0, ii = styles.length; i < ii; ++i) {
if (styles[i]['id'] === styleUrl) {
symbolizers = styles[i]['symbolizers'];
@@ -982,6 +1090,7 @@ ol.parser.KML.prototype.applyStyle_ = function(feature, styles,
}
}
}
+
}
if (goog.isDef(symbolizers)) {
feature.setSymbolizers(symbolizers);
diff --git a/test/spec/ol/parser/kml.test.js b/test/spec/ol/parser/kml.test.js
index 30e2ab1e47..6b8e1dedd6 100644
--- a/test/spec/ol/parser/kml.test.js
+++ b/test/spec/ol/parser/kml.test.js
@@ -280,6 +280,31 @@ describe('ol.parser.KML', function() {
done();
});
});
+
+ it('handles styleMap (read / write)', function(done) {
+ var url = 'spec/ol/parser/kml/stylemap.kml';
+ afterLoadXml(url, function(xml) {
+ var p = new ol.parser.KML({extractStyles: true});
+ var obj = p.read(xml);
+ var output = p.write(obj);
+ expect(goog.dom.xml.loadXml(output)).to.xmleql(xml);
+
+ var symbolizers = obj.features[0].getSymbolizers();
+ expect(symbolizers).to.have.length(1);
+
+ var symbolizer = symbolizers[0];
+ expect(symbolizer).to.be.a(ol.style.Icon);
+
+ var literal = symbolizer.createLiteral(ol.geom.GeometryType.POINT);
+ expect(literal).to.be.a(ol.style.IconLiteral);
+
+ var url = 'http://maps.google.com/mapfiles/kml/pushpin/ylw-pushpin.png';
+ expect(literal.url).to.eql(url);
+ expect(literal.width).to.eql(32);
+ expect(literal.height).to.eql(32);
+ done();
+ });
+ });
});
describe('parsing states.kml', function() {
diff --git a/test/spec/ol/parser/kml/stylemap.kml b/test/spec/ol/parser/kml/stylemap.kml
new file mode 100644
index 0000000000..70906c3025
--- /dev/null
+++ b/test/spec/ol/parser/kml/stylemap.kml
@@ -0,0 +1,29 @@
+
+
+
+
+
+
+ normal
+ #pushpin
+
+
+ highlight
+ #pushpin
+
+
+
+ Pin on a mountaintop
+ #pushpinStyleMap
+
+ 170.1435558771009,-43.60505741890396,0
+
+
+
+