diff --git a/layer/vector/KML.js b/layer/vector/KML.js index acdc4e8..b7a0104 100644 --- a/layer/vector/KML.js +++ b/layer/vector/KML.js @@ -105,7 +105,7 @@ L.Util.extend(L.KML, { } return !e || e === folder; }, - + parseStyles: function(xml) { var styles = {}; var sl = xml.getElementsByTagName('Style'); @@ -122,7 +122,7 @@ L.Util.extend(L.KML, { parseStyle: function (xml) { var style = {}, poptions = {}, ioptions = {}, el, id; - var attributes = { color: true, width: true, Icon: true, href: true, hotSpot: true }; + var attributes = { color: true, width: true, Icon: true, href: true, hotSpot: true, scale: true }; function _parse(xml) { var options = {}; @@ -130,8 +130,7 @@ L.Util.extend(L.KML, { var e = xml.childNodes[i]; var key = e.tagName; if (!attributes[key]) { continue; } - if (key === 'hotSpot') - { + if (key === 'hotSpot') { for (var j = 0; j < e.attributes.length; j++) { options[e.attributes[j].name] = e.attributes[j].nodeValue; } @@ -140,19 +139,52 @@ L.Util.extend(L.KML, { if (key === 'color') { options.opacity = parseInt(value.substring(0, 2), 16) / 255.0; options.color = '#' + value.substring(6, 8) + value.substring(4, 6) + value.substring(2, 4); + } else if (key === 'bgColor' || key == 'textColor') { + options[key] = '#' + value.substring(6, 8) + value.substring(4, 6) + value.substring(2, 4); } else if (key === 'width') { options.weight = value; } else if (key === 'Icon') { ioptions = _parse(e); if (ioptions.href) { options.href = ioptions.href; } + if (ioptions.scale) { options.scale = ioptions.scale; } } else if (key === 'href') { options.href = value; + } else if (key === 'scale') { + options.scale = parseFloat(value); } } } return options; } - + + function _abgr2rgba(kml_abgr) { + var a = parseInt(kml_abgr.substring(0, 2), 16) / 255.0; + var r = parseInt(kml_abgr.substring(6, 8), 16); + var g = parseInt(kml_abgr.substring(4, 6), 16); + var b = parseInt(kml_abgr.substring(2, 4), 16); + return 'rgba(' + r + ',' + g + ',' + b + ',' + a + ')'; + } + + function _parseBalloonStyle(xml) { + var options = {}; + for (var i = 0; i < xml.childNodes.length; i++) { + var e = xml.childNodes[i]; + var key = e.tagName; + var value = e.childNodes[0] ? e.childNodes[0].nodeValue : null; + if (key === 'bgColor' || key == 'textColor') { + options[key] = _abgr2rgba(value); + } else if (key === 'text') { + options.text = value; + } else if (key === 'displayMode') { + options.displayModeHide = (value === "hide"); + } + } + + return options; + } + + // TODO we also need LabelStyle handled + el = xml.getElementsByTagName('LineStyle'); if (el && el[0]) { style = _parse(el[0]); } el = xml.getElementsByTagName('PolyStyle'); @@ -162,13 +194,21 @@ L.Util.extend(L.KML, { el = xml.getElementsByTagName('IconStyle'); if (el && el[0]) { ioptions = _parse(el[0]); } if (ioptions.href) { - style.icon = new L.KMLIcon({ + var iconopts = { iconUrl: ioptions.href, shadowUrl: null, anchorRef: {x: ioptions.x, y: ioptions.y}, anchorType: {x: ioptions.xunits, y: ioptions.yunits} - }); + }; + if (ioptions.scale) { + // TODO should consider the original proportion + var scale = ioptions.scale ? ioptions.scale : 1.0; + iconopts.iconSize = [ 32 * scale, 32 * scale ]; + } + style.icon = new L.KMLIcon(iconopts); } + el = xml.getElementsByTagName('BalloonStyle'); + if (el && el[0]) { style.popup = _parseBalloonStyle(el[0]); } id = xml.getAttribute('id'); if (id && style) { @@ -273,24 +313,34 @@ L.Util.extend(L.KML, { layer = new L.FeatureGroup(layers); } - var name, descr = ''; - el = place.getElementsByTagName('name'); - if (el.length && el[0].childNodes.length) { - name = el[0].childNodes[0].nodeValue; - } - el = place.getElementsByTagName('description'); - for (i = 0; i < el.length; i++) { - for (j = 0; j < el[i].childNodes.length; j++) { - descr = descr + el[i].childNodes[j].nodeValue; - } - } - - if (name) { + if (! (options.popup && options.popup.displayModeHide)) { layer.on('add', function(e) { - layer.bindPopup('

' + name + '

' + descr); + if (options.popup && options.popup.text) { + // TODO should replace $[name], $[description], $[address], $[id], $[Snippet] + // c.f. https://developers.google.com/kml/documentation/kmlreference#balloonstyle + layer.bindPopup(options.popup.text, options.popup); + } else { + var name, descr = ''; + el = place.getElementsByTagName('name'); + if (el.length && el[0].childNodes.length) { + name = el[0].childNodes[0].nodeValue; + } + el = place.getElementsByTagName('description'); + for (i = 0; i < el.length; i++) { + for (j = 0; j < el[i].childNodes.length; j++) { + descr = descr + el[i].childNodes[j].nodeValue; + } + } + if (descr) { + // GoogleEarth shows it only when description is set + layer.bindPopup('' + name + '
' + descr, options.popup ? options.popup : {}); + } + } }); } + // TODO we also need a label from its name + return layer; },