diff --git a/.editorconfig b/.editorconfig index f0abb4f..604c949 100644 --- a/.editorconfig +++ b/.editorconfig @@ -11,6 +11,6 @@ trim_trailing_whitespace = true end_of_line = lf insert_final_newline = true -[*.{js,html,scss,json}] +[*.{js,html,scss,json,yml,md}] indent_size = 2 indent_style = space diff --git a/.gitignore b/.gitignore index 1f46137..e728065 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,5 @@ node_modules/ build/ .sass-cache/ config.json +.idea/ +.eslintrc diff --git a/Gruntfile.js b/Gruntfile.js index b63ad56..6fcc054 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -1,24 +1,24 @@ module.exports = function (grunt) { - grunt.loadNpmTasks("grunt-git-describe") + grunt.loadNpmTasks("grunt-git-describe"); grunt.initConfig({ "git-describe": { options: {}, default: {} } - }) + }); - grunt.registerTask("saveRevision", function() { + grunt.registerTask("saveRevision", function () { grunt.event.once("git-describe", function (rev) { - grunt.option("gitRevision", rev) - }) - grunt.task.run("git-describe") - }) + grunt.option("gitRevision", rev); + }); + grunt.task.run("git-describe"); + }); - grunt.loadTasks("tasks") + grunt.loadTasks("tasks"); - grunt.registerTask("default", ["bower-install-simple", "lint", "saveRevision", "copy", "sass", "postcss", "requirejs"]) - grunt.registerTask("lint", ["eslint"]) - grunt.registerTask("dev", ["default", "connect:server", "watch"]) -} + grunt.registerTask("default", ["bower-install-simple", "lint", "saveRevision", "copy", "sass", "postcss", "requirejs"]); + grunt.registerTask("lint", ["eslint"]); + grunt.registerTask("dev", ["default", "connect:server", "watch"]); +}; diff --git a/app.js b/app.js index e848121..ef131ef 100644 --- a/app.js +++ b/app.js @@ -29,8 +29,8 @@ require.config({ "tablesort.numeric": ["tablesort"], "helper": ["numeral-intl"] } -}) +}); require(["main", "helper"], function (main) { - getJSON("config.json").then(main) -}) + getJSON("config.json").then(main); +}); diff --git a/build.js b/build.js index 021929a..41f588b 100644 --- a/build.js +++ b/build.js @@ -1,9 +1,9 @@ ({ - baseUrl: "lib", - name: "../bower_components/almond/almond", - mainConfigFile: "app.js", - include: "../app", - wrap: true, - optimize: "uglify", - out: "app-combined.js" -}) + baseUrl: "lib", + name: "../bower_components/almond/almond", + mainConfigFile: "app.js", + include: "../app", + wrap: true, + optimize: "uglify", + out: "app-combined.js" +}); diff --git a/helper.js b/helper.js index 6e00702..1237021 100644 --- a/helper.js +++ b/helper.js @@ -1,228 +1,241 @@ function get(url) { - return new Promise(function(resolve, reject) { - var req = new XMLHttpRequest() - req.open('GET', url) + return new Promise(function (resolve, reject) { + var req = new XMLHttpRequest(); + req.open('GET', url); - req.onload = function() { + req.onload = function () { if (req.status == 200) { - resolve(req.response) + resolve(req.response); } else { - reject(Error(req.statusText)) + reject(Error(req.statusText)); } - } + }; - req.onerror = function() { - reject(Error("Network Error")) - } + req.onerror = function () { + reject(Error("Network Error")); + }; - req.send() - }) + req.send(); + }); } function getJSON(url) { - return get(url).then(JSON.parse) + return get(url).then(JSON.parse); } function sortByKey(key, d) { - return d.slice().sort( function (a, b) { - return a[key] - b[key] - }).reverse() + return d.slice().sort(function (a, b) { + return a[key] - b[key]; + }).reverse(); } function limit(key, m, d) { - return d.filter( function (d) { - return d[key].isAfter(m) - }) + return d.filter(function (d) { + return d[key].isAfter(m); + }); } function sum(a) { - return a.reduce( function (a, b) { - return a + b - }, 0) + return a.reduce(function (a, b) { + return a + b; + }, 0); } function one() { - return 1 + return 1; } function trueDefault(d) { - return d === undefined ? true : d + return d === undefined ? true : d; } function dictGet(dict, key) { - var k = key.shift() + var k = key.shift(); - if (!(k in dict)) - return null + if (!(k in dict)) { + return null; + } - if (key.length == 0) - return dict[k] + if (key.length == 0) { + return dict[k]; + } - return dictGet(dict[k], key) + return dictGet(dict[k], key); } function localStorageTest() { - var test = 'test' + var test = 'test'; try { - localStorage.setItem(test, test) - localStorage.removeItem(test) - return true - } catch(e) { - return false + localStorage.setItem(test, test); + localStorage.removeItem(test); + return true; + } catch (e) { + return false; } } function listReplace(s, subst) { for (key in subst) { - var re = new RegExp(key, 'g') - s = s.replace(re, subst[key]) + var re = new RegExp(key, 'g'); + s = s.replace(re, subst[key]); } - return s + return s; } /* Helpers working with nodes */ function offline(d) { - return !d.flags.online + return !d.flags.online; } function online(d) { - return d.flags.online + return d.flags.online; } function has_location(d) { return "location" in d.nodeinfo && - Math.abs(d.nodeinfo.location.latitude) < 90 && - Math.abs(d.nodeinfo.location.longitude) < 180 + Math.abs(d.nodeinfo.location.latitude) < 90 && + Math.abs(d.nodeinfo.location.longitude) < 180; } function subtract(a, b) { - var ids = {} + var ids = {}; - b.forEach( function (d) { - ids[d.nodeinfo.node_id] = true - }) + b.forEach(function (d) { + ids[d.nodeinfo.node_id] = true; + }); - return a.filter( function (d) { - return !(d.nodeinfo.node_id in ids) - }) + return a.filter(function (d) { + return !(d.nodeinfo.node_id in ids); + }); } /* Helpers working with links */ function showDistance(d) { - if (isNaN(d.distance)) - return + if (isNaN(d.distance)) { + return; + } - return numeral(d.distance).format("0,0") + " m" + return numeral(d.distance).format("0,0") + " m"; } function showTq(d) { - return numeral(1/d.tq).format("0%") + return numeral(1 / d.tq).format("0%"); } /* Infobox stuff (XXX: move to module) */ function attributeEntry(el, label, value) { - if (value === null || value == undefined) - return - - var tr = document.createElement("tr") - var th = document.createElement("th") - if (typeof label === "string") - th.textContent = label - else { - th.appendChild(label) - tr.className = "routerpic" + if (value === null || value == undefined) { + return; } - tr.appendChild(th) + var tr = document.createElement("tr"); + var th = document.createElement("th"); + if (typeof label === "string") { + th.textContent = label; + } else { + th.appendChild(label); + tr.className = "routerpic"; + } - var td = document.createElement("td") + tr.appendChild(th); - if (typeof value == "function") - value(td) - else - td.appendChild(document.createTextNode(value)) + var td = document.createElement("td"); - tr.appendChild(td) + if (typeof value == "function") { + value(td); + } else { + td.appendChild(document.createTextNode(value)); + } - el.appendChild(tr) + tr.appendChild(td); - return td + el.appendChild(tr); + + return td; } function createIframe(opt, width, height) { - el = document.createElement("iframe") - width = typeof width !== 'undefined' ? width : '100%' - height = typeof height !== 'undefined' ? height : '350px' + el = document.createElement("iframe"); + width = typeof width !== 'undefined' ? width : '100%'; + height = typeof height !== 'undefined' ? height : '350px'; - if (opt.src) - el.src = opt.src - else - el.src = opt + if (opt.src) { + el.src = opt.src; + } else { + el.src = opt; + } - if (opt.frameBorder) - el.frameBorder = opt.frameBorder - else - el.frameBorder = 1 + if (opt.frameBorder) { + el.frameBorder = opt.frameBorder; + } else { + el.frameBorder = 1; + } - if (opt.width) - el.width = opt.width - else - el.width = width + if (opt.width) { + el.width = opt.width; + } else { + el.width = width; + } - if (opt.height) - el.height = opt.height - else - el.height = height + if (opt.height) { + el.height = opt.height; + } else { + el.height = height; + } - el.scrolling = "no" - el.seamless = "seamless" + el.scrolling = "no"; + el.seamless = "seamless"; - return el + return el; } function showStat(o, subst) { - var content, caption - subst = typeof subst !== 'undefined' ? subst : {} + var content, caption; + subst = typeof subst !== 'undefined' ? subst : {}; if (o.thumbnail) { - content = document.createElement("img") - content.src = listReplace(o.thumbnail, subst) + content = document.createElement("img"); + content.src = listReplace(o.thumbnail, subst); } if (o.caption) { - caption = listReplace(o.caption, subst) + caption = listReplace(o.caption, subst); - if (!content) - content = document.createTextNode(caption) + if (!content) { + content = document.createTextNode(caption); + } } if (o.iframe) { - content = createIframe(o.iframe, o.width, o.height) - if (o.iframe.src) - content.src = listReplace(o.iframe.src, subst) - else - content.src = listReplace(o.iframe, subst) + content = createIframe(o.iframe, o.width, o.height); + if (o.iframe.src) { + content.src = listReplace(o.iframe.src, subst); + } else { + content.src = listReplace(o.iframe, subst); + } } - var p = document.createElement("p") + var p = document.createElement("p"); if (o.href) { - var link = document.createElement("a") - link.target = "_blank" - link.href = listReplace(o.href, subst) - link.appendChild(content) + var link = document.createElement("a"); + link.target = "_blank"; + link.href = listReplace(o.href, subst); + link.appendChild(content); - if (caption && o.thumbnail) - link.title = caption + if (caption && o.thumbnail) { + link.title = caption; + } - p.appendChild(link) - } else - p.appendChild(content) + p.appendChild(link); + } else { + p.appendChild(content); + } - return p + return p; } diff --git a/html/index.html b/html/index.html index 6f5c4c7..cc95aa5 100644 --- a/html/index.html +++ b/html/index.html @@ -1,28 +1,28 @@ -
- - - - - - - - - - - -
- Lade
-
- Karte & Knoten...
-
+ Lade
+
+ Karte & Knoten...
+
- Lade
-
- Karte & Knoten...
-
+ Lade
+
+ Karte & Knoten...
+
Mit Doppelklick und Shift+Doppelklick kann man in der Karte " - s += "auch zoomen.
" + s += "Mit Doppelklick und Shift+Doppelklick kann man in der Karte "; + s += "auch zoomen.
"; - s += "Copyright (C) Milan Pässler
" - s += "Copyright (C) Nils Schneider
" + s += "Copyright (C) Milan Pässler
"; + s += "Copyright (C) Nils Schneider
"; - s += "This program is free software: you can redistribute it and/or " - s += "modify it under the terms of the GNU Affero General Public " - s += "License as published by the Free Software Foundation, either " - s += "version 3 of the License, or (at your option) any later version.
" + s += "This program is free software: you can redistribute it and/or "; + s += "modify it under the terms of the GNU Affero General Public "; + s += "License as published by the Free Software Foundation, either "; + s += "version 3 of the License, or (at your option) any later version.
"; - s += "This program is distributed in the hope that it will be useful, " - s += "but WITHOUT ANY WARRANTY; without even the implied warranty of " - s += "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the " - s += "GNU Affero General Public License for more details.
" + s += "This program is distributed in the hope that it will be useful, "; + s += "but WITHOUT ANY WARRANTY; without even the implied warranty of "; + s += "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the "; + s += "GNU Affero General Public License for more details.
"; - s += "You should have received a copy of the GNU Affero General " - s += "Public License along with this program. If not, see " - s += "" - s += "https://www.gnu.org/licenses/.
" + s += "You should have received a copy of the GNU Affero General "; + s += "Public License along with this program. If not, see "; + s += ""; + s += "https://www.gnu.org/licenses/.
"; - s += "The source code is available at " - s += "" - s += "https://github.com/plumpudding/hopglass." + s += "
The source code is available at ";
+ s += "";
+ s += "https://github.com/plumpudding/hopglass.";
- el.innerHTML = s
- }
- }
-})
+ el.innerHTML = s;
+ };
+ };
+});
diff --git a/lib/container.js b/lib/container.js
index a33ab75..4f32a84 100644
--- a/lib/container.js
+++ b/lib/container.js
@@ -1,20 +1,21 @@
define([], function () {
return function (tag) {
- if (!tag)
- tag = "div"
+ if (!tag) {
+ tag = "div";
+ }
- var self = this
+ var self = this;
- var container = document.createElement(tag)
+ var container = document.createElement(tag);
self.add = function (d) {
- d.render(container)
- }
+ d.render(container);
+ };
self.render = function (el) {
- el.appendChild(container)
- }
+ el.appendChild(container);
+ };
- return self
- }
-})
+ return self;
+ };
+});
diff --git a/lib/datadistributor.js b/lib/datadistributor.js
index 67cf7eb..3edeaf6 100644
--- a/lib/datadistributor.js
+++ b/lib/datadistributor.js
@@ -1,80 +1,91 @@
define(["filters/nodefilter"], function (NodeFilter) {
return function () {
- var targets = []
- var filterObservers = []
- var filters = []
- var filteredData
- var data
+ var targets = [];
+ var filterObservers = [];
+ var filters = [];
+ var filteredData;
+ var data;
function remove(d) {
- targets = targets.filter( function (e) { return d !== e } )
+ targets = targets.filter(function (e) {
+ return d !== e;
+ });
}
function add(d) {
- targets.push(d)
+ targets.push(d);
- if (filteredData !== undefined)
- d.setData(filteredData)
- }
-
- function setData(d) {
- data = d
- refresh()
- }
-
- function refresh() {
- if (data === undefined)
- return
-
- var filter = filters.reduce( function (a, f) {
- return function (d) {
- return a(d) && f.run(d)
- }
- }, function () { return true })
-
- filteredData = new NodeFilter(filter)(data)
-
- targets.forEach( function (t) {
- t.setData(filteredData)
- })
- }
-
- function notifyObservers() {
- filterObservers.forEach( function (d) {
- d.filtersChanged(filters)
- })
- }
-
- function addFilter(d) {
- filters.push(d)
- notifyObservers()
- d.setRefresh(refresh)
- refresh()
- }
-
- function removeFilter(d) {
- filters = filters.filter( function (e) { return d !== e } )
- notifyObservers()
- refresh()
- }
-
- function watchFilters(d) {
- filterObservers.push(d)
-
- d.filtersChanged(filters)
-
- return function () {
- filterObservers = filterObservers.filter( function (e) { return d !== e })
+ if (filteredData !== undefined) {
+ d.setData(filteredData);
}
}
- return { add: add,
- remove: remove,
- setData: setData,
- addFilter: addFilter,
- removeFilter: removeFilter,
- watchFilters: watchFilters,
- refresh: refresh
- }
- }
-})
+ function setData(d) {
+ data = d;
+ refresh();
+ }
+
+ function refresh() {
+ if (data === undefined) {
+ return;
+ }
+
+ var filter = filters.reduce(function (a, f) {
+ return function (d) {
+ return a(d) && f.run(d);
+ };
+ }, function () {
+ return true;
+ });
+
+ filteredData = new NodeFilter(filter)(data);
+
+ targets.forEach(function (t) {
+ t.setData(filteredData);
+ });
+ }
+
+ function notifyObservers() {
+ filterObservers.forEach(function (d) {
+ d.filtersChanged(filters);
+ });
+ }
+
+ function addFilter(d) {
+ filters.push(d);
+ notifyObservers();
+ d.setRefresh(refresh);
+ refresh();
+ }
+
+ function removeFilter(d) {
+ filters = filters.filter(function (e) {
+ return d !== e;
+ });
+ notifyObservers();
+ refresh();
+ }
+
+ function watchFilters(d) {
+ filterObservers.push(d);
+
+ d.filtersChanged(filters);
+
+ return function () {
+ filterObservers = filterObservers.filter(function (e) {
+ return d !== e;
+ });
+ };
+ }
+
+ return {
+ add: add,
+ remove: remove,
+ setData: setData,
+ addFilter: addFilter,
+ removeFilter: removeFilter,
+ watchFilters: watchFilters,
+ refresh: refresh
+ };
+ };
+});
diff --git a/lib/filters/filtergui.js b/lib/filters/filtergui.js
index f6c6dac..10629d7 100644
--- a/lib/filters/filtergui.js
+++ b/lib/filters/filtergui.js
@@ -1,40 +1,43 @@
define([], function () {
return function (distributor) {
- var container = document.createElement("ul")
- container.classList.add("filters")
- var div = document.createElement("div")
+ var container = document.createElement("ul");
+ container.classList.add("filters");
+ var div = document.createElement("div");
function render(el) {
- el.appendChild(div)
+ el.appendChild(div);
}
function filtersChanged(filters) {
- while (container.firstChild)
- container.removeChild(container.firstChild)
+ while (container.firstChild) {
+ container.removeChild(container.firstChild);
+ }
- filters.forEach( function (d) {
- var li = document.createElement("li")
- var div = document.createElement("div")
- container.appendChild(li)
- li.appendChild(div)
- d.render(div)
+ filters.forEach(function (d) {
+ var li = document.createElement("li");
+ var div = document.createElement("div");
+ container.appendChild(li);
+ li.appendChild(div);
+ d.render(div);
- var button = document.createElement("button")
- button.textContent = ""
+ var button = document.createElement("button");
+ button.textContent = "";
button.onclick = function () {
- distributor.removeFilter(d)
- }
- li.appendChild(button)
- })
+ distributor.removeFilter(d);
+ };
+ li.appendChild(button);
+ });
- if (container.parentNode === div && filters.length === 0)
- div.removeChild(container)
- else if (filters.length > 0)
- div.appendChild(container)
+ if (container.parentNode === div && filters.length === 0) {
+ div.removeChild(container);
+ } else if (filters.length > 0) {
+ div.appendChild(container);
+ }
}
- return { render: render,
- filtersChanged: filtersChanged
- }
- }
-})
+ return {
+ render: render,
+ filtersChanged: filtersChanged
+ };
+ };
+});
diff --git a/lib/filters/genericnode.js b/lib/filters/genericnode.js
index 4c2a09d..831f575 100644
--- a/lib/filters/genericnode.js
+++ b/lib/filters/genericnode.js
@@ -1,52 +1,56 @@
define([], function () {
return function (name, key, value, f) {
- var negate = false
- var refresh
+ var negate = false;
+ var refresh;
- var label = document.createElement("label")
- var strong = document.createElement("strong")
- label.textContent = name + " "
- label.appendChild(strong)
+ var label = document.createElement("label");
+ var strong = document.createElement("strong");
+ label.textContent = name + " ";
+ label.appendChild(strong);
function run(d) {
- var o = dictGet(d, key.slice(0))
+ var o = dictGet(d, key.slice(0));
- if (f)
- o = f(o)
+ if (f) {
+ o = f(o);
+ }
- return o === value ? !negate : negate
+ return o === value ? !negate : negate;
}
function setRefresh(f) {
- refresh = f
+ refresh = f;
}
function draw(el) {
- if (negate)
- el.parentNode.classList.add("not")
- else
- el.parentNode.classList.remove("not")
+ if (negate) {
+ el.parentNode.classList.add("not");
+ } else {
+ el.parentNode.classList.remove("not");
+ }
- strong.textContent = (negate ? "¬" : "" ) + value
+ strong.textContent = (negate ? "¬" : "" ) + value;
}
function render(el) {
- el.appendChild(label)
- draw(el)
+ el.appendChild(label);
+ draw(el);
label.onclick = function () {
- negate = !negate
+ negate = !negate;
- draw(el)
+ draw(el);
- if (refresh)
- refresh()
- }
+ if (refresh) {
+ refresh();
+ }
+ };
}
- return { run: run,
- setRefresh: setRefresh,
- render: render
- }
- }
-})
+ return {
+ run: run,
+ setRefresh: setRefresh,
+ render: render
+ };
+ };
+});
diff --git a/lib/filters/nodefilter.js b/lib/filters/nodefilter.js
index 17e6b41..1d6bf5f 100644
--- a/lib/filters/nodefilter.js
+++ b/lib/filters/nodefilter.js
@@ -1,33 +1,36 @@
define([], function () {
return function (filter) {
return function (data) {
- var n = Object.create(data)
- n.nodes = {}
+ var n = Object.create(data);
+ n.nodes = {};
- for (var key in data.nodes)
- n.nodes[key] = data.nodes[key].filter(filter)
+ for (var key in data.nodes) {
+ n.nodes[key] = data.nodes[key].filter(filter);
+ }
- var filteredIds = new Set()
+ var filteredIds = new Set();
- n.graph = {}
- n.graph.nodes = data.graph.nodes.filter( function (d) {
- var r
- if (d.node)
- r = filter(d.node)
- else
- r = filter({})
+ n.graph = {};
+ n.graph.nodes = data.graph.nodes.filter(function (d) {
+ var r;
+ if (d.node) {
+ r = filter(d.node);
+ } else {
+ r = filter({});
+ }
- if (r)
- filteredIds.add(d.id)
+ if (r) {
+ filteredIds.add(d.id);
+ }
- return r
- })
+ return r;
+ });
- n.graph.links = data.graph.links.filter( function (d) {
- return filteredIds.has(d.source.id) && filteredIds.has(d.target.id)
- })
+ n.graph.links = data.graph.links.filter(function (d) {
+ return filteredIds.has(d.source.id) && filteredIds.has(d.target.id);
+ });
- return n
- }
- }
-})
+ return n;
+ };
+ };
+});
diff --git a/lib/forcegraph.js b/lib/forcegraph.js
index 992f1b9..b9a998c 100644
--- a/lib/forcegraph.js
+++ b/lib/forcegraph.js
@@ -1,792 +1,844 @@
define(["d3"], function (d3) {
- var margin = 200
- var NODE_RADIUS = 15
- var LINE_RADIUS = 7
+ var margin = 200;
+ var NODE_RADIUS = 15;
+ var LINE_RADIUS = 7;
return function (config, linkScale, sidebar, router) {
- var self = this
- var canvas, ctx, screenRect
- var nodesDict, linksDict
- var zoomBehavior
- var force
- var el
- var doAnimation = false
- var intNodes = []
- var intLinks = []
- var highlight
- var highlightedNodes = []
- var highlightedLinks = []
- var nodes = []
- var uplinkNodes = []
- var nonUplinkNodes = []
- var unseenNodes = []
- var unknownNodes = []
- var savedPanZoom
+ var self = this;
+ var canvas, ctx, screenRect;
+ var nodesDict, linksDict;
+ var zoomBehavior;
+ var force;
+ var el;
+ var doAnimation = false;
+ var intNodes = [];
+ var intLinks = [];
+ var highlight;
+ var highlightedNodes = [];
+ var highlightedLinks = [];
+ var nodes = [];
+ var uplinkNodes = [];
+ var nonUplinkNodes = [];
+ var unseenNodes = [];
+ var unknownNodes = [];
+ var savedPanZoom;
- var draggedNode
+ var draggedNode;
- var LINK_DISTANCE = 70
+ var LINK_DISTANCE = 70;
function graphDiameter(nodes) {
- return Math.sqrt(nodes.length / Math.PI) * LINK_DISTANCE * 1.41
+ return Math.sqrt(nodes.length / Math.PI) * LINK_DISTANCE * 1.41;
}
function savePositions() {
- if (!localStorageTest())
- return
+ if (!localStorageTest()) {
+ return;
+ }
- var save = intNodes.map( function (d) {
- return { id: d.o.id, x: d.x, y: d.y }
- })
+ var save = intNodes.map(function (d) {
+ return {id: d.o.id, x: d.x, y: d.y};
+ });
- localStorage.setItem("graph/nodeposition", JSON.stringify(save))
+ localStorage.setItem("graph/nodeposition", JSON.stringify(save));
}
function nodeName(d) {
- if (d.o.node && d.o.node.nodeinfo)
- return d.o.node.nodeinfo.hostname
- else
- return d.o.id
+ if (d.o.node && d.o.node.nodeinfo) {
+ return d.o.node.nodeinfo.hostname;
+ } else {
+ return d.o.id;
+ }
}
function dragstart() {
- var e = translateXY(d3.mouse(el))
+ var e = translateXY(d3.mouse(el));
var nodes = intNodes.filter(function (d) {
- return distancePoint(e, d) < NODE_RADIUS
- })
+ return distancePoint(e, d) < NODE_RADIUS;
+ });
- if (nodes.length === 0)
- return
+ if (nodes.length === 0) {
+ return;
+ }
- draggedNode = nodes[0]
- d3.event.sourceEvent.stopPropagation()
- d3.event.sourceEvent.preventDefault()
- draggedNode.fixed |= 2
+ draggedNode = nodes[0];
+ d3.event.sourceEvent.stopPropagation();
+ d3.event.sourceEvent.preventDefault();
+ draggedNode.fixed |= 2;
- draggedNode.px = draggedNode.x
- draggedNode.py = draggedNode.y
+ draggedNode.px = draggedNode.x;
+ draggedNode.py = draggedNode.y;
}
function dragmove() {
if (draggedNode) {
- var e = translateXY(d3.mouse(el))
+ var e = translateXY(d3.mouse(el));
- draggedNode.px = e.x
- draggedNode.py = e.y
- force.resume()
+ draggedNode.px = e.x;
+ draggedNode.py = e.y;
+ force.resume();
}
}
function dragend() {
if (draggedNode) {
- d3.event.sourceEvent.stopPropagation()
- d3.event.sourceEvent.preventDefault()
- draggedNode.fixed &= ~2
- draggedNode = undefined
+ d3.event.sourceEvent.stopPropagation();
+ d3.event.sourceEvent.preventDefault();
+ draggedNode.fixed &= ~2;
+ draggedNode = undefined;
}
}
var draggableNode = d3.behavior.drag()
- .on("dragstart", dragstart)
- .on("drag", dragmove)
- .on("dragend", dragend)
+ .on("dragstart", dragstart)
+ .on("drag", dragmove)
+ .on("dragend", dragend);
function animatePanzoom(translate, scale) {
- var translateP = zoomBehavior.translate()
- var scaleP = zoomBehavior.scale()
+ var translateP = zoomBehavior.translate();
+ var scaleP = zoomBehavior.scale();
if (!doAnimation) {
- zoomBehavior.translate(translate)
- zoomBehavior.scale(scale)
- panzoom()
+ zoomBehavior.translate(translate);
+ zoomBehavior.scale(scale);
+ panzoom();
} else {
- var start = {x: translateP[0], y: translateP[1], scale: scaleP}
- var end = {x: translate[0], y: translate[1], scale: scale}
+ var start = {x: translateP[0], y: translateP[1], scale: scaleP};
+ var end = {x: translate[0], y: translate[1], scale: scale};
- var interpolate = d3.interpolateObject(start, end)
- var duration = 500
+ var interpolate = d3.interpolateObject(start, end);
+ var duration = 500;
- var ease = d3.ease("cubic-in-out")
+ var ease = d3.ease("cubic-in-out");
d3.timer(function (t) {
- if (t >= duration)
- return true
+ if (t >= duration) {
+ return true;
+ }
- var v = interpolate(ease(t / duration))
- zoomBehavior.translate([v.x, v.y])
- zoomBehavior.scale(v.scale)
- panzoom()
+ var v = interpolate(ease(t / duration));
+ zoomBehavior.translate([v.x, v.y]);
+ zoomBehavior.scale(v.scale);
+ panzoom();
- return false
- })
+ return false;
+ });
}
}
function onPanZoom() {
- savedPanZoom = {translate: zoomBehavior.translate(),
- scale: zoomBehavior.scale()}
- panzoom()
+ savedPanZoom = {
+ translate: zoomBehavior.translate(),
+ scale: zoomBehavior.scale()
+ };
+ panzoom();
}
function panzoom() {
- var translate = zoomBehavior.translate()
- var scale = zoomBehavior.scale()
+ var translate = zoomBehavior.translate();
+ var scale = zoomBehavior.scale();
- panzoomReal(translate, scale)
+ panzoomReal(translate, scale);
}
function panzoomReal(translate, scale) {
- screenRect = {left: -translate[0] / scale, top: -translate[1] / scale,
- right: (canvas.width - translate[0]) / scale,
- bottom: (canvas.height - translate[1]) / scale}
+ screenRect = {
+ left: -translate[0] / scale, top: -translate[1] / scale,
+ right: (canvas.width - translate[0]) / scale,
+ bottom: (canvas.height - translate[1]) / scale
+ };
- requestAnimationFrame(redraw)
+ requestAnimationFrame(redraw);
}
function getSize() {
- var sidebarWidth = sidebar()
- var width = el.offsetWidth - sidebarWidth
- var height = el.offsetHeight
+ var sidebarWidth = sidebar();
+ var width = el.offsetWidth - sidebarWidth;
+ var height = el.offsetHeight;
- return [width, height]
+ return [width, height];
}
function panzoomTo(a, b) {
- var sidebarWidth = sidebar()
- var size = getSize()
+ var sidebarWidth = sidebar();
+ var size = getSize();
- var targetWidth = Math.max(1, b[0] - a[0])
- var targetHeight = Math.max(1, b[1] - a[1])
+ var targetWidth = Math.max(1, b[0] - a[0]);
+ var targetHeight = Math.max(1, b[1] - a[1]);
- var scaleX = size[0] / targetWidth
- var scaleY = size[1] / targetHeight
- var scaleMax = zoomBehavior.scaleExtent()[1]
- var scale = 0.5 * Math.min(scaleMax, Math.min(scaleX, scaleY))
+ var scaleX = size[0] / targetWidth;
+ var scaleY = size[1] / targetHeight;
+ var scaleMax = zoomBehavior.scaleExtent()[1];
+ var scale = 0.5 * Math.min(scaleMax, Math.min(scaleX, scaleY));
- var centroid = [(a[0] + b[0]) / 2, (a[1] + b[1]) / 2]
- var x = -centroid[0] * scale + size[0] / 2
- var y = -centroid[1] * scale + size[1] / 2
- var translate = [x + sidebarWidth, y]
+ var centroid = [(a[0] + b[0]) / 2, (a[1] + b[1]) / 2];
+ var x = -centroid[0] * scale + size[0] / 2;
+ var y = -centroid[1] * scale + size[1] / 2;
+ var translate = [x + sidebarWidth, y];
- animatePanzoom(translate, scale)
+ animatePanzoom(translate, scale);
}
function updateHighlight(nopanzoom) {
- highlightedNodes = []
- highlightedLinks = []
+ highlightedNodes = [];
+ highlightedLinks = [];
- if (highlight !== undefined)
+ if (highlight !== undefined) {
if (highlight.type === "node") {
- var n = nodesDict[highlight.o.nodeinfo.node_id]
+ var n = nodesDict[highlight.o.nodeinfo.node_id];
if (n) {
- highlightedNodes = [n]
-
- if (!nopanzoom)
- panzoomTo([n.x, n.y], [n.x, n.y])
- }
-
- return
- } else if (highlight.type === "link") {
- var l = linksDict[highlight.o.id]
-
- if (l) {
- highlightedLinks = [l]
+ highlightedNodes = [n];
if (!nopanzoom) {
- var x = d3.extent([l.source, l.target], function (d) { return d.x })
- var y = d3.extent([l.source, l.target], function (d) { return d.y })
- panzoomTo([x[0], y[0]], [x[1], y[1]])
+ panzoomTo([n.x, n.y], [n.x, n.y]);
}
}
- return
- }
+ return;
+ } else if (highlight.type === "link") {
+ var l = linksDict[highlight.o.id];
- if (!nopanzoom)
- if (!savedPanZoom)
- panzoomTo([0, 0], force.size())
- else
- animatePanzoom(savedPanZoom.translate, savedPanZoom.scale)
+ if (l) {
+ highlightedLinks = [l];
+
+ if (!nopanzoom) {
+ var x = d3.extent([l.source, l.target], function (d) {
+ return d.x;
+ });
+ var y = d3.extent([l.source, l.target], function (d) {
+ return d.y;
+ });
+ panzoomTo([x[0], y[0]], [x[1], y[1]]);
+ }
+ }
+
+ return;
+ }
+ }
+
+ if (!nopanzoom) {
+ if (!savedPanZoom) {
+ panzoomTo([0, 0], force.size());
+ } else {
+ animatePanzoom(savedPanZoom.translate, savedPanZoom.scale);
+ }
+ }
}
function drawLabel(d) {
var neighbours = d.neighbours.filter(function (d) {
- return !d.link.o.isVPN
- })
+ return !d.link.o.isVPN;
+ });
var sum = neighbours.reduce(function (a, b) {
- return [a[0] + b.node.x, a[1] + b.node.y]
- }, [0, 0])
+ return [a[0] + b.node.x, a[1] + b.node.y];
+ }, [0, 0]);
- var sumCos = sum[0] - d.x * neighbours.length
- var sumSin = sum[1] - d.y * neighbours.length
+ var sumCos = sum[0] - d.x * neighbours.length;
+ var sumSin = sum[1] - d.y * neighbours.length;
- var angle = Math.PI / 2
+ var angle = Math.PI / 2;
- if (neighbours.length > 0)
- angle = Math.PI + Math.atan2(sumSin, sumCos)
+ if (neighbours.length > 0) {
+ angle = Math.PI + Math.atan2(sumSin, sumCos);
+ }
- var cos = Math.cos(angle)
- var sin = Math.sin(angle)
+ var cos = Math.cos(angle);
+ var sin = Math.sin(angle);
- var width = d.labelWidth
- var height = d.labelHeight
+ var width = d.labelWidth;
+ var height = d.labelHeight;
- var x = d.x + d.labelA * Math.pow(Math.abs(cos), 2 / 5) * Math.sign(cos) - width / 2
- var y = d.y + d.labelB * Math.pow(Math.abs(sin), 2 / 5) * Math.sign(sin) - height / 2
+ var x = d.x + d.labelA * Math.pow(Math.abs(cos), 2 / 5) * Math.sign(cos) - width / 2;
+ var y = d.y + d.labelB * Math.pow(Math.abs(sin), 2 / 5) * Math.sign(sin) - height / 2;
- ctx.drawImage(d.label, x, y, width, height)
+ ctx.drawImage(d.label, x, y, width, height);
}
function visibleLinks(d) {
return (d.o.isVPN ||
- d.source.x > screenRect.left && d.source.x < screenRect.right &&
- d.source.y > screenRect.top && d.source.y < screenRect.bottom) ||
- (d.target.x > screenRect.left && d.target.x < screenRect.right &&
- d.target.y > screenRect.top && d.target.y < screenRect.bottom)
+ d.source.x > screenRect.left && d.source.x < screenRect.right &&
+ d.source.y > screenRect.top && d.source.y < screenRect.bottom) ||
+ (d.target.x > screenRect.left && d.target.x < screenRect.right &&
+ d.target.y > screenRect.top && d.target.y < screenRect.bottom);
}
function visibleNodes(d) {
return d.x + margin > screenRect.left && d.x - margin < screenRect.right &&
- d.y + margin > screenRect.top && d.y - margin < screenRect.bottom
+ d.y + margin > screenRect.top && d.y - margin < screenRect.bottom;
}
function drawNode(color, radius, scale, r) {
- var node = document.createElement("canvas")
- node.width = scale * radius * 8 * r
- node.height = node.width
+ var node = document.createElement("canvas");
+ node.width = scale * radius * 8 * r;
+ node.height = node.width;
- var nctx = node.getContext("2d")
- nctx.scale(scale * r, scale * r)
- nctx.save()
+ var nctx = node.getContext("2d");
+ nctx.scale(scale * r, scale * r);
+ nctx.save();
- nctx.translate(-node.width / scale, -node.height / scale)
- nctx.lineWidth = radius
+ nctx.translate(-node.width / scale, -node.height / scale);
+ nctx.lineWidth = radius;
- nctx.beginPath()
- nctx.moveTo(radius, 0)
- nctx.arc(0, 0, radius, 0, 2 * Math.PI)
+ nctx.beginPath();
+ nctx.moveTo(radius, 0);
+ nctx.arc(0, 0, radius, 0, 2 * Math.PI);
- nctx.strokeStyle = "rgba(255, 0, 0, 1)"
- nctx.shadowOffsetX = node.width * 1.5 + 0
- nctx.shadowOffsetY = node.height * 1.5 + 3
- nctx.shadowBlur = 12
- nctx.shadowColor = "rgba(0, 0, 0, 0.16)"
- nctx.stroke()
- nctx.shadowOffsetX = node.width * 1.5 + 0
- nctx.shadowOffsetY = node.height * 1.5 + 3
- nctx.shadowBlur = 12
- nctx.shadowColor = "rgba(0, 0, 0, 0.23)"
- nctx.stroke()
+ nctx.strokeStyle = "rgba(255, 0, 0, 1)";
+ nctx.shadowOffsetX = node.width * 1.5 + 0;
+ nctx.shadowOffsetY = node.height * 1.5 + 3;
+ nctx.shadowBlur = 12;
+ nctx.shadowColor = "rgba(0, 0, 0, 0.16)";
+ nctx.stroke();
+ nctx.shadowOffsetX = node.width * 1.5 + 0;
+ nctx.shadowOffsetY = node.height * 1.5 + 3;
+ nctx.shadowBlur = 12;
+ nctx.shadowColor = "rgba(0, 0, 0, 0.23)";
+ nctx.stroke();
- nctx.restore()
- nctx.translate(node.width / 2 / scale / r, node.height / 2 / scale / r)
+ nctx.restore();
+ nctx.translate(node.width / 2 / scale / r, node.height / 2 / scale / r);
- nctx.beginPath()
- nctx.moveTo(radius, 0)
- nctx.arc(0, 0, radius, 0, 2 * Math.PI)
+ nctx.beginPath();
+ nctx.moveTo(radius, 0);
+ nctx.arc(0, 0, radius, 0, 2 * Math.PI);
- nctx.strokeStyle = color
- nctx.lineWidth = radius
- nctx.stroke()
+ nctx.strokeStyle = color;
+ nctx.lineWidth = radius;
+ nctx.stroke();
- return node
+ return node;
}
function redraw() {
- var r = window.devicePixelRatio
- var translate = zoomBehavior.translate()
- var scale = zoomBehavior.scale()
- var links = intLinks.filter(visibleLinks)
+ var r = window.devicePixelRatio;
+ var translate = zoomBehavior.translate();
+ var scale = zoomBehavior.scale();
+ var links = intLinks.filter(visibleLinks);
- ctx.save()
- ctx.setTransform(1, 0, 0, 1, 0, 0)
- ctx.clearRect(0, 0, canvas.width, canvas.height)
- ctx.restore()
+ ctx.save();
+ ctx.setTransform(1, 0, 0, 1, 0, 0);
+ ctx.clearRect(0, 0, canvas.width, canvas.height);
+ ctx.restore();
- ctx.save()
- ctx.translate(translate[0], translate[1])
- ctx.scale(scale, scale)
+ ctx.save();
+ ctx.translate(translate[0], translate[1]);
+ ctx.scale(scale, scale);
- var clientColor = "rgba(230, 50, 75, 1.0)"
- var unknownColor = "#D10E2A"
- var nonUplinkColor = "#F2E3C6"
- var uplinkColor = "#5BAAEB"
- var unseenColor = "#FFA726"
- var highlightColor = "rgba(252, 227, 198, 0.15)"
- var nodeRadius = 6
- var cableColor = "#50B0F0"
+ var clientColor = "rgba(230, 50, 75, 1.0)";
+ var unknownColor = "#D10E2A";
+ var nonUplinkColor = "#F2E3C6";
+ var uplinkColor = "#5BAAEB";
+ var unseenColor = "#FFA726";
+ var highlightColor = "rgba(252, 227, 198, 0.15)";
+ var nodeRadius = 6;
+ var cableColor = "#50B0F0";
// -- draw links --
- ctx.save()
+ ctx.save();
links.forEach(function (d) {
- var dx = d.target.x - d.source.x
- var dy = d.target.y - d.source.y
- var a = Math.sqrt(dx * dx + dy * dy) * 2
- dx /= a
- dy /= a
+ var dx = d.target.x - d.source.x;
+ var dy = d.target.y - d.source.y;
+ var a = Math.sqrt(dx * dx + dy * dy) * 2;
+ dx /= a;
+ dy /= a;
- var distancex = d.target.x - d.source.x - (10 * dx)
- var distancey = d.target.y - d.source.y - (10 * dy)
+ var distancex = d.target.x - d.source.x - (10 * dx);
+ var distancey = d.target.y - d.source.y - (10 * dy);
- ctx.beginPath()
- ctx.moveTo(d.source.x + dx * nodeRadius, d.source.y + dy * nodeRadius)
- ctx.lineTo(d.target.x - (distancex / 2) - dx * nodeRadius, d.target.y - (distancey / 2) - dy * nodeRadius)
- ctx.strokeStyle = d.o.type === "Kabel" ? cableColor : d.color
- ctx.globalAlpha = d.o.isVPN ? 0.1 : 0.8
- ctx.lineWidth = d.o.isVPN ? 1.5 : 2.5
- ctx.stroke()
- })
+ ctx.beginPath();
+ ctx.moveTo(d.source.x + dx * nodeRadius, d.source.y + dy * nodeRadius);
+ ctx.lineTo(d.target.x - (distancex / 2) - dx * nodeRadius, d.target.y - (distancey / 2) - dy * nodeRadius);
+ ctx.strokeStyle = d.o.type === "Kabel" ? cableColor : d.color;
+ ctx.globalAlpha = d.o.isVPN ? 0.1 : 0.8;
+ ctx.lineWidth = d.o.isVPN ? 1.5 : 2.5;
+ ctx.stroke();
+ });
- ctx.restore()
+ ctx.restore();
// -- draw unknown nodes --
- ctx.beginPath()
+ ctx.beginPath();
unknownNodes.filter(visibleNodes).forEach(function (d) {
- ctx.moveTo(d.x + nodeRadius, d.y)
- ctx.arc(d.x, d.y, nodeRadius, 0, 2 * Math.PI)
- })
+ ctx.moveTo(d.x + nodeRadius, d.y);
+ ctx.arc(d.x, d.y, nodeRadius, 0, 2 * Math.PI);
+ });
- ctx.strokeStyle = unknownColor
- ctx.lineWidth = nodeRadius
+ ctx.strokeStyle = unknownColor;
+ ctx.lineWidth = nodeRadius;
- ctx.stroke()
+ ctx.stroke();
// -- draw nodes --
- ctx.save()
- ctx.scale(1 / scale / r, 1 / scale / r)
+ ctx.save();
+ ctx.scale(1 / scale / r, 1 / scale / r);
- var nonUplinkNode = drawNode(nonUplinkColor, nodeRadius, scale, r)
+ var nonUplinkNode = drawNode(nonUplinkColor, nodeRadius, scale, r);
nonUplinkNodes.filter(visibleNodes).forEach(function (d) {
- ctx.drawImage(nonUplinkNode, scale * r * d.x - nonUplinkNode.width / 2, scale * r * d.y - nonUplinkNode.height / 2)
- })
+ ctx.drawImage(nonUplinkNode, scale * r * d.x - nonUplinkNode.width / 2, scale * r * d.y - nonUplinkNode.height / 2);
+ });
- var uplinkNode = drawNode(uplinkColor, nodeRadius, scale, r)
+ var uplinkNode = drawNode(uplinkColor, nodeRadius, scale, r);
uplinkNodes.filter(visibleNodes).forEach(function (d) {
- ctx.drawImage(uplinkNode, scale * r * d.x - uplinkNode.width / 2, scale * r * d.y - uplinkNode.height / 2)
- })
+ ctx.drawImage(uplinkNode, scale * r * d.x - uplinkNode.width / 2, scale * r * d.y - uplinkNode.height / 2);
+ });
- var unseenNode = drawNode(unseenColor, nodeRadius, scale, r)
+ var unseenNode = drawNode(unseenColor, nodeRadius, scale, r);
unseenNodes.filter(visibleNodes).forEach(function (d) {
- ctx.drawImage(unseenNode, scale * r * d.x - unseenNode.width / 2, scale * r * d.y - unseenNode.height / 2)
- })
+ ctx.drawImage(unseenNode, scale * r * d.x - unseenNode.width / 2, scale * r * d.y - unseenNode.height / 2);
+ });
- ctx.restore()
+ ctx.restore();
// -- draw clients --
- ctx.save()
- ctx.beginPath()
- if (scale > 0.9)
+ ctx.save();
+ ctx.beginPath();
+ if (scale > 0.9) {
nodes.filter(visibleNodes).forEach(function (d) {
- var clients = d.o.node.statistics.clients
- if (clients === 0)
- return
+ var clients = d.o.node.statistics.clients;
+ if (clients === 0) {
+ return;
+ }
- var startDistance = 16
- var radius = 3
- var a = 1.2
- var startAngle = Math.PI
+ var startDistance = 16;
+ var radius = 3;
+ var a = 1.2;
+ var startAngle = Math.PI;
for (var orbit = 0, i = 0; i < clients; orbit++) {
- var distance = startDistance + orbit * 2 * radius * a
- var n = Math.floor((Math.PI * distance) / (a * radius))
- var delta = clients - i
+ var distance = startDistance + orbit * 2 * radius * a;
+ var n = Math.floor((Math.PI * distance) / (a * radius));
+ var delta = clients - i;
for (var j = 0; j < Math.min(delta, n); i++, j++) {
- var angle = 2 * Math.PI / n * j
- var x = d.x + distance * Math.cos(angle + startAngle)
- var y = d.y + distance * Math.sin(angle + startAngle)
+ var angle = 2 * Math.PI / n * j;
+ var x = d.x + distance * Math.cos(angle + startAngle);
+ var y = d.y + distance * Math.sin(angle + startAngle);
- ctx.moveTo(x, y)
- ctx.arc(x, y, radius, 0, 2 * Math.PI)
+ ctx.moveTo(x, y);
+ ctx.arc(x, y, radius, 0, 2 * Math.PI);
}
}
- })
+ });
+ }
- ctx.fillStyle = clientColor
- ctx.fill()
- ctx.restore()
+ ctx.fillStyle = clientColor;
+ ctx.fill();
+ ctx.restore();
// -- draw node highlights --
if (highlightedNodes.length) {
- ctx.save()
- ctx.shadowColor = "rgba(255, 255, 255, 1.0)"
- ctx.shadowBlur = 10 * nodeRadius
- ctx.shadowOffsetX = 0
- ctx.shadowOffsetY = 0
- ctx.globalCompositeOperation = "lighten"
- ctx.fillStyle = highlightColor
+ ctx.save();
+ ctx.shadowColor = "rgba(255, 255, 255, 1.0)";
+ ctx.shadowBlur = 10 * nodeRadius;
+ ctx.shadowOffsetX = 0;
+ ctx.shadowOffsetY = 0;
+ ctx.globalCompositeOperation = "lighten";
+ ctx.fillStyle = highlightColor;
- ctx.beginPath()
+ ctx.beginPath();
highlightedNodes.forEach(function (d) {
- ctx.moveTo(d.x + 5 * nodeRadius, d.y)
- ctx.arc(d.x, d.y, 5 * nodeRadius, 0, 2 * Math.PI)
- })
- ctx.fill()
+ ctx.moveTo(d.x + 5 * nodeRadius, d.y);
+ ctx.arc(d.x, d.y, 5 * nodeRadius, 0, 2 * Math.PI);
+ });
+ ctx.fill();
- ctx.restore()
+ ctx.restore();
}
// -- draw link highlights --
if (highlightedLinks.length) {
- ctx.save()
- ctx.lineWidth = 2 * 5 * nodeRadius
- ctx.shadowColor = "rgba(255, 255, 255, 1.0)"
- ctx.shadowBlur = 10 * nodeRadius
- ctx.shadowOffsetX = 0
- ctx.shadowOffsetY = 0
- ctx.globalCompositeOperation = "lighten"
- ctx.strokeStyle = highlightColor
- ctx.lineCap = "round"
+ ctx.save();
+ ctx.lineWidth = 2 * 5 * nodeRadius;
+ ctx.shadowColor = "rgba(255, 255, 255, 1.0)";
+ ctx.shadowBlur = 10 * nodeRadius;
+ ctx.shadowOffsetX = 0;
+ ctx.shadowOffsetY = 0;
+ ctx.globalCompositeOperation = "lighten";
+ ctx.strokeStyle = highlightColor;
+ ctx.lineCap = "round";
- ctx.beginPath()
+ ctx.beginPath();
highlightedLinks.forEach(function (d) {
- ctx.moveTo(d.source.x, d.source.y)
- ctx.lineTo(d.target.x, d.target.y)
- })
- ctx.stroke()
+ ctx.moveTo(d.source.x, d.source.y);
+ ctx.lineTo(d.target.x, d.target.y);
+ });
+ ctx.stroke();
- ctx.restore()
+ ctx.restore();
}
// -- draw labels --
- if (scale > 0.9)
- intNodes.filter(visibleNodes).forEach(drawLabel, scale)
+ if (scale > 0.9) {
+ intNodes.filter(visibleNodes).forEach(drawLabel, scale);
+ }
- ctx.restore()
+ ctx.restore();
}
function tickEvent() {
- redraw()
+ redraw();
}
function resizeCanvas() {
- var r = window.devicePixelRatio
- canvas.width = el.offsetWidth * r
- canvas.height = el.offsetHeight * r
- canvas.style.width = el.offsetWidth + "px"
- canvas.style.height = el.offsetHeight + "px"
- ctx.setTransform(1, 0, 0, 1, 0, 0)
- ctx.scale(r, r)
- requestAnimationFrame(redraw)
+ var r = window.devicePixelRatio;
+ canvas.width = el.offsetWidth * r;
+ canvas.height = el.offsetHeight * r;
+ canvas.style.width = el.offsetWidth + "px";
+ canvas.style.height = el.offsetHeight + "px";
+ ctx.setTransform(1, 0, 0, 1, 0, 0);
+ ctx.scale(r, r);
+ requestAnimationFrame(redraw);
}
function distance(ax, ay, bx, by) {
- return Math.pow(ax - bx, 2) + Math.pow(ay - by, 2)
+ return Math.pow(ax - bx, 2) + Math.pow(ay - by, 2);
}
function distancePoint(a, b) {
- return Math.sqrt(distance(a.x, a.y, b.x, b.y))
+ return Math.sqrt(distance(a.x, a.y, b.x, b.y));
}
function distanceLink(p, a, b) {
/* http://stackoverflow.com/questions/849211 */
- var bx = b.x - ((b.x - a.x) / 2)
- var by = b.y - ((b.y - a.y) / 2)
+ var bx = b.x - ((b.x - a.x) / 2);
+ var by = b.y - ((b.y - a.y) / 2);
- var l2 = distance(a.x, a.y, bx, by)
+ var l2 = distance(a.x, a.y, bx, by);
- if (l2 === 0)
- return distance(p.x, p.y, a.x, a.y)
+ if (l2 === 0) {
+ return distance(p.x, p.y, a.x, a.y);
+ }
- var t = ((p.x - a.x) * (bx - a.x) + (p.y - a.y) * (by - a.y)) / l2
+ var t = ((p.x - a.x) * (bx - a.x) + (p.y - a.y) * (by - a.y)) / l2;
- if (t < 0)
- return distance(p.x, p.y, a.x, a.y)
+ if (t < 0) {
+ return distance(p.x, p.y, a.x, a.y);
+ }
- if (t > 1)
- return distance(p.x, p.y, bx, by)
+ if (t > 1) {
+ return distance(p.x, p.y, bx, by);
+ }
- return Math.sqrt(distance(p.x, p.y, a.x + t * (bx - a.x), a.y + t * (by - a.y) ))
+ return Math.sqrt(distance(p.x, p.y, a.x + t * (bx - a.x), a.y + t * (by - a.y)));
}
function translateXY(d) {
- var translate = zoomBehavior.translate()
- var scale = zoomBehavior.scale()
+ var translate = zoomBehavior.translate();
+ var scale = zoomBehavior.scale();
- return {x: (d[0] - translate[0]) / scale,
- y: (d[1] - translate[1]) / scale
- }
+ return {
+ x: (d[0] - translate[0]) / scale,
+ y: (d[1] - translate[1]) / scale
+ };
}
function onClick() {
- if (d3.event.defaultPrevented)
- return
+ if (d3.event.defaultPrevented) {
+ return;
+ }
- var e = translateXY(d3.mouse(el))
+ var e = translateXY(d3.mouse(el));
var nodes = intNodes.filter(function (d) {
- return distancePoint(e, d) < NODE_RADIUS
- })
+ return distancePoint(e, d) < NODE_RADIUS;
+ });
if (nodes.length > 0) {
- router.node(nodes[0].o.node)()
- return
+ router.node(nodes[0].o.node)();
+ return;
}
var links = intLinks.filter(function (d) {
- return !d.o.isVPN
+ return !d.o.isVPN;
}).filter(function (d) {
- return distanceLink(e, d.source, d.target) < LINE_RADIUS
- })
+ return distanceLink(e, d.source, d.target) < LINE_RADIUS;
+ });
if (links.length > 0) {
- router.link(links[0].o)()
- return
+ router.link(links[0].o)();
+
}
}
function zoom(z, scale) {
- var size = getSize()
- var newSize = [size[0] / scale, size[1] / scale]
+ var size = getSize();
+ var newSize = [size[0] / scale, size[1] / scale];
- var sidebarWidth = sidebar()
- var delta = [size[0] - newSize[0], size[1] - newSize[1]]
- var translate = z.translate()
- var translateNew = [sidebarWidth + (translate[0] - sidebarWidth - delta[0] / 2) * scale, (translate[1] - delta[1] / 2) * scale]
+ var sidebarWidth = sidebar();
+ var delta = [size[0] - newSize[0], size[1] - newSize[1]];
+ var translate = z.translate();
+ var translateNew = [sidebarWidth + (translate[0] - sidebarWidth - delta[0] / 2) * scale, (translate[1] - delta[1] / 2) * scale];
- animatePanzoom(translateNew, z.scale() * scale)
+ animatePanzoom(translateNew, z.scale() * scale);
}
function keyboardZoom(z) {
return function () {
- var e = d3.event
+ var e = d3.event;
- if (e.altKey || e.ctrlKey || e.metaKey)
- return
+ if (e.altKey || e.ctrlKey || e.metaKey) {
+ return;
+ }
- if (e.keyCode === 43)
- zoom(z, 1.41)
+ if (e.keyCode === 43) {
+ zoom(z, 1.41);
+ }
- if (e.keyCode === 45)
- zoom(z, 1 / 1.41)
- }
+ if (e.keyCode === 45) {
+ zoom(z, 1 / 1.41);
+ }
+ };
}
- el = document.createElement("div")
- el.classList.add("graph")
+ el = document.createElement("div");
+ el.classList.add("graph");
zoomBehavior = d3.behavior.zoom()
- .scaleExtent([1 / 3, 3])
- .on("zoom", onPanZoom)
- .translate([sidebar(), 0])
+ .scaleExtent([1 / 3, 3])
+ .on("zoom", onPanZoom)
+ .translate([sidebar(), 0]);
canvas = d3.select(el)
- .attr("tabindex", 1)
- .on("keypress", keyboardZoom(zoomBehavior))
- .call(zoomBehavior)
- .append("canvas")
- .on("click", onClick)
- .call(draggableNode)
- .node()
+ .attr("tabindex", 1)
+ .on("keypress", keyboardZoom(zoomBehavior))
+ .call(zoomBehavior)
+ .append("canvas")
+ .on("click", onClick)
+ .call(draggableNode)
+ .node();
- ctx = canvas.getContext("2d")
+ ctx = canvas.getContext("2d");
force = d3.layout.force()
- .charge(-250)
- .gravity(0.1)
- .linkDistance(function (d) {
- if (d.o.isVPN)
- return 0
- else
- return LINK_DISTANCE
- })
- .linkStrength(function (d) {
- if (d.o.isVPN)
- return 0
- else
- return Math.max(0.5, 1 / d.o.tq)
- })
- .on("tick", tickEvent)
- .on("end", savePositions)
+ .charge(-250)
+ .gravity(0.1)
+ .linkDistance(function (d) {
+ if (d.o.isVPN) {
+ return 0;
+ } else {
+ return LINK_DISTANCE;
+ }
+ })
+ .linkStrength(function (d) {
+ if (d.o.isVPN) {
+ return 0;
+ } else {
+ return Math.max(0.5, 1 / d.o.tq);
+ }
+ })
+ .on("tick", tickEvent)
+ .on("end", savePositions);
- window.addEventListener("resize", resizeCanvas)
+ window.addEventListener("resize", resizeCanvas);
- panzoom()
+ panzoom();
self.setData = function (data) {
- var oldNodes = {}
-
- intNodes.forEach( function (d) {
- oldNodes[d.o.id] = d
- })
-
- intNodes = data.graph.nodes.map( function (d) {
- var e
- if (d.id in oldNodes)
- e = oldNodes[d.id]
- else
- e = {}
-
- e.o = d
-
- return e
- })
-
- var newNodesDict = {}
-
- intNodes.forEach( function (d) {
- newNodesDict[d.o.id] = d
- })
-
- var oldLinks = {}
-
- intLinks.forEach( function (d) {
- oldLinks[d.o.id] = d
- })
-
- intLinks = data.graph.links.map( function (d) {
- var e
- if (d.id in oldLinks)
- e = oldLinks[d.id]
- else
- e = {}
-
- e.o = d
- e.source = newNodesDict[d.source.id]
- e.target = newNodesDict[d.target.id]
-
- if (d.isVPN)
- e.color = "rgba(255, 255, 255, " + (0.6 / d.tq) + ")"
- else
- e.color = linkScale(d.tq).hex()
-
- return e
- })
-
- linksDict = {}
- nodesDict = {}
+ var oldNodes = {};
intNodes.forEach(function (d) {
- d.neighbours = {}
+ oldNodes[d.o.id] = d;
+ });
- if (d.o.node)
- nodesDict[d.o.node.nodeinfo.node_id] = d
+ intNodes = data.graph.nodes.map(function (d) {
+ var e;
+ if (d.id in oldNodes) {
+ e = oldNodes[d.id];
+ } else {
+ e = {};
+ }
- var name = nodeName(d)
+ e.o = d;
- var offset = 5
- var lineWidth = 3
- var buffer = document.createElement("canvas")
- var r = window.devicePixelRatio
- var bctx = buffer.getContext("2d")
- bctx.font = "11px Roboto"
- var width = bctx.measureText(name).width
- var scale = zoomBehavior.scaleExtent()[1] * r
- buffer.width = (width + 2 * lineWidth) * scale
- buffer.height = (16 + 2 * lineWidth) * scale
- bctx.scale(scale, scale)
- bctx.textBaseline = "middle"
- bctx.textAlign = "center"
- bctx.fillStyle = "rgba(242, 227, 198, 1.0)"
- bctx.shadowColor = "rgba(0, 0, 0, 1)"
- bctx.shadowBlur = 5
- bctx.fillText(name, buffer.width / (2 * scale), buffer.height / (2 * scale))
+ return e;
+ });
- d.label = buffer
- d.labelWidth = buffer.width / scale
- d.labelHeight = buffer.height / scale
- d.labelA = offset + buffer.width / (2 * scale)
- d.labelB = offset + buffer.height / (2 * scale)
- })
+ var newNodesDict = {};
+
+ intNodes.forEach(function (d) {
+ newNodesDict[d.o.id] = d;
+ });
+
+ var oldLinks = {};
intLinks.forEach(function (d) {
- d.source.neighbours[d.target.o.id] = {node: d.target, link: d}
- d.target.neighbours[d.source.o.id] = {node: d.source, link: d}
+ oldLinks[d.o.id] = d;
+ });
- if (d.o.source && d.o.target)
- linksDict[d.o.id] = d
- })
+ intLinks = data.graph.links.map(function (d) {
+ var e;
+ if (d.id in oldLinks) {
+ e = oldLinks[d.id];
+ } else {
+ e = {};
+ }
+
+ e.o = d;
+ e.source = newNodesDict[d.source.id];
+ e.target = newNodesDict[d.target.id];
+
+ if (d.isVPN) {
+ e.color = "rgba(255, 255, 255, " + (0.6 / d.tq) + ")";
+ } else {
+ e.color = linkScale(d.tq).hex();
+ }
+
+ return e;
+ });
+
+ linksDict = {};
+ nodesDict = {};
+
+ intNodes.forEach(function (d) {
+ d.neighbours = {};
+
+ if (d.o.node) {
+ nodesDict[d.o.node.nodeinfo.node_id] = d;
+ }
+
+ var name = nodeName(d);
+
+ var offset = 5;
+ var lineWidth = 3;
+ var buffer = document.createElement("canvas");
+ var r = window.devicePixelRatio;
+ var bctx = buffer.getContext("2d");
+ bctx.font = "11px Roboto";
+ var width = bctx.measureText(name).width;
+ var scale = zoomBehavior.scaleExtent()[1] * r;
+ buffer.width = (width + 2 * lineWidth) * scale;
+ buffer.height = (16 + 2 * lineWidth) * scale;
+ bctx.scale(scale, scale);
+ bctx.textBaseline = "middle";
+ bctx.textAlign = "center";
+ bctx.fillStyle = "rgba(242, 227, 198, 1.0)";
+ bctx.shadowColor = "rgba(0, 0, 0, 1)";
+ bctx.shadowBlur = 5;
+ bctx.fillText(name, buffer.width / (2 * scale), buffer.height / (2 * scale));
+
+ d.label = buffer;
+ d.labelWidth = buffer.width / scale;
+ d.labelHeight = buffer.height / scale;
+ d.labelA = offset + buffer.width / (2 * scale);
+ d.labelB = offset + buffer.height / (2 * scale);
+ });
intLinks.forEach(function (d) {
- if (linksDict[d.target.o.node_id + "-" + d.source.o.node_id])
- return
+ d.source.neighbours[d.target.o.id] = {node: d.target, link: d};
+ d.target.neighbours[d.source.o.id] = {node: d.source, link: d};
- var obj = { source: d.target, target: d.source, o: { isVPN: d.o.isVPN, type: "dead", id: d.target.o.node_id + "-" + d.source.o.node_id, tq: 1 }, color: "rgba(255, 255, 255, 0.6)" }
- intLinks.push(obj)
- linksDict[d.target.o.node_id + "-" + d.source.o.node_id] = obj
- })
+ if (d.o.source && d.o.target) {
+ linksDict[d.o.id] = d;
+ }
+ });
+
+ intLinks.forEach(function (d) {
+ if (linksDict[d.target.o.node_id + "-" + d.source.o.node_id]) {
+ return;
+ }
+
+ var obj = {
+ source: d.target,
+ target: d.source,
+ o: {isVPN: d.o.isVPN, type: "dead", id: d.target.o.node_id + "-" + d.source.o.node_id, tq: 1},
+ color: "rgba(255, 255, 255, 0.6)"
+ };
+ intLinks.push(obj);
+ linksDict[d.target.o.node_id + "-" + d.source.o.node_id] = obj;
+ });
intNodes.forEach(function (d) {
d.neighbours = Object.keys(d.neighbours).map(function (k) {
- return d.neighbours[k]
- })
- })
+ return d.neighbours[k];
+ });
+ });
- nodes = intNodes.filter(function (d) { return !d.o.unseen && d.o.node })
- uplinkNodes = nodes.filter(function (d) { return d.o.node.flags.uplink })
- nonUplinkNodes = nodes.filter(function (d) { return !d.o.node.flags.uplink })
- unseenNodes = intNodes.filter(function (d) { return d.o.unseen && d.o.node })
- unknownNodes = intNodes.filter(function (d) { return !d.o.node })
+ nodes = intNodes.filter(function (d) {
+ return !d.o.unseen && d.o.node;
+ });
+ uplinkNodes = nodes.filter(function (d) {
+ return d.o.node.flags.uplink;
+ });
+ nonUplinkNodes = nodes.filter(function (d) {
+ return !d.o.node.flags.uplink;
+ });
+ unseenNodes = intNodes.filter(function (d) {
+ return d.o.unseen && d.o.node;
+ });
+ unknownNodes = intNodes.filter(function (d) {
+ return !d.o.node;
+ });
if (localStorageTest()) {
- var save = JSON.parse(localStorage.getItem("graph/nodeposition"))
+ var save = JSON.parse(localStorage.getItem("graph/nodeposition"));
if (save) {
- var nodePositions = {}
- save.forEach( function (d) {
- nodePositions[d.id] = d
- })
+ var nodePositions = {};
+ save.forEach(function (d) {
+ nodePositions[d.id] = d;
+ });
- intNodes.forEach( function (d) {
+ intNodes.forEach(function (d) {
if (nodePositions[d.o.id] && (d.x === undefined || d.y === undefined)) {
- d.x = nodePositions[d.o.id].x
- d.y = nodePositions[d.o.id].y
+ d.x = nodePositions[d.o.id].x;
+ d.y = nodePositions[d.o.id].y;
}
- })
+ });
}
}
- var diameter = graphDiameter(intNodes)
+ var diameter = graphDiameter(intNodes);
force.nodes(intNodes)
- .links(intLinks)
- .size([diameter, diameter])
+ .links(intLinks)
+ .size([diameter, diameter]);
- updateHighlight(true)
+ updateHighlight(true);
- force.start()
- resizeCanvas()
- }
+ force.start();
+ resizeCanvas();
+ };
self.resetView = function () {
- highlight = undefined
- updateHighlight()
- doAnimation = true
- }
+ highlight = undefined;
+ updateHighlight();
+ doAnimation = true;
+ };
self.gotoNode = function (d) {
- highlight = {type: "node", o: d}
- updateHighlight()
- doAnimation = true
- }
+ highlight = {type: "node", o: d};
+ updateHighlight();
+ doAnimation = true;
+ };
self.gotoLink = function (d) {
- highlight = {type: "link", o: d}
- updateHighlight()
- doAnimation = true
- }
+ highlight = {type: "link", o: d};
+ updateHighlight();
+ doAnimation = true;
+ };
self.destroy = function () {
- force.stop()
- canvas.remove()
- force = null
+ force.stop();
+ canvas.remove();
+ force = null;
- if (el.parentNode)
- el.parentNode.removeChild(el)
- }
+ if (el.parentNode) {
+ el.parentNode.removeChild(el);
+ }
+ };
self.render = function (d) {
- d.appendChild(el)
- resizeCanvas()
- updateHighlight()
- }
+ d.appendChild(el);
+ resizeCanvas();
+ updateHighlight();
+ };
- return self
- }
-})
+ return self;
+ };
+});
diff --git a/lib/gui.js b/lib/gui.js
index 4e14c50..f757e29 100644
--- a/lib/gui.js
+++ b/lib/gui.js
@@ -1,125 +1,127 @@
-define([ "chroma-js", "map", "sidebar", "tabs", "container", "meshstats",
- "legend", "linklist", "nodelist", "simplenodelist", "infobox/main",
- "proportions", "forcegraph", "title", "about", "datadistributor",
- "filters/filtergui" ],
-function (chroma, Map, Sidebar, Tabs, Container, Meshstats, Legend, Linklist,
- Nodelist, SimpleNodelist, Infobox, Proportions, ForceGraph,
- Title, About, DataDistributor, FilterGUI) {
- return function (config, router) {
- var self = this
- var content
- var contentDiv
+define(["chroma-js", "map", "sidebar", "tabs", "container", "meshstats",
+ "legend", "linklist", "nodelist", "simplenodelist", "infobox/main",
+ "proportions", "forcegraph", "title", "about", "datadistributor",
+ "filters/filtergui"],
+ function (chroma, Map, Sidebar, Tabs, Container, Meshstats, Legend, Linklist,
+ Nodelist, SimpleNodelist, Infobox, Proportions, ForceGraph,
+ Title, About, DataDistributor, FilterGUI) {
+ return function (config, router) {
+ var self = this;
+ var content;
+ var contentDiv;
- var linkScale = chroma.scale(chroma.interpolate.bezier(["#04C714", "#FF5500", "#F02311"])).domain([1, 5])
- var sidebar
+ var linkScale = chroma.scale(chroma.interpolate.bezier(["#04C714", "#FF5500", "#F02311"])).domain([1, 5]);
+ var sidebar;
- var buttons = document.createElement("div")
- buttons.classList.add("buttons")
+ var buttons = document.createElement("div");
+ buttons.classList.add("buttons");
- var fanout = new DataDistributor()
- var fanoutUnfiltered = new DataDistributor()
- fanoutUnfiltered.add(fanout)
+ var fanout = new DataDistributor();
+ var fanoutUnfiltered = new DataDistributor();
+ fanoutUnfiltered.add(fanout);
- function removeContent() {
- if (!content)
- return
+ function removeContent() {
+ if (!content) {
+ return;
+ }
- router.removeTarget(content)
- fanout.remove(content)
+ router.removeTarget(content);
+ fanout.remove(content);
- content.destroy()
+ content.destroy();
- content = null
- }
-
- function addContent(K) {
- removeContent()
-
- content = new K(config, linkScale, sidebar.getWidth, router, buttons)
- content.render(contentDiv)
-
- fanout.add(content)
- router.addTarget(content)
- }
-
- function mkView(K) {
- return function () {
- addContent(K)
+ content = null;
}
- }
- var loader = document.getElementsByClassName("loader")[0]
- loader.classList.add("hide")
+ function addContent(K) {
+ removeContent();
- contentDiv = document.createElement("div")
- contentDiv.classList.add("content")
- document.body.appendChild(contentDiv)
+ content = new K(config, linkScale, sidebar.getWidth, router, buttons);
+ content.render(contentDiv);
- sidebar = new Sidebar(document.body)
+ fanout.add(content);
+ router.addTarget(content);
+ }
- contentDiv.appendChild(buttons)
+ function mkView(K) {
+ return function () {
+ addContent(K);
+ };
+ }
- var buttonToggle = document.createElement("button")
- buttonToggle.textContent = "\uF133"
- buttonToggle.onclick = function () {
- if (content.constructor === Map)
- router.view("g")
- else
- router.view("m")
- }
+ var loader = document.getElementsByClassName("loader")[0];
+ loader.classList.add("hide");
- buttons.appendChild(buttonToggle)
+ contentDiv = document.createElement("div");
+ contentDiv.classList.add("content");
+ document.body.appendChild(contentDiv);
- var title = new Title(config)
+ sidebar = new Sidebar(document.body);
- var header = new Container("header")
- var infobox = new Infobox(config, sidebar, router)
- var tabs = new Tabs()
- var overview = new Container()
- var meshstats = new Meshstats(config)
- var legend = new Legend()
- var newnodeslist = new SimpleNodelist("new", "firstseen", router, "Neue Knoten")
- var lostnodeslist = new SimpleNodelist("lost", "lastseen", router, "Verschwundene Knoten")
- var nodelist = new Nodelist(router)
- var linklist = new Linklist(linkScale, router)
- var statistics = new Proportions(config, fanout)
- var about = new About()
+ contentDiv.appendChild(buttons);
- fanoutUnfiltered.add(meshstats)
- fanoutUnfiltered.add(newnodeslist)
- fanoutUnfiltered.add(lostnodeslist)
- fanout.add(nodelist)
- fanout.add(linklist)
- fanout.add(statistics)
+ var buttonToggle = document.createElement("button");
+ buttonToggle.textContent = "\uF133";
+ buttonToggle.onclick = function () {
+ if (content.constructor === Map) {
+ router.view("g");
+ } else {
+ router.view("m");
+ }
+ };
- sidebar.add(header)
- header.add(meshstats)
- header.add(legend)
+ buttons.appendChild(buttonToggle);
- overview.add(newnodeslist)
- overview.add(lostnodeslist)
+ var title = new Title(config);
- var filterGUI = new FilterGUI(fanout)
- fanout.watchFilters(filterGUI)
- header.add(filterGUI)
+ var header = new Container("header");
+ var infobox = new Infobox(config, sidebar, router);
+ var tabs = new Tabs();
+ var overview = new Container();
+ var meshstats = new Meshstats(config);
+ var legend = new Legend();
+ var newnodeslist = new SimpleNodelist("new", "firstseen", router, "Neue Knoten");
+ var lostnodeslist = new SimpleNodelist("lost", "lastseen", router, "Verschwundene Knoten");
+ var nodelist = new Nodelist(router);
+ var linklist = new Linklist(linkScale, router);
+ var statistics = new Proportions(config, fanout);
+ var about = new About();
- sidebar.add(tabs)
- tabs.add("Aktuelles", overview)
- tabs.add("Knoten", nodelist)
- tabs.add("Verbindungen", linklist)
- tabs.add("Statistiken", statistics)
- tabs.add("Über", about)
+ fanoutUnfiltered.add(meshstats);
+ fanoutUnfiltered.add(newnodeslist);
+ fanoutUnfiltered.add(lostnodeslist);
+ fanout.add(nodelist);
+ fanout.add(linklist);
+ fanout.add(statistics);
- router.addTarget(title)
- router.addTarget(infobox)
+ sidebar.add(header);
+ header.add(meshstats);
+ header.add(legend);
- router.addView("m", mkView(Map))
- router.addView("g", mkView(ForceGraph))
+ overview.add(newnodeslist);
+ overview.add(lostnodeslist);
- router.view("m")
+ var filterGUI = new FilterGUI(fanout);
+ fanout.watchFilters(filterGUI);
+ header.add(filterGUI);
- self.setData = fanoutUnfiltered.setData
+ sidebar.add(tabs);
+ tabs.add("Aktuelles", overview);
+ tabs.add("Knoten", nodelist);
+ tabs.add("Verbindungen", linklist);
+ tabs.add("Statistiken", statistics);
+ tabs.add("Über", about);
- return self
- }
-})
+ router.addTarget(title);
+ router.addTarget(infobox);
+
+ router.addView("m", mkView(Map));
+ router.addView("g", mkView(ForceGraph));
+
+ router.view("m");
+
+ self.setData = fanoutUnfiltered.setData;
+
+ return self;
+ };
+ });
diff --git a/lib/infobox/link.js b/lib/infobox/link.js
index 82b2d9f..2d5e8c0 100644
--- a/lib/infobox/link.js
+++ b/lib/infobox/link.js
@@ -1,48 +1,49 @@
define(function () {
function showStatImg(o, d) {
- var subst = {}
- subst["{SOURCE}"] = d.source.node_id
- subst["{SOURCE_NAME}"] = d.source.node.nodeinfo.hostname ? d.source.node.nodeinfo.hostname : "unknown"
- subst["{TARGET}"] = d.target.node_id
- subst["{TARGET_NAME}"] = d.target.node.nodeinfo.hostname ? d.target.node.nodeinfo.hostname : "unknown"
- return showStat(o, subst)
+ var subst = {};
+ subst["{SOURCE}"] = d.source.node_id;
+ subst["{SOURCE_NAME}"] = d.source.node.nodeinfo.hostname ? d.source.node.nodeinfo.hostname : "unknown";
+ subst["{TARGET}"] = d.target.node_id;
+ subst["{TARGET_NAME}"] = d.target.node.nodeinfo.hostname ? d.target.node.nodeinfo.hostname : "unknown";
+ return showStat(o, subst);
}
return function (config, el, router, d) {
- var unknown = !(d.source.node)
- var h2 = document.createElement("h2")
- var a1 = document.createElement("a")
+ var unknown = !(d.source.node);
+ var h2 = document.createElement("h2");
+ var a1 = document.createElement("a");
if (!unknown) {
- a1.href = "#"
- a1.onclick = router.node(d.source.node)
+ a1.href = "#";
+ a1.onclick = router.node(d.source.node);
}
- a1.textContent = unknown ? d.source.id : d.source.node.nodeinfo.hostname
- h2.appendChild(a1)
- h2.appendChild(document.createTextNode(" → "))
- var a2 = document.createElement("a")
- a2.href = "#"
- a2.onclick = router.node(d.target.node)
- a2.textContent = d.target.node.nodeinfo.hostname
- h2.appendChild(a2)
- el.appendChild(h2)
+ a1.textContent = unknown ? d.source.id : d.source.node.nodeinfo.hostname;
+ h2.appendChild(a1);
+ h2.appendChild(document.createTextNode(" → "));
+ var a2 = document.createElement("a");
+ a2.href = "#";
+ a2.onclick = router.node(d.target.node);
+ a2.textContent = d.target.node.nodeinfo.hostname;
+ h2.appendChild(a2);
+ el.appendChild(h2);
- var attributes = document.createElement("table")
- attributes.classList.add("attributes")
+ var attributes = document.createElement("table");
+ attributes.classList.add("attributes");
- attributeEntry(attributes, "TQ", showTq(d))
- attributeEntry(attributes, "Entfernung", showDistance(d))
- attributeEntry(attributes, "Typ", d.type)
- var hw1 = unknown ? null : dictGet(d.source.node.nodeinfo, ["hardware", "model"])
- var hw2 = dictGet(d.target.node.nodeinfo, ["hardware", "model"])
- attributeEntry(attributes, "Hardware", (hw1 != null ? hw1 : "unbekannt") + " – " + (hw2 != null ? hw2 : "unbekannt"))
- el.appendChild(attributes)
+ attributeEntry(attributes, "TQ", showTq(d));
+ attributeEntry(attributes, "Entfernung", showDistance(d));
+ attributeEntry(attributes, "Typ", d.type);
+ var hw1 = unknown ? null : dictGet(d.source.node.nodeinfo, ["hardware", "model"]);
+ var hw2 = dictGet(d.target.node.nodeinfo, ["hardware", "model"]);
+ attributeEntry(attributes, "Hardware", (hw1 != null ? hw1 : "unbekannt") + " – " + (hw2 != null ? hw2 : "unbekannt"));
+ el.appendChild(attributes);
- if (config.linkInfos)
- config.linkInfos.forEach( function (linkInfo) {
- var h4 = document.createElement("h4")
- h4.textContent = linkInfo.name
- el.appendChild(h4)
- el.appendChild(showStatImg(linkInfo, d))
- })
- }
-})
+ if (config.linkInfos) {
+ config.linkInfos.forEach(function (linkInfo) {
+ var h4 = document.createElement("h4");
+ h4.textContent = linkInfo.name;
+ el.appendChild(h4);
+ el.appendChild(showStatImg(linkInfo, d));
+ });
+ }
+ };
+});
diff --git a/lib/infobox/location.js b/lib/infobox/location.js
index 08805b0..9910d33 100644
--- a/lib/infobox/location.js
+++ b/lib/infobox/location.js
@@ -1,100 +1,103 @@
define(function () {
return function (config, el, router, d) {
- var sidebarTitle = document.createElement("h2")
- sidebarTitle.textContent = "Location: " + d.toString()
- el.appendChild(sidebarTitle)
+ var sidebarTitle = document.createElement("h2");
+ sidebarTitle.textContent = "Location: " + d.toString();
+ el.appendChild(sidebarTitle);
getJSON("https://nominatim.openstreetmap.org/reverse?format=json&lat=" + d.lat + "&lon=" + d.lng + "&zoom=18&addressdetails=0")
- .then(function(result) {
- if(result.display_name)
- sidebarTitle.textContent = result.display_name
- })
+ .then(function (result) {
+ if (result.display_name) {
+ sidebarTitle.textContent = result.display_name;
+ }
+ });
- var editLat = document.createElement("input")
- editLat.type = "text"
- editLat.value = d.lat.toFixed(9)
- el.appendChild(createBox("lat", "Breitengrad", editLat))
+ var editLat = document.createElement("input");
+ editLat.type = "text";
+ editLat.value = d.lat.toFixed(9);
+ el.appendChild(createBox("lat", "Breitengrad", editLat));
- var editLng = document.createElement("input")
- editLng.type = "text"
- editLng.value = d.lng.toFixed(9)
- el.appendChild(createBox("lng", "Längengrad", editLng))
+ var editLng = document.createElement("input");
+ editLng.type = "text";
+ editLng.value = d.lng.toFixed(9);
+ el.appendChild(createBox("lng", "Längengrad", editLng));
- var editUci = document.createElement("textarea")
+ var editUci = document.createElement("textarea");
editUci.value =
"uci set gluon-node-info.@location[0]='location'; " +
"uci set gluon-node-info.@location[0].share_location='1';" +
"uci set gluon-node-info.@location[0].latitude='" + d.lat.toFixed(9) + "';" +
"uci set gluon-node-info.@location[0].longitude='" + d.lng.toFixed(9) + "';" +
- "uci commit gluon-node-info"
+ "uci commit gluon-node-info";
- el.appendChild(createBox("uci", "Befehl", editUci, false))
+ el.appendChild(createBox("uci", "Befehl", editUci, false));
- var linkPlain = document.createElement("a")
- linkPlain.textContent = "plain"
- linkPlain.onclick = function() {
- switch2plain()
- return false
- }
- linkPlain.href = "#"
+ var linkPlain = document.createElement("a");
+ linkPlain.textContent = "plain";
+ linkPlain.onclick = function () {
+ switch2plain();
+ return false;
+ };
+ linkPlain.href = "#";
- var linkUci = document.createElement("a")
- linkUci.textContent = "uci"
- linkUci.onclick = function() {
- switch2uci()
- return false
- }
- linkUci.href = "#"
+ var linkUci = document.createElement("a");
+ linkUci.textContent = "uci";
+ linkUci.onclick = function () {
+ switch2uci();
+ return false;
+ };
+ linkUci.href = "#";
- var hintText = document.createElement("p")
- hintText.appendChild(document.createTextNode("Du kannst zwischen "))
- hintText.appendChild(linkPlain)
- hintText.appendChild(document.createTextNode(" und "))
- hintText.appendChild(linkUci)
- hintText.appendChild(document.createTextNode(" wechseln."))
- el.appendChild(hintText)
+ var hintText = document.createElement("p");
+ hintText.appendChild(document.createTextNode("Du kannst zwischen "));
+ hintText.appendChild(linkPlain);
+ hintText.appendChild(document.createTextNode(" und "));
+ hintText.appendChild(linkUci);
+ hintText.appendChild(document.createTextNode(" wechseln."));
+ el.appendChild(hintText);
function createBox(name, title, inputElem, isVisible) {
- var visible = typeof isVisible !== "undefined" ? isVisible : true
- var box = document.createElement("div")
- var heading = document.createElement("h3")
- heading.textContent = title
- box.appendChild(heading)
- var btn = document.createElement("button")
- btn.className = "ion-ios-copy"
- btn.title = "Kopieren"
- btn.onclick = function() { copy2clip(inputElem.id) }
- inputElem.id = "location-" + name
- inputElem.readOnly = true
- var line = document.createElement("p")
- line.appendChild(inputElem)
- line.appendChild(btn)
- box.appendChild(line)
- box.id = "box-" + name
- box.style.display = visible ? "block" : "none"
- return box
+ var visible = typeof isVisible !== "undefined" ? isVisible : true;
+ var box = document.createElement("div");
+ var heading = document.createElement("h3");
+ heading.textContent = title;
+ box.appendChild(heading);
+ var btn = document.createElement("button");
+ btn.className = "ion-ios-copy";
+ btn.title = "Kopieren";
+ btn.onclick = function () {
+ copy2clip(inputElem.id);
+ };
+ inputElem.id = "location-" + name;
+ inputElem.readOnly = true;
+ var line = document.createElement("p");
+ line.appendChild(inputElem);
+ line.appendChild(btn);
+ box.appendChild(line);
+ box.id = "box-" + name;
+ box.style.display = visible ? "block" : "none";
+ return box;
}
function copy2clip(id) {
- var copyField = document.querySelector("#" + id)
- copyField.select()
+ var copyField = document.querySelector("#" + id);
+ copyField.select();
try {
- document.execCommand("copy")
+ document.execCommand("copy");
} catch (err) {
- console.log(err)
+ console.log(err);
}
}
function switch2plain() {
- document.getElementById("box-uci").style.display = "none"
- document.getElementById("box-lat").style.display = "block"
- document.getElementById("box-lng").style.display = "block"
+ document.getElementById("box-uci").style.display = "none";
+ document.getElementById("box-lat").style.display = "block";
+ document.getElementById("box-lng").style.display = "block";
}
function switch2uci() {
- document.getElementById("box-uci").style.display = "block"
- document.getElementById("box-lat").style.display = "none"
- document.getElementById("box-lng").style.display = "none"
+ document.getElementById("box-uci").style.display = "block";
+ document.getElementById("box-lat").style.display = "none";
+ document.getElementById("box-lng").style.display = "none";
}
- }
-})
+ };
+});
diff --git a/lib/infobox/main.js b/lib/infobox/main.js
index deebc03..dc900e4 100644
--- a/lib/infobox/main.js
+++ b/lib/infobox/main.js
@@ -1,51 +1,51 @@
define(["infobox/link", "infobox/node", "infobox/location"], function (Link, Node, Location) {
return function (config, sidebar, router) {
- var self = this
- var el
+ var self = this;
+ var el;
function destroy() {
if (el && el.parentNode) {
- el.parentNode.removeChild(el)
- el = undefined
- sidebar.reveal()
+ el.parentNode.removeChild(el);
+ el = undefined;
+ sidebar.reveal();
}
}
function create() {
- destroy()
- sidebar.ensureVisible()
- sidebar.hide()
+ destroy();
+ sidebar.ensureVisible();
+ sidebar.hide();
- el = document.createElement("div")
- sidebar.container.insertBefore(el, sidebar.container.firstChild)
+ el = document.createElement("div");
+ sidebar.container.insertBefore(el, sidebar.container.firstChild);
- el.scrollIntoView(false)
- el.classList.add("infobox")
- el.destroy = destroy
+ el.scrollIntoView(false);
+ el.classList.add("infobox");
+ el.destroy = destroy;
- var closeButton = document.createElement("button")
- closeButton.classList.add("close")
- closeButton.onclick = router.reset
- el.appendChild(closeButton)
+ var closeButton = document.createElement("button");
+ closeButton.classList.add("close");
+ closeButton.onclick = router.reset;
+ el.appendChild(closeButton);
}
- self.resetView = destroy
+ self.resetView = destroy;
self.gotoNode = function (d) {
- create()
- new Node(config, el, router, d)
- }
+ create();
+ new Node(config, el, router, d);
+ };
self.gotoLink = function (d) {
- create()
- new Link(config, el, router, d)
- }
+ create();
+ new Link(config, el, router, d);
+ };
self.gotoLocation = function (d) {
- create()
- new Location(config, el, router, d)
- }
+ create();
+ new Location(config, el, router, d);
+ };
- return self
- }
-})
+ return self;
+ };
+});
diff --git a/lib/infobox/node.js b/lib/infobox/node.js
index 34e1ee2..3654c3d 100644
--- a/lib/infobox/node.js
+++ b/lib/infobox/node.js
@@ -1,581 +1,631 @@
define(["moment", "numeral", "tablesort", "tablesort.numeric"],
function (moment, numeral, Tablesort) {
- function showGeoURI(d) {
- function showLatitude(d) {
- var suffix = Math.sign(d) > -1 ? "' N" : "' S"
- d = Math.abs(d)
- var a = Math.floor(d)
- var min = (d * 60) % 60
- a = (a < 10 ? "0" : "") + a
+ function showGeoURI(d) {
+ function showLatitude(d) {
+ var suffix = Math.sign(d) > -1 ? "' N" : "' S";
+ d = Math.abs(d);
+ var a = Math.floor(d);
+ var min = (d * 60) % 60;
+ a = (a < 10 ? "0" : "") + a;
- return a + "° " + numeral(min).format("0.000") + suffix
- }
-
- function showLongitude(d) {
- var suffix = Math.sign(d) > -1 ? "' E" : "' W"
- d = Math.abs(d)
- var a = Math.floor(d)
- var min = (d * 60) % 60
- a = (a < 100 ? "0" + (a < 10 ? "0" : "") : "") + a
-
- return a + "° " + numeral(min).format("0.000") + suffix
- }
-
- if (!has_location(d))
- return undefined
-
- return function (el) {
- var latitude = d.nodeinfo.location.latitude
- var longitude = d.nodeinfo.location.longitude
- var a = document.createElement("a")
- a.textContent = showLatitude(latitude) + " " +
- showLongitude(longitude)
-
- a.href = "geo:" + latitude + "," + longitude
- el.appendChild(a)
- }
- }
-
- function showStatus(d) {
- return function (el) {
- el.classList.add(d.flags.unseen ? "unseen" : (d.flags.online ? "online" : "offline"))
- if (d.flags.online)
- el.textContent = "online, letzte Nachricht " + d.lastseen.fromNow() + " (" + d.lastseen.format("DD.MM.YYYY, H:mm:ss") + ")"
- else
- el.textContent = "offline, letzte Nachricht " + d.lastseen.fromNow() + " (" + d.lastseen.format("DD.MM.YYYY, H:mm:ss") + ")"
- }
- }
-
- function showFirmware(d) {
- var release = dictGet(d.nodeinfo, ["software", "firmware", "release"])
- var base = dictGet(d.nodeinfo, ["software", "firmware", "base"])
-
- if (release === null || base === null)
- return undefined
-
- return release + " / " + base
- }
-
- function showSite(d, config) {
- var site = dictGet(d.nodeinfo, ["system", "site_code"])
- var rt = site
- if (config.siteNames)
- config.siteNames.forEach( function (t) {
- if(site === t.site)
- rt = t.name
- })
- return rt
- }
-
- function showUptime(d) {
- if (!("uptime" in d.statistics))
- return undefined
-
- return moment.duration(d.statistics.uptime, "seconds").humanize()
- }
-
- function showFirstseen(d) {
- if (!("firstseen" in d))
- return undefined
-
- return d.firstseen.fromNow(true)
- }
-
- function wifiChannelAlias(ch) {
- var chlist = {
- "1": "2412 MHz",
- "2": "2417 MHz",
- "3": "2422 MHz",
- "4": "2427 MHz",
- "5": "2432 MHz",
- "6": "2437 MHz",
- "7": "2442 MHz",
- "8": "2447 MHz",
- "9": "2452 MHz",
- "10": "2457 MHz",
- "11": "2462 MHz",
- "12": "2467 MHz",
- "13": "2472 MHz",
- "36": "5180 MHz (Indoors)",
- "40": "5200 MHz (Indoors)",
- "44": "5220 MHz (Indoors)",
- "48": "5240 MHz (Indoors)",
- "52": "5260 MHz (Indoors/DFS/TPC)",
- "56": "5280 MHz (Indoors/DFS/TPC)",
- "60": "5300 MHz (Indoors/DFS/TPC)",
- "64": "5320 MHz (Indoors/DFS/TPC)",
- "100": "5500 MHz (DFS) !!",
- "104": "5520 MHz (DFS) !!",
- "108": "5540 MHz (DFS) !!",
- "112": "5560 MHz (DFS) !!",
- "116": "5580 MHz (DFS) !!",
- "120": "5600 MHz (DFS) !!",
- "124": "5620 MHz (DFS) !!",
- "128": "5640 MHz (DFS) !!",
- "132": "5660 MHz (DFS) !!",
- "136": "5680 MHz (DFS) !!",
- "140": "5700 MHz (DFS) !!"
- }
- if (!(ch in chlist))
- return ""
- else
- return chlist[ch]
- }
-
- function showWifiChannel(ch) {
- if (!ch)
- return undefined
-
- return ch + " (" + wifiChannelAlias(ch) + ")"
- }
-
- function showClients(d) {
- if (!d.flags.online)
- return undefined
-
- var meshclients = getMeshClients(d)
- resetMeshClients(d)
- var before = " ("
- var after = " in der lokalen Wolke)"
- return function (el) {
- el.appendChild(document.createTextNode(d.statistics.clients > 0 ? d.statistics.clients : "keine"))
- el.appendChild(document.createTextNode(before))
- el.appendChild(document.createTextNode(meshclients > 0 ? meshclients : "keine"))
- el.appendChild(document.createTextNode(after))
- el.appendChild(document.createElement("br"))
-
- var span = document.createElement("span")
- span.classList.add("clients")
- span.textContent = " ".repeat(d.statistics.clients)
- el.appendChild(span)
-
- var spanmesh = document.createElement("span")
- spanmesh.classList.add("clientsMesh")
- spanmesh.textContent = " ".repeat(meshclients - d.statistics.clients)
- el.appendChild(spanmesh)
- }
- }
-
- function getMeshClients(node) {
- var meshclients = 0
- if (node.statistics && !isNaN(node.statistics.clients))
- meshclients = node.statistics.clients
-
- if (!node)
- return 0
-
- if (node.parsed)
- return 0
-
- node.parsed = 1
- node.neighbours.forEach(function (neighbour) {
- if (!neighbour.link.isVPN && neighbour.node)
- meshclients += getMeshClients(neighbour.node)
- })
-
- return meshclients
- }
-
- function resetMeshClients(node) {
- if (!node.parsed)
- return
-
- node.parsed = 0
-
- node.neighbours.forEach(function (neighbour) {
- if (!neighbour.link.isVPN && neighbour.node)
- resetMeshClients(neighbour.node)
- })
-
- return
- }
-
- function showMeshClients(d) {
- if (!d.flags.online)
- return undefined
-
- var meshclients = getMeshClients(d)
- resetMeshClients(d)
- return function (el) {
- el.appendChild(document.createTextNode(meshclients > 0 ? meshclients : "keine"))
- el.appendChild(document.createElement("br"))
- }
- }
-
- function showIPs(d) {
- var ips = dictGet(d.nodeinfo, ["network", "addresses"])
- if (ips === null)
- return undefined
-
- ips.sort()
-
- return function (el) {
- ips.forEach( function (ip, i) {
- var link = !ip.startsWith("fe80:")
-
- if (i > 0)
- el.appendChild(document.createElement("br"))
-
- if (link) {
- var a = document.createElement("a")
- if (ip.includes("."))
- a.href = "http://" + ip + "/"
- else
- a.href = "http://[" + ip + "]/"
- a.textContent = ip
- el.appendChild(a)
- } else
- el.appendChild(document.createTextNode(ip))
- })
- }
- }
-
- function showBar(className, v) {
- var span = document.createElement("span")
- span.classList.add("bar")
- span.classList.add(className)
-
- var bar = document.createElement("span")
- bar.style.width = (v * 100) + "%"
- span.appendChild(bar)
-
- var label = document.createElement("label")
- label.textContent = (Math.round(v * 100)) + " %"
- span.appendChild(label)
-
- return span
- }
-
- function showLoadBar(className, v) {
- var span = document.createElement("span")
- span.classList.add("bar")
- span.classList.add(className)
-
- var bar = document.createElement("span")
- if (v >= 1) {
- bar.style.width = ((v * 100) % 100) + "%"
- bar.style.background = "rgba(255, 50, 50, 0.9)"
- span.style.background = "rgba(255, 50, 50, 0.6)"
- span.appendChild(bar)
- }
- else
- {
- bar.style.width = (v * 100) + "%"
- span.appendChild(bar)
- }
-
- var label = document.createElement("label")
- label.textContent = +(Math.round(v + "e+2") + "e-2")
- span.appendChild(label)
-
- return span
- }
-
- function showLoad(d) {
- if (!("loadavg" in d.statistics))
- return undefined
-
- return function (el) {
- el.appendChild(showLoadBar("load-avg", d.statistics.loadavg))
- }
- }
-
- function showRAM(d) {
- if (!("memory_usage" in d.statistics))
- return undefined
-
- return function (el) {
- el.appendChild(showBar("memory-usage", d.statistics.memory_usage))
- }
- }
-
- function showAirtime(band, val) {
- if (!val)
- return undefined
-
- return function (el) {
- el.appendChild(showBar("airtime" + band.toString(), val))
- }
- }
-
- function createLink(target, router) {
- if (!target) return document.createTextNode("unknown")
- var unknown = !(target.node)
- var text = unknown ? (target.id ? target.id : target) : target.node.nodeinfo.hostname
- if (!unknown) {
- var link = document.createElement("a")
- link.classList.add("hostname-link")
- link.href = "#"
- link.onclick = router.node(target.node)
- link.textContent = text
- return link
- }
- return document.createTextNode(text)
- }
-
- function showGateway(d, router) {
- var nh
- if (dictGet(d.statistics, ["nexthop"]))
- nh = dictGet(d.statistics, ["nexthop"])
- if (dictGet(d.statistics, ["gateway_nexthop"]))
- nh = dictGet(d.statistics, ["gateway_nexthop"])
- var gw = dictGet(d.statistics, ["gateway"])
-
- if (!gw) return null
- return function (el) {
- var num = 0
- while (gw && nh && gw.id !== nh.id && num < 10) {
- if (num !== 0) el.appendChild(document.createTextNode(" -> "))
- el.appendChild(createLink(nh, router))
- num++
- if (!nh.node || !nh.node.statistics) break
- if (!dictGet(nh.node.statistics, ["gateway"]) || !dictGet(nh.node.statistics, ["gateway"]).id) break
- if (dictGet(nh.node.statistics, ["gateway"]).id !== gw.id) break
- if (dictGet(nh.node.statistics, ["gateway_nexthop"]))
- nh = dictGet(nh.node.statistics, ["gateway_nexthop"])
- else if (dictGet(nh.node.statistics, ["nexthop"]))
- nh = dictGet(nh.node.statistics, ["nexthop"])
- else
- break
+ return a + "° " + numeral(min).format("0.000") + suffix;
}
- if (gw && nh && gw.id !== nh.id) {
- if (num !== 0) el.appendChild(document.createTextNode(" -> "))
- num++
- el.appendChild(document.createTextNode("..."))
+
+ function showLongitude(d) {
+ var suffix = Math.sign(d) > -1 ? "' E" : "' W";
+ d = Math.abs(d);
+ var a = Math.floor(d);
+ var min = (d * 60) % 60;
+ a = (a < 100 ? "0" + (a < 10 ? "0" : "") : "") + a;
+
+ return a + "° " + numeral(min).format("0.000") + suffix;
}
- if (num !== 0) el.appendChild(document.createTextNode(" -> "))
- el.appendChild(createLink(gw, router))
- }
- }
- function showPages(d) {
- var webpages = dictGet(d.nodeinfo, ["pages"])
- if (webpages === null)
- return undefined
-
- webpages.sort()
-
- return function (el) {
- webpages.forEach( function (webpage, i) {
- if (i > 0)
- el.appendChild(document.createElement("br"))
-
- var a = document.createElement("span")
- var link = document.createElement("a")
- link.href = webpage
- if (webpage.search(/^https:\/\//i) !== -1) {
- var lock = document.createElement("span")
- lock.className = "ion-android-lock"
- a.appendChild(lock)
- var t1 = document.createTextNode(" ")
- a.appendChild(t1)
- link.textContent = webpage.replace(/^https:\/\//i, "")
- }
- else
- link.textContent = webpage.replace(/^http:\/\//i, "")
- a.appendChild(link)
- el.appendChild(a)
- })
- }
- }
-
- function showAutoupdate(d) {
- var au = dictGet(d.nodeinfo, ["software", "autoupdater"])
- if (!au)
- return undefined
-
- return au.enabled ? "aktiviert (" + au.branch + ")" : "deaktiviert"
- }
-
- function showNodeImg(o, model) {
- if (!model)
- return document.createTextNode("Knotenname")
-
- var content, caption
- var modelhash = model.split("").reduce(function(a, b) {
- a = ((a << 5) - a) + b.charCodeAt(0)
- return a & a
- }, 0)
-
- content = document.createElement("img")
- content.id = "routerpicture"
- content.classList.add("nodeImg")
- content.src = o.thumbnail.replace("{MODELHASH}", modelhash)
- content.onerror = function() {
- document.getElementById("routerpicdiv").outerHTML = "Knotenname"
- }
-
- if (o.caption) {
- caption = o.caption.replace("{MODELHASH}", modelhash)
-
- if (!content)
- content = document.createTextNode(caption)
- }
-
- var p = document.createElement("p")
- p.appendChild(content)
-
- return content
- }
-
- function showStatImg(o, d) {
- var subst = {}
- subst["{NODE_ID}"] = d.nodeinfo.node_id ? d.nodeinfo.node_id : "unknown"
- subst["{NODE_NAME}"] = d.nodeinfo.hostname ? d.nodeinfo.hostname : "unknown"
- return showStat(o, subst)
- }
-
- return function(config, el, router, d) {
- var attributes = document.createElement("table")
- attributes.classList.add("attributes")
-
- if (config.hwImg) {
- var top = document.createElement("div")
- top.id = "routerpicdiv"
- try {
- config.hwImg.forEach(function(hwImg) {
- try {
- top.appendChild(showNodeImg(hwImg, dictGet(d, ["nodeinfo", "hardware", "model"])))
- } catch (err) {
- console.log(err.message)
- }
- })
- } catch (err) {
- console.log(err.message)
+ if (!has_location(d)) {
+ return undefined;
}
- attributeEntry(attributes, top, d.nodeinfo.hostname)
- } else {
- var h2 = document.createElement("h2")
- h2.textContent = d.nodeinfo.hostname
- el.appendChild(h2)
+
+ return function (el) {
+ var latitude = d.nodeinfo.location.latitude;
+ var longitude = d.nodeinfo.location.longitude;
+ var a = document.createElement("a");
+ a.textContent = showLatitude(latitude) + " " +
+ showLongitude(longitude);
+
+ a.href = "geo:" + latitude + "," + longitude;
+ el.appendChild(a);
+ };
}
- attributeEntry(attributes, "Status", showStatus(d))
- attributeEntry(attributes, "Gateway", d.flags.gateway ? "ja" : null)
- attributeEntry(attributes, "Koordinaten", showGeoURI(d))
-
- if (config.showContact)
- attributeEntry(attributes, "Kontakt", dictGet(d.nodeinfo, ["owner", "contact"]))
-
- attributeEntry(attributes, "Hardware", dictGet(d.nodeinfo, ["hardware", "model"]))
- attributeEntry(attributes, "Primäre MAC", dictGet(d.nodeinfo, ["network", "mac"]))
- attributeEntry(attributes, "Node ID", dictGet(d.nodeinfo, ["node_id"]))
- attributeEntry(attributes, "Firmware", showFirmware(d))
- attributeEntry(attributes, "Site", showSite(d, config))
- attributeEntry(attributes, "Uptime", showUptime(d))
- attributeEntry(attributes, "Teil des Netzes", showFirstseen(d))
- attributeEntry(attributes, "Kanal 2.4 GHz", showWifiChannel(dictGet(d.nodeinfo, ["wireless", "chan2"])))
- attributeEntry(attributes, "Kanal 5 GHz", showWifiChannel(dictGet(d.nodeinfo, ["wireless", "chan5"])))
- attributeEntry(attributes, "Airtime 2.4 GHz", showAirtime(2, dictGet(d.statistics, ["wireless", "airtime2"])))
- attributeEntry(attributes, "Airtime 5 GHz", showAirtime(5, dictGet(d.statistics, ["wireless", "airtime5"])))
- attributeEntry(attributes, "Systemlast", showLoad(d))
- attributeEntry(attributes, "Arbeitsspeicher", showRAM(d))
- attributeEntry(attributes, "IP Adressen", showIPs(d))
- attributeEntry(attributes, "Webseite", showPages(d))
- attributeEntry(attributes, "Gewähltes Gateway", showGateway(d, router))
- attributeEntry(attributes, "Autom. Updates", showAutoupdate(d))
- attributeEntry(attributes, "Clients", showClients(d), showMeshClients(d))
-
- el.appendChild(attributes)
-
-
- if (config.nodeInfos)
- config.nodeInfos.forEach( function (nodeInfo) {
- var h4 = document.createElement("h4")
- h4.textContent = nodeInfo.name
- el.appendChild(h4)
- el.appendChild(showStatImg(nodeInfo, d))
- })
-
- if (d.neighbours.length > 0) {
- var h3 = document.createElement("h3")
- h3.textContent = "Links (" + d.neighbours.length + ")"
- el.appendChild(h3)
-
- var table = document.createElement("table")
- var thead = document.createElement("thead")
-
- var tr = document.createElement("tr")
- var th1 = document.createElement("th")
- th1.textContent = " "
- tr.appendChild(th1)
-
- var th2 = document.createElement("th")
- th2.textContent = "Knoten"
- th2.classList.add("sort-default")
- tr.appendChild(th2)
-
- var th3 = document.createElement("th")
- th3.textContent = "TQ"
- tr.appendChild(th3)
-
- var th4 = document.createElement("th")
- th4.textContent = "Typ"
- tr.appendChild(th4)
-
- var th5 = document.createElement("th")
- th5.textContent = "Entfernung"
- tr.appendChild(th5)
-
- thead.appendChild(tr)
- table.appendChild(thead)
-
- var tbody = document.createElement("tbody")
-
- d.neighbours.forEach( function (d) {
- var unknown = !(d.node)
- var tr = document.createElement("tr")
-
- var td1 = document.createElement("td")
- td1.appendChild(document.createTextNode(d.incoming ? " ← " : " → "))
- tr.appendChild(td1)
-
- var td2 = document.createElement("td")
- td2.appendChild(createLink(d, router))
-
- if (!unknown && has_location(d.node)) {
- var span = document.createElement("span")
- span.classList.add("icon")
- span.classList.add("ion-location")
- td2.appendChild(span)
+ function showStatus(d) {
+ return function (el) {
+ el.classList.add(d.flags.unseen ? "unseen" : (d.flags.online ? "online" : "offline"));
+ if (d.flags.online) {
+ el.textContent = "online, letzte Nachricht " + d.lastseen.fromNow() + " (" + d.lastseen.format("DD.MM.YYYY, H:mm:ss") + ")";
+ } else {
+ el.textContent = "offline, letzte Nachricht " + d.lastseen.fromNow() + " (" + d.lastseen.format("DD.MM.YYYY, H:mm:ss") + ")";
}
-
- tr.appendChild(td2)
-
- var td3 = document.createElement("td")
- var a2 = document.createElement("a")
- a2.href = "#"
- a2.textContent = showTq(d.link)
- a2.onclick = router.link(d.link)
- td3.appendChild(a2)
- tr.appendChild(td3)
-
- var td4 = document.createElement("td")
- var a3 = document.createElement("a")
- a3.href = "#"
- a3.textContent = d.link.type
- a3.onclick = router.link(d.link)
- td4.appendChild(a3)
- tr.appendChild(td4)
-
- var td5 = document.createElement("td")
- var a4 = document.createElement("a")
- a4.href = "#"
- a4.textContent = showDistance(d.link)
- a4.onclick = router.link(d.link)
- td5.appendChild(a4)
- td5.setAttribute("data-sort", d.link.distance !== undefined ? -d.link.distance : 1)
- tr.appendChild(td5)
-
- tbody.appendChild(tr)
- })
-
- table.appendChild(tbody)
- table.className = "node-links"
-
- new Tablesort(table)
-
- el.appendChild(table)
+ };
}
- }
-})
+
+ function showFirmware(d) {
+ var release = dictGet(d.nodeinfo, ["software", "firmware", "release"]);
+ var base = dictGet(d.nodeinfo, ["software", "firmware", "base"]);
+
+ if (release === null || base === null) {
+ return undefined;
+ }
+
+ return release + " / " + base;
+ }
+
+ function showSite(d, config) {
+ var site = dictGet(d.nodeinfo, ["system", "site_code"]);
+ var rt = site;
+ if (config.siteNames) {
+ config.siteNames.forEach(function (t) {
+ if (site === t.site) {
+ rt = t.name;
+ }
+ });
+ }
+ return rt;
+ }
+
+ function showUptime(d) {
+ if (!("uptime" in d.statistics)) {
+ return undefined;
+ }
+
+ return moment.duration(d.statistics.uptime, "seconds").humanize();
+ }
+
+ function showFirstseen(d) {
+ if (!("firstseen" in d)) {
+ return undefined;
+ }
+
+ return d.firstseen.fromNow(true);
+ }
+
+ function wifiChannelAlias(ch) {
+ var chlist = {
+ "1": "2412 MHz",
+ "2": "2417 MHz",
+ "3": "2422 MHz",
+ "4": "2427 MHz",
+ "5": "2432 MHz",
+ "6": "2437 MHz",
+ "7": "2442 MHz",
+ "8": "2447 MHz",
+ "9": "2452 MHz",
+ "10": "2457 MHz",
+ "11": "2462 MHz",
+ "12": "2467 MHz",
+ "13": "2472 MHz",
+ "36": "5180 MHz (Indoors)",
+ "40": "5200 MHz (Indoors)",
+ "44": "5220 MHz (Indoors)",
+ "48": "5240 MHz (Indoors)",
+ "52": "5260 MHz (Indoors/DFS/TPC)",
+ "56": "5280 MHz (Indoors/DFS/TPC)",
+ "60": "5300 MHz (Indoors/DFS/TPC)",
+ "64": "5320 MHz (Indoors/DFS/TPC)",
+ "100": "5500 MHz (DFS) !!",
+ "104": "5520 MHz (DFS) !!",
+ "108": "5540 MHz (DFS) !!",
+ "112": "5560 MHz (DFS) !!",
+ "116": "5580 MHz (DFS) !!",
+ "120": "5600 MHz (DFS) !!",
+ "124": "5620 MHz (DFS) !!",
+ "128": "5640 MHz (DFS) !!",
+ "132": "5660 MHz (DFS) !!",
+ "136": "5680 MHz (DFS) !!",
+ "140": "5700 MHz (DFS) !!"
+ };
+ if (!(ch in chlist)) {
+ return "";
+ } else {
+ return chlist[ch];
+ }
+ }
+
+ function showWifiChannel(ch) {
+ if (!ch) {
+ return undefined;
+ }
+
+ return ch + " (" + wifiChannelAlias(ch) + ")";
+ }
+
+ function showClients(d) {
+ if (!d.flags.online) {
+ return undefined;
+ }
+
+ var meshclients = getMeshClients(d);
+ resetMeshClients(d);
+ var before = " (";
+ var after = " in der lokalen Wolke)";
+ return function (el) {
+ el.appendChild(document.createTextNode(d.statistics.clients > 0 ? d.statistics.clients : "keine"));
+ el.appendChild(document.createTextNode(before));
+ el.appendChild(document.createTextNode(meshclients > 0 ? meshclients : "keine"));
+ el.appendChild(document.createTextNode(after));
+ el.appendChild(document.createElement("br"));
+
+ var span = document.createElement("span");
+ span.classList.add("clients");
+ span.textContent = " ".repeat(d.statistics.clients);
+ el.appendChild(span);
+
+ var spanmesh = document.createElement("span");
+ spanmesh.classList.add("clientsMesh");
+ spanmesh.textContent = " ".repeat(meshclients - d.statistics.clients);
+ el.appendChild(spanmesh);
+ };
+ }
+
+ function getMeshClients(node) {
+ var meshclients = 0;
+ if (node.statistics && !isNaN(node.statistics.clients)) {
+ meshclients = node.statistics.clients;
+ }
+
+ if (!node) {
+ return 0;
+ }
+
+ if (node.parsed) {
+ return 0;
+ }
+
+ node.parsed = 1;
+ node.neighbours.forEach(function (neighbour) {
+ if (!neighbour.link.isVPN && neighbour.node) {
+ meshclients += getMeshClients(neighbour.node);
+ }
+ });
+
+ return meshclients;
+ }
+
+ function resetMeshClients(node) {
+ if (!node.parsed) {
+ return;
+ }
+
+ node.parsed = 0;
+
+ node.neighbours.forEach(function (neighbour) {
+ if (!neighbour.link.isVPN && neighbour.node) {
+ resetMeshClients(neighbour.node);
+ }
+ });
+
+
+ }
+
+ function showMeshClients(d) {
+ if (!d.flags.online) {
+ return undefined;
+ }
+
+ var meshclients = getMeshClients(d);
+ resetMeshClients(d);
+ return function (el) {
+ el.appendChild(document.createTextNode(meshclients > 0 ? meshclients : "keine"));
+ el.appendChild(document.createElement("br"));
+ };
+ }
+
+ function showIPs(d) {
+ var ips = dictGet(d.nodeinfo, ["network", "addresses"]);
+ if (ips === null) {
+ return undefined;
+ }
+
+ ips.sort();
+
+ return function (el) {
+ ips.forEach(function (ip, i) {
+ var link = !ip.startsWith("fe80:");
+
+ if (i > 0) {
+ el.appendChild(document.createElement("br"));
+ }
+
+ if (link) {
+ var a = document.createElement("a");
+ if (ip.includes(".")) {
+ a.href = "http://" + ip + "/";
+ } else {
+ a.href = "http://[" + ip + "]/";
+ }
+ a.textContent = ip;
+ el.appendChild(a);
+ } else {
+ el.appendChild(document.createTextNode(ip));
+ }
+ });
+ };
+ }
+
+ function showBar(className, v) {
+ var span = document.createElement("span");
+ span.classList.add("bar");
+ span.classList.add(className);
+
+ var bar = document.createElement("span");
+ bar.style.width = (v * 100) + "%";
+ span.appendChild(bar);
+
+ var label = document.createElement("label");
+ label.textContent = (Math.round(v * 100)) + " %";
+ span.appendChild(label);
+
+ return span;
+ }
+
+ function showLoadBar(className, v) {
+ var span = document.createElement("span");
+ span.classList.add("bar");
+ span.classList.add(className);
+
+ var bar = document.createElement("span");
+ if (v >= 1) {
+ bar.style.width = ((v * 100) % 100) + "%";
+ bar.style.background = "rgba(255, 50, 50, 0.9)";
+ span.style.background = "rgba(255, 50, 50, 0.6)";
+ span.appendChild(bar);
+ }
+ else {
+ bar.style.width = (v * 100) + "%";
+ span.appendChild(bar);
+ }
+
+ var label = document.createElement("label");
+ label.textContent = +(Math.round(v + "e+2") + "e-2");
+ span.appendChild(label);
+
+ return span;
+ }
+
+ function showLoad(d) {
+ if (!("loadavg" in d.statistics)) {
+ return undefined;
+ }
+
+ return function (el) {
+ el.appendChild(showLoadBar("load-avg", d.statistics.loadavg));
+ };
+ }
+
+ function showRAM(d) {
+ if (!("memory_usage" in d.statistics)) {
+ return undefined;
+ }
+
+ return function (el) {
+ el.appendChild(showBar("memory-usage", d.statistics.memory_usage));
+ };
+ }
+
+ function showAirtime(band, val) {
+ if (!val) {
+ return undefined;
+ }
+
+ return function (el) {
+ el.appendChild(showBar("airtime" + band.toString(), val));
+ };
+ }
+
+ function createLink(target, router) {
+ if (!target) {
+ return document.createTextNode("unknown");
+ }
+ var unknown = !(target.node);
+ var text = unknown ? (target.id ? target.id : target) : target.node.nodeinfo.hostname;
+ if (!unknown) {
+ var link = document.createElement("a");
+ link.classList.add("hostname-link");
+ link.href = "#";
+ link.onclick = router.node(target.node);
+ link.textContent = text;
+ return link;
+ }
+ return document.createTextNode(text);
+ }
+
+ function showGateway(d, router) {
+ var nh;
+ if (dictGet(d.statistics, ["nexthop"])) {
+ nh = dictGet(d.statistics, ["nexthop"]);
+ }
+ if (dictGet(d.statistics, ["gateway_nexthop"])) {
+ nh = dictGet(d.statistics, ["gateway_nexthop"]);
+ }
+ var gw = dictGet(d.statistics, ["gateway"]);
+
+ if (!gw) {
+ return null;
+ }
+ return function (el) {
+ var num = 0;
+ while (gw && nh && gw.id !== nh.id && num < 10) {
+ if (num !== 0) {
+ el.appendChild(document.createTextNode(" -> "));
+ }
+ el.appendChild(createLink(nh, router));
+ num++;
+ if (!nh.node || !nh.node.statistics) {
+ break;
+ }
+ if (!dictGet(nh.node.statistics, ["gateway"]) || !dictGet(nh.node.statistics, ["gateway"]).id) {
+ break;
+ }
+ if (dictGet(nh.node.statistics, ["gateway"]).id !== gw.id) {
+ break;
+ }
+ if (dictGet(nh.node.statistics, ["gateway_nexthop"])) {
+ nh = dictGet(nh.node.statistics, ["gateway_nexthop"]);
+ } else if (dictGet(nh.node.statistics, ["nexthop"])) {
+ nh = dictGet(nh.node.statistics, ["nexthop"]);
+ } else {
+ break;
+ }
+ }
+ if (gw && nh && gw.id !== nh.id) {
+ if (num !== 0) {
+ el.appendChild(document.createTextNode(" -> "));
+ }
+ num++;
+ el.appendChild(document.createTextNode("..."));
+ }
+ if (num !== 0) {
+ el.appendChild(document.createTextNode(" -> "));
+ }
+ el.appendChild(createLink(gw, router));
+ };
+ }
+
+ function showPages(d) {
+ var webpages = dictGet(d.nodeinfo, ["pages"]);
+ if (webpages === null) {
+ return undefined;
+ }
+
+ webpages.sort();
+
+ return function (el) {
+ webpages.forEach(function (webpage, i) {
+ if (i > 0) {
+ el.appendChild(document.createElement("br"));
+ }
+
+ var a = document.createElement("span");
+ var link = document.createElement("a");
+ link.href = webpage;
+ if (webpage.search(/^https:\/\//i) !== -1) {
+ var lock = document.createElement("span");
+ lock.className = "ion-android-lock";
+ a.appendChild(lock);
+ var t1 = document.createTextNode(" ");
+ a.appendChild(t1);
+ link.textContent = webpage.replace(/^https:\/\//i, "");
+ }
+ else {
+ link.textContent = webpage.replace(/^http:\/\//i, "");
+ }
+ a.appendChild(link);
+ el.appendChild(a);
+ });
+ };
+ }
+
+ function showAutoupdate(d) {
+ var au = dictGet(d.nodeinfo, ["software", "autoupdater"]);
+ if (!au) {
+ return undefined;
+ }
+
+ return au.enabled ? "aktiviert (" + au.branch + ")" : "deaktiviert";
+ }
+
+ function showNodeImg(o, model) {
+ if (!model) {
+ return document.createTextNode("Knotenname");
+ }
+
+ var content, caption;
+ var modelhash = model.split("").reduce(function (a, b) {
+ a = ((a << 5) - a) + b.charCodeAt(0);
+ return a & a;
+ }, 0);
+
+ content = document.createElement("img");
+ content.id = "routerpicture";
+ content.classList.add("nodeImg");
+ content.src = o.thumbnail.replace("{MODELHASH}", modelhash);
+ content.onerror = function () {
+ document.getElementById("routerpicdiv").outerHTML = "Knotenname";
+ };
+
+ if (o.caption) {
+ caption = o.caption.replace("{MODELHASH}", modelhash);
+
+ if (!content) {
+ content = document.createTextNode(caption);
+ }
+ }
+
+ var p = document.createElement("p");
+ p.appendChild(content);
+
+ return content;
+ }
+
+ function showStatImg(o, d) {
+ var subst = {};
+ subst["{NODE_ID}"] = d.nodeinfo.node_id ? d.nodeinfo.node_id : "unknown";
+ subst["{NODE_NAME}"] = d.nodeinfo.hostname ? d.nodeinfo.hostname : "unknown";
+ return showStat(o, subst);
+ }
+
+ return function (config, el, router, d) {
+ var attributes = document.createElement("table");
+ attributes.classList.add("attributes");
+
+ if (config.hwImg) {
+ var top = document.createElement("div");
+ top.id = "routerpicdiv";
+ try {
+ config.hwImg.forEach(function (hwImg) {
+ try {
+ top.appendChild(showNodeImg(hwImg, dictGet(d, ["nodeinfo", "hardware", "model"])));
+ } catch (err) {
+ console.log(err.message);
+ }
+ });
+ } catch (err) {
+ console.log(err.message);
+ }
+ attributeEntry(attributes, top, d.nodeinfo.hostname);
+ } else {
+ var h2 = document.createElement("h2");
+ h2.textContent = d.nodeinfo.hostname;
+ el.appendChild(h2);
+ }
+
+ attributeEntry(attributes, "Status", showStatus(d));
+ attributeEntry(attributes, "Gateway", d.flags.gateway ? "ja" : null);
+ attributeEntry(attributes, "Koordinaten", showGeoURI(d));
+
+ if (config.showContact) {
+ attributeEntry(attributes, "Kontakt", dictGet(d.nodeinfo, ["owner", "contact"]));
+ }
+
+ attributeEntry(attributes, "Hardware", dictGet(d.nodeinfo, ["hardware", "model"]));
+ attributeEntry(attributes, "Primäre MAC", dictGet(d.nodeinfo, ["network", "mac"]));
+ attributeEntry(attributes, "Node ID", dictGet(d.nodeinfo, ["node_id"]));
+ attributeEntry(attributes, "Firmware", showFirmware(d));
+ attributeEntry(attributes, "Site", showSite(d, config));
+ attributeEntry(attributes, "Uptime", showUptime(d));
+ attributeEntry(attributes, "Teil des Netzes", showFirstseen(d));
+ attributeEntry(attributes, "Kanal 2.4 GHz", showWifiChannel(dictGet(d.nodeinfo, ["wireless", "chan2"])));
+ attributeEntry(attributes, "Kanal 5 GHz", showWifiChannel(dictGet(d.nodeinfo, ["wireless", "chan5"])));
+ attributeEntry(attributes, "Airtime 2.4 GHz", showAirtime(2, dictGet(d.statistics, ["wireless", "airtime2"])));
+ attributeEntry(attributes, "Airtime 5 GHz", showAirtime(5, dictGet(d.statistics, ["wireless", "airtime5"])));
+ attributeEntry(attributes, "Systemlast", showLoad(d));
+ attributeEntry(attributes, "Arbeitsspeicher", showRAM(d));
+ attributeEntry(attributes, "IP Adressen", showIPs(d));
+ attributeEntry(attributes, "Webseite", showPages(d));
+ attributeEntry(attributes, "Gewähltes Gateway", showGateway(d, router));
+ attributeEntry(attributes, "Autom. Updates", showAutoupdate(d));
+ attributeEntry(attributes, "Clients", showClients(d), showMeshClients(d));
+
+ el.appendChild(attributes);
+
+
+ if (config.nodeInfos) {
+ config.nodeInfos.forEach(function (nodeInfo) {
+ var h4 = document.createElement("h4");
+ h4.textContent = nodeInfo.name;
+ el.appendChild(h4);
+ el.appendChild(showStatImg(nodeInfo, d));
+ });
+ }
+
+ if (d.neighbours.length > 0) {
+ var h3 = document.createElement("h3");
+ h3.textContent = "Links (" + d.neighbours.length + ")";
+ el.appendChild(h3);
+
+ var table = document.createElement("table");
+ var thead = document.createElement("thead");
+
+ var tr = document.createElement("tr");
+ var th1 = document.createElement("th");
+ th1.textContent = " ";
+ tr.appendChild(th1);
+
+ var th2 = document.createElement("th");
+ th2.textContent = "Knoten";
+ th2.classList.add("sort-default");
+ tr.appendChild(th2);
+
+ var th3 = document.createElement("th");
+ th3.textContent = "TQ";
+ tr.appendChild(th3);
+
+ var th4 = document.createElement("th");
+ th4.textContent = "Typ";
+ tr.appendChild(th4);
+
+ var th5 = document.createElement("th");
+ th5.textContent = "Entfernung";
+ tr.appendChild(th5);
+
+ thead.appendChild(tr);
+ table.appendChild(thead);
+
+ var tbody = document.createElement("tbody");
+
+ d.neighbours.forEach(function (d) {
+ var unknown = !(d.node);
+ var tr = document.createElement("tr");
+
+ var td1 = document.createElement("td");
+ td1.appendChild(document.createTextNode(d.incoming ? " ← " : " → "));
+ tr.appendChild(td1);
+
+ var td2 = document.createElement("td");
+ td2.appendChild(createLink(d, router));
+
+ if (!unknown && has_location(d.node)) {
+ var span = document.createElement("span");
+ span.classList.add("icon");
+ span.classList.add("ion-location");
+ td2.appendChild(span);
+ }
+
+ tr.appendChild(td2);
+
+ var td3 = document.createElement("td");
+ var a2 = document.createElement("a");
+ a2.href = "#";
+ a2.textContent = showTq(d.link);
+ a2.onclick = router.link(d.link);
+ td3.appendChild(a2);
+ tr.appendChild(td3);
+
+ var td4 = document.createElement("td");
+ var a3 = document.createElement("a");
+ a3.href = "#";
+ a3.textContent = d.link.type;
+ a3.onclick = router.link(d.link);
+ td4.appendChild(a3);
+ tr.appendChild(td4);
+
+ var td5 = document.createElement("td");
+ var a4 = document.createElement("a");
+ a4.href = "#";
+ a4.textContent = showDistance(d.link);
+ a4.onclick = router.link(d.link);
+ td5.appendChild(a4);
+ td5.setAttribute("data-sort", d.link.distance !== undefined ? -d.link.distance : 1);
+ tr.appendChild(td5);
+
+ tbody.appendChild(tr);
+ });
+
+ table.appendChild(tbody);
+ table.className = "node-links";
+
+ new Tablesort(table);
+
+ el.appendChild(table);
+ }
+ };
+ });
diff --git a/lib/legend.js b/lib/legend.js
index bee87c3..b01782f 100644
--- a/lib/legend.js
+++ b/lib/legend.js
@@ -1,41 +1,41 @@
define(function () {
return function () {
- var self = this
+ var self = this;
self.render = function (el) {
- var p = document.createElement("p")
- p.setAttribute("class", "legend")
- el.appendChild(p)
+ var p = document.createElement("p");
+ p.setAttribute("class", "legend");
+ el.appendChild(p);
- var spanNew = document.createElement("span")
- spanNew.setAttribute("class", "legend-new")
- var symbolNew = document.createElement("span")
- symbolNew.setAttribute("class", "symbol")
- var textNew = document.createTextNode(" Neuer Knoten")
- spanNew.appendChild(symbolNew)
- spanNew.appendChild(textNew)
- p.appendChild(spanNew)
+ var spanNew = document.createElement("span");
+ spanNew.setAttribute("class", "legend-new");
+ var symbolNew = document.createElement("span");
+ symbolNew.setAttribute("class", "symbol");
+ var textNew = document.createTextNode(" Neuer Knoten");
+ spanNew.appendChild(symbolNew);
+ spanNew.appendChild(textNew);
+ p.appendChild(spanNew);
- var spanOnline = document.createElement("span")
- spanOnline.setAttribute("class", "legend-online")
- var symbolOnline = document.createElement("span")
- symbolOnline.setAttribute("class", "symbol")
- var textOnline = document.createTextNode(" Knoten ist online")
- spanOnline.appendChild(symbolOnline)
- spanOnline.appendChild(textOnline)
- p.appendChild(spanOnline)
+ var spanOnline = document.createElement("span");
+ spanOnline.setAttribute("class", "legend-online");
+ var symbolOnline = document.createElement("span");
+ symbolOnline.setAttribute("class", "symbol");
+ var textOnline = document.createTextNode(" Knoten ist online");
+ spanOnline.appendChild(symbolOnline);
+ spanOnline.appendChild(textOnline);
+ p.appendChild(spanOnline);
- var spanOffline = document.createElement("span")
- spanOffline.setAttribute("class", "legend-offline")
- var symbolOffline = document.createElement("span")
- symbolOffline.setAttribute("class", "symbol")
- var textOffline = document.createTextNode(" Knoten ist offline")
- spanOffline.appendChild(symbolOffline)
- spanOffline.appendChild(textOffline)
- p.appendChild(spanOffline)
- }
+ var spanOffline = document.createElement("span");
+ spanOffline.setAttribute("class", "legend-offline");
+ var symbolOffline = document.createElement("span");
+ symbolOffline.setAttribute("class", "symbol");
+ var textOffline = document.createTextNode(" Knoten ist offline");
+ spanOffline.appendChild(symbolOffline);
+ spanOffline.appendChild(textOffline);
+ p.appendChild(spanOffline);
+ };
- return self
- }
-})
+ return self;
+ };
+});
diff --git a/lib/linklist.js b/lib/linklist.js
index 1fc8574..96e7447 100644
--- a/lib/linklist.js
+++ b/lib/linklist.js
@@ -1,60 +1,66 @@
define(["sorttable", "virtual-dom"], function (SortTable, V) {
function linkName(d) {
- return (d.source.node ? d.source.node.nodeinfo.hostname : d.source.id) + " – " + d.target.node.nodeinfo.hostname
+ return (d.source.node ? d.source.node.nodeinfo.hostname : d.source.id) + " – " + d.target.node.nodeinfo.hostname;
}
- var headings = [{ name: "Knoten",
- sort: function (a, b) {
- return linkName(a).localeCompare(linkName(b))
- },
- reverse: false
- },
- { name: "TQ",
- sort: function (a, b) { return a.tq - b.tq},
- reverse: true
- },
- { name: "Typ",
- sort: function (a, b) {
- return a.type.localeCompare(b.type)
- },
- reverse: false
- },
- { name: "Entfernung",
- sort: function (a, b) {
- return (a.distance === undefined ? -1 : a.distance) -
- (b.distance === undefined ? -1 : b.distance)
- },
- reverse: true
- }]
+ var headings = [{
+ name: "Knoten",
+ sort: function (a, b) {
+ return linkName(a).localeCompare(linkName(b));
+ },
+ reverse: false
+ },
+ {
+ name: "TQ",
+ sort: function (a, b) {
+ return a.tq - b.tq;
+ },
+ reverse: true
+ },
+ {
+ name: "Typ",
+ sort: function (a, b) {
+ return a.type.localeCompare(b.type);
+ },
+ reverse: false
+ },
+ {
+ name: "Entfernung",
+ sort: function (a, b) {
+ return (a.distance === undefined ? -1 : a.distance) -
+ (b.distance === undefined ? -1 : b.distance);
+ },
+ reverse: true
+ }];
- return function(linkScale, router) {
- var table = new SortTable(headings, 2, renderRow)
+ return function (linkScale, router) {
+ var table = new SortTable(headings, 2, renderRow);
function renderRow(d) {
- var td1Content = [V.h("a", {href: "#", onclick: router.link(d)}, linkName(d))]
+ var td1Content = [V.h("a", {href: "#", onclick: router.link(d)}, linkName(d))];
- var td1 = V.h("td", td1Content)
- var td2 = V.h("td", {style: {color: linkScale(d.tq).hex()}}, showTq(d))
- var td3 = V.h("td", d.type)
- var td4 = V.h("td", showDistance(d))
+ var td1 = V.h("td", td1Content);
+ var td2 = V.h("td", {style: {color: linkScale(d.tq).hex()}}, showTq(d));
+ var td3 = V.h("td", d.type);
+ var td4 = V.h("td", showDistance(d));
- return V.h("tr", [td1, td2, td3, td4])
+ return V.h("tr", [td1, td2, td3, td4]);
}
- this.render = function (d) {
- var el = document.createElement("div")
- el.last = V.h("div")
- d.appendChild(el)
+ this.render = function (d) {
+ var el = document.createElement("div");
+ el.last = V.h("div");
+ d.appendChild(el);
- var h2 = document.createElement("h2")
- h2.textContent = "Verbindungen"
- el.appendChild(h2)
+ var h2 = document.createElement("h2");
+ h2.textContent = "Verbindungen";
+ el.appendChild(h2);
- el.appendChild(table.el)
- }
+ el.appendChild(table.el);
+ };
this.setData = function (d) {
- table.setData(d.graph.links)
- }
- }
-})
+ table.setData(d.graph.links);
+ };
+ };
+});
diff --git a/lib/locationmarker.js b/lib/locationmarker.js
index 615eeef..0f8c35a 100644
--- a/lib/locationmarker.js
+++ b/lib/locationmarker.js
@@ -29,31 +29,31 @@ define(["leaflet"], function (L) {
fillOpacity: 0.2
},
- initialize: function(latlng) {
- this.accuracyCircle = L.circle(latlng, 0, this.accuracyCircle)
- this.outerCircle = L.circleMarker(latlng, this.outerCircle)
- L.CircleMarker.prototype.initialize.call(this, latlng, this.innerCircle)
+ initialize: function (latlng) {
+ this.accuracyCircle = L.circle(latlng, 0, this.accuracyCircle);
+ this.outerCircle = L.circleMarker(latlng, this.outerCircle);
+ L.CircleMarker.prototype.initialize.call(this, latlng, this.innerCircle);
- this.on("remove", function() {
- this._map.removeLayer(this.accuracyCircle)
- this._map.removeLayer(this.outerCircle)
- })
+ this.on("remove", function () {
+ this._map.removeLayer(this.accuracyCircle);
+ this._map.removeLayer(this.outerCircle);
+ });
},
- setLatLng: function(latlng) {
- this.accuracyCircle.setLatLng(latlng)
- this.outerCircle.setLatLng(latlng)
- L.CircleMarker.prototype.setLatLng.call(this, latlng)
+ setLatLng: function (latlng) {
+ this.accuracyCircle.setLatLng(latlng);
+ this.outerCircle.setLatLng(latlng);
+ L.CircleMarker.prototype.setLatLng.call(this, latlng);
},
- setAccuracy: function(accuracy) {
- this.accuracyCircle.setRadius(accuracy)
+ setAccuracy: function (accuracy) {
+ this.accuracyCircle.setRadius(accuracy);
},
- onAdd: function(map) {
- this.accuracyCircle.addTo(map).bringToBack()
- this.outerCircle.addTo(map)
- L.CircleMarker.prototype.onAdd.call(this, map)
+ onAdd: function (map) {
+ this.accuracyCircle.addTo(map).bringToBack();
+ this.outerCircle.addTo(map);
+ L.CircleMarker.prototype.onAdd.call(this, map);
}
- })
-})
+ });
+});
diff --git a/lib/main.js b/lib/main.js
index eac2a0f..8305891 100644
--- a/lib/main.js
+++ b/lib/main.js
@@ -1,232 +1,241 @@
define(["moment", "router", "leaflet", "gui", "numeral"],
-function (moment, Router, L, GUI, numeral) {
- return function (config) {
- function handleData(data) {
- var dataNodes = {}
- dataNodes.nodes = []
- dataNodes.nodeIds = []
- var dataGraph = {}
- dataGraph.batadv = {}
- dataGraph.batadv.nodes = []
- dataGraph.batadv.links = []
+ function (moment, Router, L, GUI, numeral) {
+ return function (config) {
+ function handleData(data) {
+ var dataNodes = {};
+ dataNodes.nodes = [];
+ dataNodes.nodeIds = [];
+ var dataGraph = {};
+ dataGraph.batadv = {};
+ dataGraph.batadv.nodes = [];
+ dataGraph.batadv.links = [];
-
- function rearrangeLinks(d) {
- d.source += dataGraph.batadv.nodes.length
- d.target += dataGraph.batadv.nodes.length
- }
-
- for (var i = 0; i < data.length; ++i) {
- var vererr
- if(i % 2)
- if (data[i].version !== 1) {
- vererr = "Unsupported graph version: " + data[i].version
- console.log(vererr) //silent fail
- } else {
- data[i].batadv.links.forEach(rearrangeLinks)
- dataGraph.batadv.nodes = dataGraph.batadv.nodes.concat(data[i].batadv.nodes)
- dataGraph.batadv.links = dataGraph.batadv.links.concat(data[i].batadv.links)
- dataGraph.timestamp = data[i].timestamp
- }
- else
- if (data[i].version !== 2) {
- vererr = "Unsupported nodes version: " + data[i].version
- console.log(vererr) //silent fail
- } else {
- data[i].nodes.forEach(fillData)
- dataNodes.timestamp = data[i].timestamp
- }
- }
-
- function fillData (node) {
- var position = dataNodes.nodeIds.indexOf(node.nodeinfo.node_id)
- if(position === -1){
- dataNodes.nodes.push(node)
- dataNodes.nodeIds.push(node.nodeinfo.node_id)
+ function rearrangeLinks(d) {
+ d.source += dataGraph.batadv.nodes.length;
+ d.target += dataGraph.batadv.nodes.length;
}
- else
- if(node.flags.online === true)
- dataNodes.nodes[position] = node
- }
- var nodes = dataNodes.nodes.filter( function (d) {
- return "firstseen" in d && "lastseen" in d
- })
-
- nodes.forEach( function(node) {
- node.firstseen = moment.utc(node.firstseen).local()
- node.lastseen = moment.utc(node.lastseen).local()
- })
-
- var now = moment()
- var age = moment(now).subtract(config.maxAge, "days")
-
- var newnodes = limit("firstseen", age, sortByKey("firstseen", nodes).filter(online))
- var lostnodes = limit("lastseen", age, sortByKey("lastseen", nodes).filter(offline))
-
- var graphnodes = {}
-
- dataNodes.nodes.forEach( function (d) {
- graphnodes[d.nodeinfo.node_id] = d
- })
-
- var graph = dataGraph.batadv
-
- graph.nodes.forEach( function (d) {
- if (d.node_id in graphnodes) {
- d.node = graphnodes[d.node_id]
- if (d.unseen) {
- d.node.flags.online = true
- d.node.flags.unseen = true
+ for (var i = 0; i < data.length; ++i) {
+ var vererr;
+ if (i % 2) {
+ if (data[i].version !== 1) {
+ vererr = "Unsupported graph version: " + data[i].version;
+ console.log(vererr); //silent fail
+ } else {
+ data[i].batadv.links.forEach(rearrangeLinks);
+ dataGraph.batadv.nodes = dataGraph.batadv.nodes.concat(data[i].batadv.nodes);
+ dataGraph.batadv.links = dataGraph.batadv.links.concat(data[i].batadv.links);
+ dataGraph.timestamp = data[i].timestamp;
+ }
+ } else if (data[i].version !== 2) {
+ vererr = "Unsupported nodes version: " + data[i].version;
+ console.log(vererr); //silent fail
+ } else {
+ data[i].nodes.forEach(fillData);
+ dataNodes.timestamp = data[i].timestamp;
}
}
- })
- graph.links.forEach( function (d) {
- d.source = graph.nodes[d.source]
+ function fillData(node) {
+ var position = dataNodes.nodeIds.indexOf(node.nodeinfo.node_id);
+ if (position === -1) {
+ dataNodes.nodes.push(node);
+ dataNodes.nodeIds.push(node.nodeinfo.node_id);
+ }
+ else if (node.flags.online === true) {
+ dataNodes.nodes[position] = node;
+ }
+ }
- if (graph.nodes[d.target].node)
- d.target = graph.nodes[d.target]
- else
- d.target = undefined
- })
+ var nodes = dataNodes.nodes.filter(function (d) {
+ return "firstseen" in d && "lastseen" in d;
+ });
- var links = graph.links.filter( function (d) {
- return d.target !== undefined
- })
+ nodes.forEach(function (node) {
+ node.firstseen = moment.utc(node.firstseen).local();
+ node.lastseen = moment.utc(node.lastseen).local();
+ });
- links.forEach( function (d) {
- var unknown = (d.source.node === undefined)
- var ids
- if (unknown)
- ids = [d.source.id.replace(/:/g, ""), d.target.node.nodeinfo.node_id]
- else
- ids = [d.source.node.nodeinfo.node_id, d.target.node.nodeinfo.node_id]
- d.id = ids.join("-")
+ var now = moment();
+ var age = moment(now).subtract(config.maxAge, "days");
- if (unknown ||
- !d.source.node.nodeinfo.location ||
- !d.target.node.nodeinfo.location ||
+ var newnodes = limit("firstseen", age, sortByKey("firstseen", nodes).filter(online));
+ var lostnodes = limit("lastseen", age, sortByKey("lastseen", nodes).filter(offline));
+
+ var graphnodes = {};
+
+ dataNodes.nodes.forEach(function (d) {
+ graphnodes[d.nodeinfo.node_id] = d;
+ });
+
+ var graph = dataGraph.batadv;
+
+ graph.nodes.forEach(function (d) {
+ if (d.node_id in graphnodes) {
+ d.node = graphnodes[d.node_id];
+ if (d.unseen) {
+ d.node.flags.online = true;
+ d.node.flags.unseen = true;
+ }
+ }
+ });
+
+ graph.links.forEach(function (d) {
+ d.source = graph.nodes[d.source];
+
+ if (graph.nodes[d.target].node) {
+ d.target = graph.nodes[d.target];
+ } else {
+ d.target = undefined;
+ }
+ });
+
+ var links = graph.links.filter(function (d) {
+ return d.target !== undefined;
+ });
+
+ links.forEach(function (d) {
+ var unknown = (d.source.node === undefined);
+ var ids;
+ if (unknown) {
+ ids = [d.source.id.replace(/:/g, ""), d.target.node.nodeinfo.node_id];
+ } else {
+ ids = [d.source.node.nodeinfo.node_id, d.target.node.nodeinfo.node_id];
+ }
+ d.id = ids.join("-");
+
+ if (unknown || !d.source.node.nodeinfo.location || !d.target.node.nodeinfo.location ||
isNaN(d.source.node.nodeinfo.location.latitude) ||
isNaN(d.source.node.nodeinfo.location.longitude) ||
isNaN(d.target.node.nodeinfo.location.latitude) ||
- isNaN(d.target.node.nodeinfo.location.longitude))
- return
+ isNaN(d.target.node.nodeinfo.location.longitude)) {
+ return;
+ }
- d.latlngs = []
- d.latlngs.push(L.latLng(d.source.node.nodeinfo.location.latitude, d.source.node.nodeinfo.location.longitude))
- d.latlngs.push(L.latLng(d.target.node.nodeinfo.location.latitude, d.target.node.nodeinfo.location.longitude))
+ d.latlngs = [];
+ d.latlngs.push(L.latLng(d.source.node.nodeinfo.location.latitude, d.source.node.nodeinfo.location.longitude));
+ d.latlngs.push(L.latLng(d.target.node.nodeinfo.location.latitude, d.target.node.nodeinfo.location.longitude));
- d.distance = d.latlngs[0].distanceTo(d.latlngs[1])
- })
+ d.distance = d.latlngs[0].distanceTo(d.latlngs[1]);
+ });
- nodes.forEach( function (d) {
- d.neighbours = []
- if (d.statistics) {
- /*eslint camelcase:0*/
- if ("gateway" in d.statistics && d.statistics.gateway in graphnodes)
- d.statistics.gateway = {"node": graphnodes[d.statistics.gateway], "id": d.statistics.gateway}
- if ("nexthop" in d.statistics && d.statistics.nexthop in graphnodes)
- d.statistics.nexthop = {"node": graphnodes[d.statistics.nexthop], "id": d.statistics.nexthop}
- if ("gateway_nexthop" in d.statistics && d.statistics.gateway_nexthop in graphnodes)
- d.statistics.gateway_nexthop = {"node": graphnodes[d.statistics.gateway_nexthop], "id": d.statistics.gateway_nexthop}
- }
- })
+ nodes.forEach(function (d) {
+ d.neighbours = [];
+ if (d.statistics) {
+ /*eslint camelcase:0*/
+ if ("gateway" in d.statistics && d.statistics.gateway in graphnodes) {
+ d.statistics.gateway = {"node": graphnodes[d.statistics.gateway], "id": d.statistics.gateway};
+ }
+ if ("nexthop" in d.statistics && d.statistics.nexthop in graphnodes) {
+ d.statistics.nexthop = {"node": graphnodes[d.statistics.nexthop], "id": d.statistics.nexthop};
+ }
+ if ("gateway_nexthop" in d.statistics && d.statistics.gateway_nexthop in graphnodes) {
+ d.statistics.gateway_nexthop = {
+ "node": graphnodes[d.statistics.gateway_nexthop],
+ "id": d.statistics.gateway_nexthop
+ };
+ }
+ }
+ });
- links.forEach( function (d) {
- if (d.type === "tunnel" || d.vpn) {
- d.type = "VPN"
- d.isVPN = true
- } else if (d.type === "fastd") {
- d.type = "fastd"
- d.isVPN = true
- } else if (d.type === "l2tp") {
- d.type = "L2TP"
- d.isVPN = true
- } else if (d.type === "gre") {
- d.type = "GRE"
- d.isVPN = true
- } else if (d.type === "wireless") {
- d.type = "Wifi"
- d.isVPN = false
- } else if (d.type === "other") {
- d.type = "Kabel"
- d.isVPN = false
- } else {
- d.type = "N/A"
- d.isVPN = false
- }
+ links.forEach(function (d) {
+ if (d.type === "tunnel" || d.vpn) {
+ d.type = "VPN";
+ d.isVPN = true;
+ } else if (d.type === "fastd") {
+ d.type = "fastd";
+ d.isVPN = true;
+ } else if (d.type === "l2tp") {
+ d.type = "L2TP";
+ d.isVPN = true;
+ } else if (d.type === "gre") {
+ d.type = "GRE";
+ d.isVPN = true;
+ } else if (d.type === "wireless") {
+ d.type = "Wifi";
+ d.isVPN = false;
+ } else if (d.type === "other") {
+ d.type = "Kabel";
+ d.isVPN = false;
+ } else {
+ d.type = "N/A";
+ d.isVPN = false;
+ }
- if (d.isVPN && d.target.node)
- d.target.node.flags.uplink = true
+ if (d.isVPN && d.target.node) {
+ d.target.node.flags.uplink = true;
+ }
- var unknown = (d.source.node === undefined)
- if (unknown) {
- d.target.node.neighbours.push({ id: d.source.id, link: d, incoming: true })
- return
- }
- d.source.node.neighbours.push({ node: d.target.node, link: d, incoming: false })
- d.target.node.neighbours.push({ node: d.source.node, link: d, incoming: true })
- if (!d.isVPN)
- d.source.node.meshlinks = d.source.node.meshlinks ? d.source.node.meshlinks + 1 : 1
- })
+ var unknown = (d.source.node === undefined);
+ if (unknown) {
+ d.target.node.neighbours.push({id: d.source.id, link: d, incoming: true});
+ return;
+ }
+ d.source.node.neighbours.push({node: d.target.node, link: d, incoming: false});
+ d.target.node.neighbours.push({node: d.source.node, link: d, incoming: true});
+ if (!d.isVPN) {
+ d.source.node.meshlinks = d.source.node.meshlinks ? d.source.node.meshlinks + 1 : 1;
+ }
+ });
- links.sort( function (a, b) {
- return b.tq - a.tq
- })
+ links.sort(function (a, b) {
+ return b.tq - a.tq;
+ });
- return { now: now,
- timestamp: moment.utc(dataNodes.timestamp).local(),
- nodes: {
- all: nodes,
- new: newnodes,
- lost: lostnodes
- },
- graph: {
- links: links,
- nodes: graph.nodes
- }
- }
- }
+ return {
+ now: now,
+ timestamp: moment.utc(dataNodes.timestamp).local(),
+ nodes: {
+ all: nodes,
+ new: newnodes,
+ lost: lostnodes
+ },
+ graph: {
+ links: links,
+ nodes: graph.nodes
+ }
+ };
+ }
- numeral.language("de")
- moment.locale("de")
+ numeral.language("de");
+ moment.locale("de");
- var router = new Router()
+ var router = new Router();
- var urls = []
+ var urls = [];
- if (typeof config.dataPath === "string" || config.dataPath instanceof String)
- config.dataPath = [config.dataPath]
+ if (typeof config.dataPath === "string" || config.dataPath instanceof String) {
+ config.dataPath = [config.dataPath];
+ }
- for (var i in config.dataPath) {
- urls.push(config.dataPath[i] + "nodes.json")
- urls.push(config.dataPath[i] + "graph.json")
- }
+ for (var i in config.dataPath) {
+ urls.push(config.dataPath[i] + "nodes.json");
+ urls.push(config.dataPath[i] + "graph.json");
+ }
- function update() {
- return Promise.all(urls.map(getJSON))
- .then(handleData)
- }
+ function update() {
+ return Promise.all(urls.map(getJSON))
+ .then(handleData);
+ }
- update()
- .then(function (d) {
- var gui = new GUI(config, router)
- gui.setData(d)
- router.setData(d)
- router.start()
+ update()
+ .then(function (d) {
+ var gui = new GUI(config, router);
+ gui.setData(d);
+ router.setData(d);
+ router.start();
- window.setInterval(function () {
- update().then(function (d) {
- gui.setData(d)
- router.setData(d)
- })
- }, 60000)
- })
- .catch(function (e) {
- document.body.textContent = e
- console.log(e)
- })
- }
-})
+ window.setInterval(function () {
+ update().then(function (d) {
+ gui.setData(d);
+ router.setData(d);
+ });
+ }, 60000);
+ })
+ .catch(function (e) {
+ document.body.textContent = e;
+ console.log(e);
+ });
+ };
+ });
diff --git a/lib/map.js b/lib/map.js
index aca0097..ea44443 100644
--- a/lib/map.js
+++ b/lib/map.js
@@ -1,74 +1,75 @@
define(["map/clientlayer", "map/labelslayer",
- "d3", "leaflet", "moment", "locationmarker", "rbush",
- "leaflet.label", "leaflet.providers"],
+ "d3", "leaflet", "moment", "locationmarker", "rbush",
+ "leaflet.label", "leaflet.providers"],
function (ClientLayer, LabelsLayer, d3, L, moment, LocationMarker, rbush) {
- var options = { worldCopyJump: true,
- zoomControl: false
- }
+ var options = {
+ worldCopyJump: true,
+ zoomControl: false
+ };
var AddLayerButton = L.Control.extend({
- options: {
- position: "bottomright"
- },
+ options: {
+ position: "bottomright"
+ },
- initialize: function (f, options) {
- L.Util.setOptions(this, options)
- this.f = f
- },
+ initialize: function (f, options) {
+ L.Util.setOptions(this, options);
+ this.f = f;
+ },
- onAdd: function () {
- var button = L.DomUtil.create("button", "add-layer")
- button.textContent = "\uF2C7"
+ onAdd: function () {
+ var button = L.DomUtil.create("button", "add-layer");
+ button.textContent = "\uF2C7";
- // L.DomEvent.disableClickPropagation(button)
- // 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.f, this)
+ // L.DomEvent.disableClickPropagation(button)
+ // 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.f, this);
- this.button = button
+ this.button = button;
- return button
- }
- })
+ return button;
+ }
+ });
var LocateButton = L.Control.extend({
- options: {
- position: "bottomright"
- },
+ options: {
+ position: "bottomright"
+ },
- active: false,
- button: undefined,
+ active: false,
+ button: undefined,
- initialize: function (f, options) {
- L.Util.setOptions(this, options)
- this.f = f
- },
+ initialize: function (f, options) {
+ L.Util.setOptions(this, options);
+ this.f = f;
+ },
- onAdd: function () {
- var button = L.DomUtil.create("button", "locate-user")
- button.textContent = "\uF2E9"
+ onAdd: function () {
+ var button = L.DomUtil.create("button", "locate-user");
+ button.textContent = "\uF2E9";
- L.DomEvent.disableClickPropagation(button)
- L.DomEvent.addListener(button, "click", this.onClick, this)
+ L.DomEvent.disableClickPropagation(button);
+ L.DomEvent.addListener(button, "click", this.onClick, this);
- this.button = button
+ this.button = button;
- return button
- },
+ return button;
+ },
- update: function() {
- this.button.classList.toggle("active", this.active)
- },
+ update: function () {
+ this.button.classList.toggle("active", this.active);
+ },
- set: function(v) {
- this.active = v
- this.update()
- },
+ set: function (v) {
+ this.active = v;
+ this.update();
+ },
- onClick: function () {
- this.f(!this.active)
- }
- })
+ onClick: function () {
+ this.f(!this.active);
+ }
+ });
var CoordsPickerButton = L.Control.extend({
options: {
@@ -79,470 +80,547 @@ define(["map/clientlayer", "map/labelslayer",
button: undefined,
initialize: function (f, options) {
- L.Util.setOptions(this, options)
- this.f = f
+ L.Util.setOptions(this, options);
+ this.f = f;
},
onAdd: function () {
- var button = L.DomUtil.create("button", "coord-picker")
- button.textContent = "\uF2A6"
+ var button = L.DomUtil.create("button", "coord-picker");
+ button.textContent = "\uF2A6";
// 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)
+ L.DomEvent.addListener(button, "click", this.onClick, this);
- this.button = button
+ this.button = button;
- return button
+ return button;
},
- update: function() {
- this.button.classList.toggle("active", this.active)
+ update: function () {
+ this.button.classList.toggle("active", this.active);
},
- set: function(v) {
- this.active = v
- this.update()
+ set: function (v) {
+ this.active = v;
+ this.update();
},
onClick: function (e) {
- L.DomEvent.stopPropagation(e)
- this.f(!this.active)
+ 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))
+ var m = L.circleMarker([d.nodeinfo.location.latitude, d.nodeinfo.location.longitude], iconFunc(d));
m.resetStyle = function () {
- m.setStyle(iconFunc(d))
- }
+ m.setStyle(iconFunc(d));
+ };
- m.on("click", router.node(d))
- m.bindLabel(d.nodeinfo.hostname)
+ m.on("click", router.node(d));
+ m.bindLabel(d.nodeinfo.hostname);
- dict[d.nodeinfo.node_id] = m
+ dict[d.nodeinfo.node_id] = m;
- return m
- }
+ return m;
+ };
}
function addLinksToMap(dict, linkScale, graph, router) {
- graph = graph.filter( function (d) {
- return "distance" in d && d.type !== "VPN"
- })
+ graph = graph.filter(function (d) {
+ return "distance" in d && d.type !== "VPN";
+ });
- var lines = graph.map( function (d) {
- var opts = { color: d.type === "Kabel" ? "#50B0F0" : linkScale(d.tq).hex(),
- weight: 4,
- opacity: 0.5,
- dashArray: "none"
- }
+ var lines = graph.map(function (d) {
+ var opts = {
+ color: d.type === "Kabel" ? "#50B0F0" : linkScale(d.tq).hex(),
+ weight: 4,
+ opacity: 0.5,
+ dashArray: "none"
+ };
- var line = L.polyline(d.latlngs, opts)
+ var line = L.polyline(d.latlngs, opts);
line.resetStyle = function () {
- line.setStyle(opts)
- }
+ line.setStyle(opts);
+ };
- line.bindLabel(d.source.node.nodeinfo.hostname + " – " + d.target.node.nodeinfo.hostname + "
" + showDistance(d) + " / " + showTq(d) + "")
- line.on("click", router.link(d))
+ line.bindLabel(d.source.node.nodeinfo.hostname + " – " + d.target.node.nodeinfo.hostname + "
" + showDistance(d) + " / " + showTq(d) + "");
+ line.on("click", router.link(d));
- dict[d.id] = line
+ dict[d.id] = line;
- return line
- })
+ return line;
+ });
- return lines
+ return lines;
}
- 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: 6, fillOpacity: 0.8, opacity: 0.8, weight: 1, className: "stroke-first" }
- var iconAlert = { color: "#D43E2A", fillColor: "#D43E2A", radius: 6, fillOpacity: 0.8, opacity: 0.8, weight: 2, className: "stroke-first node-alert" }
- var iconNew = { color: "#1566A9", fillColor: "#93E929", radius: 6, fillOpacity: 1.0, opacity: 0.5, weight: 2 }
+ 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: 6,
+ fillOpacity: 0.8,
+ opacity: 0.8,
+ weight: 1,
+ className: "stroke-first"
+ };
+ var iconAlert = {
+ color: "#D43E2A",
+ fillColor: "#D43E2A",
+ radius: 6,
+ fillOpacity: 0.8,
+ opacity: 0.8,
+ weight: 2,
+ className: "stroke-first node-alert"
+ };
+ 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 barycenter
- var groupOnline, groupOffline, groupNew, groupLost, groupLines
- var savedView
+ var self = this;
+ var barycenter;
+ var groupOnline, groupOffline, groupNew, groupLost, groupLines;
+ var savedView;
- var map, userLocation
- var layerControl
- var customLayers = {}
- var baseLayers = {}
+ var map, userLocation;
+ var layerControl;
+ var customLayers = {};
+ var baseLayers = {};
var locateUserButton = new LocateButton(function (d) {
- if (d)
- enableTracking()
- else
- disableTracking()
- })
+ if (d) {
+ enableTracking();
+ } else {
+ disableTracking();
+ }
+ });
- var mybuttons = []
+ var mybuttons = [];
function addButton(button) {
- var el = button.onAdd()
- mybuttons.push(el)
- buttons.appendChild(el)
+ var el = button.onAdd();
+ mybuttons.push(el);
+ buttons.appendChild(el);
}
function clearButtons() {
- mybuttons.forEach( function (d) {
- buttons.removeChild(d)
- })
+ mybuttons.forEach(function (d) {
+ buttons.removeChild(d);
+ });
}
var showCoordsPickerButton = new CoordsPickerButton(function (d) {
- if (d)
- enableCoords()
- else
- disableCoords()
- })
+ if (d) {
+ enableCoords();
+ } else {
+ disableCoords();
+ }
+ });
function saveView() {
- savedView = {center: map.getCenter(),
- zoom: map.getZoom()}
+ savedView = {
+ center: map.getCenter(),
+ zoom: map.getZoom()
+ };
}
function enableTracking() {
- map.locate({watch: true,
- enableHighAccuracy: true,
- setView: true
- })
- locateUserButton.set(true)
+ map.locate({
+ watch: true,
+ enableHighAccuracy: true,
+ setView: true
+ });
+ locateUserButton.set(true);
}
function disableTracking() {
- map.stopLocate()
- locationError()
- locateUserButton.set(false)
+ map.stopLocate();
+ locationError();
+ locateUserButton.set(false);
}
function enableCoords() {
- map.getContainer().classList.add("pick-coordinates")
- map.on("click", showCoordinates)
- showCoordsPickerButton.set(true)
+ 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)
+ map.getContainer().classList.remove("pick-coordinates");
+ map.off("click", showCoordinates);
+ showCoordsPickerButton.set(false);
}
function showCoordinates(e) {
- router.gotoLocation(e.latlng)
+ router.gotoLocation(e.latlng);
// window.prompt("Koordinaten (Lat, Lng)", e.latlng.lat.toFixed(9) + ", " + e.latlng.lng.toFixed(9))
- disableCoords()
+ disableCoords();
}
function locationFound(e) {
- if (!userLocation)
- userLocation = new LocationMarker(e.latlng).addTo(map)
+ if (!userLocation) {
+ userLocation = new LocationMarker(e.latlng).addTo(map);
+ }
- userLocation.setLatLng(e.latlng)
- userLocation.setAccuracy(e.accuracy)
+ userLocation.setLatLng(e.latlng);
+ userLocation.setAccuracy(e.accuracy);
}
function locationError() {
if (userLocation) {
- map.removeLayer(userLocation)
- userLocation = null
+ map.removeLayer(userLocation);
+ userLocation = null;
}
}
function addLayer(layerName) {
- if (layerName in baseLayers)
- return
+ if (layerName in baseLayers) {
+ return;
+ }
- if (layerName in customLayers)
- return
+ if (layerName in customLayers) {
+ return;
+ }
try {
- var layer = L.tileLayer.provider(layerName)
- layerControl.addBaseLayer(layer, layerName)
- customLayers[layerName] = layer
+ var layer = L.tileLayer.provider(layerName);
+ layerControl.addBaseLayer(layer, layerName);
+ customLayers[layerName] = layer;
- if (localStorageTest())
- localStorage.setItem("map/customLayers", JSON.stringify(Object.keys(customLayers)))
+ if (localStorageTest()) {
+ localStorage.setItem("map/customLayers", JSON.stringify(Object.keys(customLayers)));
+ }
} catch (e) {
- return
+
}
}
function contextMenuGotoLocation(e) {
- router.gotoLocation(e.latlng)
+ router.gotoLocation(e.latlng);
}
- var el = document.createElement("div")
- el.classList.add("map")
+ var el = document.createElement("div");
+ el.classList.add("map");
- map = L.map(el, options)
+ map = L.map(el, options);
- var layers = config.mapLayers.map( function (d) {
+ var layers = config.mapLayers.map(function (d) {
return {
"name": d.name,
"layer": "url" in d ? L.tileLayer(d.url, d.config) : L.tileLayer.provider(d.name)
- }
- })
+ };
+ });
- layers[0].layer.addTo(map)
+ layers[0].layer.addTo(map);
- layers.forEach( function (d) {
- baseLayers[d.name] = d.layer
- })
+ layers.forEach(function (d) {
+ baseLayers[d.name] = d.layer;
+ });
- map.on("locationfound", locationFound)
- map.on("locationerror", locationError)
- map.on("dragend", saveView)
- map.on("contextmenu", contextMenuGotoLocation)
+ map.on("locationfound", locationFound);
+ map.on("locationerror", locationError);
+ map.on("dragend", saveView);
+ map.on("contextmenu", contextMenuGotoLocation);
- addButton(locateUserButton)
- addButton(showCoordsPickerButton)
+ addButton(locateUserButton);
+ addButton(showCoordsPickerButton);
addButton(new AddLayerButton(function () {
/*eslint no-alert:0*/
- var layerName = prompt("Leaflet Provider:")
- addLayer(layerName)
- }))
+ var layerName = prompt("Leaflet Provider:");
+ addLayer(layerName);
+ }));
- layerControl = L.control.layers(baseLayers, [], {position: "bottomright"})
- layerControl.addTo(map)
+ layerControl = L.control.layers(baseLayers, [], {position: "bottomright"});
+ layerControl.addTo(map);
if (localStorageTest()) {
- var d = JSON.parse(localStorage.getItem("map/customLayers"))
-
- if (d)
- d.forEach(addLayer)
-
- d = JSON.parse(localStorage.getItem("map/selectedLayer"))
- d = d && d.name in baseLayers ? baseLayers[d.name] : d && d.name in customLayers ? customLayers[d.name] : false
+ var d = JSON.parse(localStorage.getItem("map/customLayers"));
if (d) {
- map.removeLayer(layers[0].layer)
- map.addLayer(d)
+ d.forEach(addLayer);
+ }
+
+ d = JSON.parse(localStorage.getItem("map/selectedLayer"));
+ d = d && d.name in baseLayers ? baseLayers[d.name] : d && d.name in customLayers ? customLayers[d.name] : false;
+
+ if (d) {
+ map.removeLayer(layers[0].layer);
+ map.addLayer(d);
}
}
- var clientLayer = new ClientLayer({minZoom: 15})
- clientLayer.addTo(map)
- clientLayer.setZIndex(5)
+ var clientLayer = new ClientLayer({minZoom: 15});
+ clientLayer.addTo(map);
+ clientLayer.setZIndex(5);
- var labelsLayer = new LabelsLayer({})
- labelsLayer.addTo(map)
- labelsLayer.setZIndex(6)
+ var labelsLayer = new LabelsLayer({});
+ labelsLayer.addTo(map);
+ labelsLayer.setZIndex(6);
- map.on("baselayerchange", function(e) {
- map.options.maxZoom = e.layer.options.maxZoom
- clientLayer.options.maxZoom = map.options.maxZoom
- labelsLayer.options.maxZoom = map.options.maxZoom
- if (map.getZoom() > map.options.maxZoom) map.setZoom(map.options.maxZoom)
- if (localStorageTest())
- localStorage.setItem("map/selectedLayer", JSON.stringify({name: e.name}))
- })
+ map.on("baselayerchange", function (e) {
+ map.options.maxZoom = e.layer.options.maxZoom;
+ clientLayer.options.maxZoom = map.options.maxZoom;
+ labelsLayer.options.maxZoom = map.options.maxZoom;
+ if (map.getZoom() > map.options.maxZoom) {
+ map.setZoom(map.options.maxZoom);
+ }
+ if (localStorageTest()) {
+ localStorage.setItem("map/selectedLayer", JSON.stringify({name: e.name}));
+ }
+ });
- var nodeDict = {}
- var linkDict = {}
- var highlight
+ var nodeDict = {};
+ var linkDict = {};
+ var highlight;
function resetMarkerStyles(nodes, links) {
- Object.keys(nodes).forEach( function (d) {
- nodes[d].resetStyle()
- })
+ Object.keys(nodes).forEach(function (d) {
+ nodes[d].resetStyle();
+ });
- Object.keys(links).forEach( function (d) {
- links[d].resetStyle()
- })
+ Object.keys(links).forEach(function (d) {
+ links[d].resetStyle();
+ });
}
function setView(bounds) {
- map.fitBounds(bounds, {paddingTopLeft: [sidebar(), 0]})
+ map.fitBounds(bounds, {paddingTopLeft: [sidebar(), 0]});
}
function resetZoom() {
- if (barycenter)
- setView(barycenter.getBounds())
+ if (barycenter) {
+ setView(barycenter.getBounds());
+ }
}
function goto(m) {
- var bounds
+ var bounds;
- if ("getBounds" in m)
- bounds = m.getBounds()
- else
- bounds = L.latLngBounds([m.getLatLng()])
+ if ("getBounds" in m) {
+ bounds = m.getBounds();
+ } else {
+ bounds = L.latLngBounds([m.getLatLng()]);
+ }
- setView(bounds)
+ setView(bounds);
- return m
+ return m;
}
function updateView(nopanzoom) {
- resetMarkerStyles(nodeDict, linkDict)
- var m
+ resetMarkerStyles(nodeDict, linkDict);
+ var m;
- if (highlight !== undefined)
+ if (highlight !== undefined) {
if (highlight.type === "node") {
- m = nodeDict[highlight.o.nodeinfo.node_id]
+ m = nodeDict[highlight.o.nodeinfo.node_id];
- if (m)
- m.setStyle({ color: "orange", weight: 20, fillOpacity: 1, opacity: 0.7, className: "stroke-first" })
+ if (m) {
+ m.setStyle({color: "orange", weight: 20, fillOpacity: 1, opacity: 0.7, className: "stroke-first"});
+ }
} else if (highlight.type === "link") {
- m = linkDict[highlight.o.id]
+ m = linkDict[highlight.o.id];
- if (m)
- m.setStyle({ weight: 7, opacity: 1, dashArray: "10, 10" })
+ if (m) {
+ m.setStyle({weight: 7, opacity: 1, dashArray: "10, 10"});
+ }
}
+ }
- if (!nopanzoom)
- if (m)
- goto(m)
- else if (savedView)
- map.setView(savedView.center, savedView.zoom)
- else
- resetZoom()
+ if (!nopanzoom) {
+ if (m) {
+ goto(m);
+ } else if (savedView) {
+ map.setView(savedView.center, savedView.zoom);
+ } else {
+ resetZoom();
+ }
+ }
}
function calcBarycenter(nodes) {
- nodes = nodes.map(function (d) { return d.nodeinfo.location })
+ nodes = nodes.map(function (d) {
+ return d.nodeinfo.location;
+ });
- if (nodes.length === 0)
- return undefined
+ if (nodes.length === 0) {
+ return undefined;
+ }
- var lats = nodes.map(function (d) { return d.latitude })
- var lngs = nodes.map(function (d) { return d.longitude })
+ var lats = nodes.map(function (d) {
+ return d.latitude;
+ });
+ var lngs = nodes.map(function (d) {
+ return d.longitude;
+ });
- var barycenter = L.latLng(d3.median(lats), d3.median(lngs))
- var barycenterDev = [d3.deviation(lats), d3.deviation(lngs)]
+ var barycenter = L.latLng(d3.median(lats), d3.median(lngs));
+ var barycenterDev = [d3.deviation(lats), d3.deviation(lngs)];
- if (barycenterDev[0] === undefined)
- barycenterDev[0] = 0
+ if (barycenterDev[0] === undefined) {
+ barycenterDev[0] = 0;
+ }
- if (barycenterDev[1] === undefined)
- barycenterDev[1] = 0
+ if (barycenterDev[1] === undefined) {
+ barycenterDev[1] = 0;
+ }
var barycenterCircle = L.latLng(barycenter.lat + barycenterDev[0],
- barycenter.lng + barycenterDev[1])
+ barycenter.lng + barycenterDev[1]);
- var r = barycenter.distanceTo(barycenterCircle)
+ var r = barycenter.distanceTo(barycenterCircle);
- return L.circle(barycenter, r * config.mapSigmaScale)
+ return L.circle(barycenter, r * config.mapSigmaScale);
}
function mapRTree(d) {
- var o = [ d.nodeinfo.location.latitude, d.nodeinfo.location.longitude,
- d.nodeinfo.location.latitude, d.nodeinfo.location.longitude]
+ var o = [d.nodeinfo.location.latitude, d.nodeinfo.location.longitude,
+ d.nodeinfo.location.latitude, d.nodeinfo.location.longitude];
- o.node = d
+ o.node = d;
- return o
+ return o;
}
self.setData = function (data) {
- nodeDict = {}
- linkDict = {}
+ nodeDict = {};
+ linkDict = {};
- if (groupOffline)
- groupOffline.clearLayers()
+ if (groupOffline) {
+ groupOffline.clearLayers();
+ }
- if (groupOnline)
- groupOnline.clearLayers()
+ if (groupOnline) {
+ groupOnline.clearLayers();
+ }
- if (groupNew)
- groupNew.clearLayers()
+ if (groupNew) {
+ groupNew.clearLayers();
+ }
- if (groupLost)
- groupLost.clearLayers()
+ if (groupLost) {
+ groupLost.clearLayers();
+ }
- if (groupLines)
- groupLines.clearLayers()
+ if (groupLines) {
+ groupLines.clearLayers();
+ }
- var lines = addLinksToMap(linkDict, linkScale, data.graph.links, router)
- groupLines = L.featureGroup(lines).addTo(map)
+ var lines = addLinksToMap(linkDict, linkScale, data.graph.links, router);
+ groupLines = L.featureGroup(lines).addTo(map);
- if (typeof config.fixedCenter === "undefined")
- barycenter = calcBarycenter(data.nodes.all.filter(has_location))
- else
- barycenter = L.circle(L.latLng(new L.LatLng(config.fixedCenter.lat, config.fixedCenter.lng)), config.fixedCenter.radius * 1000)
+ if (typeof config.fixedCenter === "undefined") {
+ barycenter = calcBarycenter(data.nodes.all.filter(has_location));
+ } else {
+ barycenter = L.circle(L.latLng(new L.LatLng(config.fixedCenter.lat, config.fixedCenter.lng)), config.fixedCenter.radius * 1000);
+ }
- var nodesOnline = subtract(data.nodes.all.filter(online), data.nodes.new)
- var nodesOffline = subtract(data.nodes.all.filter(offline), data.nodes.lost)
+ var nodesOnline = subtract(data.nodes.all.filter(online), data.nodes.new);
+ var nodesOffline = subtract(data.nodes.all.filter(offline), data.nodes.lost);
var markersOnline = nodesOnline.filter(has_location)
- .map(mkMarker(nodeDict, function () { return iconOnline }, router))
+ .map(mkMarker(nodeDict, function () {
+ return iconOnline;
+ }, router));
var markersOffline = nodesOffline.filter(has_location)
- .map(mkMarker(nodeDict, function () { return iconOffline }, router))
+ .map(mkMarker(nodeDict, function () {
+ return iconOffline;
+ }, router));
var markersNew = data.nodes.new.filter(has_location)
- .map(mkMarker(nodeDict, function () { return iconNew }, router))
+ .map(mkMarker(nodeDict, function () {
+ return iconNew;
+ }, router));
var markersLost = data.nodes.lost.filter(has_location)
.map(mkMarker(nodeDict, function (d) {
- if (d.lastseen.isAfter(moment(data.now).subtract(3, "days")))
- return iconAlert
+ if (d.lastseen.isAfter(moment(data.now).subtract(3, "days"))) {
+ return iconAlert;
+ }
- return iconLost
- }, router))
+ return iconLost;
+ }, router));
- groupOffline = L.featureGroup(markersOffline).addTo(map)
- groupOnline = L.featureGroup(markersOnline).addTo(map)
- groupLost = L.featureGroup(markersLost).addTo(map)
- groupNew = L.featureGroup(markersNew).addTo(map)
+ groupOffline = L.featureGroup(markersOffline).addTo(map);
+ groupOnline = L.featureGroup(markersOnline).addTo(map);
+ groupLost = L.featureGroup(markersLost).addTo(map);
+ groupNew = L.featureGroup(markersNew).addTo(map);
- var rtreeOnlineAll = rbush(9)
+ var rtreeOnlineAll = rbush(9);
- rtreeOnlineAll.load(data.nodes.all.filter(online).filter(has_location).map(mapRTree))
+ rtreeOnlineAll.load(data.nodes.all.filter(online).filter(has_location).map(mapRTree));
- clientLayer.setData(rtreeOnlineAll)
- labelsLayer.setData({online: nodesOnline.filter(has_location),
- offline: nodesOffline.filter(has_location),
- new: data.nodes.new.filter(has_location),
- lost: data.nodes.lost.filter(has_location)
- })
+ clientLayer.setData(rtreeOnlineAll);
+ labelsLayer.setData({
+ online: nodesOnline.filter(has_location),
+ offline: nodesOffline.filter(has_location),
+ new: data.nodes.new.filter(has_location),
+ lost: data.nodes.lost.filter(has_location)
+ });
- updateView(true)
- }
+ updateView(true);
+ };
self.resetView = function () {
- disableTracking()
- highlight = undefined
- updateView()
- }
+ disableTracking();
+ highlight = undefined;
+ updateView();
+ };
self.gotoNode = function (d) {
- disableTracking()
- highlight = {type: "node", o: d}
- updateView()
- }
+ disableTracking();
+ highlight = {type: "node", o: d};
+ updateView();
+ };
self.gotoLink = function (d) {
- disableTracking()
- highlight = {type: "link", o: d}
- updateView()
- }
+ disableTracking();
+ highlight = {type: "link", o: d};
+ updateView();
+ };
self.gotoLocation = function () {
//ignore
- }
+ };
self.destroy = function () {
- clearButtons()
- map.remove()
+ clearButtons();
+ map.remove();
- if (el.parentNode)
- el.parentNode.removeChild(el)
- }
+ if (el.parentNode) {
+ el.parentNode.removeChild(el);
+ }
+ };
self.render = function (d) {
- d.appendChild(el)
- map.invalidateSize()
- }
+ d.appendChild(el);
+ map.invalidateSize();
+ };
- return self
- }
-})
+ return self;
+ };
+ });
diff --git a/lib/map/clientlayer.js b/lib/map/clientlayer.js
index c3fb439..d6ee4fc 100644
--- a/lib/map/clientlayer.js
+++ b/lib/map/clientlayer.js
@@ -1,76 +1,79 @@
define(["leaflet", "jshashes"],
function (L, jsHashes) {
- var MD5 = new jsHashes.MD5()
+ var MD5 = new jsHashes.MD5();
return L.TileLayer.Canvas.extend({
setData: function (d) {
- this.data = d
+ this.data = d;
//pre-calculate start angles
this.data.all().forEach(function (d) {
- var hash = MD5.hex(d.node.nodeinfo.node_id)
- d.startAngle = (parseInt(hash.substr(0, 2), 16) / 255) * 2 * Math.PI
- })
- this.redraw()
+ var hash = MD5.hex(d.node.nodeinfo.node_id);
+ d.startAngle = (parseInt(hash.substr(0, 2), 16) / 255) * 2 * Math.PI;
+ });
+ this.redraw();
},
drawTile: function (canvas, tilePoint) {
function getTileBBox(s, map, tileSize, margin) {
- var tl = map.unproject([s.x - margin, s.y - margin])
- var br = map.unproject([s.x + margin + tileSize, s.y + margin + tileSize])
+ var tl = map.unproject([s.x - margin, s.y - margin]);
+ var br = map.unproject([s.x + margin + tileSize, s.y + margin + tileSize]);
- return [br.lat, tl.lng, tl.lat, br.lng]
+ return [br.lat, tl.lng, tl.lat, br.lng];
}
- if (!this.data)
- return
+ if (!this.data) {
+ return;
+ }
- var tileSize = this.options.tileSize
- var s = tilePoint.multiplyBy(tileSize)
- var map = this._map
+ var tileSize = this.options.tileSize;
+ var s = tilePoint.multiplyBy(tileSize);
+ var map = this._map;
- var margin = 50
- var bbox = getTileBBox(s, map, tileSize, margin)
+ var margin = 50;
+ var bbox = getTileBBox(s, map, tileSize, margin);
- var nodes = this.data.search(bbox)
+ var nodes = this.data.search(bbox);
- if (nodes.length === 0)
- return
+ if (nodes.length === 0) {
+ return;
+ }
- var ctx = canvas.getContext("2d")
+ var ctx = canvas.getContext("2d");
- var radius = 3
- var a = 1.2
- var startDistance = 12
+ var radius = 3;
+ var a = 1.2;
+ var startDistance = 12;
- ctx.beginPath()
+ ctx.beginPath();
nodes.forEach(function (d) {
- var p = map.project([d.node.nodeinfo.location.latitude, d.node.nodeinfo.location.longitude])
- var clients = d.node.statistics.clients
+ var p = map.project([d.node.nodeinfo.location.latitude, d.node.nodeinfo.location.longitude]);
+ var clients = d.node.statistics.clients;
- if (clients === 0)
- return
+ if (clients === 0) {
+ return;
+ }
- p.x -= s.x
- p.y -= s.y
+ p.x -= s.x;
+ p.y -= s.y;
for (var orbit = 0, i = 0; i < clients; orbit++) {
- var distance = startDistance + orbit * 2 * radius * a
- var n = Math.floor((Math.PI * distance) / (a * radius))
- var delta = clients - i
+ var distance = startDistance + orbit * 2 * radius * a;
+ var n = Math.floor((Math.PI * distance) / (a * radius));
+ var delta = clients - i;
for (var j = 0; j < Math.min(delta, n); i++, j++) {
- var angle = 2 * Math.PI / n * j
- var x = p.x + distance * Math.cos(angle + d.startAngle)
- var y = p.y + distance * Math.sin(angle + d.startAngle)
+ var angle = 2 * Math.PI / n * j;
+ var x = p.x + distance * Math.cos(angle + d.startAngle);
+ var y = p.y + distance * Math.sin(angle + d.startAngle);
- ctx.moveTo(x, y)
- ctx.arc(x, y, radius, 0, 2 * Math.PI)
+ ctx.moveTo(x, y);
+ ctx.arc(x, y, radius, 0, 2 * Math.PI);
}
}
- })
+ });
- ctx.fillStyle = "rgba(220, 0, 103, 0.7)"
- ctx.fill()
+ ctx.fillStyle = "rgba(220, 0, 103, 0.7)";
+ ctx.fill();
}
- })
-})
+ });
+ });
diff --git a/lib/map/labelslayer.js b/lib/map/labelslayer.js
index 2912c10..e616877 100644
--- a/lib/map/labelslayer.js
+++ b/lib/map/labelslayer.js
@@ -1,88 +1,93 @@
define(["leaflet", "rbush"],
function (L, rbush) {
- var labelLocations = [["left", "middle", 0 / 8],
- ["center", "top", 6 / 8],
- ["right", "middle", 4 / 8],
- ["left", "top", 7 / 8],
- ["left", "ideographic", 1 / 8],
- ["right", "top", 5 / 8],
- ["center", "ideographic", 2 / 8],
- ["right", "ideographic", 3 / 8]]
+ var labelLocations = [["left", "middle", 0 / 8],
+ ["center", "top", 6 / 8],
+ ["right", "middle", 4 / 8],
+ ["left", "top", 7 / 8],
+ ["left", "ideographic", 1 / 8],
+ ["right", "top", 5 / 8],
+ ["center", "ideographic", 2 / 8],
+ ["right", "ideographic", 3 / 8]];
- var fontFamily = "Roboto"
- var nodeRadius = 4
+ var fontFamily = "Roboto";
+ var nodeRadius = 4;
- var ctx = document.createElement("canvas").getContext("2d")
+ var ctx = document.createElement("canvas").getContext("2d");
function measureText(font, text) {
- ctx.font = font
- return ctx.measureText(text)
+ ctx.font = font;
+ return ctx.measureText(text);
}
function mapRTree(d) {
- var o = [d.position.lat, d.position.lng, d.position.lat, d.position.lng]
+ var o = [d.position.lat, d.position.lng, d.position.lat, d.position.lng];
- o.label = d
+ o.label = d;
- return o
+ return o;
}
function prepareLabel(fillStyle, fontSize, offset, stroke, minZoom) {
return function (d) {
- var font = fontSize + "px " + fontFamily
- return { position: L.latLng(d.nodeinfo.location.latitude, d.nodeinfo.location.longitude),
- label: d.nodeinfo.hostname,
- offset: offset,
- fillStyle: fillStyle,
- height: fontSize * 1.2,
- font: font,
- stroke: stroke,
- minZoom: minZoom,
- width: measureText(font, d.nodeinfo.hostname).width
- }
- }
+ var font = fontSize + "px " + fontFamily;
+ return {
+ position: L.latLng(d.nodeinfo.location.latitude, d.nodeinfo.location.longitude),
+ label: d.nodeinfo.hostname,
+ offset: offset,
+ fillStyle: fillStyle,
+ height: fontSize * 1.2,
+ font: font,
+ stroke: stroke,
+ minZoom: minZoom,
+ width: measureText(font, d.nodeinfo.hostname).width
+ };
+ };
}
function calcOffset(offset, loc) {
- return [ offset * Math.cos(loc[2] * 2 * Math.PI),
- -offset * Math.sin(loc[2] * 2 * Math.PI)]
+ return [offset * Math.cos(loc[2] * 2 * Math.PI),
+ -offset * Math.sin(loc[2] * 2 * Math.PI)];
}
function labelRect(p, offset, anchor, label, minZoom, maxZoom, z) {
- var margin = 1 + 1.41 * (1 - (z - minZoom) / (maxZoom - minZoom))
+ var margin = 1 + 1.41 * (1 - (z - minZoom) / (maxZoom - minZoom));
- var width = label.width * margin
- var height = label.height * margin
+ var width = label.width * margin;
+ var height = label.height * margin;
- var dx = { left: 0,
- right: -width,
- center: -width / 2
- }
+ var dx = {
+ left: 0,
+ right: -width,
+ center: -width / 2
+ };
- var dy = { top: 0,
- ideographic: -height,
- middle: -height / 2
- }
+ var dy = {
+ top: 0,
+ ideographic: -height,
+ middle: -height / 2
+ };
- var x = p.x + offset[0] + dx[anchor[0]]
- var y = p.y + offset[1] + dy[anchor[1]]
+ var x = p.x + offset[0] + dx[anchor[0]];
+ var y = p.y + offset[1] + dy[anchor[1]];
- return [x, y, x + width, y + height]
+ return [x, y, x + width, y + height];
}
var c = L.TileLayer.Canvas.extend({
onAdd: function (map) {
- L.TileLayer.Canvas.prototype.onAdd.call(this, map)
- if (this.data)
- this.prepareLabels()
+ L.TileLayer.Canvas.prototype.onAdd.call(this, map);
+ if (this.data) {
+ this.prepareLabels();
+ }
},
setData: function (d) {
- this.data = d
- if (this._map)
- this.prepareLabels()
+ this.data = d;
+ if (this._map) {
+ this.prepareLabels();
+ }
},
prepareLabels: function () {
- var d = this.data
+ var d = this.data;
// label:
// - position (WGS84 coords)
@@ -92,137 +97,144 @@ define(["leaflet", "rbush"],
// - label (string)
// - color (string)
- var labelsOnline = d.online.map(prepareLabel("rgba(0, 0, 0, 0.9)", 10, 8, true, 13))
- var labelsOffline = d.offline.map(prepareLabel("rgba(212, 62, 42, 0.9)", 9, 5, false, 16))
- var labelsNew = d.new.map(prepareLabel("rgba(48, 99, 20, 0.9)", 11, 8, true, 0))
- var labelsLost = d.lost.map(prepareLabel("rgba(212, 62, 42, 0.9)", 11, 8, true, 0))
+ var labelsOnline = d.online.map(prepareLabel("rgba(0, 0, 0, 0.9)", 10, 8, true, 13));
+ var labelsOffline = d.offline.map(prepareLabel("rgba(212, 62, 42, 0.9)", 9, 5, false, 16));
+ var labelsNew = d.new.map(prepareLabel("rgba(48, 99, 20, 0.9)", 11, 8, true, 0));
+ var labelsLost = d.lost.map(prepareLabel("rgba(212, 62, 42, 0.9)", 11, 8, true, 0));
var labels = []
- .concat(labelsNew)
- .concat(labelsLost)
- .concat(labelsOnline)
- .concat(labelsOffline)
+ .concat(labelsNew)
+ .concat(labelsLost)
+ .concat(labelsOnline)
+ .concat(labelsOffline);
- var minZoom = this.options.minZoom
- var maxZoom = this.options.maxZoom
+ var minZoom = this.options.minZoom;
+ var maxZoom = this.options.maxZoom;
- var trees = []
+ var trees = [];
- var map = this._map
+ var map = this._map;
function nodeToRect(z) {
return function (d) {
- var p = map.project(d.position, z)
+ var p = map.project(d.position, z);
return [p.x - nodeRadius, p.y - nodeRadius,
- p.x + nodeRadius, p.y + nodeRadius]
- }
+ p.x + nodeRadius, p.y + nodeRadius];
+ };
}
for (var z = minZoom; z <= maxZoom; z++) {
- trees[z] = rbush(9)
- trees[z].load(labels.map(nodeToRect(z)))
+ trees[z] = rbush(9);
+ trees[z].load(labels.map(nodeToRect(z)));
}
labels = labels.map(function (d) {
var best = labelLocations.map(function (loc) {
- var offset = calcOffset(d.offset, loc)
- var z
+ var offset = calcOffset(d.offset, loc);
+ var z;
for (z = maxZoom; z >= d.minZoom; z--) {
- var p = map.project(d.position, z)
- var rect = labelRect(p, offset, loc, d, minZoom, maxZoom, z)
- var candidates = trees[z].search(rect)
+ var p = map.project(d.position, z);
+ var rect = labelRect(p, offset, loc, d, minZoom, maxZoom, z);
+ var candidates = trees[z].search(rect);
- if (candidates.length > 0)
- break
+ if (candidates.length > 0) {
+ break;
+ }
}
- return {loc: loc, z: z + 1}
+ return {loc: loc, z: z + 1};
}).filter(function (d) {
- return d.z <= maxZoom
+ return d.z <= maxZoom;
}).sort(function (a, b) {
- return a.z - b.z
- })[0]
+ return a.z - b.z;
+ })[0];
if (best !== undefined) {
- d.offset = calcOffset(d.offset, best.loc)
- d.minZoom = best.z
- d.anchor = best.loc
+ d.offset = calcOffset(d.offset, best.loc);
+ d.minZoom = best.z;
+ d.anchor = best.loc;
for (var z = maxZoom; z >= best.z; z--) {
- var p = map.project(d.position, z)
- var rect = labelRect(p, d.offset, best.loc, d, minZoom, maxZoom, z)
- trees[z].insert(rect)
+ var p = map.project(d.position, z);
+ var rect = labelRect(p, d.offset, best.loc, d, minZoom, maxZoom, z);
+ trees[z].insert(rect);
}
- return d
- } else
- return undefined
- }).filter(function (d) { return d !== undefined })
+ return d;
+ } else {
+ return undefined;
+ }
+ }).filter(function (d) {
+ return d !== undefined;
+ });
- this.margin = 16
+ this.margin = 16;
- if (labels.length > 0)
+ if (labels.length > 0) {
this.margin += labels.map(function (d) {
- return d.width
- }).sort().reverse()[0]
+ return d.width;
+ }).sort().reverse()[0];
+ }
- this.labels = rbush(9)
- this.labels.load(labels.map(mapRTree))
+ this.labels = rbush(9);
+ this.labels.load(labels.map(mapRTree));
- this.redraw()
+ this.redraw();
},
drawTile: function (canvas, tilePoint, zoom) {
function getTileBBox(s, map, tileSize, margin) {
- var tl = map.unproject([s.x - margin, s.y - margin])
- var br = map.unproject([s.x + margin + tileSize, s.y + margin + tileSize])
+ var tl = map.unproject([s.x - margin, s.y - margin]);
+ var br = map.unproject([s.x + margin + tileSize, s.y + margin + tileSize]);
- return [br.lat, tl.lng, tl.lat, br.lng]
+ return [br.lat, tl.lng, tl.lat, br.lng];
}
- if (!this.labels)
- return
+ if (!this.labels) {
+ return;
+ }
- var tileSize = this.options.tileSize
- var s = tilePoint.multiplyBy(tileSize)
- var map = this._map
+ var tileSize = this.options.tileSize;
+ var s = tilePoint.multiplyBy(tileSize);
+ var map = this._map;
function projectNodes(d) {
- var p = map.project(d.label.position)
+ var p = map.project(d.label.position);
- p.x -= s.x
- p.y -= s.y
+ p.x -= s.x;
+ p.y -= s.y;
- return {p: p, label: d.label}
+ return {p: p, label: d.label};
}
- var bbox = getTileBBox(s, map, tileSize, this.margin)
+ var bbox = getTileBBox(s, map, tileSize, this.margin);
- var labels = this.labels.search(bbox).map(projectNodes)
+ var labels = this.labels.search(bbox).map(projectNodes);
- var ctx = canvas.getContext("2d")
+ var ctx = canvas.getContext("2d");
- ctx.lineWidth = 5
- ctx.strokeStyle = "rgba(255, 255, 255, 0.8)"
- ctx.miterLimit = 2
+ ctx.lineWidth = 5;
+ ctx.strokeStyle = "rgba(255, 255, 255, 0.8)";
+ ctx.miterLimit = 2;
function drawLabel(d) {
- ctx.font = d.label.font
- ctx.textAlign = d.label.anchor[0]
- ctx.textBaseline = d.label.anchor[1]
- ctx.fillStyle = d.label.fillStyle
+ ctx.font = d.label.font;
+ ctx.textAlign = d.label.anchor[0];
+ ctx.textBaseline = d.label.anchor[1];
+ ctx.fillStyle = d.label.fillStyle;
- if (d.label.stroke)
- ctx.strokeText(d.label.label, d.p.x + d.label.offset[0], d.p.y + d.label.offset[1])
+ if (d.label.stroke) {
+ ctx.strokeText(d.label.label, d.p.x + d.label.offset[0], d.p.y + d.label.offset[1]);
+ }
- ctx.fillText(d.label.label, d.p.x + d.label.offset[0], d.p.y + d.label.offset[1])
+ ctx.fillText(d.label.label, d.p.x + d.label.offset[0], d.p.y + d.label.offset[1]);
}
labels.filter(function (d) {
- return zoom >= d.label.minZoom
- }).forEach(drawLabel)
+ return zoom >= d.label.minZoom;
+ }).forEach(drawLabel);
}
- })
+ });
- return c
-})
+ return c;
+ });
diff --git a/lib/meshstats.js b/lib/meshstats.js
index 9d50044..0abd3cc 100644
--- a/lib/meshstats.js
+++ b/lib/meshstats.js
@@ -1,55 +1,61 @@
define(function () {
return function (config) {
- var self = this
- var stats, timestamp
+ var self = this;
+ var stats, timestamp;
self.setData = function (d) {
- var totalNodes = sum(d.nodes.all.map(one))
- var totalOnlineNodes = sum(d.nodes.all.filter(online).map(one))
- var totalOfflineNodes = sum(d.nodes.all.filter(function (node) {return !node.flags.online}).map(one))
- var totalNewNodes = sum(d.nodes.new.map(one))
- var totalLostNodes = sum(d.nodes.lost.map(one))
- var totalClients = sum(d.nodes.all.filter(online).map( function (d) {
- return d.statistics.clients ? d.statistics.clients : 0
- }))
- var totalGateways = sum(Array.from(new Set(d.nodes.all.filter(online).map( function(d) {
- return ("gateway" in d.statistics && d.statistics.gateway.id) ? d.statistics.gateway.id : d.statistics.gateway
- }).concat(d.nodes.all.filter( function (d) {
- return d.flags.gateway
- })))).map(function(d) {
- return (typeof d === "string") ? 1 : 0
- }))
+ var totalNodes = sum(d.nodes.all.map(one));
+ var totalOnlineNodes = sum(d.nodes.all.filter(online).map(one));
+ var totalOfflineNodes = sum(d.nodes.all.filter(function (node) {
+ return !node.flags.online;
+ }).map(one));
+ var totalNewNodes = sum(d.nodes.new.map(one));
+ var totalLostNodes = sum(d.nodes.lost.map(one));
+ var totalClients = sum(d.nodes.all.filter(online).map(function (d) {
+ return d.statistics.clients ? d.statistics.clients : 0;
+ }));
+ var totalGateways = sum(Array.from(new Set(d.nodes.all.filter(online).map(function (d) {
+ return ("gateway" in d.statistics && d.statistics.gateway.id) ? d.statistics.gateway.id : d.statistics.gateway;
+ }).concat(d.nodes.all.filter(function (d) {
+ return d.flags.gateway;
+ })))).map(function (d) {
+ return (typeof d === "string") ? 1 : 0;
+ }));
- var nodetext = [{ count: totalOnlineNodes, label: "online" },
- { count: totalOfflineNodes, label: "offline" },
- { count: totalNewNodes, label: "neu" },
- { count: totalLostNodes, label: "verschwunden" }
- ].filter( function (d) { return d.count > 0 } )
- .map( function (d) { return [d.count, d.label].join(" ") } )
- .join(", ")
+ var nodetext = [{count: totalOnlineNodes, label: "online"},
+ {count: totalOfflineNodes, label: "offline"},
+ {count: totalNewNodes, label: "neu"},
+ {count: totalLostNodes, label: "verschwunden"}
+ ].filter(function (d) {
+ return d.count > 0;
+ })
+ .map(function (d) {
+ return [d.count, d.label].join(" ");
+ })
+ .join(", ");
stats.textContent = totalNodes + " Knoten " +
- "(" + nodetext + "), " +
- totalClients + " Client" + ( totalClients === 1 ? ", " : "s, " ) +
- totalGateways + " Gateways"
+ "(" + nodetext + "), " +
+ totalClients + " Client" + ( totalClients === 1 ? ", " : "s, " ) +
+ totalGateways + " Gateways";
- timestamp.textContent = "Diese Daten sind von " + d.timestamp.format("LLLL") + "."
- }
+ timestamp.textContent = "Diese Daten sind von " + d.timestamp.format("LLLL") + ".";
+ };
self.render = function (el) {
- var h2 = document.createElement("h2")
- h2.textContent = config.siteName
- el.appendChild(h2)
+ var h2 = document.createElement("h2");
+ h2.textContent = config.siteName;
+ el.appendChild(h2);
- var p = document.createElement("p")
- el.appendChild(p)
- stats = document.createTextNode("")
- p.appendChild(stats)
- p.appendChild(document.createElement("br"))
- timestamp = document.createTextNode("")
- p.appendChild(timestamp)
- }
+ var p = document.createElement("p");
+ el.appendChild(p);
+ stats = document.createTextNode("");
+ p.appendChild(stats);
+ p.appendChild(document.createElement("br"));
+ timestamp = document.createTextNode("");
+ p.appendChild(timestamp);
+ };
- return self
- }
-})
+ return self;
+ };
+});
diff --git a/lib/nodelist.js b/lib/nodelist.js
index 2130061..b81ec59 100644
--- a/lib/nodelist.js
+++ b/lib/nodelist.js
@@ -1,97 +1,107 @@
define(["sorttable", "virtual-dom", "numeral"], function (SortTable, V, numeral) {
function getUptime(now, d) {
- if (d.flags.online && "uptime" in d.statistics)
- return Math.round(d.statistics.uptime)
- else if (!d.flags.online && "lastseen" in d)
- return Math.round(-(now.unix() - d.lastseen.unix()))
+ if (d.flags.online && "uptime" in d.statistics) {
+ return Math.round(d.statistics.uptime);
+ } else if (!d.flags.online && "lastseen" in d) {
+ return Math.round(-(now.unix() - d.lastseen.unix()));
+ }
}
function showUptime(uptime) {
- var s = ""
- uptime /= 3600
+ var s = "";
+ uptime /= 3600;
- if (uptime !== undefined)
- if (Math.abs(uptime) >= 24)
- s = Math.round(uptime / 24) + "d"
- else
- s = Math.round(uptime) + "h"
+ if (uptime !== undefined) {
+ if (Math.abs(uptime) >= 24) {
+ s = Math.round(uptime / 24) + "d";
+ } else {
+ s = Math.round(uptime) + "h";
+ }
+ }
- return s
+ return s;
}
- var headings = [{ name: "Knoten",
- sort: function (a, b) {
- var aname = typeof a.nodeinfo.hostname === "string" ? a.nodeinfo.hostname : a.nodeinfo.node_id
- var bname = typeof b.nodeinfo.hostname === "string" ? b.nodeinfo.hostname : b.nodeinfo.node_id
- if (typeof aname === "string" && typeof bname === "string")
- return aname.localeCompare(bname)
- return typeof aname === "string" ? 1 : typeof bname === "string" ? -1 : 0
- },
- reverse: false
- },
- { name: "Uptime",
- sort: function (a, b) {
- return a.uptime - b.uptime
- },
- reverse: true
- },
- { name: "#Links",
- sort: function (a, b) {
- return a.meshlinks - b.meshlinks
- },
- reverse: true
- },
- { name: "Clients",
- sort: function (a, b) {
- return ("clients" in a.statistics ? a.statistics.clients : -1) -
- ("clients" in b.statistics ? b.statistics.clients : -1)
- },
- reverse: true
- }]
+ var headings = [{
+ name: "Knoten",
+ sort: function (a, b) {
+ var aname = typeof a.nodeinfo.hostname === "string" ? a.nodeinfo.hostname : a.nodeinfo.node_id;
+ var bname = typeof b.nodeinfo.hostname === "string" ? b.nodeinfo.hostname : b.nodeinfo.node_id;
+ if (typeof aname === "string" && typeof bname === "string") {
+ return aname.localeCompare(bname);
+ }
+ return typeof aname === "string" ? 1 : typeof bname === "string" ? -1 : 0;
+ },
+ reverse: false
+ },
+ {
+ name: "Uptime",
+ sort: function (a, b) {
+ return a.uptime - b.uptime;
+ },
+ reverse: true
+ },
+ {
+ name: "#Links",
+ sort: function (a, b) {
+ return a.meshlinks - b.meshlinks;
+ },
+ reverse: true
+ },
+ {
+ name: "Clients",
+ sort: function (a, b) {
+ return ("clients" in a.statistics ? a.statistics.clients : -1) -
+ ("clients" in b.statistics ? b.statistics.clients : -1);
+ },
+ reverse: true
+ }];
- return function(router) {
+ return function (router) {
function renderRow(d) {
- var td1Content = []
- var aClass = ["hostname", d.flags.online ? "online" : "offline"]
+ var td1Content = [];
+ var aClass = ["hostname", d.flags.online ? "online" : "offline"];
- td1Content.push(V.h("a", { className: aClass.join(" "),
- onclick: router.node(d),
- href: "#!n:" + d.nodeinfo.node_id
- }, d.nodeinfo.hostname))
+ td1Content.push(V.h("a", {
+ className: aClass.join(" "),
+ onclick: router.node(d),
+ href: "#!n:" + d.nodeinfo.node_id
+ }, d.nodeinfo.hostname));
- if (has_location(d))
- td1Content.push(V.h("span", {className: "icon ion-location"}))
+ if (has_location(d)) {
+ td1Content.push(V.h("span", {className: "icon ion-location"}));
+ }
- var td1 = V.h("td", td1Content)
- var td2 = V.h("td", showUptime(d.uptime))
- var td3 = V.h("td", d.meshlinks.toString())
- var td4 = V.h("td", numeral("clients" in d.statistics ? d.statistics.clients : "").format("0,0"))
+ var td1 = V.h("td", td1Content);
+ var td2 = V.h("td", showUptime(d.uptime));
+ var td3 = V.h("td", d.meshlinks.toString());
+ var td4 = V.h("td", numeral("clients" in d.statistics ? d.statistics.clients : "").format("0,0"));
- return V.h("tr", [td1, td2, td3, td4])
+ return V.h("tr", [td1, td2, td3, td4]);
}
- var table = new SortTable(headings, 0, renderRow)
+ var table = new SortTable(headings, 0, renderRow);
this.render = function (d) {
- var el = document.createElement("div")
- d.appendChild(el)
+ var el = document.createElement("div");
+ d.appendChild(el);
- var h2 = document.createElement("h2")
- h2.textContent = "Alle Knoten"
- el.appendChild(h2)
+ var h2 = document.createElement("h2");
+ h2.textContent = "Alle Knoten";
+ el.appendChild(h2);
- el.appendChild(table.el)
- }
+ el.appendChild(table.el);
+ };
this.setData = function (d) {
var data = d.nodes.all.map(function (e) {
- var n = Object.create(e)
- n.uptime = getUptime(d.now, e) || 0
- n.meshlinks = e.meshlinks || 0
- return n
- })
+ var n = Object.create(e);
+ n.uptime = getUptime(d.now, e) || 0;
+ n.meshlinks = e.meshlinks || 0;
+ return n;
+ });
- table.setData(data)
- }
- }
-})
+ table.setData(data);
+ };
+ };
+});
diff --git a/lib/proportions.js b/lib/proportions.js
index f5b0b26..8523165 100644
--- a/lib/proportions.js
+++ b/lib/proportions.js
@@ -1,236 +1,278 @@
-define(["chroma-js", "virtual-dom", "numeral-intl", "filters/genericnode", "vercomp" ],
+define(["chroma-js", "virtual-dom", "numeral-intl", "filters/genericnode", "vercomp"],
function (Chroma, V, numeral, Filter, vercomp) {
- return function (config, filterManager) {
- var self = this
- var scale = Chroma.scale("YlGnBu").mode("lab")
+ return function (config, filterManager) {
+ var self = this;
+ var scale = Chroma.scale("YlGnBu").mode("lab");
- var statusTable = document.createElement("table")
- statusTable.classList.add("proportion")
+ var statusTable = document.createElement("table");
+ statusTable.classList.add("proportion");
- var fwTable = document.createElement("table")
- fwTable.classList.add("proportion")
+ var fwTable = document.createElement("table");
+ fwTable.classList.add("proportion");
- var hwTable = document.createElement("table")
- hwTable.classList.add("proportion")
+ var hwTable = document.createElement("table");
+ hwTable.classList.add("proportion");
- var geoTable = document.createElement("table")
- geoTable.classList.add("proportion")
+ var geoTable = document.createElement("table");
+ geoTable.classList.add("proportion");
- var autoTable = document.createElement("table")
- autoTable.classList.add("proportion")
+ var autoTable = document.createElement("table");
+ autoTable.classList.add("proportion");
- var uplinkTable = document.createElement("table")
- uplinkTable.classList.add("proportion")
+ var uplinkTable = document.createElement("table");
+ uplinkTable.classList.add("proportion");
- var gwNodesTable = document.createElement("table")
- gwNodesTable.classList.add("proportion")
+ var gwNodesTable = document.createElement("table");
+ gwNodesTable.classList.add("proportion");
- var gwClientsTable = document.createElement("table")
- gwClientsTable.classList.add("proportion")
+ var gwClientsTable = document.createElement("table");
+ gwClientsTable.classList.add("proportion");
- var siteTable = document.createElement("table")
- siteTable.classList.add("proportion")
+ var siteTable = document.createElement("table");
+ siteTable.classList.add("proportion");
- function showStatGlobal(o) {
- return showStat(o)
- }
-
- function count(nodes, key, f) {
- var dict = {}
-
- nodes.forEach( function (d) {
- var v = dictGet(d, key.slice(0))
-
- if (f !== undefined)
- v = f(v)
-
- if (v === null)
- return
-
- dict[v] = 1 + (v in dict ? dict[v] : 0)
- })
-
- return Object.keys(dict).map(function (d) { return [d, dict[d], key, f] })
- }
-
- function countClients(nodes, key, f) {
- var dict = {}
-
- nodes.forEach( function (d) {
- var v = dictGet(d, key.slice(0))
-
- if (f !== undefined)
- v = f(v)
-
- if (v === null)
- return
-
- dict[v] = d.statistics.clients + (v in dict ? dict[v] : 0)
- })
-
- return Object.keys(dict).map(function (d) { return [d, dict[d], key, f] })
- }
-
-
- function addFilter(filter) {
- return function () {
- filterManager.addFilter(filter)
-
- return false
+ function showStatGlobal(o) {
+ return showStat(o);
}
- }
- function fillTable(name, table, data) {
- if (!table.last)
- table.last = V.h("table")
+ function count(nodes, key, f) {
+ var dict = {};
- var max = 0
- data.forEach(function (d) {
- if (d[1] > max)
- max = d[1]
- })
+ nodes.forEach(function (d) {
+ var v = dictGet(d, key.slice(0));
- var items = data.map(function (d) {
- var v = d[1] / max
- var c1 = Chroma.contrast(scale(v), "white")
- var c2 = Chroma.contrast(scale(v), "black")
+ if (f !== undefined) {
+ v = f(v);
+ }
- var filter = new Filter(name, d[2], d[0], d[3])
+ if (v === null) {
+ return;
+ }
- var a = V.h("a", { href: "#", onclick: addFilter(filter) }, d[0])
+ dict[v] = 1 + (v in dict ? dict[v] : 0);
+ });
- var th = V.h("th", a)
- var td = V.h("td", V.h("span", {style: {
- width: Math.round(v * 100) + "%",
- backgroundColor: scale(v).hex(),
- color: c1 > c2 ? "white" : "black"
- }}, numeral(d[1]).format("0,0")))
+ return Object.keys(dict).map(function (d) {
+ return [d, dict[d], key, f];
+ });
+ }
- return V.h("tr", [th, td])
- })
+ function countClients(nodes, key, f) {
+ var dict = {};
- var tableNew = V.h("table", items)
- table = V.patch(table, V.diff(table.last, tableNew))
- table.last = tableNew
- }
+ nodes.forEach(function (d) {
+ var v = dictGet(d, key.slice(0));
- self.setData = function (data) {
- var onlineNodes = data.nodes.all.filter(online)
- var nodes = onlineNodes.concat(data.nodes.lost)
- var nodeDict = {}
+ if (f !== undefined) {
+ v = f(v);
+ }
- data.nodes.all.forEach(function (d) {
- nodeDict[d.nodeinfo.node_id] = d
- })
+ if (v === null) {
+ return;
+ }
- var statusDict = count(nodes, ["flags", "online"], function (d) {
- return d ? "online" : "offline"
- })
- var fwDict = count(nodes, ["nodeinfo", "software", "firmware", "release"])
- var hwDict = count(nodes, ["nodeinfo", "hardware", "model"], function (d) {
- if (d) {
- d = d.replace(/\(r\)|\(tm\)/gi, "").replace(/AMD |Intel |TP-Link | CPU| Processor/g, "")
- if (d.indexOf("@") > 0) d = d.substring(0, d.indexOf("@"))
+ dict[v] = d.statistics.clients + (v in dict ? dict[v] : 0);
+ });
+
+ return Object.keys(dict).map(function (d) {
+ return [d, dict[d], key, f];
+ });
+ }
+
+
+ function addFilter(filter) {
+ return function () {
+ filterManager.addFilter(filter);
+
+ return false;
+ };
+ }
+
+ function fillTable(name, table, data) {
+ if (!table.last) {
+ table.last = V.h("table");
}
- return d
- })
- var geoDict = count(nodes, ["nodeinfo", "location"], function (d) {
- return d && d.longitude && d.latitude ? "ja" : "nein"
- })
- var autoDict = count(nodes, ["nodeinfo", "software", "autoupdater"], function (d) {
- if (d === null)
- return null
- else if (d.enabled)
- return d.branch
- else
- return "(deaktiviert)"
- })
+ var max = 0;
+ data.forEach(function (d) {
+ if (d[1] > max) {
+ max = d[1];
+ }
+ });
- var uplinkDict = count(nodes, ["flags", "uplink"], function (d) {
- return d ? "ja" : "nein"
- })
+ var items = data.map(function (d) {
+ var v = d[1] / max;
+ var c1 = Chroma.contrast(scale(v), "white");
+ var c2 = Chroma.contrast(scale(v), "black");
- var gwNodesDict = count(onlineNodes, ["statistics", "gateway"], function (d) {
- if (d === null)
- return null
+ var filter = new Filter(name, d[2], d[0], d[3]);
- if (d.node)
- return d.node.nodeinfo.hostname
+ var a = V.h("a", {href: "#", onclick: addFilter(filter)}, d[0]);
- if (d.id)
- return d.id
+ var th = V.h("th", a);
+ var td = V.h("td", V.h("span", {
+ style: {
+ width: Math.round(v * 100) + "%",
+ backgroundColor: scale(v).hex(),
+ color: c1 > c2 ? "white" : "black"
+ }
+ }, numeral(d[1]).format("0,0")));
- return d
- })
+ return V.h("tr", [th, td]);
+ });
- var gwClientsDict = countClients(onlineNodes, ["statistics", "gateway"], function (d) {
- if (d === null)
- return null
-
- if (d.node)
- return d.node.nodeinfo.hostname
-
- if (d.id)
- return d.id
-
- return d
- })
-
- var siteDict = count(nodes, ["nodeinfo", "system", "site_code"], function (d) {
- var rt = d
- if (config.siteNames)
- config.siteNames.forEach( function (t) {
- if(d === t.site)
- rt = t.name
- })
- return rt
- })
-
- fillTable("Status", statusTable, statusDict.sort(function (a, b) { return b[1] - a[1] }))
- fillTable("Firmware", fwTable, fwDict.sort(function (a, b) { return vercomp(b[0], a[0]) }))
- fillTable("Hardware", hwTable, hwDict.sort(function (a, b) { return b[1] - a[1] }))
- fillTable("Koordinaten", geoTable, geoDict.sort(function (a, b) { return b[1] - a[1] }))
- fillTable("Uplink", uplinkTable, uplinkDict.sort(function (a, b) { return b[1] - a[1] }))
- fillTable("Autom. Updates", autoTable, autoDict.sort(function (a, b) { return b[1] - a[1] }))
- fillTable("Gateway", gwNodesTable, gwNodesDict.sort(function (a, b) { return b[1] - a[1] }))
- fillTable("Gateway", gwClientsTable, gwClientsDict.sort(function (a, b) { return b[1] - a[1] }))
- fillTable("Site", siteTable, siteDict.sort(function (a, b) { return b[1] - a[1] }))
- }
-
-
- self.render = function (el) {
- var h2
- self.renderSingle(el, "Status", statusTable)
- self.renderSingle(el, "Nodes an Gateway", gwNodesTable)
- self.renderSingle(el, "Clients an Gateway", gwClientsTable)
- self.renderSingle(el, "Firmwareversionen", fwTable)
- self.renderSingle(el, "Uplink", uplinkTable)
- self.renderSingle(el, "Hardwaremodelle", hwTable)
- self.renderSingle(el, "Auf der Karte sichtbar", geoTable)
- self.renderSingle(el, "Autoupdater", autoTable)
- self.renderSingle(el, "Site", siteTable)
-
- if (config.globalInfos)
- config.globalInfos.forEach(function (globalInfo) {
- h2 = document.createElement("h2")
- h2.textContent = globalInfo.name
- el.appendChild(h2)
- el.appendChild(showStatGlobal(globalInfo))
- })
+ var tableNew = V.h("table", items);
+ table = V.patch(table, V.diff(table.last, tableNew));
+ table.last = tableNew;
}
- self.renderSingle = function (el, heading, table) {
- var h2
- h2 = document.createElement("h2")
- h2.textContent = heading
- h2.onclick = function () {
- table.classList.toggle("hidden")
- }
- el.appendChild(h2)
- el.appendChild(table)
- }
- return self
- }
-})
+ self.setData = function (data) {
+ var onlineNodes = data.nodes.all.filter(online);
+ var nodes = onlineNodes.concat(data.nodes.lost);
+ var nodeDict = {};
+
+ data.nodes.all.forEach(function (d) {
+ nodeDict[d.nodeinfo.node_id] = d;
+ });
+
+ var statusDict = count(nodes, ["flags", "online"], function (d) {
+ return d ? "online" : "offline";
+ });
+ var fwDict = count(nodes, ["nodeinfo", "software", "firmware", "release"]);
+ var hwDict = count(nodes, ["nodeinfo", "hardware", "model"], function (d) {
+ if (d) {
+ d = d.replace(/\(r\)|\(tm\)/gi, "").replace(/AMD |Intel |TP-Link | CPU| Processor/g, "");
+ if (d.indexOf("@") > 0) {
+ d = d.substring(0, d.indexOf("@"));
+ }
+ }
+ return d;
+ });
+ var geoDict = count(nodes, ["nodeinfo", "location"], function (d) {
+ return d && d.longitude && d.latitude ? "ja" : "nein";
+ });
+
+ var autoDict = count(nodes, ["nodeinfo", "software", "autoupdater"], function (d) {
+ if (d === null) {
+ return null;
+ } else if (d.enabled) {
+ return d.branch;
+ } else {
+ return "(deaktiviert)";
+ }
+ });
+
+ var uplinkDict = count(nodes, ["flags", "uplink"], function (d) {
+ return d ? "ja" : "nein";
+ });
+
+ var gwNodesDict = count(onlineNodes, ["statistics", "gateway"], function (d) {
+ if (d === null) {
+ return null;
+ }
+
+ if (d.node) {
+ return d.node.nodeinfo.hostname;
+ }
+
+ if (d.id) {
+ return d.id;
+ }
+
+ return d;
+ });
+
+ var gwClientsDict = countClients(onlineNodes, ["statistics", "gateway"], function (d) {
+ if (d === null) {
+ return null;
+ }
+
+ if (d.node) {
+ return d.node.nodeinfo.hostname;
+ }
+
+ if (d.id) {
+ return d.id;
+ }
+
+ return d;
+ });
+
+ var siteDict = count(nodes, ["nodeinfo", "system", "site_code"], function (d) {
+ var rt = d;
+ if (config.siteNames) {
+ config.siteNames.forEach(function (t) {
+ if (d === t.site) {
+ rt = t.name;
+ }
+ });
+ }
+ return rt;
+ });
+
+ fillTable("Status", statusTable, statusDict.sort(function (a, b) {
+ return b[1] - a[1];
+ }));
+ fillTable("Firmware", fwTable, fwDict.sort(function (a, b) {
+ return vercomp(b[0], a[0]);
+ }));
+ fillTable("Hardware", hwTable, hwDict.sort(function (a, b) {
+ return b[1] - a[1];
+ }));
+ fillTable("Koordinaten", geoTable, geoDict.sort(function (a, b) {
+ return b[1] - a[1];
+ }));
+ fillTable("Uplink", uplinkTable, uplinkDict.sort(function (a, b) {
+ return b[1] - a[1];
+ }));
+ fillTable("Autom. Updates", autoTable, autoDict.sort(function (a, b) {
+ return b[1] - a[1];
+ }));
+ fillTable("Gateway", gwNodesTable, gwNodesDict.sort(function (a, b) {
+ return b[1] - a[1];
+ }));
+ fillTable("Gateway", gwClientsTable, gwClientsDict.sort(function (a, b) {
+ return b[1] - a[1];
+ }));
+ fillTable("Site", siteTable, siteDict.sort(function (a, b) {
+ return b[1] - a[1];
+ }));
+ };
+
+
+ self.render = function (el) {
+ var h2;
+ self.renderSingle(el, "Status", statusTable);
+ self.renderSingle(el, "Nodes an Gateway", gwNodesTable);
+ self.renderSingle(el, "Clients an Gateway", gwClientsTable);
+ self.renderSingle(el, "Firmwareversionen", fwTable);
+ self.renderSingle(el, "Uplink", uplinkTable);
+ self.renderSingle(el, "Hardwaremodelle", hwTable);
+ self.renderSingle(el, "Auf der Karte sichtbar", geoTable);
+ self.renderSingle(el, "Autoupdater", autoTable);
+ self.renderSingle(el, "Site", siteTable);
+
+ if (config.globalInfos) {
+ config.globalInfos.forEach(function (globalInfo) {
+ h2 = document.createElement("h2");
+ h2.textContent = globalInfo.name;
+ el.appendChild(h2);
+ el.appendChild(showStatGlobal(globalInfo));
+ });
+ }
+ };
+
+ self.renderSingle = function (el, heading, table) {
+ var h2;
+ h2 = document.createElement("h2");
+ h2.textContent = heading;
+ h2.onclick = function () {
+ table.classList.toggle("hidden");
+ };
+ el.appendChild(h2);
+ el.appendChild(table);
+ };
+ return self;
+ };
+ });
diff --git a/lib/router.js b/lib/router.js
index fb56bb1..f719cc0 100644
--- a/lib/router.js
+++ b/lib/router.js
@@ -1,214 +1,230 @@
define(function () {
return function () {
- var self = this
- var objects = { nodes: {}, links: {} }
- var targets = []
- var views = {}
- var currentView
- var currentObject
- var running = false
+ var self = this;
+ var objects = {nodes: {}, links: {}};
+ var targets = [];
+ var views = {};
+ var currentView;
+ var currentObject;
+ var running = false;
function saveState() {
- var e = []
+ var e = [];
- if (currentView)
- e.push("v:" + currentView)
-
- if (currentObject) {
- if ("node" in currentObject)
- e.push("n:" + encodeURIComponent(currentObject.node.nodeinfo.node_id))
-
- if ("link" in currentObject)
- e.push("l:" + encodeURIComponent(currentObject.link.id))
+ if (currentView) {
+ e.push("v:" + currentView);
}
- var s = "#!" + e.join(";")
+ if (currentObject) {
+ if ("node" in currentObject) {
+ e.push("n:" + encodeURIComponent(currentObject.node.nodeinfo.node_id));
+ }
- window.history.pushState(s, undefined, s)
+ if ("link" in currentObject) {
+ e.push("l:" + encodeURIComponent(currentObject.link.id));
+ }
+ }
+
+ var s = "#!" + e.join(";");
+
+ window.history.pushState(s, undefined, s);
}
function resetView(push) {
- push = trueDefault(push)
+ push = trueDefault(push);
- targets.forEach( function (t) {
- t.resetView()
- })
+ targets.forEach(function (t) {
+ t.resetView();
+ });
if (push) {
- currentObject = undefined
- saveState()
+ currentObject = undefined;
+ saveState();
}
}
function gotoNode(d) {
- if (!d)
- return false
+ if (!d) {
+ return false;
+ }
- targets.forEach( function (t) {
- t.gotoNode(d)
- })
+ targets.forEach(function (t) {
+ t.gotoNode(d);
+ });
- return true
+ return true;
}
function gotoLink(d) {
- if (!d)
- return false
+ if (!d) {
+ return false;
+ }
- targets.forEach( function (t) {
- t.gotoLink(d)
- })
+ targets.forEach(function (t) {
+ t.gotoLink(d);
+ });
- return true
+ return true;
}
function gotoLocation(d) {
- if (!d)
- return false
+ if (!d) {
+ return false;
+ }
- targets.forEach( function (t) {
- if(!t.gotoLocation)console.warn("has no gotoLocation", t)
- t.gotoLocation(d)
- })
+ targets.forEach(function (t) {
+ if (!t.gotoLocation) {
+ console.warn("has no gotoLocation", t);
+ }
+ t.gotoLocation(d);
+ });
- return true
+ return true;
}
function loadState(s) {
- if (!s)
- return false
+ if (!s) {
+ return false;
+ }
- s = decodeURIComponent(s)
+ s = decodeURIComponent(s);
- if (!s.startsWith("#!"))
- return false
+ if (!s.startsWith("#!")) {
+ return false;
+ }
- var targetSet = false
+ var targetSet = false;
s.slice(2).split(";").forEach(function (d) {
- var args = d.split(":")
+ var args = d.split(":");
if (args[0] === "v" && args[1] in views) {
- currentView = args[1]
- views[args[1]]()
+ currentView = args[1];
+ views[args[1]]();
}
- var id
+ var id;
if (args[0] === "n") {
- id = args[1]
+ id = args[1];
if (id in objects.nodes) {
- currentObject = { node: objects.nodes[id] }
- gotoNode(objects.nodes[id])
- targetSet = true
+ currentObject = {node: objects.nodes[id]};
+ gotoNode(objects.nodes[id]);
+ targetSet = true;
}
}
if (args[0] === "l") {
- id = args[1]
+ id = args[1];
if (id in objects.links) {
- currentObject = { link: objects.links[id] }
- gotoLink(objects.links[id])
- targetSet = true
+ currentObject = {link: objects.links[id]};
+ gotoLink(objects.links[id]);
+ targetSet = true;
}
}
- })
+ });
- return targetSet
+ return targetSet;
}
self.start = function () {
- running = true
+ running = true;
- if (!loadState(window.location.hash))
- resetView(false)
+ if (!loadState(window.location.hash)) {
+ resetView(false);
+ }
window.onpopstate = function (d) {
- if (!loadState(d.state))
- resetView(false)
- }
- }
+ if (!loadState(d.state)) {
+ resetView(false);
+ }
+ };
+ };
self.view = function (d) {
if (d in views) {
- views[d]()
+ views[d]();
- if (!currentView || running)
- currentView = d
-
- if (!running)
- return
-
- saveState()
-
- if (!currentObject) {
- resetView(false)
- return
+ if (!currentView || running) {
+ currentView = d;
}
- if ("node" in currentObject)
- gotoNode(currentObject.node)
+ if (!running) {
+ return;
+ }
- if ("link" in currentObject)
- gotoLink(currentObject.link)
+ saveState();
+
+ if (!currentObject) {
+ resetView(false);
+ return;
+ }
+
+ if ("node" in currentObject) {
+ gotoNode(currentObject.node);
+ }
+
+ if ("link" in currentObject) {
+ gotoLink(currentObject.link);
+ }
}
- }
+ };
self.node = function (d) {
return function () {
if (gotoNode(d)) {
- currentObject = { node: d }
- saveState()
+ currentObject = {node: d};
+ saveState();
}
- return false
- }
- }
+ return false;
+ };
+ };
self.link = function (d) {
return function () {
if (gotoLink(d)) {
- currentObject = { link: d }
- saveState()
+ currentObject = {link: d};
+ saveState();
}
- return false
- }
- }
+ return false;
+ };
+ };
- self.gotoLocation = gotoLocation
+ self.gotoLocation = gotoLocation;
self.reset = function () {
- resetView()
- }
+ resetView();
+ };
self.addTarget = function (d) {
- targets.push(d)
- }
+ targets.push(d);
+ };
self.removeTarget = function (d) {
- targets = targets.filter( function (e) {
- return d !== e
- })
- }
+ targets = targets.filter(function (e) {
+ return d !== e;
+ });
+ };
self.addView = function (k, d) {
- views[k] = d
- }
+ views[k] = d;
+ };
self.setData = function (data) {
- objects.nodes = {}
- objects.links = {}
+ objects.nodes = {};
+ objects.links = {};
- data.nodes.all.forEach( function (d) {
- objects.nodes[d.nodeinfo.node_id] = d
- })
+ data.nodes.all.forEach(function (d) {
+ objects.nodes[d.nodeinfo.node_id] = d;
+ });
- data.graph.links.forEach( function (d) {
- objects.links[d.id] = d
- })
- }
+ data.graph.links.forEach(function (d) {
+ objects.links[d.id] = d;
+ });
+ };
- return self
- }
-})
+ return self;
+ };
+});
diff --git a/lib/sidebar.js b/lib/sidebar.js
index 464c0fa..4c839cc 100644
--- a/lib/sidebar.js
+++ b/lib/sidebar.js
@@ -1,49 +1,50 @@
define([], function () {
return function (el) {
- var self = this
+ var self = this;
- var sidebar = document.createElement("div")
- sidebar.classList.add("sidebar")
- el.appendChild(sidebar)
+ var sidebar = document.createElement("div");
+ sidebar.classList.add("sidebar");
+ el.appendChild(sidebar);
- var button = document.createElement("button")
- sidebar.appendChild(button)
+ var button = document.createElement("button");
+ sidebar.appendChild(button);
- button.classList.add("sidebarhandle")
+ button.classList.add("sidebarhandle");
button.onclick = function () {
- sidebar.classList.toggle("hidden")
- }
+ sidebar.classList.toggle("hidden");
+ };
- var container = document.createElement("div")
- container.classList.add("container")
- sidebar.appendChild(container)
+ var container = document.createElement("div");
+ container.classList.add("container");
+ sidebar.appendChild(container);
self.getWidth = function () {
- if (sidebar.classList.contains("hidden"))
- return 0
+ if (sidebar.classList.contains("hidden")) {
+ return 0;
+ }
- var small = window.matchMedia("(max-width: 630pt)")
- return small.matches ? 0 : sidebar.offsetWidth
- }
+ var small = window.matchMedia("(max-width: 630pt)");
+ return small.matches ? 0 : sidebar.offsetWidth;
+ };
self.add = function (d) {
- d.render(container)
- }
+ d.render(container);
+ };
self.ensureVisible = function () {
- sidebar.classList.remove("hidden")
- }
+ sidebar.classList.remove("hidden");
+ };
self.hide = function () {
- container.classList.add("hidden")
- }
+ container.classList.add("hidden");
+ };
self.reveal = function () {
- container.classList.remove("hidden")
- }
+ container.classList.remove("hidden");
+ };
- self.container = sidebar
+ self.container = sidebar;
- return self
- }
-})
+ return self;
+ };
+});
diff --git a/lib/simplenodelist.js b/lib/simplenodelist.js
index 8a763df..a327203 100644
--- a/lib/simplenodelist.js
+++ b/lib/simplenodelist.js
@@ -1,63 +1,66 @@
define(["moment", "virtual-dom"], function (moment, V) {
- return function(nodes, field, router, title) {
- var self = this
- var el, tbody
+ return function (nodes, field, router, title) {
+ var self = this;
+ var el, tbody;
self.render = function (d) {
- el = document.createElement("div")
- d.appendChild(el)
- }
+ el = document.createElement("div");
+ d.appendChild(el);
+ };
self.setData = function (data) {
- var list = data.nodes[nodes]
+ var list = data.nodes[nodes];
if (list.length === 0) {
- while (el.firstChild)
- el.removeChild(el.firstChild)
+ while (el.firstChild) {
+ el.removeChild(el.firstChild);
+ }
- tbody = null
+ tbody = null;
- return
+ return;
}
if (!tbody) {
- var h2 = document.createElement("h2")
- h2.textContent = title
- el.appendChild(h2)
+ var h2 = document.createElement("h2");
+ h2.textContent = title;
+ el.appendChild(h2);
- var table = document.createElement("table")
- el.appendChild(table)
+ var table = document.createElement("table");
+ el.appendChild(table);
- tbody = document.createElement("tbody")
- tbody.last = V.h("tbody")
- table.appendChild(tbody)
+ tbody = document.createElement("tbody");
+ tbody.last = V.h("tbody");
+ table.appendChild(tbody);
}
- var items = list.map( function (d) {
- var time = moment(d[field]).from(data.now)
- var td1Content = []
+ var items = list.map(function (d) {
+ var time = moment(d[field]).from(data.now);
+ var td1Content = [];
- var aClass = ["hostname", d.flags.online ? "online" : "offline"]
+ var aClass = ["hostname", d.flags.online ? "online" : "offline"];
- td1Content.push(V.h("a", { className: aClass.join(" "),
- onclick: router.node(d),
- href: "#!n:" + d.nodeinfo.node_id
- }, d.nodeinfo.hostname))
+ td1Content.push(V.h("a", {
+ className: aClass.join(" "),
+ onclick: router.node(d),
+ href: "#!n:" + d.nodeinfo.node_id
+ }, d.nodeinfo.hostname));
- if (has_location(d))
- td1Content.push(V.h("span", {className: "icon ion-location"}))
+ if (has_location(d)) {
+ td1Content.push(V.h("span", {className: "icon ion-location"}));
+ }
- var td1 = V.h("td", td1Content)
- var td2 = V.h("td", time)
+ var td1 = V.h("td", td1Content);
+ var td2 = V.h("td", time);
- return V.h("tr", [td1, td2])
- })
+ return V.h("tr", [td1, td2]);
+ });
- var tbodyNew = V.h("tbody", items)
- tbody = V.patch(tbody, V.diff(tbody.last, tbodyNew))
- tbody.last = tbodyNew
- }
+ var tbodyNew = V.h("tbody", items);
+ tbody = V.patch(tbody, V.diff(tbody.last, tbodyNew));
+ tbody.last = tbodyNew;
+ };
- return self
- }
-})
+ return self;
+ };
+});
diff --git a/lib/sorttable.js b/lib/sorttable.js
index d6a39a1..881efba 100644
--- a/lib/sorttable.js
+++ b/lib/sorttable.js
@@ -1,57 +1,62 @@
define(["virtual-dom"], function (V) {
- return function(headings, sortIndex, renderRow) {
- var data
- var sortReverse = false
- var el = document.createElement("table")
- var elLast = V.h("table")
+ return function (headings, sortIndex, renderRow) {
+ var data;
+ var sortReverse = false;
+ var el = document.createElement("table");
+ var elLast = V.h("table");
function sortTable(i) {
- sortReverse = i === sortIndex ? !sortReverse : false
- sortIndex = i
+ sortReverse = i === sortIndex ? !sortReverse : false;
+ sortIndex = i;
- updateView()
+ updateView();
}
function sortTableHandler(i) {
- return function () { sortTable(i) }
+ return function () {
+ sortTable(i);
+ };
}
function updateView() {
- var children = []
+ var children = [];
if (data.length !== 0) {
var th = headings.map(function (d, i) {
- var properties = { onclick: sortTableHandler(i),
- className: "sort-header"
- }
+ var properties = {
+ onclick: sortTableHandler(i),
+ className: "sort-header"
+ };
- if (sortIndex === i)
- properties.className += sortReverse ? " sort-up" : " sort-down"
+ if (sortIndex === i) {
+ properties.className += sortReverse ? " sort-up" : " sort-down";
+ }
- return V.h("th", properties, d.name)
- })
+ return V.h("th", properties, d.name);
+ });
- var links = data.slice(0).sort(headings[sortIndex].sort)
+ var links = data.slice(0).sort(headings[sortIndex].sort);
- if (headings[sortIndex].reverse ? !sortReverse : sortReverse)
- links = links.reverse()
+ if (headings[sortIndex].reverse ? !sortReverse : sortReverse) {
+ links = links.reverse();
+ }
- children.push(V.h("thead", V.h("tr", th)))
- children.push(V.h("tbody", links.map(renderRow)))
+ children.push(V.h("thead", V.h("tr", th)));
+ children.push(V.h("tbody", links.map(renderRow)));
}
- var elNew = V.h("table", children)
- el = V.patch(el, V.diff(elLast, elNew))
- elLast = elNew
+ var elNew = V.h("table", children);
+ el = V.patch(el, V.diff(elLast, elNew));
+ elLast = elNew;
}
this.setData = function (d) {
- data = d
- updateView()
- }
+ data = d;
+ updateView();
+ };
- this.el = el
+ this.el = el;
- return this
- }
-})
+ return this;
+ };
+});
diff --git a/lib/tabs.js b/lib/tabs.js
index 7605742..f4fed6d 100644
--- a/lib/tabs.js
+++ b/lib/tabs.js
@@ -1,57 +1,61 @@
define([], function () {
return function () {
- var self = this
+ var self = this;
- var tabs = document.createElement("ul")
- tabs.classList.add("tabs")
+ var tabs = document.createElement("ul");
+ tabs.classList.add("tabs");
- var container = document.createElement("div")
+ var container = document.createElement("div");
function gotoTab(li) {
- for (var i = 0; i < tabs.children.length; i++)
- tabs.children[i].classList.remove("visible")
+ for (var i = 0; i < tabs.children.length; i++) {
+ tabs.children[i].classList.remove("visible");
+ }
- while (container.firstChild)
- container.removeChild(container.firstChild)
+ while (container.firstChild) {
+ container.removeChild(container.firstChild);
+ }
- li.classList.add("visible")
+ li.classList.add("visible");
- var tab = document.createElement("div")
- tab.classList.add("tab")
- container.appendChild(tab)
- li.child.render(tab)
+ var tab = document.createElement("div");
+ tab.classList.add("tab");
+ container.appendChild(tab);
+ li.child.render(tab);
}
function switchTab() {
- gotoTab(this)
+ gotoTab(this);
- return false
+ return false;
}
self.add = function (title, d) {
- var li = document.createElement("li")
- li.textContent = title
- li.onclick = switchTab
- li.child = d
- tabs.appendChild(li)
+ var li = document.createElement("li");
+ li.textContent = title;
+ li.onclick = switchTab;
+ li.child = d;
+ tabs.appendChild(li);
- var anyVisible = false
+ var anyVisible = false;
- for (var i = 0; i < tabs.children.length; i++)
+ for (var i = 0; i < tabs.children.length; i++) {
if (tabs.children[i].classList.contains("visible")) {
- anyVisible = true
- break
+ anyVisible = true;
+ break;
}
+ }
- if (!anyVisible)
- gotoTab(li)
- }
+ if (!anyVisible) {
+ gotoTab(li);
+ }
+ };
self.render = function (el) {
- el.appendChild(tabs)
- el.appendChild(container)
- }
+ el.appendChild(tabs);
+ el.appendChild(container);
+ };
- return self
- }
-})
+ return self;
+ };
+});
diff --git a/lib/title.js b/lib/title.js
index e9377a4..4c99c2c 100644
--- a/lib/title.js
+++ b/lib/title.js
@@ -1,35 +1,38 @@
define(function () {
- return function (config) {
+ return function (config) {
function setTitle(d) {
- var title = [config.siteName]
+ var title = [config.siteName];
- if (d !== undefined)
- title.push(d)
+ if (d !== undefined) {
+ title.push(d);
+ }
- document.title = title.join(": ")
+ document.title = title.join(": ");
}
this.resetView = function () {
- setTitle()
- }
+ setTitle();
+ };
this.gotoNode = function (d) {
- if (d)
- setTitle(d.nodeinfo.hostname)
- }
+ if (d) {
+ setTitle(d.nodeinfo.hostname);
+ }
+ };
this.gotoLink = function (d) {
- if (d)
- setTitle((d.source.node ? d.source.node.nodeinfo.hostname : d.source.id) + " – " + d.target.node.nodeinfo.hostname)
- }
+ if (d) {
+ setTitle((d.source.node ? d.source.node.nodeinfo.hostname : d.source.id) + " – " + d.target.node.nodeinfo.hostname);
+ }
+ };
- this.gotoLocation = function() {
+ this.gotoLocation = function () {
//ignore
- }
+ };
this.destroy = function () {
- }
+ };
- return this
- }
-})
+ return this;
+ };
+});
diff --git a/lib/vercomp.js b/lib/vercomp.js
index 428f258..4752b11 100644
--- a/lib/vercomp.js
+++ b/lib/vercomp.js
@@ -1,60 +1,68 @@
define([], function () {
function order(c) {
- if (/^\d$/.test(c))
- return 0
- else if (/^[a-z]$/i.test(c))
- return c.charCodeAt(0)
- else if (c === "~")
- return -1
- else if (c)
- return c.charCodeAt(0) + 256
- else
- return 0
+ if (/^\d$/.test(c)) {
+ return 0;
+ } else if (/^[a-z]$/i.test(c)) {
+ return c.charCodeAt(0);
+ } else if (c === "~") {
+ return -1;
+ } else if (c) {
+ return c.charCodeAt(0) + 256;
+ } else {
+ return 0;
+ }
}
// Based on dpkg code
function vercomp(a, b) {
- var apos = 0, bpos = 0
+ var apos = 0, bpos = 0;
while (apos < a.length || bpos < b.length) {
- var firstDiff = 0
+ var firstDiff = 0;
while ((apos < a.length && !/^\d$/.test(a[apos])) || (bpos < b.length && !/^\d$/.test(b[bpos]))) {
- var ac = order(a[apos])
- var bc = order(b[bpos])
+ var ac = order(a[apos]);
+ var bc = order(b[bpos]);
- if (ac !== bc)
- return ac - bc
+ if (ac !== bc) {
+ return ac - bc;
+ }
- apos++
- bpos++
+ apos++;
+ bpos++;
}
- while (a[apos] === "0")
- apos++
+ while (a[apos] === "0") {
+ apos++;
+ }
- while (b[bpos] === "0")
- bpos++
+ while (b[bpos] === "0") {
+ bpos++;
+ }
while (/^\d$/.test(a[apos]) && /^\d$/.test(b[bpos])) {
- if (firstDiff === 0)
- firstDiff = a.charCodeAt(apos) - b.charCodeAt(bpos)
+ if (firstDiff === 0) {
+ firstDiff = a.charCodeAt(apos) - b.charCodeAt(bpos);
+ }
- apos++
- bpos++
+ apos++;
+ bpos++;
}
- if (/^\d$/.test(a[apos]))
- return 1
+ if (/^\d$/.test(a[apos])) {
+ return 1;
+ }
- if (/^\d$/.test(b[bpos]))
- return -1
+ if (/^\d$/.test(b[bpos])) {
+ return -1;
+ }
- if (firstDiff !== 0)
- return firstDiff
+ if (firstDiff !== 0) {
+ return firstDiff;
+ }
}
- return 0
+ return 0;
}
- return vercomp
-})
+ return vercomp;
+});
diff --git a/scss/main.scss b/scss/main.scss
index 47cbed9..0415212 100644
--- a/scss/main.scss
+++ b/scss/main.scss
@@ -131,14 +131,14 @@ table.attributes tr.routerpic td {
font-weight: bold;
/*background-color: red;*/
font-size: large;
- vertical-align:bottom;
+ vertical-align: bottom;
}
table.attributes tr.routerpic th {
font-weight: bold;
/*background-color: red;*/
font-size: large;
- vertical-align:bottom;
+ vertical-align: bottom;
}
.nodenamesidebar {
@@ -146,7 +146,7 @@ table.attributes tr.routerpic th {
font-weight: bold;
/*background-color: red;*/
font-size: large;
- vertical-align:bottom;
+ vertical-align: bottom;
bottom: 0px;
}
diff --git a/tasks/build.js b/tasks/build.js
index d76ccfc..2fd1e83 100644
--- a/tasks/build.js
+++ b/tasks/build.js
@@ -1,11 +1,11 @@
-module.exports = function(grunt) {
+module.exports = function (grunt) {
grunt.config.merge({
bowerdir: "bower_components",
copy: {
html: {
options: {
process: function (content) {
- return content.replace("#revision#", grunt.option("gitRevision"))
+ return content.replace("#revision#", grunt.option("gitRevision"));
}
},
src: ["*.html"],
@@ -26,31 +26,31 @@ module.exports = function(grunt) {
dest: "build/vendor/"
},
robotoSlab: {
- src: [ "fonts/*",
- "roboto-slab-fontface.css"
- ],
+ src: ["fonts/*",
+ "roboto-slab-fontface.css"
+ ],
expand: true,
dest: "build/",
cwd: "bower_components/roboto-slab-fontface"
},
roboto: {
- src: [ "fonts/*",
- "roboto-fontface.css"
- ],
+ src: ["fonts/*",
+ "roboto-fontface.css"
+ ],
expand: true,
dest: "build/",
cwd: "bower_components/roboto-fontface"
},
ionicons: {
- src: [ "fonts/*",
- "css/ionicons.min.css"
- ],
+ src: ["fonts/*",
+ "css/ionicons.min.css"
+ ],
expand: true,
dest: "build/",
cwd: "bower_components/ionicons/"
},
leafletImages: {
- src: [ "images/*" ],
+ src: ["images/*"],
expand: true,
dest: "build/",
cwd: "bower_components/leaflet/dist/"
@@ -83,26 +83,26 @@ module.exports = function(grunt) {
cssmin: {
target: {
files: {
- "build/style.css": [ "bower_components/leaflet/dist/leaflet.css",
- "bower_components/Leaflet.label/dist/leaflet.label.css",
- "style.css"
- ]
+ "build/style.css": ["bower_components/leaflet/dist/leaflet.css",
+ "bower_components/Leaflet.label/dist/leaflet.label.css",
+ "style.css"
+ ]
}
}
},
"bower-install-simple": {
- options: {
- directory: "<%=bowerdir%>",
- color: true,
- interactive: false,
- production: true
- },
- "prod": {
- options: {
- production: true
- }
- }
+ options: {
+ directory: "<%=bowerdir%>",
+ color: true,
+ interactive: false,
+ production: true
},
+ "prod": {
+ options: {
+ production: true
+ }
+ }
+ },
requirejs: {
compile: {
options: {
@@ -116,11 +116,11 @@ module.exports = function(grunt) {
}
}
}
- })
+ });
- grunt.loadNpmTasks("grunt-bower-install-simple")
- grunt.loadNpmTasks("grunt-contrib-copy")
- grunt.loadNpmTasks("grunt-contrib-requirejs")
- grunt.loadNpmTasks("grunt-sass")
- grunt.loadNpmTasks("grunt-postcss")
-}
+ grunt.loadNpmTasks("grunt-bower-install-simple");
+ grunt.loadNpmTasks("grunt-contrib-copy");
+ grunt.loadNpmTasks("grunt-contrib-requirejs");
+ grunt.loadNpmTasks("grunt-sass");
+ grunt.loadNpmTasks("grunt-postcss");
+};
diff --git a/tasks/clean.js b/tasks/clean.js
index 989ef08..ed0e234 100644
--- a/tasks/clean.js
+++ b/tasks/clean.js
@@ -3,7 +3,7 @@ module.exports = function (grunt) {
clean: {
build: ["build/**/*", "node_modules/grunt-newer/.cache"]
}
- })
+ });
- grunt.loadNpmTasks("grunt-contrib-clean")
-}
+ grunt.loadNpmTasks("grunt-contrib-clean");
+};
diff --git a/tasks/development.js b/tasks/development.js
index 6c799d2..2c00cd7 100644
--- a/tasks/development.js
+++ b/tasks/development.js
@@ -24,8 +24,8 @@ module.exports = function (grunt) {
tasks: []
}
}
- })
+ });
- grunt.loadNpmTasks("grunt-contrib-connect")
- grunt.loadNpmTasks("grunt-contrib-watch")
-}
+ grunt.loadNpmTasks("grunt-contrib-connect");
+ grunt.loadNpmTasks("grunt-contrib-watch");
+};
diff --git a/tasks/linting.js b/tasks/linting.js
index a05bce0..71311dc 100644
--- a/tasks/linting.js
+++ b/tasks/linting.js
@@ -31,8 +31,8 @@ module.exports = function (grunt) {
src: ["Gruntfile.js", "tasks/*.js"]
}
}
- })
+ });
- grunt.loadNpmTasks("grunt-check-dependencies")
- grunt.loadNpmTasks("grunt-eslint")
-}
+ grunt.loadNpmTasks("grunt-check-dependencies");
+ grunt.loadNpmTasks("grunt-eslint");
+};