diff --git a/CHANGELOG.md b/CHANGELOG.md index 6c0379f..385c969 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ ### Change Log for Node-RED Worldmap - - v2.42.2 - More KML and GEOJson drag drop fixes + - v2.42.3 - More KML and GEOJson drag drop fixes - v2.42.1 - Remove extraneous debug logging, fix KMZ icons - v2.42.0 - Add handling for TAK type spots, waypoints, alerts, sensors. Better KML/KMZ handling. - v2.41.0 - Bump leaflet libs to latest stable (1.9.4) diff --git a/README.md b/README.md index b33abf0..5ec8bdf 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ Feel free to [![](https://img.shields.io/static/v1?label=Sponsor&message=%E2%9D% ### Updates -- v2.42.2 - More KML and GEOJson drag drop fixes +- v2.42.3 - More KML and GEOJson drag drop fixes - v2.42.1 - Remove extraneous debug logging, fix KMZ icons - v2.42.0 - Add handling for TAK type spots, waypoints, alerts, sensors. Better KML/KMZ handling. - v2.41.0 - Bump leaflet libs to latest stable (1.9.4) diff --git a/package.json b/package.json index a999b90..b5cbe4f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "node-red-contrib-web-worldmap", - "version": "2.42.2", + "version": "2.42.3", "description": "A Node-RED node to provide a web page of a world map for plotting things on.", "dependencies": { "@turf/bezier-spline": "~6.5.0", diff --git a/worldmap/index.html b/worldmap/index.html index 15fa726..a4c98f7 100644 --- a/worldmap/index.html +++ b/worldmap/index.html @@ -68,8 +68,8 @@ + - diff --git a/worldmap/leaflet/L.KML.js b/worldmap/leaflet/L.KML.js deleted file mode 100644 index cfec2ab..0000000 --- a/worldmap/leaflet/L.KML.js +++ /dev/null @@ -1,470 +0,0 @@ -/*! - Copyright (c) 2011-2015, Pavel Shramov, Bruno Bergot - MIT licence -*/ - -L.KML = L.FeatureGroup.extend({ - - initialize: function (kml) { - this._kml = kml; - this._layers = {}; - - if (kml) { - this.addKML(kml); - } - }, - - addKML: function (xml) { - var layers = L.KML.parseKML(xml); - if (!layers || !layers.length) return; - for (var i = 0; i < layers.length; i++) { - this.fire('addlayer', { - layer: layers[i] - }); - this.addLayer(layers[i]); - } - this.latLngs = L.KML.getLatLngs(xml); - this.fire('loaded'); - }, - - latLngs: [] -}); - -L.Util.extend(L.KML, { - - parseKML: function (xml) { - var style = this.parseStyles(xml); - this.parseStyleMap(xml, style); - var el = xml.getElementsByTagName('Folder'); - var layers = [], l; - for (var i = 0; i < el.length; i++) { - if (!this._check_folder(el[i])) { continue; } - l = this.parseFolder(el[i], style); - if (l) { layers.push(l); } - } - el = xml.getElementsByTagName('Placemark'); - for (var j = 0; j < el.length; j++) { - if (!this._check_folder(el[j])) { continue; } - l = this.parsePlacemark(el[j], xml, style); - if (l) { layers.push(l); } - } - el = xml.getElementsByTagName('GroundOverlay'); - for (var k = 0; k < el.length; k++) { - l = this.parseGroundOverlay(el[k]); - if (l) { layers.push(l); } - } - return layers; - }, - - // Return false if e's first parent Folder is not [folder] - // - returns true if no parent Folders - _check_folder: function (e, folder) { - e = e.parentNode; - while (e && e.tagName !== 'Folder') - { - e = e.parentNode; - } - return !e || e === folder; - }, - - parseStyles: function (xml) { - var styles = {}; - var sl = xml.getElementsByTagName('Style'); - for (var i=0, len=sl.length; i 1) { - 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) { - layer.on('add', function () { - layer.bindPopup('

' + name + '

