From 1eca8867751df644a62752fbbfbc6a6de849de74 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89tienne=20Simon?= Date: Mon, 11 May 2015 20:00:04 -0400 Subject: Add visualizer. Lasciate ogni speranza voi ch'entrate: I am the bone of my javascript DOM is my body and JQuery is my blood I have created over a thousand lines Unknown to death Nor known to life Have withstood pain to create many functions Yet those hands shall never type anything So, as I pray, Unlimited Openlayers Works --- visualizer/script.js | 1037 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1037 insertions(+) create mode 100644 visualizer/script.js (limited to 'visualizer/script.js') diff --git a/visualizer/script.js b/visualizer/script.js new file mode 100644 index 0000000..98c9593 --- /dev/null +++ b/visualizer/script.js @@ -0,0 +1,1037 @@ +/***************/ +/*** General ***/ +/***************/ + +window.app = {}; +var app = window.app; + +app.mainLayer = new ol.layer.Tile({ source: new ol.source.OSM() }); + + +/****************/ +/*** Geometry ***/ +/****************/ + +app.geometry = {} +app.geometry.REarth = 6371000; +app.geometry.toRadians = function(x){ return x * Math.PI / 180; }; + +app.geometry.haversine = function(lat1, lon1, lat2, lon2){ + var lat1 = app.geometry.toRadians(lat1); + var lon1 = app.geometry.toRadians(lon1); + var lat2 = app.geometry.toRadians(lat2); + var lon2 = app.geometry.toRadians(lon2); + + var dlat = Math.abs(lat1-lat2); + var dlon = Math.abs(lon1-lon2); + + var alpha = Math.pow(Math.sin(dlat/2), 2) + Math.cos(lat1) * Math.cos(lat2) * Math.pow(Math.sin(dlon/2), 2); + var d = Math.atan2(Math.sqrt(alpha), Math.sqrt(1-alpha)); + + return 2 * app.geometry.REarth * d; +}; + +app.geometry.equirectangular = function(lat1, lon1, lat2, lon2){ + var lat1 = app.geometry.toRadians(lat1); + var lon1 = app.geometry.toRadians(lon1); + var lat2 = app.geometry.toRadians(lat2); + var lon2 = app.geometry.toRadians(lon2); + var x = (lon2-lon1) * Math.cos((lat1+lat2)/2); + var y = (lat2-lat1); + return Math.sqrt(x*x + y*y) * app.geometry.REarth; +}; + + +/***************/ +/*** Measure ***/ +/***************/ + +app.measure = {}; +app.measure.tooltip_list = []; + +app.measure.source = new ol.source.Vector(); + +app.measure.layer = new ol.layer.Vector({ + source: app.measure.source, + style: new ol.style.Style({ + fill: new ol.style.Fill({ + color: 'rgba(255, 255, 255, 0.2)' + }), + stroke: new ol.style.Stroke({ + color: '#FC3', + width: 2 + }), + image: new ol.style.Circle({ + radius: 7, + fill: new ol.style.Fill({ + color: '#FC3' + }) + }) + }) +}); + +app.measure.pointerMoveHandler = function(evt){ + if(evt.dragging){ return; } + var tooltipCoord = evt.coordinate; + + if(app.measure.sketch){ + var output; + var geom = (app.measure.sketch.getGeometry()); + if(geom instanceof ol.geom.LineString){ + output = app.measure.formatLength((geom)); + tooltipCoord = geom.getLastCoordinate(); + } + app.measure.tooltipElement.innerHTML = output; + app.measure.tooltip.setPosition(tooltipCoord); + } +}; + +app.measure.addInteraction = function(){ + app.measure.draw = new ol.interaction.Draw({ + source: app.measure.source, + type: ('LineString'), + style: new ol.style.Style({ + fill: new ol.style.Fill({ + color: 'rgba(255, 255, 255, 0.2)' + }), + stroke: new ol.style.Stroke({ + color: 'rgba(0, 0, 0, 0.5)', + lineDash: [10, 10], + width: 2 + }), + image: new ol.style.Circle({ + radius: 5, + stroke: new ol.style.Stroke({ + color: 'rgba(0, 0, 0, 0.7)' + }), + fill: new ol.style.Fill({ + color: 'rgba(255, 255, 255, 0.2)' + }) + }) + }) + }); + app.map.addInteraction(app.measure.draw); + + app.measure.createTooltip(); + + app.measure.draw.on('drawstart', + function(evt){ + app.measure.sketch = evt.feature; + }, this); + + app.measure.draw.on('drawend', + function(evt){ + app.measure.tooltipElement.className = 'measure-tooltip measure-tooltip-static'; + app.measure.tooltip.setOffset([0, -7]); + app.measure.sketch = null; + app.measure.tooltipElement = null; + app.measure.createTooltip(); + }, this); +}; + +app.measure.createTooltip = function(){ + if(app.measure.tooltipElement){ + app.measure.tooltipElement.parentNode.removeChild(app.measure.tooltipElement); + } + app.measure.tooltipElement = document.createElement('div'); + app.measure.tooltipElement.className = 'measure-tooltip measure-tooltip-value'; + app.measure.tooltip = new ol.Overlay({ + element: app.measure.tooltipElement, + offset: [0, -15], + positioning: 'bottom-center' + }); + app.measure.tooltip_list.push(app.measure.tooltip); + app.map.addOverlay(app.measure.tooltip); +}; + +app.measure.formatLength = function(line){ + var length_euclidean = line.getLength(); + var length_equirectangular = 0; + var length_haversine = 0; + var coordinates = line.getCoordinates(); + var sourceProj = app.map.getView().getProjection(); + for(var i = 0, ii = coordinates.length - 1; i < ii; ++i){ + var c1 = ol.proj.transform(coordinates[i], sourceProj, 'EPSG:4326'); + var c2 = ol.proj.transform(coordinates[i + 1], sourceProj, 'EPSG:4326'); + length_equirectangular += app.geometry.equirectangular(c1[1], c1[0], c2[1], c2[0]); + length_haversine += app.geometry.haversine(c1[1], c1[0], c2[1], c2[0]); + } + + var disp = function(x){ + if(x > 100){ + return Math.round(x / 1000 * 1000) / 1000 + 'km'; + } else { + return Math.round(x * 1000) / 1000 + 'm'; + } + } + + var length_euclidean = disp(length_euclidean); + var length_equirectangular = disp(length_equirectangular); + var length_haversine = disp(length_haversine); + + var display_euclidean = $('input#measure-euclidean').prop('checked'); + var display_equirectangular = $('input#measure-equirectangular').prop('checked'); + var display_haversine = $('input#measure-haversine').prop('checked'); + + var header = true; + if(display_euclidean + display_equirectangular + display_haversine == 1){ + header = false; + } + + var str = ''; + if(display_euclidean){ + if(header){ str += 'euclidean: '; } + str += length_euclidean; + } + if(display_equirectangular){ + if(header){ if(display_euclidean){ str += '
'; } str += 'equirectangular: '; } + str += length_equirectangular; + } + if(display_haversine){ + if(header){ str += '
haversine: '; } + str += length_haversine; + } + return str; +}; + + +/*******************/ +/*** DataDisplay ***/ +/*******************/ + +app.dataDisplay = {}; +app.dataDisplay.layers = {}; +app.dataDisplay.heatmapRadius = 5; +app.dataDisplay.heatmapBlur = 5; +app.dataDisplay.pathPointMode = 1; // endpoints +app.dataDisplay.pathPointResolution = 50; + +app.dataDisplay.loadLayer = function(path){ + $.ajax({url: path, cache: false, dataType: 'json', + success: function(result){ + app.dataDisplay.layers[path] = app.dataDisplay.preprocess(result); + app.map.addLayer(app.dataDisplay.layers[path]); + } + }); +}; + +app.dataDisplay.unloadLayer = function(path){ + app.map.removeLayer(app.dataDisplay.layers[path]); + delete app.dataDisplay.layers[path]; +}; + +app.dataDisplay.rawStyle = function(feature, resolution){ + var style = [ new ol.style.Style({ + stroke: new ol.style.Stroke({ + color: '#00F', + width: 5 + }), + image: new ol.style.Circle({ + radius: 5, + fill: new ol.style.Fill({ + color: '#00F' + }) + }) + }), + new ol.style.Style({ + stroke: new ol.style.Stroke({ + color: '#000', + width: 2 + }), + image: new ol.style.Circle({ + radius: 2, + fill: new ol.style.Fill({ + color: '#FFF' + }) + }) + }) + ]; + + if(feature.get('display') == 'path' && resolution < app.dataDisplay.pathPointResolution){ + if(app.dataDisplay.pathPointMode == 2){ + var polyline = feature.getGeometry(); + var points = polyline.getCoordinates(); + for(var i=1; i= 1){ + var polyline = feature.getGeometry(); + var first = polyline.getFirstCoordinate(); + var last = polyline.getLastCoordinate(); + style.push(new ol.style.Style({ + geometry: new ol.geom.Point(first), + image: new ol.style.Circle({ + radius: 5, + fill: new ol.style.Fill({ + color: '#0F0' + }) + }) + })); + style.push(new ol.style.Style({ + geometry: new ol.geom.Point(last), + image: new ol.style.Circle({ + radius: 5, + fill: new ol.style.Fill({ + color: '#F00' + }) + }) + })); + } + } + + return style; +}; + +app.dataDisplay.clusterStyleCache = {}; +app.dataDisplay.clusterStyle = function(feature, resolution){ + var size = feature.get('features').length; + var style = app.dataDisplay.clusterStyleCache[size]; + if(!style){ + style = [new ol.style.Style({ + image: new ol.style.Circle({ + radius: 10, + stroke: new ol.style.Stroke({ + color: '#FFF' + }), + fill: new ol.style.Fill({ + color: '#39C' + }) + }), + text: new ol.style.Text({ + text: size.toString(), + fill: new ol.style.Fill({ + color: '#FFF' + }) + }) + })]; + app.dataDisplay.clusterStyleCache[size] = style; + } + return style; +}; + +app.dataDisplay.preprocess = function(egj){ + var source = new ol.source.GeoJSON({ + projection: 'EPSG:3857', + object: egj.data + }); + + if(egj.type == 'raw'){ + return new ol.layer.Vector({ + source: source, + style: app.dataDisplay.rawStyle + }); + + } else if(egj.type == 'cluster'){ + return new ol.layer.Vector({ + source: new ol.source.Cluster({ + distance: 40, + source: source + }), + style: app.dataDisplay.clusterStyle + }); + + } else if(egj.type == 'heatmap'){ + return new ol.layer.Heatmap({ + source: source, + blur: app.dataDisplay.heatmapBlur, + radius: app.dataDisplay.heatmapRadius + }); + } +}; + +app.dataDisplay.reloadPathes = function(){ + for(var layer in app.dataDisplay.layers){ + if(app.dataDisplay.layers[layer].getSource().getFeatures()[0].get('display') == 'path'){ + app.dataDisplay.layers[layer].changed(); + } + } +}; + +app.dataDisplay.reloadHeatmaps = function(){ + for(var key in app.dataDisplay.layers){ + var layer = app.dataDisplay.layers[key]; + if(layer instanceof ol.layer.Heatmap){ + layer.setBlur(app.dataDisplay.heatmapBlur); + layer.setRadius(app.dataDisplay.heatmapRadius); + } + } +}; + + +/****************/ +/*** DataList ***/ +/****************/ + +app.dataList = {}; +app.dataList.current = {}; +app.dataList.idgen = 0; + +app.dataList.init = function(){ + app.dataList.elementTree = {}; + app.dataList.elementTree.parent = null; + app.dataList.elementTree.children = {}; + app.dataList.elementTree.checkbox = null; + app.dataList.elementTree.ul = $('#datalist-tree ul'); + + app.dataList.updateList(); + setInterval(app.dataList.updateList, 1000); +}; + +app.dataList.updateList = function(){ + $.ajax({url: '/ls/', cache: false, dataType: 'json', + success: function(result){ + result.forEach(function(file){ + file.uri = file.path.join('/') + '/' + file.name + if(file.uri in app.dataList.current){ + if(file.mtime > app.dataList.current[file.uri].mtime){ + var act = app.dataList.current[file.uri]; + if(act.checkbox.prop('checked')){ + app.dataList.unloadLayer(file.uri); + app.dataList.loadLayer(file.uri); + } + act.mtime = file.mtime; + } + } else { + app.dataList.insert(file); + } + }); + } + }); +}; + +app.dataList.insert = function(file){ + var cur = app.dataList.elementTree; + var prev = null; + for(var i = 1; i') + .prop('id', 'folder-'+app.dataList.idgen) + .hide(); + + var hidelink = $('') + .prop('href', '') + .append('hide') + .hide(); + var showlink = $('') + .prop('href', '') + .append('show'); + + var playlink = $('') + .prop('href', '') + .append('play'); + var stoplink = $('') + .prop('href', '') + .append('stop') + .hide(); + + n.checkbox = $('') + .prop('type', 'checkbox') + .prop('id', 'data-'+app.dataList.idgen) + .prop('name', n.uri); + n.checkbox.change(app.dataList.selectData); + var item = $('
  • ') + .append(n.checkbox) + .append($('
  • ') + .append(file.checkbox) + .append($('