//class defs class Entry { constructor(data) { this.date = data[0].replaceAll("/", ".").replace(",", ""); this.conntype = data[1].toUpperCase(); this.loc = [parseFloat(data[3]), parseFloat(data[2])]; // long, lat this.speed = [parseFloat(data[4]), parseFloat(data[6])]; // dl, up this.size = [parseInt(data[5]), parseInt(data[7])]; // dl, up this.ping = parseInt(data[8]); this.server = data[9]; this.intIP = data[10]; this.extIP = data[11]; this.url = data[12]; } toHTML() { return this.conntype + " [" + this.date + "] " + "
\n" + this.speedStr + "
\nPing: " + this.ping + "ms
\nresult Page🔗
\n"; } get speedStr() { return this.speed[0].toFixed(2) + " Mbps ↓ / " + this.speed[1].toFixed(2) + " Mbps ↑"; } }; /** @type {HTMLDivElement} */ var statusBox = document.getElementById("statusbox"); var layerlist = document.getElementById("layerlist"); var popupcontainer = document.getElementById('popup'); var popupcontent = document.getElementById('popup-content'); var popupcloser = document.getElementById('popup-closer'); var zoomstart = 15; var dotradius = 5; var isInit = false; var entryList = []; var layers = {}; //mapping of layers: name -> layerobj //init map var overlay = new ol.Overlay({ element: popupcontainer, autoPan: true, autoPanAnimation: { duration: 250, }, }); popupcloser.onclick = function () { popupcontent.innerHTML = ""; overlay.setPosition(undefined); popupcloser.blur(); return false; }; var map = new ol.Map({ target: 'map', layers: [ new ol.layer.Tile({ source: new ol.source.OSM() }) ], view: new ol.View({ center: ol.proj.fromLonLat([0, 0]), zoom: zoomstart }), overlays: [overlay] }); var highlightStyle = new ol.style.Style({ image: new ol.style.Circle({ radius: dotradius, fill: new ol.style.Fill({color: 'green'}) }) }); var defaultStyle = new ol.style.Style({ image: new ol.style.Circle({ radius: dotradius, fill: new ol.style.Fill({color: 'red'}) }) }); //liste of features, that have the highlighted style var highlighted = []; // event listener map.on("pointermove", e => { var newhighlighted = []; //gather overlay information var fids = []; //list of currently hovered feature ids map.forEachFeatureAtPixel(e.pixel, feature => { var fid = feature.getProperties().id; fids.push(fid); feature.setStyle(highlightStyle); newhighlighted.push(feature); }) if(newhighlighted.length > 0) { //remove highlight style from non hovered elements highlighted.filter(h => newhighlighted.indexOf(h) == -1).forEach(h => h.setStyle(defaultStyle)); highlighted = newhighlighted; } // display information if(fids.length > 0) { popupcontent.innerHTML = ""; overlay.setPosition(e.coordinate); } for(var i = 0; i < fids.length; ++i) { var entry = entryList[fids[i]]; //console.log(entry); //print entry popupcontent.innerHTML += entry.toHTML(); if(i+1 < fids.length) popupcontent.innerHTML += "
\n"; } }); // this function should take a csv line and parse it to an array function parseLine(line) { out = []; while(line.length > 0) { //line starts with , -> empty if(line[0] === ',') { //empty string line = line.substr(1); out.push(""); continue; } var end = line.length; var start = 0; var closing_len = 1; //length ofclosing string // starts with " if(line[0] === '"') { start = 1; //find second " end = line.indexOf('"', 1)-1; closing_len = 3; //warum 3 ??? ich verstehs nich ich hätte 2 gedacht } else { //use next , as end var newend = line.indexOf(','); if(newend > 0) end = newend; } //getarg out.push(line.substr(start, end)); //remove arg from line line = line.substr(end+closing_len); } return out; } function showError(error) { var span = document.createElement('p'); span.classList.add('error'); span.innerHTML = `Error: ${error}`; statusBox.appendChild(span); } function showSuccess(success) { var span = document.createElement('p'); span.classList.add('success'); span.innerHTML = `Success: ${success}`; statusBox.appendChild(span); } function clearStatus() { statusBox.innerHTML = ""; } function addElement(elem, features) { var id = entryList.length; entryList.push(elem); var dot = ol.proj.fromLonLat(elem.loc); if(!isInit) { isInit = true; map.setView(new ol.View({center: dot, zoom: zoomstart})); console.log(dot); } var feat = new ol.Feature({ geometry: new ol.geom.Point(dot), type: 'point', id: id }); features.push(feat); } function loadedFile(text, filename) { //remove \r and split var lines = text.replaceAll("\r", "").split("\n"); var featuresLTE = []; var features = []; //check for IOS if(lines[0] === "Date,ConnType,ConnDetails,Lat,Lon,Download,DownloadBytes,Upload,UploadBytes,Latency,ServerName,InternalIp,ExternalIp,Is SpeedTest VPN") { showError("IOS files are not supported. Only Android for now."); return; } for(var i = 1; i < lines.length; ++i) { var line = lines[i]; if(line.length < 10) continue; var lineSplit = parseLine(line); var elem = new Entry(lineSplit); if(elem.conntype === "LTE") { addElement(elem, featuresLTE); } else { addElement(elem, features); } } addLayer(featuresLTE, filename + " LTE"); addLayer(features, filename + " nonLTE"); } function addLayer(features, name) { var sourceLayer = new ol.source.Vector({ features }); var vectorLayer = new ol.layer.Vector({ source: sourceLayer, style: defaultStyle }); layers[name] = vectorLayer; map.addLayer(vectorLayer); //add button to list layerlist.innerHTML += `${name}:
\n` } function loadFile(file) { console.log("loadFile: " + file.name); console.log(file); var text = file.text(); text.then(t => loadedFile(t, file.name)); } function triggerImport(event) { clearStatus(); isInit = false; //try to read the files var filelist = document.getElementById("files").files; if(filelist.length == 0) { showError("No file selected"); return false; } var successC = 0; for(var i = 0; i < filelist.length; ++i) { var f = filelist[i]; try { loadFile(f); ++successC; } catch(e) { showError(`The file ${f.name} is not in the csv format`); } } if(successC > 0) showSuccess("Loaded " + successC + " files"); return false; } function triggerLayer(btnevent, layername) { var btn = btnevent.target; var btnname = btn.innerText; var mode = btn.classList.contains("off"); // true = layer is off, false = layer is on if(mode) btn.classList.remove("off"); else btn.classList.add("off"); var layer = layers[layername]; if(btnname == "30%") layer.setOpacity(mode ? 1 : 0.3); else layer.setVisible(mode); }