' + descr, { className: 'kml-popup'}); - }); - } - - return layer; - }, - - parseCoords: function (xml) { - var el = xml.getElementsByTagName('coordinates'); - return this._read_coords(el[0]); - }, - - parseLineString: function (line, xml, options) { - var coords = this.parseCoords(line); - if (!coords.length) { return; } - return new L.Polyline(coords, options); - }, - - parseTrack: function (line, xml, options) { - var el = xml.getElementsByTagName('gx:coord'); - if (el.length === 0) { el = xml.getElementsByTagName('coord'); } - var coords = []; - for (var j = 0; j < el.length; j++) { - coords = coords.concat(this._read_gxcoords(el[j])); - } - if (!coords.length) { return; } - return new L.Polyline(coords, options); - }, - - parsePoint: function (line, xml, options) { - var el = line.getElementsByTagName('coordinates'); - if (!el.length) { - return; - } - var ll = el[0].childNodes[0].nodeValue.split(','); - return new L.KMLMarker(new L.LatLng(ll[1], ll[0]), options); - }, - - parsePolygon: function (line, xml, options) { - var el, polys = [], inner = [], i, coords; - el = line.getElementsByTagName('outerBoundaryIs'); - for (i = 0; i < el.length; i++) { - coords = this.parseCoords(el[i]); - if (coords) { - polys.push(coords); - } - } - el = line.getElementsByTagName('innerBoundaryIs'); - for (i = 0; i < el.length; i++) { - coords = this.parseCoords(el[i]); - if (coords) { - inner.push(coords); - } - } - if (!polys.length) { - return; - } - if (options.fillColor) { - options.fill = true; - } - if (polys.length === 1) { - return new L.Polygon(polys.concat(inner), options); - } - return new L.MultiPolygon(polys, options); - }, - - getLatLngs: function (xml) { - var el = xml.getElementsByTagName('coordinates'); - var coords = []; - for (var j = 0; j < el.length; j++) { - // text might span many childNodes - coords = coords.concat(this._read_coords(el[j])); - } - return coords; - }, - - _read_coords: function (el) { - var text = '', coords = [], i; - for (i = 0; i < el.childNodes.length; i++) { - text = text + el.childNodes[i].nodeValue; - } - text = text.split(/[\s\n]+/); - for (i = 0; i < text.length; i++) { - var ll = text[i].split(','); - if (ll.length < 2) { - continue; - } - coords.push(new L.LatLng(ll[1], ll[0])); - } - return coords; - }, - - _read_gxcoords: function (el) { - var text = '', coords = []; - text = el.firstChild.nodeValue.split(' '); - coords.push(new L.LatLng(text[1], text[0])); - return coords; - }, - - parseGroundOverlay: function (xml) { - var latlonbox = xml.getElementsByTagName('LatLonBox')[0]; - var bounds = new L.LatLngBounds( - [ - latlonbox.getElementsByTagName('south')[0].childNodes[0].nodeValue, - latlonbox.getElementsByTagName('west')[0].childNodes[0].nodeValue - ], - [ - latlonbox.getElementsByTagName('north')[0].childNodes[0].nodeValue, - latlonbox.getElementsByTagName('east')[0].childNodes[0].nodeValue - ] - ); - var attributes = {Icon: true, href: true, color: true}; - function _parse (xml) { - var options = {}, ioptions = {}; - for (var i = 0; i < xml.childNodes.length; i++) { - var e = xml.childNodes[i]; - var key = e.tagName; - if (!attributes[key]) { continue; } - var value = e.childNodes[0].nodeValue; - if (key === 'Icon') { - ioptions = _parse(e); - if (ioptions.href) { options.href = ioptions.href; } - } else if (key === 'href') { - options.href = value; - } else 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); - } - } - return options; - } - var options = {}; - options = _parse(xml); - if (latlonbox.getElementsByTagName('rotation')[0] !== undefined) { - var rotation = latlonbox.getElementsByTagName('rotation')[0].childNodes[0].nodeValue; - options.rotation = parseFloat(rotation); - } - return new L.RotatedImageOverlay(options.href, bounds, {opacity: options.opacity, angle: options.rotation}); - } - -}); - -L.KMLIcon = L.Icon.extend({ - options: { - iconSize: [32, 32], - iconAnchor: [16, 16], - }, - _setIconStyles: function (img, name) { - L.Icon.prototype._setIconStyles.apply(this, [img, name]); - if( img.complete ) { - this.applyCustomStyles( img ) - } else { - img.onload = this.applyCustomStyles.bind(this,img) - } - - }, - applyCustomStyles: function(img) { - var options = this.options; - this.options.popupAnchor = [0,(-0.83*img.height)]; - if (options.anchorType.x === 'fraction') - img.style.marginLeft = (-options.anchorRef.x * img.width) + 'px'; - if (options.anchorType.y === 'fraction') - img.style.marginTop = ((-(1 - options.anchorRef.y) * img.height) + 1) + 'px'; - if (options.anchorType.x === 'pixels') - img.style.marginLeft = (-options.anchorRef.x) + 'px'; - if (options.anchorType.y === 'pixels') - img.style.marginTop = (options.anchorRef.y - img.height + 1) + 'px'; - } -}); - - -L.KMLMarker = L.Marker.extend({ - options: { - icon: new L.KMLIcon.Default() - } -}); - -// Inspired by https://github.com/bbecquet/Leaflet.PolylineDecorator/tree/master/src -L.RotatedImageOverlay = L.ImageOverlay.extend({ - options: { - angle: 0 - }, - _reset: function () { - L.ImageOverlay.prototype._reset.call(this); - this._rotate(); - }, - _animateZoom: function (e) { - L.ImageOverlay.prototype._animateZoom.call(this, e); - this._rotate(); - }, - _rotate: function () { - if (L.DomUtil.TRANSFORM) { - // use the CSS transform rule if available - this._image.style[L.DomUtil.TRANSFORM] += ' rotate(' + this.options.angle + 'deg)'; - } else if (L.Browser.ie) { - // fallback for IE6, IE7, IE8 - var rad = this.options.angle * (Math.PI / 180), - costheta = Math.cos(rad), - sintheta = Math.sin(rad); - this._image.style.filter += ' progid:DXImageTransform.Microsoft.Matrix(sizingMethod=\'auto expand\', M11=' + - costheta + ', M12=' + (-sintheta) + ', M21=' + sintheta + ', M22=' + costheta + ')'; - } - }, - getBounds: function () { - return this._bounds; - } -}); diff --git a/worldmap/leaflet/leaflet-kmz.js b/worldmap/leaflet/leaflet-kmz.js index 1b09389..f09521b 100644 --- a/worldmap/leaflet/leaflet-kmz.js +++ b/worldmap/leaflet/leaflet-kmz.js @@ -232,9 +232,10 @@ var preferCanvas = this._map ? this._map.options.preferCanvas : this.options.preferCanvas; // var emptyIcon = "data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg'/%3E"; // parse GeoJSON + //console.log("DATA",data) var layer = L.geoJson(data, { pointToLayer: (feature, latlng) => { - // console.log("FEAT",feature) + //console.log("FEAT",feature) if (preferCanvas) { return L.kmzMarker(latlng, { iconUrl: data.properties.icons[feature.properties.icon] || feature.properties.icon, @@ -249,12 +250,25 @@ iconAnchor: [14, 14], }) if (feature.properties && feature.properties.SymbolSpecification) { - var mysymbol = new ms.Symbol(feature.properties.SymbolSpecification.split(':')[1]); + var mysymbol; + if (feature.properties.MilitaryEchelon && feature.properties.SymbolSpecification.split(':')[0] === "APP-6D") { + var a = feature.properties.SymbolSpecification.split(':')[1].substr(0,8); + var c = feature.properties.SymbolSpecification.split(':')[1].substr(10); + var b = parseInt(feature.properties.MilitaryEchelon) + 10; + mysymbol = new ms.Symbol("" + a + b + c); + } + else { + mysymbol = new ms.Symbol(feature.properties.SymbolSpecification.split(':')[1]); + } + mysymbol = mysymbol.setOptions({ size:20 }); + if (feature.properties.name) { mysymbol = mysymbol.setOptions({ uniqueDesignation:feature.properties.name }); } + if (feature.properties.MilitaryParentId) { mysymbol = mysymbol.setOptions({ higherFormation:feature.properties.MilitaryParentId }); } kicon = L.icon({ iconUrl: mysymbol.toDataURL(), iconAnchor: [mysymbol.getAnchor().x, mysymbol.getAnchor().y], }); + //console.log("META",mysymbol.getMetadata()) } if (kicon.options.iconUrl === undefined) { // No icon found so just use default marker. return L.marker(latlng); @@ -268,7 +282,7 @@ // TODO: handle L.svg renderer within the L.KMZMarker class? }, style: (feature) => { - // console.log("FEATSTYLE",feature) + //console.log("FEATSTYLE",feature) var styles = {}; var prop = feature.properties; @@ -293,17 +307,17 @@ return styles; }, onEachFeature: (feature, layer) => { - // console.log("POP",feature.properties) + //console.log("POP",feature.properties) //if (!this.options.ballon) return; - var prop = feature.properties; var name = (prop.name || "").trim(); - var desc = (prop.description || "").trim(); + // var desc = (prop.description || "").trim(); + var desc = prop.description || ""; var p = '
'; if (name || desc) { // if (this.options.bindPopup) { - // p += '' + name + '' + '
' + desc + '
'; + p += '' + name + '' + '
' + desc + ''; // } if (this.options.bindTooltip) { layer.bindTooltip('' + name + '', { @@ -314,18 +328,20 @@ } var u = {}; - if (prop.FeaturePlatformId) { u.FeaturePlatformId = prop.FeaturePlatformId; } - if (prop.FeatureAddress) { u.FeatureAddress = prop.FeatureAddress; } - if (prop.SymbolSpecification) { u.Symbol = prop.SymbolSpecification; } - if (prop.Speed) { u.Speed = prop.Speed; } - if (prop.FeatureLastModified) { u.LastUpdate = prop.FeatureLastModified; } - if (u.LastUpdate) { u.LastUpdate = (new Date(u.LastUpdate*1000)).toISOString(); } + if (prop.MilitaryParentId) { u.group = prop.MilitaryParentId; } + if (prop.FeaturePlatformId) { u["platform id"] = prop.FeaturePlatformId; } + if (prop.FeatureAddress) { u.address = prop.FeatureAddress; } + if (prop.SymbolSpecification) { u[prop.SymbolSpecification.split(':')[0]] = prop.SymbolSpecification.split(':')[1]; } + if (prop.Speed && prop.Speed !== "0") { u.speed = prop.Speed; } + if (prop.FeatureLastModified) { u["last update"] = prop.FeatureLastModified; } + if (u["last update"]) { u["last update"] = (new Date(u["last update"]*1000)).toISOString(); } + p += ''; Object.entries(u).forEach(([key, value]) => { - p += ''+key+' : '+value+'
'; + p += ''; }); - p += ''; - if (p !== '
') { + p += '
'+key+''+value+'
'; + if (p !== '
') { layer.bindPopup(p); } }, diff --git a/worldmap/leaflet/togeojson.umd.js b/worldmap/leaflet/togeojson.umd.js new file mode 100644 index 0000000..4f8704e --- /dev/null +++ b/worldmap/leaflet/togeojson.umd.js @@ -0,0 +1,2 @@ +!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports):"function"==typeof define&&define.amd?define(["exports"],e):e((t="undefined"!=typeof globalThis?globalThis:t||self).toGeoJSON={})}(this,(function(t){"use strict";function e(t,e){return Array.from(t.getElementsByTagName(e))}function n(t){return"#"===t[0]?t:`#${t}`}function o(t){return t?.normalize(),t&&t.textContent||""}function r(t,e,n){const o=t.getElementsByTagName(e),r=o.length?o[0]:null;return r&&n&&n(r),r}function i(t,e,n){const o={};if(!t)return o;const r=t.getElementsByTagName(e),i=r.length?r[0]:null;return i&&n?n(i,o):o}function s(t,e,n){const i=o(r(t,e));return i&&n&&n(i)||{}}function c(t,e,n){const i=parseFloat(o(r(t,e)));if(!isNaN(i))return i&&n&&n(i)||{}}function a(t,e,n){const i=parseFloat(o(r(t,e)));if(!isNaN(i))return n&&n(i),i}function l(t,e){const n={};for(const o of e)s(t,o,(t=>{n[o]=t}));return n}function u(t){return 1===t?.nodeType}function f(t){return i(t,"line",(t=>Object.assign({},s(t,"color",(t=>({stroke:`#${t}`}))),c(t,"opacity",(t=>({"stroke-opacity":t}))),c(t,"width",(t=>({"stroke-width":96*t/25.4}))))))}function p(t){let e=[];if(null===t)return e;for(const n of Array.from(t.childNodes)){if(!u(n))continue;const t=g(n.nodeName);if("gpxtpx:TrackPointExtension"===t)e=e.concat(p(n));else{const r=o(n);e.push([t,d(r)])}}return e}function g(t){return["heart","gpxtpx:hr","hr"].includes(t)?"heart":t}function d(t){const e=parseFloat(t);return isNaN(e)?t:e}function m(t){const e=[parseFloat(t.getAttribute("lon")||""),parseFloat(t.getAttribute("lat")||"")];if(isNaN(e[0])||isNaN(e[1]))return null;a(t,"ele",(t=>{e.push(t)}));const n=r(t,"time");return{coordinates:e,time:n?o(n):null,extendedValues:p(r(t,"extensions"))}}function h(t){const n=l(t,["name","cmt","desc","type","time","keywords"]),r=Array.from(t.getElementsByTagNameNS("http://www.garmin.com/xmlschemas/GpxExtensions/v3","*"));for(const e of r)e.parentNode?.parentNode===t&&(n[e.tagName.replace(":","_")]=o(e));const i=e(t,"link");return i.length&&(n.links=i.map((t=>Object.assign({href:t.getAttribute("href")},l(t,["text","type"]))))),n}function y(t,n){const o=e(t,n),r=[],i=[],s={};for(let t=0;t1,a=Object.assign({_gpxType:"trk"},h(t),f(r(t,"extensions")),i.length?{coordinateProperties:{times:c?i:i[0]}}:{});for(const t of s){o.push(t.line),a.coordinateProperties||(a.coordinateProperties={});const e=a.coordinateProperties,n=Object.entries(t.extendedValues);for(let t=0;tnew Array(t.line.length).fill(null)))),e[o][t]=r):e[o]=r}}return{type:"Feature",properties:a,geometry:c?{type:"MultiLineString",coordinates:o}:{type:"LineString",coordinates:o[0]}}}function x(t){const e=Object.assign(h(t),l(t,["sym"])),n=m(t);return n?{type:"Feature",properties:e,geometry:{type:"Point",coordinates:n.coordinates}}:null}function*k(t){for(const n of e(t,"trk")){const t=N(n);t&&(yield t)}for(const n of e(t,"rte")){const t=b(n);t&&(yield t)}for(const n of e(t,"wpt")){const t=x(n);t&&(yield t)}}const A=[["heartRate","heartRates"],["Cadence","cadences"],["Speed","speeds"],["Watts","watts"]],S=[["TotalTimeSeconds","totalTimeSeconds"],["DistanceMeters","distanceMeters"],["MaximumSpeed","maxSpeed"],["AverageHeartRateBpm","avgHeartRate"],["MaximumHeartRateBpm","maxHeartRate"],["AvgSpeed","avgSpeed"],["AvgWatts","avgWatts"],["MaxWatts","maxWatts"]];function v(t,e){const n=[];for(const[i,s]of e){let e=r(t,i);if(!e){const n=t.getElementsByTagNameNS("http://www.garmin.com/xmlschemas/ActivityExtension/v2",i);n.length&&(e=n[0])}const c=parseFloat(o(e));isNaN(c)||n.push([s,c])}return n}function T(t){const e=[a(t,"LongitudeDegrees"),a(t,"LatitudeDegrees")];if(void 0===e[0]||isNaN(e[0])||void 0===e[1]||isNaN(e[1]))return null;const n=r(t,"HeartRateBpm"),i=o(r(t,"Time"));return r(t,"AltitudeMeters",(t=>{const n=parseFloat(o(t));isNaN(n)||e.push(n)})),{coordinates:e,time:i||null,heartRate:n?parseFloat(o(n)):null,extensions:v(t,A)}}function F(t){const n=e(t,"Trackpoint"),o=[],r=[],i=[];if(n.length<2)return null;const s={},c={extendedProperties:s};for(let t=0;t({name:o(t)}))));for(const t of n)l=F(t),l&&(r.push(l.line),l.times.length&&s.push(l.times),l.heartRates.length&&c.push(l.heartRates),a.push(l.extendedProperties));for(let t=0;tArray(t.length).fill(null)))),u[o][t]=e[o])}return 0===r.length?null:((s.length||c.length)&&(u.coordinateProperties=Object.assign(s.length?{times:1===r.length?s[0]:s}:{},c.length?{heart:1===r.length?c[0]:c}:{})),{type:"Feature",properties:u,geometry:1===r.length?{type:"LineString",coordinates:r[0]}:{type:"MultiLineString",coordinates:r}})}function*O(t){for(const n of e(t,"Lap")){const t=P(n);t&&(yield t)}for(const n of e(t,"Courses")){const t=P(n);t&&(yield t)}}function w(t,e){const n={},o="stroke"==e||"fill"===e?e:e+"-color";return"#"===t[0]&&(t=t.substring(1)),6===t.length||3===t.length?n[o]="#"+t:8===t.length&&(n[e+"-opacity"]=parseInt(t.substring(0,2),16)/255,n[o]="#"+t.substring(6,8)+t.substring(4,6)+t.substring(2,4)),n}function M(t,e,n){const o={};return a(t,e,(t=>{o[n]=t})),o}function j(t,e){return i(t,"color",(t=>w(o(t),e)))}function L(t){return i(t,"Icon",((t,e)=>(s(t,"href",(t=>{e.icon=t})),e)))}function G(t){return Object.assign({},function(t){return i(t,"PolyStyle",((t,e)=>Object.assign(e,i(t,"color",(t=>w(o(t),"fill"))),s(t,"fill",(t=>{if("0"===t)return{"fill-opacity":0}})),s(t,"outline",(t=>{if("0"===t)return{"stroke-opacity":0}})))))}(t),function(t){return i(t,"LineStyle",(t=>Object.assign(j(t,"stroke"),M(t,"width","stroke-width"))))}(t),function(t){return i(t,"LabelStyle",(t=>Object.assign(j(t,"label"),M(t,"scale","label-scale"))))}(t),function(t){return i(t,"IconStyle",(t=>Object.assign(j(t,"icon"),M(t,"scale","icon-scale"),M(t,"heading","icon-heading"),i(t,"hotSpot",(t=>{const e=parseFloat(t.getAttribute("x")||""),n=parseFloat(t.getAttribute("y")||""),o=t.getAttribute("xunits")||"",r=t.getAttribute("yunits")||"";return isNaN(e)||isNaN(n)?{}:{"icon-offset":[e,n],"icon-offset-units":[o,r]}})),L(t))))}(t))}const R=t=>Number(t),B={string:t=>t,int:R,uint:R,short:R,ushort:R,float:R,double:R,bool:t=>Boolean(t)};function E(t,n){return i(t,"ExtendedData",((t,i)=>{for(const n of e(t,"Data"))i[n.getAttribute("name")||""]=o(r(n,"value"));for(const r of e(t,"SimpleData")){const t=r.getAttribute("name")||"",e=n[t]||B.string;i[t]=e(o(r))}return i}))}function C(t){const e=r(t,"description");for(const t of Array.from(e?.childNodes||[]))if(4===t.nodeType)return{description:{"@type":"html",value:o(t)}};return{}}function D(t){return i(t,"TimeSpan",(t=>({timespan:{begin:o(r(t,"begin")),end:o(r(t,"end"))}})))}function W(t){return i(t,"TimeStamp",(t=>({timestamp:o(r(t,"when"))})))}function H(t,e){return s(t,"styleUrl",(t=>(t=n(t),e[t]?Object.assign({styleUrl:t},e[t]):{styleUrl:t})))}const _=/\s*/g,I=/^\s*|\s*$/g,U=/\s+/;function V(t){return t.replace(_,"").split(",").map(parseFloat).filter((t=>!isNaN(t))).slice(0,3)}function $(t){return t.replace(I,"").split(U).map(V).filter((t=>t.length>=2))}function q(t){let n=e(t,"coord");var r,i,s;0===n.length&&(r=t,i="coord",s="*",n=Array.from(r.getElementsByTagNameNS(s,i)));const c=n.map((t=>o(t).split(" ").map(parseFloat)));return 0===c.length?null:{geometry:c.length>2?{type:"LineString",coordinates:c}:{type:"Point",coordinates:c[0]},times:e(t,"when").map((t=>o(t)))}}function z(t){if(0===t.length)return t;const e=t[0],n=t[t.length-1];let o=!0;for(let t=0;t=2&&n.push({type:"Point",coordinates:t});break}case"LinearRing":case"LineString":{const t=$(J(i));t.length>=2&&n.push({type:"LineString",coordinates:t});break}case"Polygon":{const t=[];for(const n of e(i,"LinearRing")){const e=z($(J(n)));e.length>=4&&t.push(e)}t.length&&n.push({type:"Polygon",coordinates:t});break}case"Track":case"gx:Track":{const t=q(i);if(!t)break;const{times:e,geometry:r}=t;n.push(r),e.length&&o.push(e);break}}}return{geometries:n,coordTimes:o}}function K(t,e,n,o){const{coordTimes:r,geometries:i}=Q(t),s=function(t){return 0===t.length?null:1===t.length?t[0]:{type:"GeometryCollection",geometries:t}}(i);if(!s&&o.skipNullGeometry)return null;const c={type:"Feature",geometry:s,properties:Object.assign(l(t,["name","address","visibility","open","phoneNumber","description"]),C(t),H(t,e),G(t),E(t,n),D(t),W(t),r.length?{coordinateProperties:{times:1===r.length?r[0]:r}}:{})};void 0!==c.properties?.visibility&&(c.properties.visibility="0"!==c.properties.visibility);const a=t.getAttribute("id");return null!==a&&""!==a&&(c.id=a),c}function X(t){if(r(t,"gx:LatLonQuad")){return{geometry:{type:"Polygon",coordinates:[z($(J(t)))]}}}return function(t){const e=r(t,"LatLonBox");if(e){const t=a(e,"north"),n=a(e,"west"),o=a(e,"east"),r=a(e,"south"),i=a(e,"rotation");if("number"==typeof t&&"number"==typeof r&&"number"==typeof n&&"number"==typeof o){const e=[n,r,o,t];let s=[[[n,t],[o,t],[o,r],[n,r],[n,t]]];return"number"==typeof i&&(s=function(t,e,n){const o=[(t[0]+t[2])/2,(t[1]+t[3])/2];return[e[0].map((t=>{const e=t[1]-o[1],r=t[0]-o[0],i=Math.sqrt(Math.pow(e,2)+Math.pow(r,2)),s=Math.atan2(e,r)+n*Y;return[o[0]+Math.cos(s)*i,o[1]+Math.sin(s)*i]}))]}(e,s,i)),{bbox:e,geometry:{type:"Polygon",coordinates:s}}}}return null}(t)}const Y=Math.PI/180;function Z(t,e,n,o){const r=X(t),i=r?.geometry||null;if(!i&&o.skipNullGeometry)return null;const s={type:"Feature",geometry:i,properties:Object.assign({"@geometry-type":"groundoverlay"},l(t,["name","address","visibility","open","phoneNumber","description"]),C(t),H(t,e),G(t),L(t),E(t,n),D(t),W(t))};r?.bbox&&(s.bbox=r.bbox),void 0!==s.properties?.visibility&&(s.properties.visibility="0"!==s.properties.visibility);const c=t.getAttribute("id");return null!==c&&""!==c&&(s.id=c),s}function tt(t){let e=t.getAttribute("id");const o=t.parentNode;return!e&&u(o)&&"CascadingStyle"===o.localName&&(e=o.getAttribute("kml:id")||o.getAttribute("id")),n(e||"")}function et(t){const o={};for(const n of e(t,"Style"))o[tt(n)]=G(n);for(const r of e(t,"StyleMap")){const t=n(r.getAttribute("id")||"");s(r,"styleUrl",(e=>{e=n(e),o[e]&&(o[t]=o[e])}))}return o}function nt(t){const n={};for(const o of e(t,"SimpleField"))n[o.getAttribute("name")||""]=B[o.getAttribute("type")||""]||B.string;return n}const ot=["name","visibility","open","address","description","phoneNumber","visibility"];function*rt(t,n={skipNullGeometry:!1}){const o=et(t),r=nt(t);for(const i of e(t,"Placemark")){const t=K(i,o,r,n);t&&(yield t)}for(const i of e(t,"GroundOverlay")){const t=Z(i,o,r,n);t&&(yield t)}}t.gpx=function(t){return{type:"FeatureCollection",features:Array.from(k(t))}},t.gpxGen=k,t.kml=function(t,e={skipNullGeometry:!1}){return{type:"FeatureCollection",features:Array.from(rt(t,e))}},t.kmlGen=rt,t.kmlWithFolders=function(t,e={skipNullGeometry:!1}){const n=et(t),r=nt(t),i={type:"root",children:[]};return function t(e,i,s){if(u(e))switch(e.tagName){case"GroundOverlay":{const t=Z(e,n,r,s);t&&i.children.push(t);break}case"Placemark":{const t=K(e,n,r,s);t&&i.children.push(t);break}case"Folder":{const t=function(t){const e={};for(const n of Array.from(t.childNodes))u(n)&&ot.includes(n.tagName)&&(e[n.tagName]=o(n));return{type:"folder",meta:e,children:[]}}(e);i.children.push(t),i=t;break}}if(e.childNodes)for(let n=0;n>>1;n[o]1){var c,a=[],s={LineString:o,MultiLineString:i,Polygon:i,MultiPolygon:function(n){n.forEach(i)}};u(t),a.forEach(arguments.length<3?function(n){f.push(n[0].i)}:function(n){r(n[0].g,n[n.length-1].g)&&f.push(n[0].i)})}else for(var l=0,h=n.arcs.length;l1)for(var u,f,c=1,a=e(i[0]);ca&&(f=i[0],i[0]=i[c],i[c]=f,a=u);return i})}}function l(n,t){return n[1][2]-t[1][2]}var h=function(){},p=function(n,t){return"GeometryCollection"===t.type?{type:"FeatureCollection",features:t.geometries.map(function(t){return i(n,t)})}:i(n,t)},v=function(n,t){function r(t){var r,e=n.arcs[t<0?~t:t],o=e[0];return n.transform?(r=[0,0],e.forEach(function(n){r[0]+=n[0],r[1]+=n[1]})):r=e[e.length-1],t<0?[r,o]:[o,r]}function e(n,t){for(var r in n){var e=n[r];delete t[e.start],delete e.start,delete e.end,e.forEach(function(n){o[n<0?~n:n]=1}),f.push(e)}}var o={},i={},u={},f=[],c=-1;return t.forEach(function(r,e){var o,i=n.arcs[r<0?~r:r];i.length<3&&!i[1][0]&&!i[1][1]&&(o=t[++c],t[c]=r,t[e]=o)}),t.forEach(function(n){var t,e,o=r(n),f=o[0],c=o[1];if(t=u[f])if(delete u[t.end],t.push(n),t.end=c,e=i[c]){delete i[e.start];var a=e===t?t:t.concat(e);i[a.start=t.start]=u[a.end=e.end]=a}else i[t.start]=u[t.end]=t;else if(t=i[c])if(delete i[t.start],t.unshift(n),t.start=f,e=u[f]){delete u[e.end];var s=e===t?t:e.concat(t);i[s.start=e.start]=u[s.end=t.end]=s}else i[t.start]=u[t.end]=t;else t=[n],i[t.start=f]=u[t.end=c]=t}),e(u,i),e(i,u),t.forEach(function(n){o[n<0?~n:n]||f.push([n])}),f},g=function(n){return u(n,f.apply(this,arguments))},d=function(n){return u(n,s.apply(this,arguments))},y=function(n){function t(n,t){n.forEach(function(n){n<0&&(n=~n);var r=i[n];r?r.push(t):i[n]=[t]})}function r(n,r){n.forEach(function(n){t(n,r)})}function e(n,t){"GeometryCollection"===n.type?n.geometries.forEach(function(n){e(n,t)}):n.type in f&&f[n.type](n.arcs,t)}var i={},u=n.map(function(){return[]}),f={LineString:t,MultiLineString:r,Polygon:r,MultiPolygon:function(n,t){n.forEach(function(n){r(n,t)})}};n.forEach(e);for(var c in i)for(var a=i[c],s=a.length,l=0;l0;){var r=(t+1>>1)-1,o=e[r];if(l(n,o)>=0)break;e[o._=t]=o,e[n._=t=r]=n}}function t(n,t){for(;;){var r=t+1<<1,i=r-1,u=t,f=e[u];if(i0&&(n=e[o],t(e[n._=0]=n,0)),r}},r.remove=function(r){var i,u=r._;if(e[u]===r)return u!==--o&&(i=e[o],(l(i,r)<0?n:t)(e[i._=u]=i,u)),u},r},E=function(n,e){function o(n){f.remove(n),n[1][2]=e(n),f.push(n)}var i=t(n.transform),u=r(n.transform),f=m();return null==e&&(e=c),n.arcs.forEach(function(n){var t,r,c,a,s=[],l=0;for(r=0,c=n.length;r"; - } else { - words += i +" : "+data[i]+"
"; + if (data.popup) { words = data.popup; } + else { + words += ''; + for (var i in data) { + if ((i != "name") && (i != "length") && (i != "clickable")) { + if (typeof data[i] === "object") { + // + words += ''; + } else { + // words += i +" : "+data[i]+"
"; + words += ''; + } } } + words += ''; + words += '
'+ i +'' + JSON.stringify(data[i]) + '
'+ i +'' + data[i] + '
lat, lon'+ marker.getLatLng().toString().replace('LatLng(','').replace(')','') + '
'; } - if (data.popup) { words = data.popup; } - else { words = words + marker.getLatLng().toString().replace('LatLng(','lat, lon : ').replace(')',''); } words = ""+data.name+"
" + words; //"
" + words; var wopt = {autoClose:false, closeButton:true, closeOnClick:false, minWidth:200}; if (words.indexOf('