From d5850c47d48835e60e91e55f5da9fb8f45bc4d81 Mon Sep 17 00:00:00 2001 From: astridx Date: Sat, 5 Sep 2020 16:18:52 +0200 Subject: [PATCH 1/2] wip --- dist/current | 2 +- .../components/com_aggpxtrack/aggpxtrack.xml | 4 ++-- dist/zips/com_aggpxtrack.zip | Bin 82359 -> 82361 bytes dist/zips/plg_fields_aggpxtrack.zip | Bin 1629893 -> 1629912 bytes .../plg_installer_aggpxtrackinstaller.zip | Bin 4346 -> 4346 bytes jorobo.ini | 2 +- .../plg_fields_aggpxtrack/js/aggpxtrack.js | 2 ++ 7 files changed, 6 insertions(+), 4 deletions(-) diff --git a/dist/current b/dist/current index 0b6ebf0..e0b0be2 120000 --- a/dist/current +++ b/dist/current @@ -1 +1 @@ -/home/astrid/git/joomla-development/pkg_aggpxtrack/dist/aggpxtrack-1.1.5 \ No newline at end of file +/home/astrid/git/joomla-development/pkg_aggpxtrack/dist/aggpxtrack-1.1.6 \ No newline at end of file diff --git a/dist/tmp/cbuild/administrator/components/com_aggpxtrack/aggpxtrack.xml b/dist/tmp/cbuild/administrator/components/com_aggpxtrack/aggpxtrack.xml index a1e95dc..a19e45d 100644 --- a/dist/tmp/cbuild/administrator/components/com_aggpxtrack/aggpxtrack.xml +++ b/dist/tmp/cbuild/administrator/components/com_aggpxtrack/aggpxtrack.xml @@ -2,12 +2,12 @@ com_aggpxtrack Astrid Günther - 2020-09-03 + 2020-09-05 (C) 2020 Astrid Günther. All rights reserved. GNU General Public License version 2 or later; see LICENSE.txt info@astrid-guenther.de www.astrid-guenther.de - 1.1.5 + 1.1.6 COM_AGGPXTRACK_XML_DESCRIPTION script.php diff --git a/dist/zips/com_aggpxtrack.zip b/dist/zips/com_aggpxtrack.zip index 1bdece6cc81be075054f71e70538623ae59f3d90..e1e0e128e873acee58b305552c0fbb90fd8e241b 100644 GIT binary patch delta 3426 zcmeHJX;c(f7Oo34G&_tSEiH=+OM^hOgV1b(fD)h;ku@%W3sFP@iAD(`B5sJW={#i= zIiN?vm=ejoj zuA+$3QpC}ZU97HQLNT9vX*OT!&r)XwS0N7RzRb{2N1*w@uUrHwq}~X0OVicR@H=uw1C2+=+Legx#ITw%?JT|{ zo)xqRD5{(O%^_e1Jc-e9ZTX$*L_iOxla1;qykw`nrC5!kUeiAnp>b`wGGc9=Ou3vy z*<8j`QrKWFsgN0Aly7AT7>)s_Wn?*phqx%Sp+<3;Y{)(9BPRq7=q+owfa8Wn0ggu+ z-Eh3s=);V1u6&1#}KKYf+S!G!`6*RWRt1WNVl=I z^nNt|VS`{%)!^MXiayD}ph-daU!%VA6P~&`x~kqxUrp_cO1mYeOWObGeA%$w_?i3N zgig~nCHZC+8dv+wvUxXOp1I+w)~8R$a5z57r-z=vtjtdSrZM z_l&n9+xWq>|JFAxw4M8Ybm`AFyoHL-LT~DG_lwJlIcXom2YQ6W+H^ZUkHotF485kbfeYL8c8|EC}-x(GC zZpm@2#+aN1CcC{)L}&*^+tmz@WX}AlG^6Ra^#;BjyW&zFg}qNapI`h?XRPfnwK0!_ zOK+Eox3_*Ae%mjOyK9r;>g(#(K~c?U_woYk!knyhvCaOnj@xUl__UpGZJT*8dW~Z3 zY5Bj0dj@lIHj8{uxb^;H_SqBjPO3dE5jV`^Z9MvRPo1Vs;(r{V>u_k~g^cj95&t94 z4peq79UZI6%`=*xy0__Ca)@)|$FDG-~m_+V2I@41Bk!h;Ug}qtrISa;*z1r9p zzM`aS%l2h<$F@3Ltn95w5tQpYZ%yvs_W0{wX`O}KA4YGS&P&;z_F2H~<&~nt2|pj) zmT;r#hX?9?kqL^+-g`51N6HWVee2MTN1nN(Zr6u~Uc_b`9Pb(ZrTdV(zBLKan{GFHAMkxbxey@84d6 zDZ5@CIK)$yZ_<-mEMGZic(Za#Z+(I1jO5yjSlsixm&Tp_Vo#TM=oKQq@VXYEt)&W}#py<~JUz}9IH-u^>`<*cmC7Wal zjY`ar2N8&oBtFD3b1545kccGFx1__-5b?4EPvo*Jp#!vONQ^~C!mL5?XN~6`0jrF-+QD8#S|^N1dlu=jhcA(e7r;_9&IkZsH{`tl z79bMpz)}?s5RM3a-YrKXz!9);$=8k$jmYngEEPPDMGnt{M5LZhAc0P-=BN|kJCAfa z!F<%{I|J4`gYZeAGgu*9GX*wtVPRhvR(;q7u*o4EE)aqqA~)LKSqM&e^|27r(YPjr zl^^&8t}OqlE6ew~e&8cexW|n}hTK@q5_bqi>Zm)Lm}l;ggh-SJtUyEN0c+9VdBQ3* zwtKRgpFAN`<=}|&Ql4z2&I|Zz?n6>BI54kmbM!LsroreZ2rlym?AJ&Z1HO6AfRcb= z9dgMVuuUNy46*SAO$Z6!hXoycXs`uA$=R1$8cZ_La)N=E8KwAF~+O`r@QD2Gf=G} zp!`%W#)E$ur`00Ei8U}BbJhmWrx)%;5!XNvk>>%xAyxC)dpgTd<*Jl{A6R0>T>NNi zTusGGXaHJ7>c=Ke#_->8CV4%guL(ND(w`0Oa>Rc^Mqu!{tX*qu-*qC*)PPKM$T`YyPH69Cw$6N>_p&AqwJ7vCT(@FnXR?JgN8Od7lfR8f0e2LmY#Vt00B5b!k|==?}m zfjJp)2ff+M>N3X!_510ht)N$Euj1QWxOzg%6bEWm+g*bxT6b%pNU0Z?hcGd3dxRM# qt5Z}9-4^Ri(e=#+>eIBG_1U?~q;lw-P}Cy&8^WikRkrj(sQ&?>LgIoGyg zI_YHnEmpeR(8PAIqsfM`NJ?AGCFh#-(B9az9pf0%U~ist#3omEejG}TnV;0NIcnM9 zfYD7Y9oXi!3b3teb;I^fs}Ivk)ubPT4h<4cruI%XX;GA1AQ_l9l+1OhON3IM^j=$s zmLkBO>=uEVCbOK1?j!?U*D%YeZh^*%>!us1n64RCg3!Zs&$J3fWg0IhC$x(%^}92V z>nm{`yn*rZK@V*0he9!N-q45ae4Y=-ArU!p5SLrp`7jk1Okyz^%_yJdOseQJ6S2Pg zZ1EU}q7JB1lviZ}IFi#|phMCuL2tb}r_KJ>V1d?9)}+#ok}<7e^WI!RboKPTm$EU* z__Seh&-u+2{=&L1pCvS#XmdD4m+ZFIM|AzmrCYa4^u+z%_I{&Z|30uxhr8#ArjN$d zdvAYh-liR?QuvA8^v>FF8@;)puG85S5OHsFZFWmb_?N|QkIUci4IH0}j&9$%(O}(D zQGcQO?*m;t@{;JA9(mFFIpd$RXFW=<10i9N&Ea9e#lSA)%ND^-(eP8;cWK8eFi92>%IcM(P z&I;%>k0{JAYkcoq=pWpzj7U*Mv2k8n`gP8YD@uJDYlwp{5Wn`dN$A~lWjkCNn z%hfNl?b0iaVw?EBQ%((;@`0D5xu!iPvJrA?KsGu%`ooWzM?J4!*tILJufDv!<%=0R z&Cg2ylb+i&*^el7OAg#jjY#DcWJG-TzFCxWi!dePY$4$uHZ4{!zB+UHou!MR_wx^0^6JwWy!nih8yQ%Ys@VI?P~KL z__Y>krgrwppI<*3ckxki!5iZjHAh58(>FZS-rr|gaeVyI-nv4~f1Bl`9slbqoma1W zzuophc>SgJhBxCq?p~j4>zIi?lVGA0()RMm{NnyK8(%7(F=fj-W%e>#=qmC9?2ay) z#}h^J&-r-V@@5O$aEBjQFjGfx>h(_cBzU~^HbYc~LJHIV{V$M(No87GsAo~TGMr^m ztQzcNkxT<@F@bDc8+@@-*?L{5Vbv~uAgr2V1g$KmX9|(XkrW;zVKsG6&OZAID9V>h zQQ>qoiHKMXrZV;Qz`+=z!>4dZU-MBb7L9A*ejS3dpL&Db^#sQC4AB31GaUogX&+-H=rB~&WM zLEG_v#+9-JS71`4e-DmJHhyz*MjDg z^lGKi1GQfj-(H%&VqV$u7_s_!tFtD;&5}+}o6WJuq7dNOj9CM9DC1yu{$ZE=to-;G UWqK_rDw_Un;?bSj(mhlE1$6u1t^fc4 diff --git a/dist/zips/plg_fields_aggpxtrack.zip b/dist/zips/plg_fields_aggpxtrack.zip index ad79f9d728075c6918935638559242878cf74582..53cb99460955ed8f8f953600f673529599157bd2 100644 GIT binary patch delta 6514 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 delta 6741 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 Rq~|g}L=Uq7L~W%&BLEw|7U=*0 delta 660 zcmeyR_)C#Dz?+#xgn@~HgJE5%@bVaATVd^)rohJp>NU0aiVf~kz|97KR+T>i-TT^d&?X9pe&X2p-X5YSPv$=oo0#?FSl6t=<{T3V-aQAa^9w|O*sDq<1kT%XqP%VItbJ{4 zoZD5kBE+})3FhrE+-A!qta$Hr$V<_xxhlFvpK3dul3D% zK3ZPw<8lkgm=M?GLiCz3~9{0(XTVnD%vu~cxF44Wrb9>$S z1?!&qd6!wpyjagI)zWJ3ndEG>B%f)2X|CE~t*eW2mK~i|IOUA^>$56-heM4z7d`!( zW;(NOvOG&7Aeewnt5oTcIOg_${38p`@ z7=dX4E{(|ntO6kR=493+Mlj<9TO61%86^9Uj}0}VC#P`S0_%0;JOeeu0!({zeE`#T z+~2^oIgb+}K{WE%f&~xqSc2)lJWgP`mQQ+eEUzw@-OF1JrrG(5p>iHz`UI43#}APQ R>AB1g(ZehNQClg{2ms_D5{du- diff --git a/jorobo.ini b/jorobo.ini index 608322d..d22911b 100644 --- a/jorobo.ini +++ b/jorobo.ini @@ -1,5 +1,5 @@ extension = aggpxtrack -version = 1.1.5 +version = 1.1.6 source = src target = package diff --git a/src/media/plg_fields_aggpxtrack/js/aggpxtrack.js b/src/media/plg_fields_aggpxtrack/js/aggpxtrack.js index b6e84cb..01e2785 100644 --- a/src/media/plg_fields_aggpxtrack/js/aggpxtrack.js +++ b/src/media/plg_fields_aggpxtrack/js/aggpxtrack.js @@ -298,6 +298,8 @@ document.addEventListener('DOMContentLoaded', function () { L.control.locate({ position: currentposition_position, initialZoomLevel: currentposition_initialZoomLevel, + keepCurrentZoomLevel: true, + setView: 'always', strings: { 'title': Joomla.JText._('PLG_AGGPXTRACK_CURRENTPOSITION_STRING'), }, From e8ebbfad7c6806bb02f9d94075a9a27e0db5cfac Mon Sep 17 00:00:00 2001 From: astridx Date: Sun, 13 Sep 2020 11:05:49 +0200 Subject: [PATCH 2/2] important for location --- .../plg_fields_aggpxtrack/leaflet-gpx/gpx.js | 825 +++++++++++------- .../leaflet-gpx/gpx_meineVersion.js | 635 ++++++++++++++ 2 files changed, 1162 insertions(+), 298 deletions(-) create mode 100644 src/media/plg_fields_aggpxtrack/leaflet-gpx/gpx_meineVersion.js diff --git a/src/media/plg_fields_aggpxtrack/leaflet-gpx/gpx.js b/src/media/plg_fields_aggpxtrack/leaflet-gpx/gpx.js index 49a3728..da8d9d2 100644 --- a/src/media/plg_fields_aggpxtrack/leaflet-gpx/gpx.js +++ b/src/media/plg_fields_aggpxtrack/leaflet-gpx/gpx.js @@ -1,42 +1,4 @@ -/** - * Copyright (C) 2011-2012 Pavel Shramov - * Copyright (C) 2013-2017 Maxime Petazzoni - * All Rights Reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * - Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -/* - * Thanks to Pavel Shramov who provided the initial implementation and Leaflet - * integration. Original code was at https://github.com/shramov/leaflet-plugins. - * - * It was then cleaned-up and modified to record and make available more - * information about the GPX track while it is being parsed so that the result - * can be used to display additional information about the track that is - * rendered on the Leaflet map. - */ - -var L = L || require('leaflet'); +var L = L || require("leaflet"); var _MAX_POINT_INTERVAL_MS = 15000; var _SECOND_IN_MILLIS = 1000; @@ -44,51 +6,62 @@ var _MINUTE_IN_MILLIS = 60 * _SECOND_IN_MILLIS; var _HOUR_IN_MILLIS = 60 * _MINUTE_IN_MILLIS; var _DAY_IN_MILLIS = 24 * _HOUR_IN_MILLIS; +var _GPX_STYLE_NS = "http://www.topografix.com/GPX/gpx_style/0/2"; + var _DEFAULT_MARKER_OPTS = { - startIconUrl: 'pin-icon-start.png', - endIconUrl: 'pin-icon-end.png', - shadowUrl: 'pin-shadow.png', - wptIconUrls : { - '': 'pin-icon-wpt.png', + startIconUrl: "pin-icon-start.png", + endIconUrl: "pin-icon-end.png", + shadowUrl: "pin-shadow.png", + wptIcons: [], + wptIconsType: [], + wptIconUrls: { + "": "pin-icon-wpt.png", + }, + wptIconTypeUrls: { + "": "pin-icon-wpt.png", }, + pointMatchers: [], iconSize: [33, 50], shadowSize: [50, 50], iconAnchor: [16, 45], shadowAnchor: [16, 47], - clickable: false + clickable: false, }; var _DEFAULT_POLYLINE_OPTS = { - color: 'blue' + color: "blue", }; var _DEFAULT_GPX_OPTS = { - parseElements: ['track', 'route', 'waypoint'], + parseElements: ["track", "route", "waypoint"], show_kilometer_point: false, - kilometer_point_options : { - kilometer_point_color: 'blue', - kilometer_point_color_text: 'white', + kilometer_point_options: { + kilometer_point_color: "blue", + kilometer_point_color_text: "white", kilometer_point_intervall: 1, kilometer_point_radius: 10, }, show_mile_point: true, - mile_point_options : { - mile_point_color: 'blue', - mile_point_color_text: 'white', + mile_point_options: { + mile_point_color: "blue", + mile_point_color_text: "white", mile_intervall: 1, mile_point_radius: 10, }, + joinTrackSegments: true, }; + L.GPX = L.FeatureGroup.extend({ - initialize: function(gpx, options) { - options.max_point_interval = options.max_point_interval || _MAX_POINT_INTERVAL_MS; + initialize: function (gpx, options) { + options.max_point_interval = + options.max_point_interval || _MAX_POINT_INTERVAL_MS; options.marker_options = this._merge_objs( _DEFAULT_MARKER_OPTS, - options.marker_options || {}); - options.polyline_options = this._merge_objs( - _DEFAULT_POLYLINE_OPTS, - options.polyline_options || {}); + options.marker_options || {} + ); + options.polyline_options = options.polyline_options || {}; options.gpx_options = this._merge_objs( _DEFAULT_GPX_OPTS, - options.gpx_options || {}); + options.gpx_options || {} + ); L.Util.setOptions(this, options); @@ -104,196 +77,297 @@ L.GPX = L.FeatureGroup.extend({ } }, - get_duration_string: function(duration, hidems) { - var s = ''; + get_duration_string: function (duration, hidems) { + var s = ""; if (duration >= _DAY_IN_MILLIS) { - s += Math.floor(duration / _DAY_IN_MILLIS) + 'd '; + s += Math.floor(duration / _DAY_IN_MILLIS) + "d "; duration = duration % _DAY_IN_MILLIS; } if (duration >= _HOUR_IN_MILLIS) { - s += Math.floor(duration / _HOUR_IN_MILLIS) + ':'; + s += Math.floor(duration / _HOUR_IN_MILLIS) + ":"; duration = duration % _HOUR_IN_MILLIS; } var mins = Math.floor(duration / _MINUTE_IN_MILLIS); duration = duration % _MINUTE_IN_MILLIS; - if (mins < 10) s += '0'; - s += mins + '\''; + if (mins < 10) s += "0"; + s += mins + "'"; var secs = Math.floor(duration / _SECOND_IN_MILLIS); duration = duration % _SECOND_IN_MILLIS; - if (secs < 10) s += '0'; + if (secs < 10) s += "0"; s += secs; - if (!hidems && duration > 0) s += '.' + Math.round(Math.floor(duration)*1000)/1000; + if (!hidems && duration > 0) + s += "." + Math.round(Math.floor(duration) * 1000) / 1000; else s += '"'; return s; }, - get_duration_string_iso: function(duration, hidems) { + get_duration_string_iso: function (duration, hidems) { var s = this.get_duration_string(duration, hidems); - return s.replace("'",':').replace('"',''); + return s.replace("'", ":").replace('"', ""); }, // Public methods - to_miles: function(v) { return v / 1.60934; }, - to_ft: function(v) { return v * 3.28084; }, - m_to_km: function(v) { return v / 1000; }, - m_to_mi: function(v) { return v / 1609.34; }, - - get_name: function() { return this._info.name; }, - get_desc: function() { return this._info.desc; }, - get_author: function() { return this._info.author; }, - get_copyright: function() { return this._info.copyright; }, - get_distance: function() { return this._info.length; }, - get_distance_imp: function() { return this.to_miles(this.m_to_km(this.get_distance())); }, - - get_start_time: function() { return this._info.duration.start; }, - get_end_time: function() { return this._info.duration.end; }, - get_moving_time: function() { return this._info.duration.moving; }, - get_total_time: function() { return this._info.duration.total; }, - - get_moving_pace: function() { return this.get_moving_time() / this.m_to_km(this.get_distance()); }, - get_moving_pace_imp: function() { return this.get_moving_time() / this.get_distance_imp(); }, - - get_moving_speed: function() { return this.m_to_km(this.get_distance()) / (this.get_moving_time() / (3600 * 1000)) ; }, - get_moving_speed_imp:function() { return this.to_miles(this.m_to_km(this.get_distance())) / (this.get_moving_time() / (3600 * 1000)) ; }, - - get_total_speed: function() { return this.m_to_km(this.get_distance()) / (this.get_total_time() / (3600 * 1000)); }, - get_total_speed_imp: function() { return this.to_miles(this.m_to_km(this.get_distance())) / (this.get_total_time() / (3600 * 1000)); }, - - get_elevation_gain: function() { return this._info.elevation.gain; }, - get_elevation_loss: function() { return this._info.elevation.loss; }, - get_elevation_gain_imp: function() { return this.to_ft(this.get_elevation_gain()); }, - get_elevation_loss_imp: function() { return this.to_ft(this.get_elevation_loss()); }, - get_elevation_data: function() { + to_miles: function (v) { + return v / 1.60934; + }, + to_ft: function (v) { + return v * 3.28084; + }, + m_to_km: function (v) { + return v / 1000; + }, + m_to_mi: function (v) { + return v / 1609.34; + }, + + get_name: function () { + return this._info.name; + }, + get_desc: function () { + return this._info.desc; + }, + get_author: function () { + return this._info.author; + }, + get_copyright: function () { + return this._info.copyright; + }, + get_distance: function () { + return this._info.length; + }, + get_distance_imp: function () { + return this.to_miles(this.m_to_km(this.get_distance())); + }, + + get_start_time: function () { + return this._info.duration.start; + }, + get_end_time: function () { + return this._info.duration.end; + }, + get_moving_time: function () { + return this._info.duration.moving; + }, + get_total_time: function () { + return this._info.duration.total; + }, + + get_moving_pace: function () { + return this.get_moving_time() / this.m_to_km(this.get_distance()); + }, + get_moving_pace_imp: function () { + return this.get_moving_time() / this.get_distance_imp(); + }, + + get_moving_speed: function () { + return ( + this.m_to_km(this.get_distance()) / + (this.get_moving_time() / (3600 * 1000)) + ); + }, + get_moving_speed_imp: function () { + return ( + this.to_miles(this.m_to_km(this.get_distance())) / + (this.get_moving_time() / (3600 * 1000)) + ); + }, + + get_total_speed: function () { + return ( + this.m_to_km(this.get_distance()) / + (this.get_total_time() / (3600 * 1000)) + ); + }, + get_total_speed_imp: function () { + return ( + this.to_miles(this.m_to_km(this.get_distance())) / + (this.get_total_time() / (3600 * 1000)) + ); + }, + + get_elevation_gain: function () { + return this._info.elevation.gain; + }, + get_elevation_loss: function () { + return this._info.elevation.loss; + }, + get_elevation_gain_imp: function () { + return this.to_ft(this.get_elevation_gain()); + }, + get_elevation_loss_imp: function () { + return this.to_ft(this.get_elevation_loss()); + }, + get_elevation_data: function () { var _this = this; - return this._info.elevation._points.map( - function(p) { return _this._prepare_data_point(p, _this.m_to_km, null, - function(a, b) { return a.toFixed(2) + ' km, ' + b.toFixed(0) + ' m'; }); + return this._info.elevation._points.map(function (p) { + return _this._prepare_data_point(p, _this.m_to_km, null, function (a, b) { + return a.toFixed(2) + " km, " + b.toFixed(0) + " m"; }); + }); }, - get_elevation_data_imp: function() { + get_elevation_data_imp: function () { var _this = this; - return this._info.elevation._points.map( - function(p) { return _this._prepare_data_point(p, _this.m_to_mi, _this.to_ft, - function(a, b) { return a.toFixed(2) + ' mi, ' + b.toFixed(0) + ' ft'; }); + return this._info.elevation._points.map(function (p) { + return _this._prepare_data_point(p, _this.m_to_mi, _this.to_ft, function ( + a, + b + ) { + return a.toFixed(2) + " mi, " + b.toFixed(0) + " ft"; }); + }); + }, + get_elevation_max: function () { + return this._info.elevation.max; + }, + get_elevation_min: function () { + return this._info.elevation.min; + }, + get_elevation_max_imp: function () { + return this.to_ft(this.get_elevation_max()); + }, + get_elevation_min_imp: function () { + return this.to_ft(this.get_elevation_min()); }, - get_elevation_max: function() { return this._info.elevation.max; }, - get_elevation_min: function() { return this._info.elevation.min; }, - get_elevation_max_imp: function() { return this.to_ft(this.get_elevation_max()); }, - get_elevation_min_imp: function() { return this.to_ft(this.get_elevation_min()); }, - get_average_hr: function() { return this._info.hr.avg; }, - get_average_temp: function() { return this._info.atemp.avg; }, - get_average_cadence: function() { return this._info.cad.avg; }, - get_heartrate_data: function() { + get_average_hr: function () { + return this._info.hr.avg; + }, + get_average_temp: function () { + return this._info.atemp.avg; + }, + get_average_cadence: function () { + return this._info.cad.avg; + }, + get_heartrate_data: function () { var _this = this; - return this._info.hr._points.map( - function(p) { return _this._prepare_data_point(p, _this.m_to_km, null, - function(a, b) { return a.toFixed(2) + ' km, ' + b.toFixed(0) + ' bpm'; }); + return this._info.hr._points.map(function (p) { + return _this._prepare_data_point(p, _this.m_to_km, null, function (a, b) { + return a.toFixed(2) + " km, " + b.toFixed(0) + " bpm"; }); + }); }, - get_heartrate_data_imp: function() { + get_heartrate_data_imp: function () { var _this = this; - return this._info.hr._points.map( - function(p) { return _this._prepare_data_point(p, _this.m_to_mi, null, - function(a, b) { return a.toFixed(2) + ' mi, ' + b.toFixed(0) + ' bpm'; }); + return this._info.hr._points.map(function (p) { + return _this._prepare_data_point(p, _this.m_to_mi, null, function (a, b) { + return a.toFixed(2) + " mi, " + b.toFixed(0) + " bpm"; }); + }); }, - get_cadence_data: function() { + get_cadence_data: function () { var _this = this; - return this._info.cad._points.map( - function(p) { return _this._prepare_data_point(p, _this.m_to_km, null, - function(a, b) { return a.toFixed(2) + ' km, ' + b.toFixed(0) + ' rpm'; }); + return this._info.cad._points.map(function (p) { + return _this._prepare_data_point(p, _this.m_to_km, null, function (a, b) { + return a.toFixed(2) + " km, " + b.toFixed(0) + " rpm"; }); + }); }, - get_temp_data: function() { + get_temp_data: function () { var _this = this; - return this._info.atemp._points.map( - function(p) { return _this._prepare_data_point(p, _this.m_to_km, null, - function(a, b) { return a.toFixed(2) + ' km, ' + b.toFixed(0) + ' degrees'; }); + return this._info.atemp._points.map(function (p) { + return _this._prepare_data_point(p, _this.m_to_km, null, function (a, b) { + return a.toFixed(2) + " km, " + b.toFixed(0) + " degrees"; }); + }); }, - get_cadence_data_imp: function() { + get_cadence_data_imp: function () { var _this = this; - return this._info.cad._points.map( - function(p) { return _this._prepare_data_point(p, _this.m_to_mi, null, - function(a, b) { return a.toFixed(2) + ' mi, ' + b.toFixed(0) + ' rpm'; }); + return this._info.cad._points.map(function (p) { + return _this._prepare_data_point(p, _this.m_to_mi, null, function (a, b) { + return a.toFixed(2) + " mi, " + b.toFixed(0) + " rpm"; }); + }); }, - get_temp_data_imp: function() { + get_temp_data_imp: function () { var _this = this; - return this._info.atemp._points.map( - function(p) { return _this._prepare_data_point(p, _this.m_to_mi, null, - function(a, b) { return a.toFixed(2) + ' mi, ' + b.toFixed(0) + ' degrees'; }); + return this._info.atemp._points.map(function (p) { + return _this._prepare_data_point(p, _this.m_to_mi, null, function (a, b) { + return a.toFixed(2) + " mi, " + b.toFixed(0) + " degrees"; }); + }); }, - reload: function() { + reload: function () { this._init_info(); this.clearLayers(); this._parse(this._gpx, this.options, this.options.async); }, // Private methods - _merge_objs: function(a, b) { + _merge_objs: function (a, b) { var _ = {}; - for (var attr in a) { _[attr] = a[attr]; } - for (var attr in b) { _[attr] = b[attr]; } + for (var attr in a) { + _[attr] = a[attr]; + } + for (var attr in b) { + _[attr] = b[attr]; + } return _; }, - _prepare_data_point: function(p, trans1, trans2, trans_tooltip) { - var r = [trans1 && trans1(p[0]) || p[0], trans2 && trans2(p[1]) || p[1]]; - r.push(trans_tooltip && trans_tooltip(r[0], r[1]) || (r[0] + ': ' + r[1])); + _prepare_data_point: function (p, trans1, trans2, trans_tooltip) { + var r = [ + (trans1 && trans1(p[0])) || p[0], + (trans2 && trans2(p[1])) || p[1], + ]; + r.push((trans_tooltip && trans_tooltip(r[0], r[1])) || r[0] + ": " + r[1]); return r; }, - _init_info: function() { + _init_info: function () { this._info = { name: null, length: 0.0, - elevation: {gain: 0.0, loss: 0.0, max: 0.0, min: Infinity, _points: []}, - hr: {avg: 0, _total: 0, _points: []}, - duration: {start: null, end: null, moving: 0, total: 0}, - atemp: {avg: 0, _total: 0, _points: []}, - cad: {avg: 0, _total: 0, _points: []} + elevation: { gain: 0.0, loss: 0.0, max: 0.0, min: Infinity, _points: [] }, + hr: { avg: 0, _total: 0, _points: [] }, + duration: { start: null, end: null, moving: 0, total: 0 }, + atemp: { avg: 0, _total: 0, _points: [] }, + cad: { avg: 0, _total: 0, _points: [] }, }; }, - _load_xml: function(url, cb, options, async) { + _load_xml: function (url, cb, options, async) { if (async == undefined) async = this.options.async; if (options == undefined) options = this.options; var req = new window.XMLHttpRequest(); - req.open('GET', url, async); + req.open("GET", url, async); try { - req.overrideMimeType('text/xml'); // unsupported by IE - } catch(e) {} - req.onreadystatechange = function() { + req.overrideMimeType("text/xml"); // unsupported by IE + } catch (e) {} + req.onreadystatechange = function () { if (req.readyState != 4) return; - if(req.status == 200) cb(req.responseXML, options); + if (req.status == 200) cb(req.responseXML, options); }; req.send(null); }, - _parse: function(input, options, async) { + _parse: function (input, options, async) { var _this = this; - var cb = function(gpx, options) { + var cb = function (gpx, options) { var layers = _this._parse_gpx_data(gpx, options); - if (!layers) return; + if (!layers) { + _this.fire("error", { + err: + "No parseable layers of type(s) " + + JSON.stringify(options.gpx_options.parseElements), + }); + return; + } _this.addLayer(layers); - _this.fire('loaded'); - } - if (input.substr(0,1)==='<') { // direct XML has to start with a < + _this.fire("loaded", { layers: layers, element: gpx }); + }; + if (input.substr(0, 1) === "<") { + // direct XML has to start with a < var parser = new DOMParser(); if (async) { - setTimeout(function() { + setTimeout(function () { cb(parser.parseFromString(input, "text/xml"), options); }); } else { @@ -304,98 +378,111 @@ L.GPX = L.FeatureGroup.extend({ } }, - _parse_gpx_data: function(xml, options) { - var j, i, el, layers = []; - var tags = []; - - var parseElements = options.gpx_options.parseElements; - if (parseElements.indexOf('route') > -1) { - tags.push(['rte','rtept']); - } - if (parseElements.indexOf('track') > -1) { - tags.push(['trkseg','trkpt']); - } + _parse_gpx_data: function (xml, options) { + var i, + t, + l, + el, + layers = []; - var name = xml.getElementsByTagName('name'); + var name = xml.getElementsByTagName("name"); if (name.length > 0) { this._info.name = name[0].textContent; } - var desc = xml.getElementsByTagName('desc'); + var desc = xml.getElementsByTagName("desc"); if (desc.length > 0) { this._info.desc = desc[0].textContent; } - var author = xml.getElementsByTagName('author'); + var author = xml.getElementsByTagName("author"); if (author.length > 0) { this._info.author = author[0].textContent; } - var copyright = xml.getElementsByTagName('copyright'); + var copyright = xml.getElementsByTagName("copyright"); if (copyright.length > 0) { this._info.copyright = copyright[0].textContent; } - for (j = 0; j < tags.length; j++) { - el = xml.getElementsByTagName(tags[j][0]); - for (i = 0; i < el.length; i++) { - var coords = this._parse_trkseg(el[i], xml, options, tags[j][1]); - if (coords.length === 0) continue; - - // add track - var l = new L.Polyline(coords, options.polyline_options); - this.fire('addline', { line: l }) - layers.push(l); - - if (options.marker_options.startIcon || options.marker_options.startIconUrl) { - // add start pin - var p = new L.Marker(coords[0], { - clickable: options.marker_options.clickable, - icon: options.marker_options.startIcon || new L.GPXTrackIcon({iconUrl: options.marker_options.startIconUrl}) - }); - this.fire('addpoint', { point: p, point_type: 'start' }); - layers.push(p); - } + var parseElements = options.gpx_options.parseElements; + if (parseElements.indexOf("route") > -1) { + // routes are tags inside sections + var routes = xml.getElementsByTagName("rte"); + for (i = 0; i < routes.length; i++) { + layers = layers.concat( + this._parse_segment(routes[i], options, {}, "rtept") + ); + } + } - if (options.marker_options.endIcon || options.marker_options.endIconUrl) { - // add end pin - p = new L.Marker(coords[coords.length-1], { - clickable: options.marker_options.clickable, - icon: options.marker_options.endIcon || new L.GPXTrackIcon({iconUrl: options.marker_options.endIconUrl}) - }); - this.fire('addpoint', { point: p, point_type: 'end' }); - layers.push(p); + if (parseElements.indexOf("track") > -1) { + // tracks are tags in one or more sections in each + var tracks = xml.getElementsByTagName("trk"); + for (i = 0; i < tracks.length; i++) { + var track = tracks[i]; + var polyline_options = this._extract_styling(track); + + if (options.gpx_options.joinTrackSegments) { + layers = layers.concat( + this._parse_segment(track, options, polyline_options, "trkpt") + ); + } else { + var segments = track.getElementsByTagName("trkseg"); + for (j = 0; j < segments.length; j++) { + layers = layers.concat( + this._parse_segment( + segments[j], + options, + polyline_options, + "trkpt" + ) + ); + } } } } - this._info.hr.avg = Math.round(this._info.hr._total / this._info.hr._points.length); - this._info.cad.avg = Math.round(this._info.cad._total / this._info.cad._points.length); - this._info.atemp.avg = Math.round(this._info.atemp._total / this._info.atemp._points.length); + this._info.hr.avg = Math.round( + this._info.hr._total / this._info.hr._points.length + ); + this._info.cad.avg = Math.round( + this._info.cad._total / this._info.cad._points.length + ); + this._info.atemp.avg = Math.round( + this._info.atemp._total / this._info.atemp._points.length + ); // parse waypoints and add markers for each of them - if (parseElements.indexOf('waypoint') > -1) { - el = xml.getElementsByTagName('wpt'); + if (parseElements.indexOf("waypoint") > -1) { + el = xml.getElementsByTagName("wpt"); for (i = 0; i < el.length; i++) { var ll = new L.LatLng( - el[i].getAttribute('lat'), - el[i].getAttribute('lon')); + el[i].getAttribute("lat"), + el[i].getAttribute("lon") + ); - var nameEl = el[i].getElementsByTagName('name'); - var name = ''; + var nameEl = el[i].getElementsByTagName("name"); + var name = ""; if (nameEl.length > 0) { name = nameEl[0].textContent; } - var descEl = el[i].getElementsByTagName('desc'); - var desc = ''; + var descEl = el[i].getElementsByTagName("desc"); + var desc = ""; if (descEl.length > 0) { desc = descEl[0].textContent; } - var symEl = el[i].getElementsByTagName('sym'); - var symKey = ''; + var symEl = el[i].getElementsByTagName("sym"); + var symKey = ""; if (symEl.length > 0) { symKey = symEl[0].textContent; } + var typeEl = el[i].getElementsByTagName("type"); + var typeKey = ""; + if (typeEl.length > 0) { + typeKey = typeEl[0].textContent; + } + /* * Add waypoint marker based on the waypoint symbol key. * @@ -406,82 +493,120 @@ L.GPX = L.FeatureGroup.extend({ */ var wptIcons = options.marker_options.wptIcons; var wptIconUrls = options.marker_options.wptIconUrls; + var wptIconsType = options.marker_options.wptIconsType; + var wptIconTypeUrls = options.marker_options.wptIconTypeUrls; var symIcon; if (wptIcons && wptIcons[symKey]) { symIcon = wptIcons[symKey]; + } else if (wptIconsType && wptIconsType[typeKey]) { + symIcon = wptIconsType[typeKey]; } else if (wptIconUrls && wptIconUrls[symKey]) { - symIcon = new L.GPXTrackIcon({iconUrl: wptIconUrls[symKey]}); - } else if (wptIcons && wptIcons['']) { - symIcon = wptIcons['']; - } else if (wptIconUrls && wptIconUrls['']) { - symIcon = new L.GPXTrackIcon({iconUrl: wptIconUrls['']}); + symIcon = new L.GPXTrackIcon({ iconUrl: wptIconUrls[symKey] }); + } else if (wptIconTypeUrls && wptIconTypeUrls[typeKey]) { + symIcon = new L.GPXTrackIcon({ iconUrl: wptIconTypeUrls[typeKey] }); + } else if (wptIcons && wptIcons[""]) { + symIcon = wptIcons[""]; + } else if (wptIconUrls && wptIconUrls[""]) { + symIcon = new L.GPXTrackIcon({ iconUrl: wptIconUrls[""] }); } else { - console.log('No icon or icon URL configured for symbol type "' + symKey - + '", and no fallback configured; ignoring waypoint.'); + console.log( + 'No icon or icon URL configured for symbol type "' + + symKey + + '", and no fallback configured; ignoring waypoint.' + ); continue; } var marker = new L.Marker(ll, { - clickable: true, + clickable: options.marker_options.clickable, title: name, - icon: symIcon + icon: symIcon, + type: "waypoint", + }); + marker + .bindPopup( + "" + name + "" + (desc.length > 0 ? "
" + desc : "") + ) + .openPopup(); + this.fire("addpoint", { + point: marker, + point_type: "waypoint", + element: el[i], }); - marker.bindPopup("" + name + "" + (desc.length > 0 ? '
' + desc : '')).openPopup(); - this.fire('addpoint', { point: marker, point_type: 'waypoint' }); layers.push(marker); } } if (layers.length > 1) { - return new L.FeatureGroup(layers); + return new L.FeatureGroup(layers); } else if (layers.length == 1) { return layers[0]; } }, - _parse_trkseg: function(line, xml, options, tag) { + _parse_segment: function (line, options, polyline_options, tag) { var el = line.getElementsByTagName(tag); var kilometer_point_layers = []; var mile_point_layers = []; var _this = this; if (!el.length) return []; + var coords = []; + var markers = []; + var layers = []; var last = null; for (var i = 0; i < el.length; i++) { - var _, ll = new L.LatLng( - el[i].getAttribute('lat'), - el[i].getAttribute('lon')); + var _, + ll = new L.LatLng(el[i].getAttribute("lat"), el[i].getAttribute("lon")); ll.meta = { time: null, ele: null, hr: null, cad: null, atemp: null }; - _ = el[i].getElementsByTagName('time'); + _ = el[i].getElementsByTagName("time"); if (_.length > 0) { ll.meta.time = new Date(Date.parse(_[0].textContent)); } else { - ll.meta.time = new Date('1970-01-01T00:00:00'); + ll.meta.time = new Date("1970-01-01T00:00:00"); } - _ = el[i].getElementsByTagName('ele'); + _ = el[i].getElementsByTagName("ele"); if (_.length > 0) { ll.meta.ele = parseFloat(_[0].textContent); } - _ = el[i].getElementsByTagNameNS('*', 'hr'); + _ = el[i].getElementsByTagName("name"); + if (_.length > 0) { + var name = _[0].textContent; + var ptMatchers = options.marker_options.pointMatchers || []; + + for (var j = 0; j < ptMatchers.length; j++) { + if (ptMatchers[j].regex.test(name)) { + markers.push({ + label: name, + coords: ll, + icon: ptMatchers[j].icon, + element: el[i], + }); + break; + } + } + } + + _ = el[i].getElementsByTagNameNS("*", "hr"); if (_.length > 0) { ll.meta.hr = parseInt(_[0].textContent); this._info.hr._points.push([this._info.length, ll.meta.hr]); this._info.hr._total += ll.meta.hr; } - _ = el[i].getElementsByTagNameNS('*', 'cad'); + _ = el[i].getElementsByTagNameNS("*", "cad"); if (_.length > 0) { ll.meta.cad = parseInt(_[0].textContent); this._info.cad._points.push([this._info.length, ll.meta.cad]); this._info.cad._total += ll.meta.cad; } - _ = el[i].getElementsByTagNameNS('*', 'atemp'); + _ = el[i].getElementsByTagNameNS("*", "atemp"); if (_.length > 0) { ll.meta.atemp = parseInt(_[0].textContent); this._info.atemp._points.push([this._info.length, ll.meta.atemp]); @@ -505,68 +630,98 @@ L.GPX = L.FeatureGroup.extend({ /* * Add points to the line. */ - if (options.gpx_options.show_kilometer_point || options.gpx_options.show_mile_point) { + if ( + options.gpx_options.show_kilometer_point || + options.gpx_options.show_mile_point + ) { if (this._parse_current_kilometer != null) { // Kilometer Point if (options.gpx_options.show_kilometer_point) { - if ((parseInt(this._info.length/1000) - this._parse_current_kilometer) > options.gpx_options.kilometer_point_options.kilometer_point_intervall-1) { - this._parse_current_kilometer = parseInt(this._info.length/1000); - var marker = new L.circleMarker(ll, { - radius: options.gpx_options.kilometer_point_options.kilometer_point_radius, - stroke: false, - fillColor: options.gpx_options.kilometer_point_options.kilometer_point_color, - fillOpacity: 1, - }).bindTooltip(this._parse_current_kilometer.toString(), { - direction: 'center', - permanent: true, - interactive: true, - className: 'kilometer_tooltip' - }); - kilometer_point_layers.push(marker); + if ( + parseInt(this._info.length / 1000) - + this._parse_current_kilometer > + options.gpx_options.kilometer_point_options + .kilometer_point_intervall - + 1 + ) { + this._parse_current_kilometer = parseInt( + this._info.length / 1000 + ); + var marker = new L.circleMarker(ll, { + radius: + options.gpx_options.kilometer_point_options + .kilometer_point_radius, + stroke: false, + fillColor: + options.gpx_options.kilometer_point_options + .kilometer_point_color, + fillOpacity: 1, + }).bindTooltip(this._parse_current_kilometer.toString(), { + direction: "center", + permanent: true, + interactive: true, + className: "kilometer_tooltip", + }); + kilometer_point_layers.push(marker); } } // Mile Point if (options.gpx_options.show_mile_point) { - if ((parseInt(this.to_miles(this._info.length)/1000) - this._parse_current_mile) > options.gpx_options.mile_point_options.mile_intervall) { - this._parse_current_mile = parseInt(this.to_miles(this._info.length)/1000); + if ( + parseInt(this.to_miles(this._info.length) / 1000) - + this._parse_current_mile > + options.gpx_options.mile_point_options.mile_intervall + ) { + this._parse_current_mile = parseInt( + this.to_miles(this._info.length) / 1000 + ); var marker = new L.circleMarker(ll, { - radius: options.gpx_options.mile_point_options.mile_point_radius, - stroke: false, - fillColor: options.gpx_options.mile_point_options.mile_point_color, + radius: + options.gpx_options.mile_point_options.mile_point_radius, + stroke: false, + fillColor: + options.gpx_options.mile_point_options.mile_point_color, fillOpacity: 1, }).bindTooltip(this._parse_current_mile.toString(), { - direction: 'center', + direction: "center", permanent: true, interactive: true, - className: 'mile_tooltip' + className: "mile_tooltip", }); mile_point_layers.push(marker); } } } else { - this._parse_current_kilometer = parseInt(this._info.length/1000); - this._parse_current_mile = parseInt(this._info.length/1000); + this._parse_current_kilometer = parseInt(this._info.length / 1000); + this._parse_current_mile = parseInt(this._info.length / 1000); // Append style element for the tooltip of the points - var element = document.createElement('style'); + var element = document.createElement("style"); document.head.appendChild(element); var sheet = element.sheet; - var styles = ''; - styles += '.kilometer_tooltip, .mile_tooltip {'; - styles += 'background: none!important;'; - styles += 'border: none!important;'; - styles += 'font-weight: 900!important;'; - styles += 'font-size: larger!important;'; - styles += 'box-shadow: none!important;'; - styles += '}'; + var styles = ""; + styles += ".kilometer_tooltip, .mile_tooltip {"; + styles += "background: none!important;"; + styles += "border: none!important;"; + styles += "font-weight: 900!important;"; + styles += "font-size: larger!important;"; + styles += "box-shadow: none!important;"; + styles += "}"; sheet.insertRule(styles, 0); - var styles_kilometer = '.kilometer_tooltip {'; - styles_kilometer += 'color: ' + options.gpx_options.kilometer_point_options.kilometer_point_color_text + ';'; - styles_kilometer += '}'; + var styles_kilometer = ".kilometer_tooltip {"; + styles_kilometer += + "color: " + + options.gpx_options.kilometer_point_options + .kilometer_point_color_text + + ";"; + styles_kilometer += "}"; sheet.insertRule(styles_kilometer, 0); - var styles_mile = '.mile_tooltip {'; - styles_mile += 'color: ' + options.gpx_options.mile_point_options.mile_point_color_text + ';'; - styles_mile += '}'; + var styles_mile = ".mile_tooltip {"; + styles_mile += + "color: " + + options.gpx_options.mile_point_options.mile_point_color_text + + ";"; + styles_mile += "}"; sheet.insertRule(styles_mile, 0); } } @@ -592,44 +747,118 @@ L.GPX = L.FeatureGroup.extend({ } if (kilometer_point_layers.length > 1) { - _this.addLayer(new L.FeatureGroup(kilometer_point_layers)); + _this.addLayer(new L.FeatureGroup(kilometer_point_layers)); } if (mile_point_layers.length > 1) { - _this.addLayer(new L.FeatureGroup(mile_point_layers)); + _this.addLayer(new L.FeatureGroup(mile_point_layers)); } - return coords; + // add track + var l = new L.Polyline( + coords, + this._extract_styling(line, polyline_options, options.polyline_options) + ); + this.fire("addline", { line: l, element: line }); + layers.push(l); + + if ( + options.marker_options.startIcon || + options.marker_options.startIconUrl + ) { + // add start pin + var marker = new L.Marker(coords[0], { + clickable: options.marker_options.clickable, + icon: + options.marker_options.startIcon || + new L.GPXTrackIcon({ iconUrl: options.marker_options.startIconUrl }), + }); + this.fire("addpoint", { + point: marker, + point_type: "start", + element: el[0], + }); + layers.push(marker); + } + + if (options.marker_options.endIcon || options.marker_options.endIconUrl) { + // add end pin + var marker = new L.Marker(coords[coords.length - 1], { + clickable: options.marker_options.clickable, + icon: + options.marker_options.endIcon || + new L.GPXTrackIcon({ iconUrl: options.marker_options.endIconUrl }), + }); + this.fire("addpoint", { + point: marker, + point_type: "end", + element: el[el.length - 1], + }); + layers.push(marker); + } + + // add named markers + for (var i = 0; i < markers.length; i++) { + var marker = new L.Marker(markers[i].coords, { + clickable: options.marker_options.clickable, + title: markers[i].label, + icon: markers[i].icon, + }); + this.fire("addpoint", { + point: marker, + point_type: "label", + element: markers[i].element, + }); + layers.push(marker); + } + + return layers; }, - _dist2d: function(a, b) { + _extract_styling: function (el, base, overrides) { + var style = this._merge_objs(_DEFAULT_POLYLINE_OPTS, base); + var e = el.getElementsByTagNameNS(_GPX_STYLE_NS, "line"); + if (e.length > 0) { + var _ = e[0].getElementsByTagName("color"); + if (_.length > 0) style.color = "#" + _[0].textContent; + var _ = e[0].getElementsByTagName("opacity"); + if (_.length > 0) style.opacity = _[0].textContent; + var _ = e[0].getElementsByTagName("weight"); + if (_.length > 0) style.weight = _[0].textContent; + var _ = e[0].getElementsByTagName("linecap"); + if (_.length > 0) style.lineCap = _[0].textContent; + } + return this._merge_objs(style, overrides); + }, + + _dist2d: function (a, b) { var R = 6371000; var dLat = this._deg2rad(b.lat - a.lat); var dLon = this._deg2rad(b.lng - a.lng); - var r = Math.sin(dLat/2) * - Math.sin(dLat/2) + + var r = + Math.sin(dLat / 2) * Math.sin(dLat / 2) + Math.cos(this._deg2rad(a.lat)) * - Math.cos(this._deg2rad(b.lat)) * - Math.sin(dLon/2) * - Math.sin(dLon/2); - var c = 2 * Math.atan2(Math.sqrt(r), Math.sqrt(1-r)); + Math.cos(this._deg2rad(b.lat)) * + Math.sin(dLon / 2) * + Math.sin(dLon / 2); + var c = 2 * Math.atan2(Math.sqrt(r), Math.sqrt(1 - r)); var d = R * c; return d; }, - _dist3d: function(a, b) { + _dist3d: function (a, b) { var planar = this._dist2d(a, b); var height = Math.abs(b.meta.ele - a.meta.ele); return Math.sqrt(Math.pow(planar, 2) + Math.pow(height, 2)); }, - _deg2rad: function(deg) { - return deg * Math.PI / 180; - } + _deg2rad: function (deg) { + return (deg * Math.PI) / 180; + }, }); -if (typeof module === 'object' && typeof module.exports === 'object') { +if (typeof module === "object" && typeof module.exports === "object") { module.exports = L; -} else if (typeof define === 'function' && define.amd) { +} else if (typeof define === "function" && define.amd) { define(L); } diff --git a/src/media/plg_fields_aggpxtrack/leaflet-gpx/gpx_meineVersion.js b/src/media/plg_fields_aggpxtrack/leaflet-gpx/gpx_meineVersion.js new file mode 100644 index 0000000..49a3728 --- /dev/null +++ b/src/media/plg_fields_aggpxtrack/leaflet-gpx/gpx_meineVersion.js @@ -0,0 +1,635 @@ +/** + * Copyright (C) 2011-2012 Pavel Shramov + * Copyright (C) 2013-2017 Maxime Petazzoni + * All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Thanks to Pavel Shramov who provided the initial implementation and Leaflet + * integration. Original code was at https://github.com/shramov/leaflet-plugins. + * + * It was then cleaned-up and modified to record and make available more + * information about the GPX track while it is being parsed so that the result + * can be used to display additional information about the track that is + * rendered on the Leaflet map. + */ + +var L = L || require('leaflet'); + +var _MAX_POINT_INTERVAL_MS = 15000; +var _SECOND_IN_MILLIS = 1000; +var _MINUTE_IN_MILLIS = 60 * _SECOND_IN_MILLIS; +var _HOUR_IN_MILLIS = 60 * _MINUTE_IN_MILLIS; +var _DAY_IN_MILLIS = 24 * _HOUR_IN_MILLIS; + +var _DEFAULT_MARKER_OPTS = { + startIconUrl: 'pin-icon-start.png', + endIconUrl: 'pin-icon-end.png', + shadowUrl: 'pin-shadow.png', + wptIconUrls : { + '': 'pin-icon-wpt.png', + }, + iconSize: [33, 50], + shadowSize: [50, 50], + iconAnchor: [16, 45], + shadowAnchor: [16, 47], + clickable: false +}; +var _DEFAULT_POLYLINE_OPTS = { + color: 'blue' +}; +var _DEFAULT_GPX_OPTS = { + parseElements: ['track', 'route', 'waypoint'], + show_kilometer_point: false, + kilometer_point_options : { + kilometer_point_color: 'blue', + kilometer_point_color_text: 'white', + kilometer_point_intervall: 1, + kilometer_point_radius: 10, + }, + show_mile_point: true, + mile_point_options : { + mile_point_color: 'blue', + mile_point_color_text: 'white', + mile_intervall: 1, + mile_point_radius: 10, + }, +}; +L.GPX = L.FeatureGroup.extend({ + initialize: function(gpx, options) { + options.max_point_interval = options.max_point_interval || _MAX_POINT_INTERVAL_MS; + options.marker_options = this._merge_objs( + _DEFAULT_MARKER_OPTS, + options.marker_options || {}); + options.polyline_options = this._merge_objs( + _DEFAULT_POLYLINE_OPTS, + options.polyline_options || {}); + options.gpx_options = this._merge_objs( + _DEFAULT_GPX_OPTS, + options.gpx_options || {}); + + L.Util.setOptions(this, options); + + // Base icon class for track pins. + L.GPXTrackIcon = L.Icon.extend({ options: options.marker_options }); + + this._gpx = gpx; + this._layers = {}; + this._init_info(); + + if (gpx) { + this._parse(gpx, options, this.options.async); + } + }, + + get_duration_string: function(duration, hidems) { + var s = ''; + + if (duration >= _DAY_IN_MILLIS) { + s += Math.floor(duration / _DAY_IN_MILLIS) + 'd '; + duration = duration % _DAY_IN_MILLIS; + } + + if (duration >= _HOUR_IN_MILLIS) { + s += Math.floor(duration / _HOUR_IN_MILLIS) + ':'; + duration = duration % _HOUR_IN_MILLIS; + } + + var mins = Math.floor(duration / _MINUTE_IN_MILLIS); + duration = duration % _MINUTE_IN_MILLIS; + if (mins < 10) s += '0'; + s += mins + '\''; + + var secs = Math.floor(duration / _SECOND_IN_MILLIS); + duration = duration % _SECOND_IN_MILLIS; + if (secs < 10) s += '0'; + s += secs; + + if (!hidems && duration > 0) s += '.' + Math.round(Math.floor(duration)*1000)/1000; + else s += '"'; + + return s; + }, + + get_duration_string_iso: function(duration, hidems) { + var s = this.get_duration_string(duration, hidems); + return s.replace("'",':').replace('"',''); + }, + + // Public methods + to_miles: function(v) { return v / 1.60934; }, + to_ft: function(v) { return v * 3.28084; }, + m_to_km: function(v) { return v / 1000; }, + m_to_mi: function(v) { return v / 1609.34; }, + + get_name: function() { return this._info.name; }, + get_desc: function() { return this._info.desc; }, + get_author: function() { return this._info.author; }, + get_copyright: function() { return this._info.copyright; }, + get_distance: function() { return this._info.length; }, + get_distance_imp: function() { return this.to_miles(this.m_to_km(this.get_distance())); }, + + get_start_time: function() { return this._info.duration.start; }, + get_end_time: function() { return this._info.duration.end; }, + get_moving_time: function() { return this._info.duration.moving; }, + get_total_time: function() { return this._info.duration.total; }, + + get_moving_pace: function() { return this.get_moving_time() / this.m_to_km(this.get_distance()); }, + get_moving_pace_imp: function() { return this.get_moving_time() / this.get_distance_imp(); }, + + get_moving_speed: function() { return this.m_to_km(this.get_distance()) / (this.get_moving_time() / (3600 * 1000)) ; }, + get_moving_speed_imp:function() { return this.to_miles(this.m_to_km(this.get_distance())) / (this.get_moving_time() / (3600 * 1000)) ; }, + + get_total_speed: function() { return this.m_to_km(this.get_distance()) / (this.get_total_time() / (3600 * 1000)); }, + get_total_speed_imp: function() { return this.to_miles(this.m_to_km(this.get_distance())) / (this.get_total_time() / (3600 * 1000)); }, + + get_elevation_gain: function() { return this._info.elevation.gain; }, + get_elevation_loss: function() { return this._info.elevation.loss; }, + get_elevation_gain_imp: function() { return this.to_ft(this.get_elevation_gain()); }, + get_elevation_loss_imp: function() { return this.to_ft(this.get_elevation_loss()); }, + get_elevation_data: function() { + var _this = this; + return this._info.elevation._points.map( + function(p) { return _this._prepare_data_point(p, _this.m_to_km, null, + function(a, b) { return a.toFixed(2) + ' km, ' + b.toFixed(0) + ' m'; }); + }); + }, + get_elevation_data_imp: function() { + var _this = this; + return this._info.elevation._points.map( + function(p) { return _this._prepare_data_point(p, _this.m_to_mi, _this.to_ft, + function(a, b) { return a.toFixed(2) + ' mi, ' + b.toFixed(0) + ' ft'; }); + }); + }, + get_elevation_max: function() { return this._info.elevation.max; }, + get_elevation_min: function() { return this._info.elevation.min; }, + get_elevation_max_imp: function() { return this.to_ft(this.get_elevation_max()); }, + get_elevation_min_imp: function() { return this.to_ft(this.get_elevation_min()); }, + + get_average_hr: function() { return this._info.hr.avg; }, + get_average_temp: function() { return this._info.atemp.avg; }, + get_average_cadence: function() { return this._info.cad.avg; }, + get_heartrate_data: function() { + var _this = this; + return this._info.hr._points.map( + function(p) { return _this._prepare_data_point(p, _this.m_to_km, null, + function(a, b) { return a.toFixed(2) + ' km, ' + b.toFixed(0) + ' bpm'; }); + }); + }, + get_heartrate_data_imp: function() { + var _this = this; + return this._info.hr._points.map( + function(p) { return _this._prepare_data_point(p, _this.m_to_mi, null, + function(a, b) { return a.toFixed(2) + ' mi, ' + b.toFixed(0) + ' bpm'; }); + }); + }, + get_cadence_data: function() { + var _this = this; + return this._info.cad._points.map( + function(p) { return _this._prepare_data_point(p, _this.m_to_km, null, + function(a, b) { return a.toFixed(2) + ' km, ' + b.toFixed(0) + ' rpm'; }); + }); + }, + get_temp_data: function() { + var _this = this; + return this._info.atemp._points.map( + function(p) { return _this._prepare_data_point(p, _this.m_to_km, null, + function(a, b) { return a.toFixed(2) + ' km, ' + b.toFixed(0) + ' degrees'; }); + }); + }, + get_cadence_data_imp: function() { + var _this = this; + return this._info.cad._points.map( + function(p) { return _this._prepare_data_point(p, _this.m_to_mi, null, + function(a, b) { return a.toFixed(2) + ' mi, ' + b.toFixed(0) + ' rpm'; }); + }); + }, + get_temp_data_imp: function() { + var _this = this; + return this._info.atemp._points.map( + function(p) { return _this._prepare_data_point(p, _this.m_to_mi, null, + function(a, b) { return a.toFixed(2) + ' mi, ' + b.toFixed(0) + ' degrees'; }); + }); + }, + + reload: function() { + this._init_info(); + this.clearLayers(); + this._parse(this._gpx, this.options, this.options.async); + }, + + // Private methods + _merge_objs: function(a, b) { + var _ = {}; + for (var attr in a) { _[attr] = a[attr]; } + for (var attr in b) { _[attr] = b[attr]; } + return _; + }, + + _prepare_data_point: function(p, trans1, trans2, trans_tooltip) { + var r = [trans1 && trans1(p[0]) || p[0], trans2 && trans2(p[1]) || p[1]]; + r.push(trans_tooltip && trans_tooltip(r[0], r[1]) || (r[0] + ': ' + r[1])); + return r; + }, + + _init_info: function() { + this._info = { + name: null, + length: 0.0, + elevation: {gain: 0.0, loss: 0.0, max: 0.0, min: Infinity, _points: []}, + hr: {avg: 0, _total: 0, _points: []}, + duration: {start: null, end: null, moving: 0, total: 0}, + atemp: {avg: 0, _total: 0, _points: []}, + cad: {avg: 0, _total: 0, _points: []} + }; + }, + + _load_xml: function(url, cb, options, async) { + if (async == undefined) async = this.options.async; + if (options == undefined) options = this.options; + + var req = new window.XMLHttpRequest(); + req.open('GET', url, async); + try { + req.overrideMimeType('text/xml'); // unsupported by IE + } catch(e) {} + req.onreadystatechange = function() { + if (req.readyState != 4) return; + if(req.status == 200) cb(req.responseXML, options); + }; + req.send(null); + }, + + _parse: function(input, options, async) { + var _this = this; + var cb = function(gpx, options) { + var layers = _this._parse_gpx_data(gpx, options); + if (!layers) return; + _this.addLayer(layers); + _this.fire('loaded'); + } + if (input.substr(0,1)==='<') { // direct XML has to start with a < + var parser = new DOMParser(); + if (async) { + setTimeout(function() { + cb(parser.parseFromString(input, "text/xml"), options); + }); + } else { + cb(parser.parseFromString(input, "text/xml"), options); + } + } else { + this._load_xml(input, cb, options, async); + } + }, + + _parse_gpx_data: function(xml, options) { + var j, i, el, layers = []; + var tags = []; + + var parseElements = options.gpx_options.parseElements; + if (parseElements.indexOf('route') > -1) { + tags.push(['rte','rtept']); + } + if (parseElements.indexOf('track') > -1) { + tags.push(['trkseg','trkpt']); + } + + var name = xml.getElementsByTagName('name'); + if (name.length > 0) { + this._info.name = name[0].textContent; + } + var desc = xml.getElementsByTagName('desc'); + if (desc.length > 0) { + this._info.desc = desc[0].textContent; + } + var author = xml.getElementsByTagName('author'); + if (author.length > 0) { + this._info.author = author[0].textContent; + } + var copyright = xml.getElementsByTagName('copyright'); + if (copyright.length > 0) { + this._info.copyright = copyright[0].textContent; + } + + for (j = 0; j < tags.length; j++) { + el = xml.getElementsByTagName(tags[j][0]); + for (i = 0; i < el.length; i++) { + var coords = this._parse_trkseg(el[i], xml, options, tags[j][1]); + if (coords.length === 0) continue; + + // add track + var l = new L.Polyline(coords, options.polyline_options); + this.fire('addline', { line: l }) + layers.push(l); + + if (options.marker_options.startIcon || options.marker_options.startIconUrl) { + // add start pin + var p = new L.Marker(coords[0], { + clickable: options.marker_options.clickable, + icon: options.marker_options.startIcon || new L.GPXTrackIcon({iconUrl: options.marker_options.startIconUrl}) + }); + this.fire('addpoint', { point: p, point_type: 'start' }); + layers.push(p); + } + + if (options.marker_options.endIcon || options.marker_options.endIconUrl) { + // add end pin + p = new L.Marker(coords[coords.length-1], { + clickable: options.marker_options.clickable, + icon: options.marker_options.endIcon || new L.GPXTrackIcon({iconUrl: options.marker_options.endIconUrl}) + }); + this.fire('addpoint', { point: p, point_type: 'end' }); + layers.push(p); + } + } + } + + this._info.hr.avg = Math.round(this._info.hr._total / this._info.hr._points.length); + this._info.cad.avg = Math.round(this._info.cad._total / this._info.cad._points.length); + this._info.atemp.avg = Math.round(this._info.atemp._total / this._info.atemp._points.length); + + // parse waypoints and add markers for each of them + if (parseElements.indexOf('waypoint') > -1) { + el = xml.getElementsByTagName('wpt'); + for (i = 0; i < el.length; i++) { + var ll = new L.LatLng( + el[i].getAttribute('lat'), + el[i].getAttribute('lon')); + + var nameEl = el[i].getElementsByTagName('name'); + var name = ''; + if (nameEl.length > 0) { + name = nameEl[0].textContent; + } + + var descEl = el[i].getElementsByTagName('desc'); + var desc = ''; + if (descEl.length > 0) { + desc = descEl[0].textContent; + } + + var symEl = el[i].getElementsByTagName('sym'); + var symKey = ''; + if (symEl.length > 0) { + symKey = symEl[0].textContent; + } + + /* + * Add waypoint marker based on the waypoint symbol key. + * + * First look for a configured icon for that symKey. If not found, look + * for a configured icon URL for that symKey and build an icon from it. + * Otherwise, fall back to the default icon if one was configured, or + * finally to the default icon URL. + */ + var wptIcons = options.marker_options.wptIcons; + var wptIconUrls = options.marker_options.wptIconUrls; + var symIcon; + if (wptIcons && wptIcons[symKey]) { + symIcon = wptIcons[symKey]; + } else if (wptIconUrls && wptIconUrls[symKey]) { + symIcon = new L.GPXTrackIcon({iconUrl: wptIconUrls[symKey]}); + } else if (wptIcons && wptIcons['']) { + symIcon = wptIcons['']; + } else if (wptIconUrls && wptIconUrls['']) { + symIcon = new L.GPXTrackIcon({iconUrl: wptIconUrls['']}); + } else { + console.log('No icon or icon URL configured for symbol type "' + symKey + + '", and no fallback configured; ignoring waypoint.'); + continue; + } + + var marker = new L.Marker(ll, { + clickable: true, + title: name, + icon: symIcon + }); + marker.bindPopup("" + name + "" + (desc.length > 0 ? '
' + desc : '')).openPopup(); + this.fire('addpoint', { point: marker, point_type: 'waypoint' }); + layers.push(marker); + } + } + + if (layers.length > 1) { + return new L.FeatureGroup(layers); + } else if (layers.length == 1) { + return layers[0]; + } + }, + + _parse_trkseg: function(line, xml, options, tag) { + var el = line.getElementsByTagName(tag); + var kilometer_point_layers = []; + var mile_point_layers = []; + var _this = this; + + if (!el.length) return []; + var coords = []; + var last = null; + + for (var i = 0; i < el.length; i++) { + var _, ll = new L.LatLng( + el[i].getAttribute('lat'), + el[i].getAttribute('lon')); + ll.meta = { time: null, ele: null, hr: null, cad: null, atemp: null }; + + _ = el[i].getElementsByTagName('time'); + if (_.length > 0) { + ll.meta.time = new Date(Date.parse(_[0].textContent)); + } else { + ll.meta.time = new Date('1970-01-01T00:00:00'); + } + + _ = el[i].getElementsByTagName('ele'); + if (_.length > 0) { + ll.meta.ele = parseFloat(_[0].textContent); + } + + _ = el[i].getElementsByTagNameNS('*', 'hr'); + if (_.length > 0) { + ll.meta.hr = parseInt(_[0].textContent); + this._info.hr._points.push([this._info.length, ll.meta.hr]); + this._info.hr._total += ll.meta.hr; + } + + _ = el[i].getElementsByTagNameNS('*', 'cad'); + if (_.length > 0) { + ll.meta.cad = parseInt(_[0].textContent); + this._info.cad._points.push([this._info.length, ll.meta.cad]); + this._info.cad._total += ll.meta.cad; + } + + _ = el[i].getElementsByTagNameNS('*', 'atemp'); + if (_.length > 0) { + ll.meta.atemp = parseInt(_[0].textContent); + this._info.atemp._points.push([this._info.length, ll.meta.atemp]); + this._info.atemp._total += ll.meta.atemp; + } + + if (ll.meta.ele > this._info.elevation.max) { + this._info.elevation.max = ll.meta.ele; + } + + if (ll.meta.ele < this._info.elevation.min) { + this._info.elevation.min = ll.meta.ele; + } + + this._info.elevation._points.push([this._info.length, ll.meta.ele]); + this._info.duration.end = ll.meta.time; + + if (last != null) { + this._info.length += this._dist3d(last, ll); + + /* + * Add points to the line. + */ + if (options.gpx_options.show_kilometer_point || options.gpx_options.show_mile_point) { + if (this._parse_current_kilometer != null) { + // Kilometer Point + if (options.gpx_options.show_kilometer_point) { + if ((parseInt(this._info.length/1000) - this._parse_current_kilometer) > options.gpx_options.kilometer_point_options.kilometer_point_intervall-1) { + this._parse_current_kilometer = parseInt(this._info.length/1000); + var marker = new L.circleMarker(ll, { + radius: options.gpx_options.kilometer_point_options.kilometer_point_radius, + stroke: false, + fillColor: options.gpx_options.kilometer_point_options.kilometer_point_color, + fillOpacity: 1, + }).bindTooltip(this._parse_current_kilometer.toString(), { + direction: 'center', + permanent: true, + interactive: true, + className: 'kilometer_tooltip' + }); + kilometer_point_layers.push(marker); + } + } + // Mile Point + if (options.gpx_options.show_mile_point) { + if ((parseInt(this.to_miles(this._info.length)/1000) - this._parse_current_mile) > options.gpx_options.mile_point_options.mile_intervall) { + this._parse_current_mile = parseInt(this.to_miles(this._info.length)/1000); + var marker = new L.circleMarker(ll, { + radius: options.gpx_options.mile_point_options.mile_point_radius, + stroke: false, + fillColor: options.gpx_options.mile_point_options.mile_point_color, + fillOpacity: 1, + }).bindTooltip(this._parse_current_mile.toString(), { + direction: 'center', + permanent: true, + interactive: true, + className: 'mile_tooltip' + }); + mile_point_layers.push(marker); + } + } + } else { + this._parse_current_kilometer = parseInt(this._info.length/1000); + this._parse_current_mile = parseInt(this._info.length/1000); + + // Append style element for the tooltip of the points + var element = document.createElement('style'); + document.head.appendChild(element); + var sheet = element.sheet; + var styles = ''; + styles += '.kilometer_tooltip, .mile_tooltip {'; + styles += 'background: none!important;'; + styles += 'border: none!important;'; + styles += 'font-weight: 900!important;'; + styles += 'font-size: larger!important;'; + styles += 'box-shadow: none!important;'; + styles += '}'; + sheet.insertRule(styles, 0); + var styles_kilometer = '.kilometer_tooltip {'; + styles_kilometer += 'color: ' + options.gpx_options.kilometer_point_options.kilometer_point_color_text + ';'; + styles_kilometer += '}'; + sheet.insertRule(styles_kilometer, 0); + var styles_mile = '.mile_tooltip {'; + styles_mile += 'color: ' + options.gpx_options.mile_point_options.mile_point_color_text + ';'; + styles_mile += '}'; + sheet.insertRule(styles_mile, 0); + } + } + + var t = ll.meta.ele - last.meta.ele; + if (t > 0) { + this._info.elevation.gain += t; + } else { + this._info.elevation.loss += Math.abs(t); + } + + t = Math.abs(ll.meta.time - last.meta.time); + this._info.duration.total += t; + if (t < options.max_point_interval) { + this._info.duration.moving += t; + } + } else if (this._info.duration.start == null) { + this._info.duration.start = ll.meta.time; + } + + last = ll; + coords.push(ll); + } + + if (kilometer_point_layers.length > 1) { + _this.addLayer(new L.FeatureGroup(kilometer_point_layers)); + } + + if (mile_point_layers.length > 1) { + _this.addLayer(new L.FeatureGroup(mile_point_layers)); + } + + return coords; + }, + + _dist2d: function(a, b) { + var R = 6371000; + var dLat = this._deg2rad(b.lat - a.lat); + var dLon = this._deg2rad(b.lng - a.lng); + var r = Math.sin(dLat/2) * + Math.sin(dLat/2) + + Math.cos(this._deg2rad(a.lat)) * + Math.cos(this._deg2rad(b.lat)) * + Math.sin(dLon/2) * + Math.sin(dLon/2); + var c = 2 * Math.atan2(Math.sqrt(r), Math.sqrt(1-r)); + var d = R * c; + return d; + }, + + _dist3d: function(a, b) { + var planar = this._dist2d(a, b); + var height = Math.abs(b.meta.ele - a.meta.ele); + return Math.sqrt(Math.pow(planar, 2) + Math.pow(height, 2)); + }, + + _deg2rad: function(deg) { + return deg * Math.PI / 180; + } +}); + +if (typeof module === 'object' && typeof module.exports === 'object') { + module.exports = L; +} else if (typeof define === 'function' && define.amd) { + define(L); +}