From bd7a93de73349805765fea0ddde9eb29ac6cb2a0 Mon Sep 17 00:00:00 2001 From: Xaver Maierhofer Date: Sun, 30 Apr 2017 14:59:39 +0200 Subject: [PATCH] [TASK] Move polyfills and test properties --- config.default.json | 32 ++++ lib/map.js | 333 ++--------------------------------------- lib/map/button.js | 154 +++++++++++++++++++ lib/map/clientlayer.js | 17 ++- lib/map/labellayer.js | 126 +++++++++++++++- 5 files changed, 334 insertions(+), 328 deletions(-) create mode 100644 lib/map/button.js diff --git a/config.default.json b/config.default.json index 385d278..39f1abc 100644 --- a/config.default.json +++ b/config.default.json @@ -16,5 +16,37 @@ "fr", "ru" ], + "icon": { + "base": { + "fillOpacity": 0.6, + "opacity": 0.6, + "weight": 2, + "radius": 6, + "className": "stroke-first" + }, + "online": { + "color": "#1566A9", + "fillColor": "#1566A9" + }, + "offline": { + "color": "#D43E2A", + "fillColor": "#D43E2A", + "radius": 3 + }, + "lost": { + "color": "#D43E2A", + "fillColor": "#D43E2A", + "radius": 4 + }, + "alert": { + "color": "#D43E2A", + "fillColor": "#D43E2A", + "radius": 5 + }, + "new": { + "color": "#1566A9", + "fillColor": "#93E929" + } + }, "cacheBreaker": "" } diff --git a/lib/map.js b/lib/map.js index f569e49..d82c4fd 100644 --- a/lib/map.js +++ b/lib/map.js @@ -1,5 +1,5 @@ -define(['map/clientlayer', 'map/labellayer', 'leaflet', 'moment', 'map/locationmarker', 'rbush', 'helper'], - function (ClientLayer, LabelLayer, L, moment, LocationMarker, rbush, helper) { +define(['map/clientlayer', 'map/labellayer', 'map/button', 'leaflet'], + function (ClientLayer, LabelLayer, Button, L) { 'use strict'; var options = { @@ -8,197 +8,14 @@ define(['map/clientlayer', 'map/labellayer', 'leaflet', 'moment', 'map/locationm minZoom: 0 }; - var ButtonBase = L.Control.extend({ - options: { - position: 'bottomright' - }, - - active: false, - button: undefined, - - initialize: function (f, o) { - L.Util.setOptions(this, o); - this.f = f; - }, - - update: function () { - this.button.classList.toggle('active', this.active); - }, - - set: function (v) { - this.active = v; - this.update(); - } - }); - - var LocateButton = ButtonBase.extend({ - onAdd: function () { - var button = L.DomUtil.create('button', 'ion-locate shadow'); - button.setAttribute('data-tooltip', _.t('button.tracking')); - L.DomEvent.disableClickPropagation(button); - L.DomEvent.addListener(button, 'click', this.onClick, this); - - this.button = button; - - return button; - }, - - onClick: function () { - this.f(!this.active); - } - }); - - var CoordsPickerButton = ButtonBase.extend({ - onAdd: function () { - var button = L.DomUtil.create('button', 'ion-pin shadow'); - button.setAttribute('data-tooltip', _.t('button.location')); - - // Click propagation isn't disabled as this causes problems with the - // location picking mode; instead propagation is stopped in onClick(). - L.DomEvent.addListener(button, 'click', this.onClick, this); - - this.button = button; - - return button; - }, - - onClick: function (e) { - L.DomEvent.stopPropagation(e); - this.f(!this.active); - } - }); - - function mkMarker(dict, iconFunc, router) { - return function (d) { - var m = L.circleMarker([d.nodeinfo.location.latitude, d.nodeinfo.location.longitude], iconFunc(d)); - - m.resetStyle = function resetStyle() { - m.setStyle(iconFunc(d)); - }; - - m.on('click', function () { - router.fullUrl({ node: d.nodeinfo.node_id }); - }); - m.bindTooltip(d.nodeinfo.hostname); - - dict[d.nodeinfo.node_id] = m; - - return m; - }; - } - - function addLinksToMap(dict, linkScale, graph, router) { - graph = graph.filter(function (d) { - return 'distance' in d && !d.vpn; - }); - - return graph.map(function (d) { - var opts = { - color: linkScale(1 / d.tq), - weight: 4, - opacity: 0.5, - dashArray: 'none' - }; - - var line = L.polyline(d.latlngs, opts); - - line.resetStyle = function resetStyle() { - line.setStyle(opts); - }; - - line.bindTooltip(d.source.node.nodeinfo.hostname + ' – ' + d.target.node.nodeinfo.hostname + '
' + helper.showDistance(d) + ' / ' + helper.showTq(d) + ''); - line.on('click', function () { - router.fullUrl({ link: d.id }); - }); - - dict[d.id] = line; - - return line; - }); - } - - var iconOnline = { - color: '#1566A9', - fillColor: '#1566A9', - radius: 6, - fillOpacity: 0.5, - opacity: 0.5, - weight: 2, - className: 'stroke-first' - }; - var iconOffline = { - color: '#D43E2A', - fillColor: '#D43E2A', - radius: 3, - fillOpacity: 0.5, - opacity: 0.5, - weight: 1, - className: 'stroke-first' - }; - var iconLost = { - color: '#D43E2A', - fillColor: '#D43E2A', - radius: 4, - fillOpacity: 0.8, - opacity: 0.8, - weight: 1, - className: 'stroke-first' - }; - var iconAlert = { - color: '#D43E2A', - fillColor: '#D43E2A', - radius: 5, - fillOpacity: 0.8, - opacity: 0.8, - weight: 2, - className: 'stroke-first' - }; - var iconNew = { color: '#1566A9', fillColor: '#93E929', radius: 6, fillOpacity: 1.0, opacity: 0.5, weight: 2 }; - return function (config, linkScale, sidebar, router, buttons) { var self = this; - var groupOnline; - var groupOffline; - var groupNew; - var groupLost; - var groupLines; var savedView; var map; - var userLocation; var layerControl; var baseLayers = {}; - var locateUserButton = new LocateButton(function (d) { - if (d) { - enableTracking(); - } else { - disableTracking(); - } - }); - - var mybuttons = []; - - function addButton(button) { - var el = button.onAdd(); - mybuttons.push(el); - buttons.appendChild(el); - } - - function clearButtons() { - mybuttons.forEach(function (d) { - buttons.removeChild(d); - }); - } - - var showCoordsPickerButton = new CoordsPickerButton(function (d) { - if (d) { - enableCoords(); - } else { - disableCoords(); - } - }); - function saveView() { savedView = { center: map.getCenter(), @@ -206,54 +23,6 @@ define(['map/clientlayer', 'map/labellayer', 'leaflet', 'moment', 'map/locationm }; } - function enableTracking() { - map.locate({ - watch: true, - enableHighAccuracy: true, - setView: true - }); - locateUserButton.set(true); - } - - function disableTracking() { - map.stopLocate(); - locationError(); - locateUserButton.set(false); - } - - function enableCoords() { - map.getContainer().classList.add('pick-coordinates'); - map.on('click', showCoordinates); - showCoordsPickerButton.set(true); - } - - function disableCoords() { - map.getContainer().classList.remove('pick-coordinates'); - map.off('click', showCoordinates); - showCoordsPickerButton.set(false); - } - - function showCoordinates(e) { - router.fullUrl({ zoom: map.getZoom(), lat: e.latlng.lat, lng: e.latlng.lng }); - disableCoords(); - } - - function locationFound(e) { - if (!userLocation) { - userLocation = new LocationMarker(e.latlng).addTo(map); - } - - userLocation.setLatLng(e.latlng); - userLocation.setAccuracy(e.accuracy); - } - - function locationError() { - if (userLocation) { - map.removeLayer(userLocation); - userLocation = null; - } - } - function contextMenuOpenLayerMenu() { document.querySelector('.leaflet-control-layers').classList.add('leaflet-control-layers-expanded'); } @@ -288,13 +57,14 @@ define(['map/clientlayer', 'map/labellayer', 'leaflet', 'moment', 'map/locationm baseLayers[d.name] = d.layer; }); - map.on('locationfound', locationFound); - map.on('locationerror', locationError); + var button = new Button(config, map, router, buttons); + + map.on('locationfound', button.locationFound); + map.on('locationerror', button.locationError); map.on('dragend', saveView); map.on('contextmenu', contextMenuOpenLayerMenu); - addButton(locateUserButton); - addButton(showCoordsPickerButton); + button.init(); layerControl = L.control.layers(baseLayers, [], { position: 'bottomright' }); layerControl.addTo(map); @@ -392,116 +162,41 @@ define(['map/clientlayer', 'map/labellayer', 'leaflet', 'moment', 'map/locationm } } - function mapRTree(d) { - return { - minX: d.nodeinfo.location.latitude, minY: d.nodeinfo.location.longitude, - maxX: d.nodeinfo.location.latitude, maxY: d.nodeinfo.location.longitude, - node: d - }; - } - self.setData = function setData(data) { nodeDict = {}; linkDict = {}; - if (groupOffline) { - groupOffline.clearLayers(); - } - - if (groupOnline) { - groupOnline.clearLayers(); - } - - if (groupNew) { - groupNew.clearLayers(); - } - - if (groupLost) { - groupLost.clearLayers(); - } - - if (groupLines) { - groupLines.clearLayers(); - } - - var lines = addLinksToMap(linkDict, linkScale, data.graph.links, router); - groupLines = L.featureGroup(lines).addTo(map); - - var nodesOnline = helper.subtract(data.nodes.all.filter(helper.online), data.nodes.new); - var nodesOffline = helper.subtract(data.nodes.all.filter(helper.offline), data.nodes.lost); - - var markersOnline = nodesOnline.filter(helper.hasLocation) - .map(mkMarker(nodeDict, function () { - return iconOnline; - }, router)); - - var markersOffline = nodesOffline.filter(helper.hasLocation) - .map(mkMarker(nodeDict, function () { - return iconOffline; - }, router)); - - var markersNew = data.nodes.new.filter(helper.hasLocation) - .map(mkMarker(nodeDict, function () { - return iconNew; - }, router)); - - var markersLost = data.nodes.lost.filter(helper.hasLocation) - .map(mkMarker(nodeDict, function (d) { - if (d.lastseen.isAfter(moment(data.now).subtract(config.maxAgeAlert, 'days'))) { - return iconAlert; - } - - if (d.lastseen.isAfter(moment(data.now).subtract(config.maxAge, 'days'))) { - return iconLost; - } - return null; - }, router)); - - groupOffline = L.featureGroup(markersOffline).addTo(map); - groupLost = L.featureGroup(markersLost).addTo(map); - groupOnline = L.featureGroup(markersOnline).addTo(map); - groupNew = L.featureGroup(markersNew).addTo(map); - - var rtreeOnlineAll = rbush(9); - - rtreeOnlineAll.load(data.nodes.all.filter(helper.online).filter(helper.hasLocation).map(mapRTree)); - - clientLayer.setData(rtreeOnlineAll); - labelLayer.setData({ - online: nodesOnline.filter(helper.hasLocation), - offline: nodesOffline.filter(helper.hasLocation), - new: data.nodes.new.filter(helper.hasLocation), - lost: data.nodes.lost.filter(helper.hasLocation) - }); + clientLayer.setData(data); + labelLayer.setData(data, map, nodeDict, linkDict, linkScale, router, config); updateView(true); }; self.resetView = function resetView() { - disableTracking(); + button.disableTracking(); highlight = undefined; updateView(); }; self.gotoNode = function gotoNode(d) { - disableTracking(); + button.disableTracking(); highlight = { type: 'node', o: d }; updateView(); }; self.gotoLink = function gotoLink(d) { - disableTracking(); + button.disableTracking(); highlight = { type: 'link', o: d }; updateView(); }; self.gotoLocation = function gotoLocation(d) { - disableTracking(); + button.disableTracking(); map.setView([d.lat, d.lng], d.zoom); }; self.destroy = function destroy() { - clearButtons(); + button.clearButtons(); map.remove(); if (el.parentNode) { diff --git a/lib/map/button.js b/lib/map/button.js new file mode 100644 index 0000000..4352fa5 --- /dev/null +++ b/lib/map/button.js @@ -0,0 +1,154 @@ +define(['map/clientlayer', 'map/labellayer', 'leaflet', 'moment', 'map/locationmarker'], + function (ClientLayer, LabelLayer, L, moment, LocationMarker) { + 'use strict'; + var self = {}; + + var ButtonBase = L.Control.extend({ + options: { + position: 'bottomright' + }, + + active: false, + button: undefined, + + initialize: function (f, o) { + L.Util.setOptions(this, o); + this.f = f; + }, + + update: function () { + this.button.classList.toggle('active', this.active); + }, + + set: function (v) { + this.active = v; + this.update(); + } + }); + + var LocateButton = ButtonBase.extend({ + onAdd: function () { + var button = L.DomUtil.create('button', 'ion-locate shadow'); + button.setAttribute('data-tooltip', _.t('button.tracking')); + L.DomEvent.disableClickPropagation(button); + L.DomEvent.addListener(button, 'click', this.onClick, this); + + this.button = button; + + return button; + }, + + onClick: function () { + this.f(!this.active); + } + }); + + var CoordsPickerButton = ButtonBase.extend({ + onAdd: function () { + var button = L.DomUtil.create('button', 'ion-pin shadow'); + button.setAttribute('data-tooltip', _.t('button.location')); + + // Click propagation isn't disabled as this causes problems with the + // location picking mode; instead propagation is stopped in onClick(). + L.DomEvent.addListener(button, 'click', this.onClick, this); + + this.button = button; + + return button; + }, + + onClick: function (e) { + L.DomEvent.stopPropagation(e); + this.f(!this.active); + } + }); + + return function (config, map, router, buttons) { + var userLocation; + + var locateUserButton = new LocateButton(function (d) { + if (d) { + enableTracking(); + } else { + self.disableTracking(); + } + }); + + var mybuttons = []; + + function addButton(button) { + var el = button.onAdd(); + mybuttons.push(el); + buttons.appendChild(el); + } + + self.clearButtons = function clearButtons() { + mybuttons.forEach(function (d) { + buttons.removeChild(d); + }); + }; + + var showCoordsPickerButton = new CoordsPickerButton(function (d) { + if (d) { + enableCoords(); + } else { + disableCoords(); + } + }); + + function enableTracking() { + map.locate({ + watch: true, + enableHighAccuracy: true, + setView: true + }); + locateUserButton.set(true); + } + + self.disableTracking = function disableTracking() { + map.stopLocate(); + self.locationError(); + locateUserButton.set(false); + }; + + function enableCoords() { + map.getContainer().classList.add('pick-coordinates'); + map.on('click', showCoordinates); + showCoordsPickerButton.set(true); + } + + function disableCoords() { + map.getContainer().classList.remove('pick-coordinates'); + map.off('click', showCoordinates); + showCoordsPickerButton.set(false); + } + + function showCoordinates(e) { + router.fullUrl({ zoom: map.getZoom(), lat: e.latlng.lat, lng: e.latlng.lng }); + disableCoords(); + } + + self.locationFound = function locationFound(e) { + if (!userLocation) { + userLocation = new LocationMarker(e.latlng).addTo(map); + } + + userLocation.setLatLng(e.latlng); + userLocation.setAccuracy(e.accuracy); + }; + + self.locationError = function locationError() { + if (userLocation) { + map.removeLayer(userLocation); + userLocation = null; + } + }; + + self.init = function init() { + addButton(locateUserButton); + addButton(showCoordsPickerButton); + }; + + return self; + }; + }); diff --git a/lib/map/clientlayer.js b/lib/map/clientlayer.js index 06d1432..ac09e33 100644 --- a/lib/map/clientlayer.js +++ b/lib/map/clientlayer.js @@ -1,10 +1,19 @@ -define(['leaflet', 'helper'], - function (L, helper) { +define(['leaflet', 'rbush', 'helper'], + function (L, rbush, helper) { 'use strict'; return L.GridLayer.extend({ - setData: function (d) { - this.data = d; + mapRTree: function mapRTree(d) { + return { + minX: d.nodeinfo.location.latitude, minY: d.nodeinfo.location.longitude, + maxX: d.nodeinfo.location.latitude, maxY: d.nodeinfo.location.longitude, + node: d + }; + }, + setData: function (data) { + var rtreeOnlineAll = rbush(9); + + this.data = rtreeOnlineAll.load(data.nodes.all.filter(helper.online).filter(helper.hasLocation).map(this.mapRTree)); // pre-calculate start angles this.data.all().forEach(function (n) { diff --git a/lib/map/labellayer.js b/lib/map/labellayer.js index e136826..92b6550 100644 --- a/lib/map/labellayer.js +++ b/lib/map/labellayer.js @@ -1,7 +1,13 @@ -define(['leaflet', 'rbush', 'helper'], - function (L, rbush, helper) { +define(['leaflet', 'rbush', 'helper', 'moment'], + function (L, rbush, helper, moment) { 'use strict'; + var groupOnline; + var groupOffline; + var groupNew; + var groupLost; + var groupLines; + var labelLocations = [['left', 'middle', 0 / 8], ['center', 'top', 6 / 8], ['right', 'middle', 4 / 8], @@ -43,7 +49,7 @@ define(['leaflet', 'rbush', 'helper'], function calcOffset(offset, loc) { return [offset * Math.cos(loc[2] * 2 * Math.PI), - -offset * Math.sin(loc[2] * 2 * Math.PI)]; + offset * Math.sin(loc[2] * 2 * Math.PI)]; } function labelRect(p, offset, anchor, label, minZoom, maxZoom, z) { @@ -70,6 +76,59 @@ define(['leaflet', 'rbush', 'helper'], return { minX: x, minY: y, maxX: x + width, maxY: y + height }; } + function mkMarker(dict, iconFunc, router) { + return function (d) { + var m = L.circleMarker([d.nodeinfo.location.latitude, d.nodeinfo.location.longitude], iconFunc(d)); + + m.resetStyle = function resetStyle() { + m.setStyle(iconFunc(d)); + }; + + m.on('click', function () { + router.fullUrl({ node: d.nodeinfo.node_id }); + }); + m.bindTooltip(d.nodeinfo.hostname); + + dict[d.nodeinfo.node_id] = m; + + return m; + }; + } + + function addLinksToMap(dict, linkScale, graph, router) { + graph = graph.filter(function (d) { + return 'distance' in d && !d.vpn; + }); + + return graph.map(function (d) { + var opts = { + color: linkScale(1 / d.tq), + weight: 4, + opacity: 0.5, + dashArray: 'none' + }; + + var line = L.polyline(d.latlngs, opts); + + line.resetStyle = function resetStyle() { + line.setStyle(opts); + }; + + line.bindTooltip(d.source.node.nodeinfo.hostname + ' – ' + d.target.node.nodeinfo.hostname + '
' + helper.showDistance(d) + ' / ' + helper.showTq(d) + ''); + line.on('click', function () { + router.fullUrl({ link: d.id }); + }); + + dict[d.id] = line; + + return line; + }); + } + + function getIcon(config, color) { + return Object.assign({}, config.icon.base, config.icon[color]); + } + return L.GridLayer.extend({ onAdd: function (map) { L.GridLayer.prototype.onAdd.call(this, map); @@ -77,8 +136,65 @@ define(['leaflet', 'rbush', 'helper'], this.prepareLabels(); } }, - setData: function (d) { - this.data = d; + setData: function (data, map, nodeDict, linkDict, linkScale, router, config) { + var iconOnline = getIcon(config, 'online'); + var iconOffline = getIcon(config, 'offline'); + var iconLost = getIcon(config, 'lost'); + var iconAlert = getIcon(config, 'alert'); + var iconNew = getIcon(config, 'new'); + // Check if init or data is already set + if (groupLines) { + groupOffline.clearLayers(); + groupOnline.clearLayers(); + groupNew.clearLayers(); + groupLost.clearLayers(); + groupLines.clearLayers(); + } + + var lines = addLinksToMap(linkDict, linkScale, data.graph.links, router); + groupLines = L.featureGroup(lines).addTo(map); + + var nodesOnline = helper.subtract(data.nodes.all.filter(helper.online), data.nodes.new); + var nodesOffline = helper.subtract(data.nodes.all.filter(helper.offline), data.nodes.lost); + + var markersOnline = nodesOnline.filter(helper.hasLocation) + .map(mkMarker(nodeDict, function () { + return iconOnline; + }, router)); + + var markersOffline = nodesOffline.filter(helper.hasLocation) + .map(mkMarker(nodeDict, function () { + return iconOffline; + }, router)); + + var markersNew = data.nodes.new.filter(helper.hasLocation) + .map(mkMarker(nodeDict, function () { + return iconNew; + }, router)); + + var markersLost = data.nodes.lost.filter(helper.hasLocation) + .map(mkMarker(nodeDict, function (d) { + if (d.lastseen.isAfter(moment(data.now).subtract(config.maxAgeAlert, 'days'))) { + return iconAlert; + } + + if (d.lastseen.isAfter(moment(data.now).subtract(config.maxAge, 'days'))) { + return iconLost; + } + return null; + }, router)); + + groupOffline = L.featureGroup(markersOffline).addTo(map); + groupLost = L.featureGroup(markersLost).addTo(map); + groupOnline = L.featureGroup(markersOnline).addTo(map); + groupNew = L.featureGroup(markersNew).addTo(map); + + this.data = { + online: nodesOnline.filter(helper.hasLocation), + offline: nodesOffline.filter(helper.hasLocation), + new: data.nodes.new.filter(helper.hasLocation), + lost: data.nodes.lost.filter(helper.hasLocation) + }; this.updateLayer(); }, updateLayer: function () {