2a7839d47797709e6bb017b12ab269b7a39eba43
1 L
.KML
= L
.FeatureGroup
.extend({
6 initialize: function(kml
, options
) {
7 L
.Util
.setOptions(this, options
);
12 this.addKML(kml
, options
, this.options
.async
);
16 loadXML: function(url
, cb
, options
, async
) {
17 if (async
=== undefined) async
= this.options
.async
;
18 if (options
=== undefined) options
= this.options
;
20 var req
= new window
.XMLHttpRequest();
21 req
.open('GET', url
, async
);
23 req
.overrideMimeType('text/xml'); // unsupported by IE
25 req
.onreadystatechange = function() {
26 if (req
.readyState
!== 4) return;
27 if (req
.status
=== 200) cb(req
.responseXML
, options
);
32 addKML: function(url
, options
, async
) {
34 var cb = function(gpx
, options
) { _this
._addKML(gpx
, options
); };
35 this.loadXML(url
, cb
, options
, async
);
38 _addKML: function(xml
, options
) {
39 var layers
= L
.KML
.parseKML(xml
);
40 if (!layers
|| !layers
.length
) return;
41 for (var i
= 0; i
< layers
.length
; i
++) {
42 this.fire('addlayer', {
45 this.addLayer(layers
[i
]);
47 this.latLngs
= L
.KML
.getLatLngs(xml
);
54 L
.Util
.extend(L
.KML
, {
56 parseKML: function (xml
) {
57 var style
= this.parseStyle(xml
);
58 this.parseStyleMap(xml
, style
);
59 var el
= xml
.getElementsByTagName('Folder');
61 for (var i
= 0; i
< el
.length
; i
++) {
62 if (!this._check_folder(el
[i
])) { continue; }
63 l
= this.parseFolder(el
[i
], style
);
64 if (l
) { layers
.push(l
); }
66 el
= xml
.getElementsByTagName('Placemark');
67 for (var j
= 0; j
< el
.length
; j
++) {
68 if (!this._check_folder(el
[j
])) { continue; }
69 l
= this.parsePlacemark(el
[j
], xml
, style
);
70 if (l
) { layers
.push(l
); }
75 // Return false if e's first parent Folder is not [folder]
76 // - returns true if no parent Folders
77 _check_folder: function (e
, folder
) {
79 while (e
&& e
.tagName
!== 'Folder')
83 return !e
|| e
=== folder
;
86 parseStyle: function (xml
) {
88 var sl
= xml
.getElementsByTagName('Style');
90 //for (var i = 0; i < sl.length; i++) {
91 var attributes
= {color
: true, width
: true, Icon
: true, href
: true,
94 function _parse(xml
) {
96 for (var i
= 0; i
< xml
.childNodes
.length
; i
++) {
97 var e
= xml
.childNodes
[i
];
99 if (!attributes
[key
]) { continue; }
100 if (key
=== 'hotSpot')
102 for (var j
= 0; j
< e
.attributes
.length
; j
++) {
103 options
[e
.attributes
[j
].name
] = e
.attributes
[j
].nodeValue
;
106 var value
= e
.childNodes
[0].nodeValue
;
107 if (key
=== 'color') {
108 options
.opacity
= parseInt(value
.substring(0, 2), 16) / 255.0;
109 options
.color
= '#' + value
.substring(6, 8) + value
.substring(4, 6) + value
.substring(2, 4);
110 } else if (key
=== 'width') {
111 options
.weight
= value
;
112 } else if (key
=== 'Icon') {
113 ioptions
= _parse(e
);
114 if (ioptions
.href
) { options
.href
= ioptions
.href
; }
115 } else if (key
=== 'href') {
116 options
.href
= value
;
123 for (var i
= 0; i
< sl
.length
; i
++) {
125 var options
= {}, poptions
= {}, ioptions
= {};
126 el
= e
.getElementsByTagName('LineStyle');
127 if (el
&& el
[0]) { options
= _parse(el
[0]); }
128 el
= e
.getElementsByTagName('PolyStyle');
129 if (el
&& el
[0]) { poptions
= _parse(el
[0]); }
130 if (poptions
.color
) { options
.fillColor
= poptions
.color
; }
131 if (poptions
.opacity
) { options
.fillOpacity
= poptions
.opacity
; }
132 el
= e
.getElementsByTagName('IconStyle');
133 if (el
&& el
[0]) { ioptions
= _parse(el
[0]); }
135 // save anchor info until the image is loaded
136 options
.icon
= new L
.KMLIcon({
137 iconUrl
: ioptions
.href
,
139 iconAnchorRef
: {x
: ioptions
.x
, y
: ioptions
.y
},
140 iconAnchorType
: {x
: ioptions
.xunits
, y
: ioptions
.yunits
}
143 style
['#' + e
.getAttribute('id')] = options
;
148 parseStyleMap: function (xml
, existingStyles
) {
149 var sl
= xml
.getElementsByTagName('StyleMap');
151 for (var i
= 0; i
< sl
.length
; i
++) {
153 var smKey
, smStyleUrl
;
155 el
= e
.getElementsByTagName('key');
156 if (el
&& el
[0]) { smKey
= el
[0].textContent
; }
157 el
= e
.getElementsByTagName('styleUrl');
158 if (el
&& el
[0]) { smStyleUrl
= el
[0].textContent
; }
160 if (smKey
=== 'normal')
162 existingStyles
['#' + e
.getAttribute('id')] = existingStyles
[smStyleUrl
];
169 parseFolder: function (xml
, style
) {
170 var el
, layers
= [], l
;
171 el
= xml
.getElementsByTagName('Folder');
172 for (var i
= 0; i
< el
.length
; i
++) {
173 if (!this._check_folder(el
[i
], xml
)) { continue; }
174 l
= this.parseFolder(el
[i
], style
);
175 if (l
) { layers
.push(l
); }
177 el
= xml
.getElementsByTagName('Placemark');
178 for (var j
= 0; j
< el
.length
; j
++) {
179 if (!this._check_folder(el
[j
], xml
)) { continue; }
180 l
= this.parsePlacemark(el
[j
], xml
, style
);
181 if (l
) { layers
.push(l
); }
183 if (!layers
.length
) { return; }
184 if (layers
.length
=== 1) { return layers
[0]; }
185 return new L
.FeatureGroup(layers
);
188 parsePlacemark: function (place
, xml
, style
) {
189 var i
, j
, el
, options
= {};
190 el
= place
.getElementsByTagName('styleUrl');
191 for (i
= 0; i
< el
.length
; i
++) {
192 var url
= el
[i
].childNodes
[0].nodeValue
;
193 for (var a
in style
[url
]) {
194 options
[a
] = style
[url
][a
];
199 var parse
= ['LineString', 'Polygon', 'Point'];
205 el
= place
.getElementsByTagName(tag
);
206 for (i
= 0; i
< el
.length
; i
++) {
207 var l
= this['parse' + tag
](el
[i
], xml
, options
);
208 if (l
) { layers
.push(l
); }
213 if (!layers
.length
) {
216 var layer
= layers
[0];
217 if (layers
.length
> 1) {
218 layer
= new L
.FeatureGroup(layers
);
221 var name
, descr
= '';
222 el
= place
.getElementsByTagName('name');
223 if (el
.length
&& el
[0].childNodes
.length
) {
224 name
= el
[0].childNodes
[0].nodeValue
;
226 el
= place
.getElementsByTagName('description');
227 for (i
= 0; i
< el
.length
; i
++) {
228 for (j
= 0; j
< el
[i
].childNodes
.length
; j
++) {
229 descr
= descr
+ el
[i
].childNodes
[j
].nodeValue
;
234 layer
.bindPopup('<h2>' + name
+ '</h2>' + descr
);
240 parseCoords: function (xml
) {
241 var el
= xml
.getElementsByTagName('coordinates');
242 return this._read_coords(el
[0]);
245 parseLineString: function (line
, xml
, options
) {
246 var coords
= this.parseCoords(line
);
247 if (!coords
.length
) { return; }
248 return new L
.Polyline(coords
, options
);
251 parsePoint: function (line
, xml
, options
) {
252 var el
= line
.getElementsByTagName('coordinates');
256 var ll
= el
[0].childNodes
[0].nodeValue
.split(',');
257 return new L
.KMLMarker(new L
.LatLng(ll
[1], ll
[0]), options
);
260 parsePolygon: function (line
, xml
, options
) {
261 var el
, polys
= [], inner
= [], i
, coords
;
262 el
= line
.getElementsByTagName('outerBoundaryIs');
263 for (i
= 0; i
< el
.length
; i
++) {
264 coords
= this.parseCoords(el
[i
]);
269 el
= line
.getElementsByTagName('innerBoundaryIs');
270 for (i
= 0; i
< el
.length
; i
++) {
271 coords
= this.parseCoords(el
[i
]);
279 if (options
.fillColor
) {
282 if (polys
.length
=== 1) {
283 return new L
.Polygon(polys
.concat(inner
), options
);
285 return new L
.MultiPolygon(polys
, options
);
288 getLatLngs: function (xml
) {
289 var el
= xml
.getElementsByTagName('coordinates');
291 for (var j
= 0; j
< el
.length
; j
++) {
292 // text might span many childNodes
293 coords
= coords
.concat(this._read_coords(el
[j
]));
298 _read_coords: function (el
) {
299 var text
= '', coords
= [], i
;
300 for (i
= 0; i
< el
.childNodes
.length
; i
++) {
301 text
= text
+ el
.childNodes
[i
].nodeValue
;
303 text
= text
.split(/[\s\n]+/);
304 for (i
= 0; i
< text
.length
; i
++) {
305 var ll
= text
[i
].split(',');
309 coords
.push(new L
.LatLng(ll
[1], ll
[0]));
316 L
.KMLIcon
= L
.Icon
.extend({
318 createIcon: function () {
319 var img
= this._createIcon('icon');
320 img
.onload = function () {
322 this.style
.width
= i
.width
+ 'px';
323 this.style
.height
= i
.height
+ 'px';
325 if (this.anchorType
.x
=== 'UNITS_FRACTION' || this.anchorType
.x
=== 'fraction') {
326 img
.style
.marginLeft
= (-this.anchor
.x
* i
.width
) + 'px';
328 if (this.anchorType
.y
=== 'UNITS_FRACTION' || this.anchorType
.x
=== 'fraction') {
329 img
.style
.marginTop
= (-(1 - this.anchor
.y
) * i
.height
) + 'px';
331 this.style
.display
= '';
336 _setIconStyles: function (img
, name
) {
337 L
.Icon
.prototype._setIconStyles
.apply(this, [img
, name
]);
338 // save anchor information to the image
339 img
.anchor
= this.options
.iconAnchorRef
;
340 img
.anchorType
= this.options
.iconAnchorType
;
345 L
.KMLMarker
= L
.Marker
.extend({
347 icon
: new L
.KMLIcon
.Default()