ptanov

viewer.html

Jun 5th, 2020
821
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
HTML 5 54.00 KB | None | 0 0
  1. <!DOCTYPE html>
  2. <html><head>
  3. <!-- based on https://jsfiddle.net/xrz53a7k/show/ https://jsfiddle.net/xrz53a7k/ https://vts-geospatial.org/tutorials/gpx-viewer.html -->
  4.   <meta http-equiv="content-type" content="text/html; charset=UTF-8">
  5.   <title></title>
  6.   <meta http-equiv="content-type" content="text/html; charset=UTF-8">
  7.   <meta name="robots" content="noindex, nofollow">
  8.   <meta name="googlebot" content="noindex, nofollow">
  9.   <meta name="viewport" content="width=device-width, initial-scale=1">
  10.  
  11.  
  12.   <script type="text/javascript" src="/js/lib/dummy.js"></script>
  13.  
  14.     <link rel="stylesheet" type="text/css" href="/css/result-light.css">
  15.  
  16.       <link rel="stylesheet" type="text/css" href="https://cdn.melown.com/libs/vtsjs/browser/v2/vts-browser.min.css">
  17.       <script type="text/javascript" src="https://cdn.melown.com/libs/vtsjs/browser/v2/vts-browser.min.js"></script>
  18.  
  19.   <style id="compiled-css" type="text/css">
  20.               .pointer-div2 {
  21.             position: absolute;
  22.             left: 0px;
  23.             top: 0px;
  24.             width: 2px;
  25.             height : 120px;
  26.             display: none;
  27.             background-color: rgba(255,0,0,0.5);
  28.             z-index: 1;
  29.         }
  30.  
  31.         .distance-div {
  32.             font-family: Arial, 'Helvetica Neue', Helvetica, sans-serif;
  33.             position: absolute;
  34.             left: 0px;
  35.             top: 0px;
  36.             display: none;
  37.             padding: 5px;
  38.             background: #ffde59;
  39.             border: 2px solid #000000;
  40.             border-radius: 4px;
  41.             pointer-events: none;
  42.             font-size: 12px;
  43.             font-weight: bold;            
  44.             z-index: 2;
  45.         }
  46.  
  47.         .distance-div:after, .distance-div:before {
  48.             top: 100%;
  49.             left: 50%;
  50.             border: solid transparent;
  51.             content: " ";
  52.             height: 0;
  53.             width: 0;
  54.             position: absolute;
  55.             pointer-events: none;
  56.         }
  57.  
  58.         .distance-div:after {
  59.             border-color: rgba(255, 222, 89, 0);
  60.             border-top-color: #ffde59;
  61.             border-width: 7px;
  62.             margin-left: -7px;
  63.         }
  64.         .distance-div:before {
  65.             border-color: rgba(0, 0, 0, 0);
  66.             border-top-color: #000000;
  67.             border-width: 10px;
  68.             margin-left: -10px;
  69.         }
  70.  
  71.         .profile-div {
  72.             font-family: Arial, 'Helvetica Neue', Helvetica, sans-serif;
  73.             position: absolute;
  74.             left: 10px;
  75.             right: 10px;
  76.             bottom: 10px;
  77.             height: 122px;
  78.             background-color: rgba(255,255,255,0.47);
  79.             padding: 10px 20px;
  80.             border-radius: 5px;
  81.         }
  82.  
  83.         .profile-canvas-holder {
  84.             position: absolute;
  85.             left: 2px;
  86.             top: 2px;
  87.             right: 2px;
  88.             bottom: 2px;
  89.             background-color: rgba(255,255,255,0.60);
  90.         }
  91.  
  92.         .profile-canvas {
  93.             position: absolute;
  94.             left: 0px;
  95.             top: 0px;
  96.             width: 100%;
  97.             height: 100%;
  98.         }
  99.     /* EOS */
  100.   </style>
  101.  
  102.   <script id="insert"></script>
  103.  
  104.  
  105.     <script>
  106.       const customConsole = (w) => {
  107.         const pushToConsole = (payload, type) => {
  108.           w.parent.postMessage({
  109.             console: {
  110.               payload: payload,
  111.               type:    type
  112.             }
  113.           }, "*")
  114.         }
  115.  
  116.         w.onerror = (message, url, line, column) => {
  117.           // the line needs to correspond with the editor panel
  118.           // unfortunately this number needs to be altered every time this view is changed
  119.           line = line - 70
  120.           if (line < 0){
  121.            pushToConsole(message, "error")
  122.          } else {
  123.            pushToConsole(`[${line}:${column}] ${message}`, "error")
  124.          }
  125.        }
  126.  
  127.        let console = (function(systemConsole){
  128.          return {
  129.            log: function(){
  130.              let args = Array.from(arguments)
  131.              pushToConsole(args, "log")
  132.              systemConsole.log.apply(this, args)
  133.            },
  134.            info: function(){
  135.              let args = Array.from(arguments)
  136.  
  137.              pushToConsole(args, "info")
  138.              systemConsole.info.apply(this, args)
  139.            },
  140.            warn: function(){
  141.              let args = Array.from(arguments)
  142.              pushToConsole(args, "warn")
  143.              systemConsole.warn.apply(this, args)
  144.            },
  145.            error: function(){
  146.              let args = Array.from(arguments)
  147.              pushToConsole(args, "error")
  148.              systemConsole.error.apply(this, args)
  149.            },
  150.            system: function(){
  151.              let args = Array.from(arguments)
  152.              pushToConsole(args, "system")
  153.            }
  154.          }
  155.        }(window.console))
  156.  
  157.        window.console = console
  158.  
  159.        console.system("Running fiddle")
  160.      }
  161.  
  162.      if (window.parent){
  163.        customConsole(window)
  164.      }
  165.    </script>
  166. </head>
  167. <body>
  168.     <div id="map-div" style="width:100%; height:100%;">
  169. <div class="vts-browser"><div style="display: block;"><div id="vts-map" class="vts-map"> <canvas width="821" height="244" style="display: block;"></canvas></div></div><div style="display: block;"><div id="vts-compass" style="bottom: 170px;"><div id="vts-compass-frame"><img id="vts-compass-compass" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGMAAABjCAYAAACPO76VAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNiAoV2luZG93cykiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6ODRDNjZFNDJCQjNCMTFFM0IyN0ZCQTZFQTAwNzEzNDUiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6ODRDNjZFNDNCQjNCMTFFM0IyN0ZCQTZFQTAwNzEzNDUiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo4NEM2NkU0MEJCM0IxMUUzQjI3RkJBNkVBMDA3MTM0NSIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo4NEM2NkU0MUJCM0IxMUUzQjI3RkJBNkVBMDA3MTM0NSIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/Pgg3VBcAAAzUSURBVHja7F1bbBTX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" style="transform: rotateX(21deg) rotateZ(-45deg);"></div><div id="vts-compass-frame2"><img id="vts-compass-compass2" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGMAAABjCAYAAACPO76VAAAACXBIWXMAAC4jAAAuIwF4pT92AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAABG9JREFUeNrtnM9LFGEcxkeEPCQVmbkh7EXoEgW6noIQzQwKoQ5Lkgh7SA8iddlCQfAQFApdghAxooJCsEMe9JAEek8i81YQCIEYQvgHZM9L37Fpmpl9Z3d+rs8DDw7unuaz3+ddX+d9DIOiKIqiKIqiKIqiKIqiKIqiKIqiKMpTQ0NDyqNwTq7/MRUNAKsfwL2EER+MLHxBru/BA4QR3zR0wY/lWmmEMKKHcVh+tsEv5PoGPE4Y0cP4LD9b4AW57oC/whvwB3gZfgN3886FG1EmjAZ41WEa6uAm+DTcyLsXPAz11fWkDUYtvAVPwHfgAnwdbmVMhQtjDj4jN3gNPiTXF+E8fAsuwvfhQScIuVwuMusK762H69IGYwY+LwDew+3wcZkOQ2fhThoMvK8TnkrjZEzCV+RGF2XhXoE/wuvwJ7jGK5aSAkOm4Qm8DTemEcYYfNNtCnTWiCTAkGn4Bu/B+bSuGcPwF3gJfg1Pww/l661uLMQGwzINe+L5tH+1PSpbIOdkG0TtRWWSDsM2Dco/UhlPQSpqGA7TsJfqeEorDLjHNg3pj6cUwjgCzzpAYDxFDENNw6YLCOU+Uggfhtc0mH5LAuHDKDUNyjtwhgTCg6EzDab7effDg6EzDYynkGH4mQbGU4gw/EwD4ykkGMfgZz4hMJ5CgHEV/l4GCMZTgDDUNDwvAwLjKeD1odxp2I8nP/92JQx3P6oAwn48EUYw64N5U3+VG09+H0ggDOc1woymn/Bl2WH1A2KhnKdDCON/WxfrgvzurA8gCmAzYVQOwxpPi7bXdIEUyn1uijDc46nZ4T2lgCxW8hAbYfz1U69PtwYQN4AE4BNGT6lPtwaQQqWPdxLGn93XzVKfbgff1QVI6cOY1Ywnt+2RkgApPRh+48m+PaJA9Ab1FPpBhuEnnpw2Cxd1I40qDUM3npymoRDG+YyDCsMaT0thTANh6MGwxtMunA1jGghDD4Y1ngY1pkH9T+JUFMfIDhoMazy9g2s8pmHHug1OGMHCcIunBvilwzRkoj5geZBgOMXTNXgrjGkgDHcYl2zxdAJ+FeY0EIYziHrLQRUVT7ejmAbCcIZhPbq1G9U06MIo97RuGkF0ejy50Z9LwDlwuekZOSB6QQ6MZuUAaVXGU+TT4BNGixydnpaj1EtytHq4GuPJPEPXF/HBSkcYOmUCUjowVo3xNK8OM8YBwgNGjdRqrEvNxorUbhTldVXHMVlN8aSmIR8XBDsMjymolSKadimmMaSoZqZa4mnePNqbMBiDUr1UlCqmvFQzGVLVtCbXqsJpLu3xtG1vHYgThMMUtEopWUFKyiaktKzWVmamys1G0xxPU04H3RMAo1Fq+Zqkps8OaFVq/aww0vt3hleDWQJgdEth5bIUWG5IoWWHvL5gNgJZYVABy2PRHpfKV0MqYNts1bC8eRHCGJEyZEPKkbvYwRsfjAGpCTdkGyRLAPHB6JUCfU5DAmDkpJ+XN4miKIqiKIqiKIqiKIqiKIqiKIpKpn4DKrVAiBFUfdUAAAAASUVORK5CYII=" style="transform: rotateX(21deg) rotateZ(-45deg);"></div><div id="vts-compass-frame3"><img id="vts-compass-compass3" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGMAAABjCAYAAACPO76VAAAACXBIWXMAAC4jAAAuIwF4pT92AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAABG9JREFUeNrtnM9LFGEcxkeEPCQVmbkh7EXoEgW6noIQzQwKoQ5Lkgh7SA8iddlCQfAQFApdghAxooJCsEMe9JAEek8i81YQCIEYQvgHZM9L37Fpmpl9Z3d+rs8DDw7unuaz3+ddX+d9DIOiKIqiKIqiKIqiKIqiKIqiKIqiKMpTQ0NDyqNwTq7/MRUNAKsfwL2EER+MLHxBru/BA4QR3zR0wY/lWmmEMKKHcVh+tsEv5PoGPE4Y0cP4LD9b4AW57oC/whvwB3gZfgN3886FG1EmjAZ41WEa6uAm+DTcyLsXPAz11fWkDUYtvAVPwHfgAnwdbmVMhQtjDj4jN3gNPiTXF+E8fAsuwvfhQScIuVwuMusK762H69IGYwY+LwDew+3wcZkOQ2fhThoMvK8TnkrjZEzCV+RGF2XhXoE/wuvwJ7jGK5aSAkOm4Qm8DTemEcYYfNNtCnTWiCTAkGn4Bu/B+bSuGcPwF3gJfg1Pww/l661uLMQGwzINe+L5tH+1PSpbIOdkG0TtRWWSDsM2Dco/UhlPQSpqGA7TsJfqeEorDLjHNg3pj6cUwjgCzzpAYDxFDENNw6YLCOU+Uggfhtc0mH5LAuHDKDUNyjtwhgTCg6EzDab7effDg6EzDYynkGH4mQbGU4gw/EwD4ykkGMfgZz4hMJ5CgHEV/l4GCMZTgDDUNDwvAwLjKeD1odxp2I8nP/92JQx3P6oAwn48EUYw64N5U3+VG09+H0ggDOc1woymn/Bl2WH1A2KhnKdDCON/WxfrgvzurA8gCmAzYVQOwxpPi7bXdIEUyn1uijDc46nZ4T2lgCxW8hAbYfz1U69PtwYQN4AE4BNGT6lPtwaQQqWPdxLGn93XzVKfbgff1QVI6cOY1Ywnt+2RkgApPRh+48m+PaJA9Ab1FPpBhuEnnpw2Cxd1I40qDUM3npymoRDG+YyDCsMaT0thTANh6MGwxtMunA1jGghDD4Y1ngY1pkH9T+JUFMfIDhoMazy9g2s8pmHHug1OGMHCcIunBvilwzRkoj5geZBgOMXTNXgrjGkgDHcYl2zxdAJ+FeY0EIYziHrLQRUVT7ejmAbCcIZhPbq1G9U06MIo97RuGkF0ejy50Z9LwDlwuekZOSB6QQ6MZuUAaVXGU+TT4BNGixydnpaj1EtytHq4GuPJPEPXF/HBSkcYOmUCUjowVo3xNK8OM8YBwgNGjdRqrEvNxorUbhTldVXHMVlN8aSmIR8XBDsMjymolSKadimmMaSoZqZa4mnePNqbMBiDUr1UlCqmvFQzGVLVtCbXqsJpLu3xtG1vHYgThMMUtEopWUFKyiaktKzWVmamys1G0xxPU04H3RMAo1Fq+Zqkps8OaFVq/aww0vt3hleDWQJgdEth5bIUWG5IoWWHvL5gNgJZYVABy2PRHpfKV0MqYNts1bC8eRHCGJEyZEPKkbvYwRsfjAGpCTdkGyRLAPHB6JUCfU5DAmDkpJ+XN4miKIqiKIqiKIqiKIqiKIqiKIpKpn4DKrVAiBFUfdUAAAAASUVORK5CYII=" style="transform: rotateX(21deg) rotateZ(-45deg);"></div> </div></div><div style="display: block;"><div id="vts-credits" class="vts-credits" style="bottom: 134px;"><div class="vts-credits-supercell"><div class="vts-credits-cell">Imagery: ©2005-16 Jonathan de Ferranti</div><div class="vts-credits-cell-button" id="vts-credits-imagery-more">and others</div><div class="vts-credits-separator"></div></div><div class="vts-credits-supercell"><div class="vts-credits-cell">Map Data: <a href="https://www.openstreetmap.org/about/" target="blank"> © OpenStreetMap contributors</a></div><div class="vts-credits-cell-button" id="vts-credits-mapdata-more">and others</div><div class="vts-credits-separator"></div></div><div class="vts-credits-supercell"><div class="vts-credits-cell">Powered by <a class="vts-logo" href="https://www.melown.com/products/vts/" target="blank">VTS 3D Geospatial Software Stack</a></div><div class="vts-credits-separator"></div></div></div></div><div style="display: none;"><img id="vts-fullscreen" class="vts-fullscreen" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAAAwUlEQVRo3u2YwRWDIBBEIc+SLMKmckpTFkFPePKQQ57DsitR/z/D6KgMDikBAMCTycKYxai9Bul8MYkic+NFS7BOs4FUa/1IrzTn9xk6O6+rrwEMjGayTlS/UXWeujbcDKgpEZRObgYOc1oYt7CIMXCFFLKmTrS+aqAEP8iSAGBYI1s776FLv7eReaWHWd/cyLz3Bas+vxIYGNXIhBTxOhcKNdCaHvPfGPjVYb3OhVjEGLhrI/Pewc9uZDQvAABwZQMKFi+DmFdLbgAAAABJRU5ErkJggg=="></div><div style="display: block;"><div id="vts-zoom" class="vts-zoom"><div id="vts-zoom-plus" class="vts-zoom-plus" style="bottom: 140px;"><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABkAAAAZCAYAAADE6YVjAAAASUlEQVRIx+2Tyw0AIAhDq0d2KsMzFFddQBO9+En6rqR5kFBAiBVINpJtJ1NPLCbJe5IyG7j78IMyEwBgZsNcRJQrl6gnkgjxIx12Cg3wDaLBUAAAAABJRU5ErkJggg=="></div><div id="vts-zoom-minus" class="vts-zoom-minus" style="bottom: 140px;"><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABkAAAAZCAYAAADE6YVjAAAALUlEQVRIx2NgGAWjYBSMAqoCRlwSdnZ2/8kx8NChQxhmMo2G8ygYBaNgFGAHAElYBARpOBYqAAAAAElFTkSuQmCC"></div> </div></div><div style="display: block;"><div id="vts-space" class="vts-space" style="bottom: 140px;"><img id="vts-space-2d" class="vts-space-button" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABkAAAAZCAYAAADE6YVjAAABqElEQVRIx+2UsWoUURSGv3Nn1sIiaKMBSbD0AdRBdmbdB7DMA0gaSSVRbFRYiGAaUWJhEAQVEey10yacO/gAwqZNSKWwhShs4ew9NtewTDI6sRCE/at7h8P/nfnvuRdmmum/lkxvut1u5pwbAOfNrAMMzWy9LMt3v2qKorCaRwC+A9vApqq+bITkeX4Z+CAiab3IzJa9988bIPXaR977G9Pf3NT6joikZvYmSZL5JElOAPcBRORu3UxVRVVlNBodCyEsmtkAMBFZjQ3va79rETluZl+rqrrpvf8c41t3zt0GFpo6Hw6HP4A9YK0oinlgRUSuAVsHIKqaH8hSJIsR7LQ54KqqNtI0XTGzS01xURuCBeBZhD1pAzGz3Vh/+o+QXq93zjnnReSsmb1W1Y0jTm3yW0ie5xdDCB5YNLMX4/H4KmAtzc/EP/py6MHH8bwAvAfmgDXv/eAo7Xc6nSsxro+HQrIsO2Vmb0VkDrilqg9aert+v39yMpksAfciZLPpMj4UkdUmJ1WVNpcReKyq15viWvrLp8mAb8CnEMLTsixfzV7rmf6dfgKmzKAWE7bqxgAAAABJRU5ErkJggg==" style="display: block;"><img id="vts-space-3d" class="vts-space-button" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABkAAAAZCAYAAADE6YVjAAAB8klEQVRIx+1Uv4sTQRT+3mRygyDInYXFabaxsRNOIiG7mEPQxsJCLQVF8AeiaCNWigrWiniCVfA/0Eo4ONnZ4P4FURAL9yyCEMQfRMzs7LOZk2HZxNgIQr7qzbw373t838wAc8zxX4P8RbvdPimEuMLM+4loAcAmM3eTJLkHgAEgiiIu9SgAfAfwBsCa1rpbJqltBWEYXhBCdAE0HEENwBIRrQZBQFmWvQKAIAhuVwyqAOwGcLzRaOzIsuylXyB+VxKdc+FTY8yyMWZbURSn3N7l8nRaa9Ja03A4XCiKosHMtwAwEV0Lw/BQJYnW+oAxZu9oNLqUpulASrmdiPa49GCS3v1+3/R6vc0kSe4AeOIGPu/XSH+Rpul7J906ER0GAGYeADgzi8F5nj+QUl5k5tZEEk+6fV6sfO+mgZk/uDO7KuUqYcUYswTgGYBFAPf/8tbW/kiitR6kafqZma+7CVdmbL7s6j9VyhVF0QtmbuV5fnDLm/F4rJRSICKehaFerx9zcr2uJGHmn0S0U0r5uNlsnlVKWQCPXG5jSm/R6XQWrbUnANx1JGuTjL/JzEeJ6IhS6qNH/kUIcaPc2X/51lo/9TCO441KT5IkeWetXQWwDuAHgG/M/BxAK47jt9MuFYCvAHpFUZzWWl+d/9Zz/Dv8ApJPyD0fWCwOAAAAAElFTkSuQmCC" style="display: none;"> </div></div><div style="display: block;"><div class="vts-search"><div class="vts-search-input"><input type="text" id="vts-search-input" autocomplete="off" spellcheck="false" placeholder="Search location..."></div><div id="vts-search-list" class="vts-search-list" style="display: none;"></div></div></div><div style="display: none;"><div id="vts-link" class="vts-link" style="left: 115px;"><div id="vts-link-button" class="vts-link-button"><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABkAAAAZCAYAAADE6YVjAAABrUlEQVRIx+2VMWtUQRSFz5nZjVrpD9gNVhpLQbZZ5vWaIoUECayNRSpbo9UiJI1pBRs7DVjYGBC1ntm3yHaiwgYsZP+EmMe7x8K3YJEH+xYLwT3NcGe483HvnJkBVvovxWWSsiy7BeAxgGuSpmY2zPP8/V+DhBAekDysQgPgAMDMbo5Gow9n5bgmgF6vd47kAYBC0t0Y45qkPQAguV+X1wgymUx+ShqUZZmllI4AlEVRPJckkht1ea1FNu/3+1ve+31JV0h+dc49mq+12+0dkpQ0XfpMQgh7JJ9U4SmANf3WZUnXvfevAbQBbMYY3zVu1x+Awsx2YoznzewOgKcke3OApId1AADwCwIGJG90u12f5/nx+vr6Jefc0RyQUjpsfE9CCJsk3wIoyrLcljRttVrznv8AcAEAFgHUtovksNrkXp7nx+Px+ETSbQBfKrN8NrOtRQC17pK0QbJMKb2az5nZd+fc/ZRSBKAm1q+r5ASADyHsVuPAe/+R5JtlnqEzIWY2rGDPsiw7JfmysulB0ypq3TWbzb51Op0JyaskLwL4BGA3xvhi9aes9G/pF4AdwlhUZ8RfAAAAAElFTkSuQmCC"></div><div id="vts-link-text-holder" class="vts-link-text-holder" style="display: none;"><div class="vts-link-text"><textarea id="vts-link-text-input" rows="4" cols="50" wrap="hard"></textarea></div></div> </div></div><div style="display: none;"><a target="_blank" href="https://github.com/Melown/vts-browser-js"><img style="position: absolute; top: 0; right: 0; border: 0;" src="https://camo.githubusercontent.com/52760788cde945287fbb584134c4cbc2bc36f904/68747470733a2f2f73332e616d617a6f6e6177732e636f6d2f6769746875622f726962626f6e732f666f726b6d655f72696768745f77686974655f6666666666662e706e67" alt="Fork me on GitHub" data-canonical-src="https://s3.amazonaws.com/github/ribbons/forkme_right_white_ffffff.png"></a></div><div style="display: none;"><div id="vts-measure" class="vts-measure" style="left: 115px;"><img id="vts-measure-button" class="vts-measure-button" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABkAAAAZCAYAAADE6YVjAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA2lpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNS1jMDIxIDc5LjE1NDkxMSwgMjAxMy8xMC8yOS0xMTo0NzoxNiAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDpkNjI1MjFjMi1mYzE5LTcyNDUtOTI5My1kNTU3MmE5N2E1MjgiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6ODJGRUI2NzE2NzkwMTFFN0EzRUZFNzQ1NEFCMkVFQUQiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6ODJGRUI2NzA2NzkwMTFFN0EzRUZFNzQ1NEFCMkVFQUQiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIChXaW5kb3dzKSI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOjRBMjkwN0JENjc4QzExRTc5QTQwRjk4NjQzOEI4RDczIiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOjRBMjkwN0JFNjc4QzExRTc5QTQwRjk4NjQzOEI4RDczIi8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+k3ySjQAAAdJJREFUeNrclk0oBGEYgHemjZOLm8tSyt9BqT2I1O7JSdSSkpsDxZGLi5MTjn5K4SDh4OfiaPfkIDebOPiPUqKUiLKet96pzzT7MztxMPX0le+b95n3Z2ZZmUwm9NuXHfqLK1smsVhsED5hKkhswc4mYJmHVxgNIvIslyE4hnLYDSqycwiaoCGVSnUFFdk5BH2wKHtBRbYKqlVwbQhGoNU5GETkZHKpggjMqaBFhaGgIltv/mKphRuQss1oZkPuG4oRWTLHlmU5fSlhOYNKSEK7xIUugj+6hmSHpROm2RvL9Q7arqf80IykdDEdgll4IWi/Bm+ECT8Z2R7l+DBKV6N/PoRnEbBuwIKf0nm+8S7RGuzDLaxLMuw/5OuR+bn60ROPt9/pUUQnUEa6A56SyeSWeTYejzs9GkC8ZIpySjxEy1APbdCM6MAlGmeZdIahYIlLVAU9kIA7KZFxrJrA5+bU8RBjBf+eGD26gk0oI4AItiU4dMOqHh+GTylbQT3JU7oj2IMLmNBJrIATKIUoD5L2LfEQJbRPvXAP0iPZj5J92vNl9Fk6mSCZsBV4dwuyflb8XJrRqX6C3iDsFhSdiXOzZlSnwxD2yuBHJv/iX6JvAQYAPSICqA82OnoAAAAASUVORK5CYII=" style="display: block;"><img id="vts-measure-button2" class="vts-measure-button" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABkAAAAZCAYAAADE6YVjAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyFpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNS1jMDIxIDc5LjE1NDkxMSwgMjAxMy8xMC8yOS0xMTo0NzoxNiAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIChXaW5kb3dzKSIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDo2Nzg3NzczMzY3OEMxMUU3QjU2QUUxNTNCNzc4MzVBQiIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDo2Nzg3NzczNDY3OEMxMUU3QjU2QUUxNTNCNzc4MzVBQiI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOjY3ODc3NzMxNjc4QzExRTdCNTZBRTE1M0I3NzgzNUFCIiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOjY3ODc3NzMyNjc4QzExRTdCNTZBRTE1M0I3NzgzNUFCIi8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+owD8TQAAAepJREFUeNrcls8rBGEYx993lIMfxR4kF/+AKMqBg7K1ajelLEWK025tKOTnjVykuAklNgcHuzmQg4MiTtz4Aza3TeGActDr+45nZt41s7tmBwdbn2l35933M9/3eead5UII9tsvjf3FK2uSiGgBKdDtZW6JllXA2DG4A3teRM7LZQl2QRuY9irScghGQRXb5KteRVoOQSMY0895FGkk8JHgSBH0gllzpAeRkeSRBAEwQIIZUJMxukARly3GOZdpivA5DnpAM2iQ5zFx3KE55DIugT6cT+a7PTTlKt9xHAT74AzU6vWJiEVQ4iWR9uXHhkgu3QhYB/JK3zBZE6WoBkE3Ivt9YolOQBd9uwJedQFjC+A8XyJ1J3G+4zNFV+CCmmMejINnY8sQG0wVzZnFlnW2Fd55ezGaIUAtPgzqwAsmv8mYMCLW8DaqdyY1g73w+RMFQRh0glse1RtDHRvDcdJp6XInsScKU3u3gnukSfCoOcoH0YPa3jif/P7zxEqUoPqUkWBZ398YqwdTNHqLdu+YuyTONToEl+AaTIAhUE61qwTtuJC0e4klkssQAn7QTy3+BA5AhRQgfdoovHvJp6iYli5EdTqlBKZA7a7CJFaiHdABUqBUFfyMxBJt06PBrwpskn/xl+hDgAEAH0j0b9rsgVUAAAAASUVORK5CYII=" style="display: none;"><div id="vts-measure-text-holder" class="vts-measure-text-holder" style="display: none;"><div class="vts-measure-text-holder2"><div class="vts-measure-text"><textarea id="vts-measure-text-input" rows="10" cols="67" wrap="hard"></textarea></div><div class="vts-measure-tools"><div id="vts-measure-position" class="vts-measure-tools-button">Position</div><div id="vts-measure-length" class="vts-measure-tools-button">Length</div><div id="vts-measure-track" class="vts-measure-tools-button">Track Length</div><div id="vts-measure-area" class="vts-measure-tools-button">Area</div><div id="vts-measure-volume" class="vts-measure-tools-button">Volume</div><div id="vts-measure-clear" class="vts-measure-tools-button">Clear Log</div><div id="vts-measure-metric" class="vts-measure-tools-button">Units: Meters</div></div></div></div><div id="vts-measure-info" class="vts-measure-info"></div><div id="vts-measure-buttons" class="vts-measure-compute"><div id="vts-measure-undo" class="vts-measure-tools-button">Undo</div><div id="vts-measure-compute" class="vts-measure-tools-button">Compute</div></div> </div></div><div style="display: none;"><div id="vts-measure" class="vts-measure" style="left: 115px;"><img id="vts-measure-button" class="vts-measure-button" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABkAAAAZCAYAAADE6YVjAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA2lpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNS1jMDIxIDc5LjE1NDkxMSwgMjAxMy8xMC8yOS0xMTo0NzoxNiAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDpkNjI1MjFjMi1mYzE5LTcyNDUtOTI5My1kNTU3MmE5N2E1MjgiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6ODJGRUI2NzE2NzkwMTFFN0EzRUZFNzQ1NEFCMkVFQUQiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6ODJGRUI2NzA2NzkwMTFFN0EzRUZFNzQ1NEFCMkVFQUQiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIChXaW5kb3dzKSI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOjRBMjkwN0JENjc4QzExRTc5QTQwRjk4NjQzOEI4RDczIiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOjRBMjkwN0JFNjc4QzExRTc5QTQwRjk4NjQzOEI4RDczIi8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+k3ySjQAAAdJJREFUeNrclk0oBGEYgHemjZOLm8tSyt9BqT2I1O7JSdSSkpsDxZGLi5MTjn5K4SDh4OfiaPfkIDebOPiPUqKUiLKet96pzzT7MztxMPX0le+b95n3Z2ZZmUwm9NuXHfqLK1smsVhsED5hKkhswc4mYJmHVxgNIvIslyE4hnLYDSqycwiaoCGVSnUFFdk5BH2wKHtBRbYKqlVwbQhGoNU5GETkZHKpggjMqaBFhaGgIltv/mKphRuQss1oZkPuG4oRWTLHlmU5fSlhOYNKSEK7xIUugj+6hmSHpROm2RvL9Q7arqf80IykdDEdgll4IWi/Bm+ECT8Z2R7l+DBKV6N/PoRnEbBuwIKf0nm+8S7RGuzDLaxLMuw/5OuR+bn60ROPt9/pUUQnUEa6A56SyeSWeTYejzs9GkC8ZIpySjxEy1APbdCM6MAlGmeZdIahYIlLVAU9kIA7KZFxrJrA5+bU8RBjBf+eGD26gk0oI4AItiU4dMOqHh+GTylbQT3JU7oj2IMLmNBJrIATKIUoD5L2LfEQJbRPvXAP0iPZj5J92vNl9Fk6mSCZsBV4dwuyflb8XJrRqX6C3iDsFhSdiXOzZlSnwxD2yuBHJv/iX6JvAQYAPSICqA82OnoAAAAASUVORK5CYII=" style="display: block;"><img id="vts-measure-button2" class="vts-measure-button" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABkAAAAZCAYAAADE6YVjAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyFpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNS1jMDIxIDc5LjE1NDkxMSwgMjAxMy8xMC8yOS0xMTo0NzoxNiAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIChXaW5kb3dzKSIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDo2Nzg3NzczMzY3OEMxMUU3QjU2QUUxNTNCNzc4MzVBQiIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDo2Nzg3NzczNDY3OEMxMUU3QjU2QUUxNTNCNzc4MzVBQiI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOjY3ODc3NzMxNjc4QzExRTdCNTZBRTE1M0I3NzgzNUFCIiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOjY3ODc3NzMyNjc4QzExRTdCNTZBRTE1M0I3NzgzNUFCIi8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+owD8TQAAAepJREFUeNrcls8rBGEYx993lIMfxR4kF/+AKMqBg7K1ajelLEWK025tKOTnjVykuAklNgcHuzmQg4MiTtz4Aza3TeGActDr+45nZt41s7tmBwdbn2l35933M9/3eead5UII9tsvjf3FK2uSiGgBKdDtZW6JllXA2DG4A3teRM7LZQl2QRuY9irScghGQRXb5KteRVoOQSMY0895FGkk8JHgSBH0gllzpAeRkeSRBAEwQIIZUJMxukARly3GOZdpivA5DnpAM2iQ5zFx3KE55DIugT6cT+a7PTTlKt9xHAT74AzU6vWJiEVQ4iWR9uXHhkgu3QhYB/JK3zBZE6WoBkE3Ivt9YolOQBd9uwJedQFjC+A8XyJ1J3G+4zNFV+CCmmMejINnY8sQG0wVzZnFlnW2Fd55ezGaIUAtPgzqwAsmv8mYMCLW8DaqdyY1g73w+RMFQRh0glse1RtDHRvDcdJp6XInsScKU3u3gnukSfCoOcoH0YPa3jif/P7zxEqUoPqUkWBZ398YqwdTNHqLdu+YuyTONToEl+AaTIAhUE61qwTtuJC0e4klkssQAn7QTy3+BA5AhRQgfdoovHvJp6iYli5EdTqlBKZA7a7CJFaiHdABUqBUFfyMxBJt06PBrwpskn/xl+hDgAEAH0j0b9rsgVUAAAAASUVORK5CYII=" style="display: none;"><div id="vts-measure-text-holder" class="vts-measure-text-holder" style="display: none;"><div class="vts-measure-text-holder2"><div class="vts-measure-text"><textarea id="vts-measure-text-input" rows="6" cols="50" wrap="hard"></textarea></div><div class="vts-measure-tools"><div id="vts-measure-clear" class="vts-measure-tools-button">Clear</div></div></div></div><div id="vts-measure-info" class="vts-measure-info"></div> </div></div><div style="display: none;"><div class="vts-layers" <="" div=""></div></div><div style="display: block;"><div class="vts-fallback"><div class="vts-fallback-text"><p>VTS Browser needs <a href="http://get.webgl.org/">WebGL</a> capable web browser.</p></div> </div></div><div style="display: none;"><div class="vts-popup-background" id="vts-popup-background"><div id="vts-popup" <="" div=""></div></div></div><div style="display: none;"><div id="vts-loading" class="vts-loading"><div class="vts-loading-progress"><div id="vts-loading-dot1" class="vts-loading-dot" style="opacity: 0.1248;"></div><div id="vts-loading-dot2" class="vts-loading-dot" style="opacity: 0.637381;"></div><div id="vts-loading-dot3" class="vts-loading-dot" style="opacity: 0.789372;"></div><div id="vts-loading-dot4" class="vts-loading-dot" style="opacity: 0.455468;"></div><div id="vts-loading-dot5" class="vts-loading-dot" style="opacity: -0.0890522;"></div></div> </div></div><div style="display: block;"><div id="distance-div" class="distance-div"></div><div id="height-div" class="distance-div"></div><div id="height-div2" class="pointer-div2"></div></div><div style="display: block;"><div id="profile-div" class="profile-div"><div id="profile-canvas-holder" class="profile-canvas-holder"><canvas id="profile-canvas" class="profile-canvas" width="797" height="118"></canvas></div></div></div></div></div>
  170.  
  171.   <!-- TODO: Missing CoffeeScript 2 -->
  172.  
  173.   <script type="text/javascript">//<![CDATA[
  174.  
  175.  
  176. var browser, renderer, map;
  177. var geodata, lineGeometry = null;
  178. var demoTexture = null;
  179. var usedMouseCoords = [0,0];
  180. var linePoint, lineSegment = 0;
  181. var distancePointer, heightPointer, heightPointer2;
  182. var trackHeights = [], trackLengths = [];
  183. var trackMinHeight, trackMaxHeight;
  184. var canvas, canvasCtx;
  185. var pathLength = 0, pathDistance = 0;
  186.  
  187. (function startDemo() {
  188.    // create map in the html div with id 'map-div'
  189.    // parameter 'map' sets path to the map which will be displayed
  190.    // you can create your own map on melown.com
  191.    // position parameter is described in documentation
  192.    // https://github.com/Melown/vts-browser-js/wiki/VTS-Browser-Map-API#position
  193.    // view parameter is described in documentation
  194.    // https://github.com/Melown/vts-browser-js/wiki/VTS-Browser-Map-API#definition-of-view
  195.    browser = vts.browser('map-div', {
  196.        map: 'https://cdn.melown.com/mario/store/melown2015/map-config/melown/VTS-Tutorial-Map-4/mapConfig.json',
  197.        position : [ 'obj', 23.3,42.6, 'float', 0.00, 0.00, -180.00, 0.00, 21255.06, 55.00 ]
  198.    });
  199.  
  200.    //check whether browser is supported
  201.    if (!browser) {
  202.        console.log('Your web browser does not support WebGL');
  203.        return;
  204.    }
  205.  
  206.    //move map controls little bit higher
  207.    browser.ui.getControl('credits').getElement('vts-credits').setStyle('bottom', '134px');
  208.    browser.ui.getControl('space').getElement('vts-space').setStyle('bottom', '140px');
  209.    browser.ui.getControl('zoom').getElement('vts-zoom-plus').setStyle('bottom', '140px');
  210.    browser.ui.getControl('zoom').getElement('vts-zoom-minus').setStyle('bottom', '140px');
  211.    browser.ui.getControl('compass').getElement('vts-compass').setStyle('bottom', '170px');
  212.  
  213.    // create ui control with info pointers
  214.    var infoPointers = browser.ui.addControl('info-pointers',
  215.        '<div id="distance-div" class="distance-div">' +
  216.        '</div>' +
  217.        '<div id="height-div" class="distance-div">' +
  218.        '</div>' +
  219.        '<div id="height-div2" class="pointer-div2">' +
  220.        '</div>');
  221.  
  222.    distancePointer = infoPointers.getElement('distance-div');
  223.    heightPointer = infoPointers.getElement('height-div');
  224.    heightPointer2 = infoPointers.getElement('height-div2');
  225.  
  226.    // create panel with path profile
  227.    var profilePanel = browser.ui.addControl('profile-panel',
  228.        '<div id="profile-div" class="profile-div">' +
  229.            '<div id="profile-canvas-holder" class="profile-canvas-holder">' +
  230.                '<canvas id="profile-canvas" class="profile-canvas">' +
  231.                '</canvas>' +
  232.            '</div>' +
  233.        '</div>');
  234.  
  235.    renderer = browser.renderer;
  236.  
  237.    //add mouse events to map element
  238.    var mapElement = browser.ui.getMapElement();
  239.    mapElement.on('mousemove', onMouseMove);
  240.    mapElement.on('mouseleave', onMouseLeave);
  241.    mapElement.on('dragover', onDragover);
  242.    mapElement.on('drop', onDrop);
  243.    mapElement.on('resize', onResize, window);
  244.  
  245.    //add mouse events to canvas element
  246.    canvas = profilePanel.getElement('profile-canvas');
  247.    canvas.on('mousemove', onCanvasHover);
  248.    canvas.on('dragover', onDragover);
  249.    canvas.on('drop', onDrop);
  250.    canvasCtx = canvas.getElement().getContext("2d");
  251.    drawCanvasMessage('Drop GPX file here')
  252.  
  253.    //callback once is map config loaded
  254.    browser.on('map-loaded', onMapLoaded);
  255.  
  256.    //callback when path hovered
  257.    browser.on('geo-feature-hover', onFeatureHover);
  258.  
  259.    loadTexture();
  260. })();
  261.  
  262.  
  263. function loadTexture() {
  264.    //load icon used for displaying path point
  265.    var demoImage = vts.utils.loadImage(
  266.        'http://maps.google.com/mapfiles/kml/shapes/placemark_circle.png',
  267.        (function(){
  268.            demoTexture = renderer.createTexture({ source: demoImage });
  269.        }));
  270. }
  271.  
  272. //add render slot for dynamic rendering
  273. function onMapLoaded() {
  274.    map = browser.map;
  275.    map.addRenderSlot('custom-render', onCustomRender, true);
  276.    map.moveRenderSlotAfter('after-map-render', 'custom-render');
  277. }
  278.  
  279. // prevent default browser behaviour for droping files
  280. function onDragover(event) {
  281.    var e = event.event;
  282.    e.stopPropagation();
  283.    e.preventDefault();
  284.    e.dataTransfer.dropEffect = 'copy';
  285. };
  286.  
  287. //load droped file
  288. function onDrop(event) {
  289.    if (!map) {
  290.        return;
  291.    }
  292.  
  293.    // prevent default browser behaviour for droping files
  294.    var e = event.event;
  295.    e.stopPropagation();
  296.    e.preventDefault();
  297.  
  298.    var files = e.dataTransfer.files; // Array of all files
  299.  
  300.    for (var i = 0, li = files.length; i < li; i++) {
  301.        var reader = new FileReader();
  302.  
  303.        reader.onloadend = function (event) {
  304.            var parser = new DOMParser();
  305.            var data = parser.parseFromString(event.target.result, 'text/xml');
  306.            loadGPX(data);
  307.        };
  308.  
  309.        //remove old layyer and hide pointers
  310.        map.removeFreeLayer('gpx-geodata');
  311.        distancePointer.setStyle("display", "none");
  312.        heightPointer.setStyle("display", "none");
  313.        heightPointer2.setStyle("display", "none");
  314.        lineGeometry = null;
  315.  
  316.        drawCanvasMessage('Loading ...')
  317.        reader.readAsText(files[i], 'text/plain');            
  318.    }
  319. }
  320.  
  321. function getElementChildValue(element, name) {
  322.    var child = element.getElementsByTagName(name)[0];
  323.    if (child) {
  324.        if(child.childNodes[0]) {
  325.            return child.childNodes[0].nodeValue;
  326.        }
  327.    }
  328.  
  329.    return null;
  330. };
  331.  
  332. function loadGPX(data) {
  333.    var gpx = data.getElementsByTagName('gpx')[0];
  334.  
  335.    if (!gpx) {
  336.        return;
  337.    }
  338.  
  339.    var coords, heightMode, i, li, j, lj, points, name, properties;
  340.  
  341.    //crete geodaata
  342.    geodata = map.createGeodata();
  343.  
  344.    //process way points
  345.    var wayPoints = gpx.getElementsByTagName('wpt');
  346.  
  347.    if (wayPoints.length) {
  348.        //create new group
  349.        //all waypoints will be stored in this group
  350.        geodata.addGroup('waypoints');
  351.  
  352.        for (i = 0, li = wayPoints.length; i < li; i++) {
  353.  
  354.            var wayPoint = wayPoints[i];
  355.            coords = [wayPoint.getAttribute('lon'), wayPoint.getAttribute('lat'), 0];
  356.  
  357.            properties = {};
  358.  
  359.            name = getElementChildValue(wayPoint, 'name');
  360.            if (name !== null) {
  361.                properties.name = name;
  362.            }
  363.  
  364.            var elevation = getElementChildValue(wayPoint, 'ele');
  365.            if (elevation !== null) {
  366.                heightMode = 'fix';
  367.                coords[2] = parseFloat(elevation);
  368.            } else {
  369.                heightMode = 'float';
  370.            }
  371.  
  372.            geodata.addPoint(coords, heightMode, properties);
  373.        }
  374.    }
  375.  
  376.    //process routes
  377.    var routes = gpx.getElementsByTagName('rte');
  378.  
  379.    if (routes.length) {
  380.        //create new group
  381.        //all routes  will be stored in this group
  382.        geodata.addGroup('routes');
  383.  
  384.        for (i = 0, li = routes.length; i < li; i++) {
  385.  
  386.            var route = routes[i];
  387.            var routePoints = route.getElementsByTagName('rtept');
  388.  
  389.            points = new Array(routePoints.length);
  390.  
  391.            //add route points with their names
  392.            for (j = 0, lj = routePoints.length; j < lj; j++) {
  393.                var routePoint = routePoints[j];
  394.                coords = [routePoint.getAttribute('lon'), routePoint.getAttribute('lat'), 0];
  395.  
  396.                properties = {};
  397.  
  398.                name = getElementChildValue(routePoint, 'name');
  399.                if (name !== null) {
  400.                    properties.name = name;
  401.                }
  402.  
  403.                var elevation = getElementChildValue(routePoint, 'ele');
  404.                if (elevation !== null) {
  405.                    heightMode = 'fix';
  406.                    coords[2] = parseFloat(elevation);
  407.                } else {
  408.                    heightMode = 'float';
  409.                }
  410.  
  411.                geodata.addPoint(coords, heightMode, properties);
  412.                points[j] = coords;
  413.            }
  414.  
  415.            // add route line
  416.            if (routePoints.length) {
  417.                properties = {};
  418.  
  419.                var name = getElementChildValue(route, 'name');
  420.                if (name !== null) {
  421.                    properties.name = name;
  422.                }
  423.  
  424.                geodata.addLineString(points, heightMode, properties, 'some-path');
  425.            }
  426.        }
  427.    }
  428.  
  429.    //process tracks
  430.    var tracks = gpx.getElementsByTagName('trk');
  431.  
  432.    if (tracks.length) {
  433.        //create new group
  434.        //all waypoints will be stored in this group
  435.        geodata.addGroup('tracks');
  436.  
  437.        for (i = 0, li = tracks.length; i < li; i++) {
  438.            var track = tracks[i];
  439.            var trackSegments = track.getElementsByTagName('trkseg');
  440.  
  441.            // get total trak points
  442.            var totalPoints = 0, trackPoints, index = 0;
  443.  
  444.            for (j = 0, lj = trackSegments.length; j < lj; j++) {
  445.                trackPoints  = trackSegments[j].getElementsByTagName('trkpt');
  446.                totalPoints += trackPoints.length;
  447.            }
  448.  
  449.            points = new Array(totalPoints);
  450.  
  451.            for (j = 0, lj = trackSegments.length; j < lj; j++) {
  452.  
  453.                trackPoints = trackSegments[j].getElementsByTagName('trkpt');
  454.  
  455.                //add track points with their names
  456.                for (var k = 0, lk = trackPoints.length; k < lk; k++) {
  457.                    var trackPoint = trackPoints[k];
  458.                    coords = [trackPoint.getAttribute('lon'), trackPoint.getAttribute('lat'), 0];
  459.  
  460.                    properties = {};
  461.  
  462.                    name = getElementChildValue(trackPoint, 'name');
  463.                    if (name !== null) {
  464.                        properties.name = name;
  465.                    }
  466.  
  467.                    var elevation = getElementChildValue(trackPoint, 'ele');
  468.                    if (elevation !== null) {
  469.                        heightMode = 'fix';
  470.                        coords[2] = parseFloat(elevation);
  471.                    } else {
  472.                        heightMode = 'float';
  473.                    }
  474.  
  475.                    geodata.addPoint(coords, heightMode, properties);
  476.                    points[index] = coords;
  477.                    index++;
  478.                }
  479.            }
  480.  
  481.            //add track line
  482.            if (points.length) {
  483.                properties = {};
  484.  
  485.                var name = getElementChildValue(track, 'name');
  486.                if (name !== null) {
  487.                    properties.name = name;
  488.                }
  489.  
  490.                geodata.addLineString(points, heightMode, properties, 'some-path');
  491.            }
  492.  
  493.        }
  494.    }
  495.  
  496.    drawCanvasMessage('Processing heights ...')
  497. //    geodata.processHeights('heightmap-by-precision', 62, onHeightProcessed);
  498.    geodata.processHeights('node-by-precision', 62, onHeightProcessed);
  499. };
  500.  
  501. //when are heights converted then we can create free layer
  502. // and dispaly that layer on the map
  503. function onHeightProcessed() {
  504.    //extrack gemteru with id == 'some-path'
  505.    lineGeometry = geodata.extractGeometry('some-path');
  506.    
  507.    //center map postion to track gemetery
  508.    centerPositonToGeometry(lineGeometry);
  509.  
  510.    //draw track profile
  511.    drawPathProfile(lineGeometry);
  512.  
  513.    //style used for displaying geodata
  514.    var style = {
  515.        'constants': {
  516.            '@icon-marker': ['icons', 6, 8, 18, 18]
  517.        },
  518.    
  519.        'bitmaps': {
  520.            'icons': 'http://maps.google.com/mapfiles/kml/shapes/placemark_circle.png'
  521.        },
  522.  
  523.        "layers" : {
  524.            "track-line" : {
  525.                "filter" : ["==", "#type", "line"],
  526.                "line": true,
  527.                "line-width" : 4,
  528.                "line-color": [255,0,255,255],
  529.                "zbuffer-offset" : [-5,0,0],
  530.                "z-index" : -1
  531.            },
  532.  
  533.            "track-shadow" : {
  534.                "filter" : ["==", "#type", "line"],
  535.                "line": true,
  536.                "line-width" : 20,
  537.                "line-color": [0,0,0,120],
  538.                "zbuffer-offset" : [-5,0,0],
  539.                "hover-event" : true,
  540.                "advanced-hit" : true
  541.  
  542.            },
  543.  
  544.            "way-points" : {
  545.                "filter" : ["all", ["==", "#type", "point"], ["==", "#group", "waypoints"]],
  546.                "point": true,
  547.                "point-radius" : 20,
  548.                "point-color": [0,255,255,255],              
  549.                "zbuffer-offset" : [-5,0,0]
  550.            },
  551.  
  552.        }
  553.    };
  554.  
  555.    //meke free layres
  556.    var freeLayer = geodata.makeFreeLayer(style);
  557.  
  558.    //add free layer to the map
  559.    map.addFreeLayer('gpxgeodata', freeLayer);
  560.  
  561.    //add free layer to the list of free layers
  562.    //which will be rendered on the map
  563.    var view = map.getView();
  564.    view.freeLayers.gpxgeodata = {};
  565.    map.setView(view);
  566. }
  567.  
  568. // move map position to the center of gemetru and adjust
  569. // view extent to size of geometry
  570. function centerPositonToGeometry(geometry) {
  571.    if (!geometry.getElements()) {
  572.        return;
  573.    }
  574.  
  575.    //get detailed info about map reference frame
  576.    var refFrame = map.getReferenceFrame();
  577.    var navigationSrsId = refFrame.navigationSrs;
  578.    var navigationSrs = map.getSrsInfo(navigationSrsId);
  579.    var physicalSrsId = refFrame.physicalSrs;
  580.    var physicalSrs = map.getSrsInfo(physicalSrsId);
  581.  
  582.    var i, li, midPoint = [0,0,0], line, vec3 = vts.vec3;
  583.  
  584.    //find center of gemetry
  585.    for (i = 0, li = geometry.getElements() + 1; i < li; i++) {
  586.        if (i == (li - 1)) { //last line point
  587.            line = geometry.getElement(i-1);
  588.            coords = line[1];
  589.        } else {
  590.            line = geometry.getElement(i);
  591.            coords = line[0];
  592.        }
  593.  
  594.        midPoint[0] += coords[0];
  595.        midPoint[1] += coords[1];
  596.        midPoint[2] += coords[2];
  597.    };
  598.  
  599.  
  600.    midPoint[0] /= li;
  601.    midPoint[1] /= li;
  602.    midPoint[2] /= li;
  603.  
  604.    // construct line which goes through the center of geometry
  605.    // and mesure most distant point from this line
  606.  
  607.    var cameraPosition = midPoint;
  608.    var cameraVector = [-cameraPosition[0], -cameraPosition[1], -cameraPosition[2]];
  609.    vec3.normalize(cameraVector);
  610.  
  611.    var viewExtent = 500;                
  612.  
  613.    for (i = 0, li = geometry.getElements() + 1; i < li; i++) {
  614.        if (i == (li - 1)) { //last line point
  615.            line = geometry.getElement(i - 1);
  616.            coords = line[1];
  617.        } else {
  618.            line = geometry.getElement(i);
  619.            coords = line[0];
  620.        }
  621.  
  622.        //get line point distance
  623.        var ab = cameraVector;
  624.        var av = [coords[0] - cameraPosition[0], coords[1] - cameraPosition[1], coords[2] - cameraPosition[2]];
  625.  
  626.        var b = [cameraPosition[0] + cameraVector[0], cameraPosition[1] + cameraVector[1], cameraPosition[2] + cameraVector[2]];
  627.        var bv = [coords[0] - b[0], coords[1] - b[1], coords[2] - b[2]];
  628.  
  629.        var af = [0,0,0];
  630.        vec3.cross(ab, av, af);
  631.  
  632.        var d = (vec3.length(bv) / vec3.length(ab)) * 2;
  633.  
  634.        if (d > viewExtent) {
  635.            viewExtent = d;
  636.        }
  637.    }
  638.  
  639.    //limit view extent according to planet radius
  640.    if (viewExtent > navigationSrs.a*1.4) {
  641.        viewExtent = navigationSrs.a*1.4;
  642.    }
  643.  
  644.    //convert coods from physical to nav
  645.    var navCoords = vts.proj4(physicalSrs.srsDef, navigationSrs.srsDef, midPoint);
  646.    navCoords[2] = 0;
  647.  
  648.    //set new map positon
  649.    var pos = map.getPosition();
  650.    pos.setCoords(navCoords);
  651.    pos.setOrientation([0, -70, 0]);
  652.    pos.setViewExtent(viewExtent);
  653.    map.setPosition(pos);
  654. }
  655.  
  656. //set heigth profile pointer accoring to current track position
  657. function setProfilePointer(p) {
  658.    var rect = canvas.getRect();
  659.    var x = (pathDistance / pathLength) * rect.width;
  660.  
  661.    var rect2 = heightPointer.getRect();
  662.    p = map.convertCoordsFromPhysToPublic(p);
  663.  
  664.    heightPointer.setStyle('display', 'block');
  665.    heightPointer.setStyle('left', (rect.left + x -(rect2.width*0.5)) + 'px');
  666.    heightPointer.setStyle('top', (rect.top) + 'px');
  667.    heightPointer.setHtml((p[2]).toFixed(2) + " m");
  668.  
  669.    heightPointer2.setStyle('display', 'block');
  670.    heightPointer2.setStyle('left', (rect.left + x - 1) + 'px');
  671.    heightPointer2.setStyle('top', (rect.top) + 'px');
  672. }
  673.  
  674. //redraw track profile when browser window is resized
  675. function onResize() {
  676.    refereshCanvasDimensions();
  677.    drawPathProfile(lineGeometry);
  678. }
  679.  
  680. //sets canvas size accoding to HTML element size
  681. function refereshCanvasDimensions() {
  682.    var rect = canvas.getRect();
  683.    var canvasElement = canvas.getElement();
  684.    if (canvasElement.width != rect.width) {
  685.        canvasElement.width = rect.width;
  686.    }
  687.    if (canvasElement.height != rect.height) {
  688.        canvasElement.height = rect.height;
  689.    }
  690.    return [rect.width, rect.height];
  691. }
  692.  
  693. //display status message in the canvas
  694. function drawCanvasMessage(message) {
  695.    var dim = refereshCanvasDimensions();
  696.    canvasCtx.clearRect(0, 0, dim[0], dim[1]);
  697.    canvasCtx.font="30px Arial, 'Helvetica Neue', Helvetica, sans-serif";
  698.    canvasCtx.fillStyle = "rgba(0,0,0,1)";
  699.    canvasCtx.fillText(message, dim[0]*0.5 - canvasCtx.measureText(message).width*0.5, 70);
  700. }
  701.  
  702. //process track geometry and display track profile
  703. function drawPathProfile(geometry) {
  704.    if (!geometry) {
  705.        return;
  706.    }
  707.  
  708.    var totalElements = geometry.getElements();
  709.  
  710.    if (!totalElements) {
  711.        return;
  712.    }
  713.  
  714.    pathLength = geometry.getPathLength();
  715.  
  716.    trackHeights = new Array(totalElements);
  717.    trackLengths = new Array(totalElements);
  718.    trackMinHeight = Number.POSITIVE_INFINITY;
  719.    trackMaxHeight = Number.NEGATIVE_INFINITY;
  720.  
  721.    var totalLength = 0;
  722.  
  723.    //get track point heights and length between track points
  724.    for (var i = 0, li = totalElements; i < li; i++) {
  725.        var l = geometry.getElement(i);
  726.        var p = map.convertCoordsFromPhysToPublic(l[0]);
  727.        trackHeights[i] = p[2];
  728.  
  729.        totalLength += vts.vec3.length([l[1][0] - l[0][0], l[1][1] - l[0][1], l[1][2] - l[0][2]]);
  730.        trackLengths[i] = totalLength;
  731.  
  732.        if (p[2] > trackMaxHeight) {
  733.            trackMaxHeight = p[2];
  734.        }
  735.  
  736.        if (p[2] < trackMinHeight) {
  737.            trackMinHeight = p[2];
  738.        }
  739.    }
  740.  
  741.    //draw track profile
  742.    var dim = refereshCanvasDimensions();
  743.    var lx = dim[0], ly = dim[1];
  744.  
  745.    canvasCtx.clearRect(0,0,lx,ly);
  746.    canvasCtx.beginPath();
  747.    canvasCtx.moveTo(-1,ly-1);
  748.  
  749.    if (trackMaxHeight == trackMinHeight) {
  750.        canvasCtx.lineTo(lx,ly);
  751.    } else {
  752.  
  753.        canvasCtx.lineTo(-1, (ly - 2) - ((trackHeights[0] - trackMinHeight) / (trackMaxHeight - trackMinHeight)) * (ly-30) );
  754.  
  755.        for (var i = 0, li = trackHeights.length; i < li; i++) {
  756.            canvasCtx.lineTo((trackLengths[i]/pathLength)*lx, (ly - 2) - ((trackHeights[i] - trackMinHeight) / (trackMaxHeight - trackMinHeight)) * (ly-30) );
  757.        }
  758.    }
  759.  
  760.    canvasCtx.lineTo(lx,ly-1);
  761.    canvasCtx.lineTo(0,ly-1);
  762.  
  763.    // Create gradient
  764.    var grd = canvasCtx.createLinearGradient(0,0,0,ly);
  765.    grd.addColorStop(0,"rgba(252,186,136,0.3)");
  766.    grd.addColorStop(1,"rgba(94,45,18,0.3)");
  767.  
  768.    // Fill profile with gradient
  769.    canvasCtx.fillStyle = grd;
  770.    canvasCtx.fill();
  771.  
  772.    //draw profile outline
  773.    canvasCtx.strokeStyle = "rgba(50,50,50,0.7)";
  774.    canvasCtx.stroke();
  775. }
  776.  
  777.  
  778. function onMouseMove(event) {
  779.    if (map) {
  780.        var coords = event.getMouseCoords();
  781.        usedMouseCoords = coords;
  782.        //set map to hover cusor over provided coordinates permanently
  783.        map.hover(coords[0], coords[1], true);
  784.    }
  785. }
  786.  
  787.  
  788. function onMouseLeave(event) {
  789.    if (map) {
  790.        var coords = event.getMouseCoords();
  791.        //stop cursor hovering
  792.        map.hover(coords[0], coords[1], false);
  793.    }
  794. };
  795.  
  796.  
  797. function onFeatureHover(event) {
  798.    lineSegment = event.element;
  799.  
  800.    if (lineGeometry) {
  801.        //get distance of cursor on the line segment
  802.        var res = lineGeometry.getRelationToCanvasPoint(lineSegment, usedMouseCoords[0], usedMouseCoords[1]);
  803.  
  804.        //get path length to line segment and length of the segment itself
  805.        var lineSegmentInfo = lineGeometry.getPathLengthToElement(lineSegment);
  806.  
  807.        //compute path distance to point where cursor is hovering over the track
  808.        pathDistance = lineSegmentInfo.lengthToElement + (lineSegmentInfo.elementLengh * vts.math.clamp(res.distance, 0, 1));
  809.  
  810.        //get point coodinates
  811.        linePoint = lineGeometry.getPathPoint(pathDistance);
  812.  
  813.        //refresh pointer in height profile
  814.        setProfilePointer(linePoint);
  815.  
  816.        //force redraw map (we have to redraw track point)
  817.        map.redraw();
  818.    }
  819. }
  820.  
  821. function onCanvasHover(event) {
  822.    if (map && lineGeometry) {
  823.        var coords = event.getMouseCoords();
  824.        usedMouseCoords = coords;
  825.  
  826.        //compute new path distance from cursor position in canvas
  827.        var rect = canvas.getRect();
  828.        pathDistance = ((coords[0] - rect.left) / canvas.getElement().width) * pathLength;
  829.  
  830.        //get point coodinates
  831.        linePoint = lineGeometry.getPathPoint(pathDistance);
  832.  
  833.        //refresh pointer in height profile
  834.        setProfilePointer(linePoint);
  835.  
  836.        //force redraw map (we have to redraw track point)
  837.        map.redraw();
  838.    }
  839. }
  840.  
  841. function onCustomRender() {
  842.    if (demoTexture && lineGeometry && linePoint) { //check whether texture is loaded
  843.  
  844.        //get canvas postion of the track point
  845.        var p = map.convertCoordsFromPhysToCanvas(linePoint);
  846.  
  847.        //display distance pointer in the track point coordiantes
  848.        var rect = distancePointer.getRect();
  849.        distancePointer.setStyle("display", "block");
  850.        distancePointer.setStyle("left", (p[0]-(rect.width*0.5)) + "px");
  851.        distancePointer.setStyle("top", (p[1]-50) + "px");
  852.        distancePointer.setHtml((pathDistance*0.001).toFixed(2) + " Km");
  853.  
  854.        //draw point image at the last line point
  855.        renderer.drawImage({
  856.            rect : [p[0]-12*1.5, p[1]-12*1.5, 24*1.5, 24*1.5],
  857.            texture : demoTexture,
  858.            color : [255,0,255,255],
  859.            depth : p[2],
  860.            depthTest : false,
  861.            blend : true
  862.            });
  863.    }
  864. }
  865.  
  866.  
  867.  
  868.  //]]></script>
  869.  
  870.   <script>
  871.     // tell the embed parent frame the height of the content
  872.     if (window.parent && window.parent.parent){
  873.      window.parent.parent.postMessage(["resultsFrame", {
  874.        height: document.body.getBoundingClientRect().height,
  875.        slug: "xrz53a7k"
  876.      }], "*")
  877.    }
  878.  
  879.    // always overwrite window.name, in case users try to set it manually
  880.    window.name = "result"
  881.  </script>
  882.  
  883.    <script>
  884.      let allLines = []
  885.  
  886.      window.addEventListener("message", (message) => {
  887.        if (message.data.console){
  888.          let insert = document.querySelector("#insert")
  889.          allLines.push(message.data.console.payload)
  890.          insert.innerHTML = allLines.join(";\r")
  891.  
  892.           let result = eval.call(null, message.data.console.payload)
  893.           if (result !== undefined){
  894.             console.log(result)
  895.           }
  896.         }
  897.       })
  898.     </script>
  899.  
  900.  
  901.  
  902. </body></html>
  903. <script>
  904. browser.on("map-loaded", function() {
  905.     var gpxElement = document.getElementById("gpsdata");
  906.     if (gpxElement) {
  907.         loadGPX(new DOMParser().parseFromString(gpxElement.innerHTML, "text/xml"));
  908.     }
  909. });
  910. </script>
Add Comment
Please, Sign In to add comment