283 lines
7.2 KiB
JavaScript
283 lines
7.2 KiB
JavaScript
"use strict"
|
||
define([ "lib/helper", "lib/gui/signalgraph", "lib/gui/signal"],
|
||
function (Helper, SignalGraph, Signal) {
|
||
|
||
var graphColors = ["#396AB1", "#DA7C30", "#3E9651", "#CC2529", "#535154", "#6B4C9A", "#922428", "#948B3D"]
|
||
//graphColors = ["#7293CB", "#E1974C", "#84BA5B", "#D35E60", "#808585", "#9067A7", "#AB6857", "#CCC210"];
|
||
|
||
var inactiveTime = 200
|
||
|
||
function SignalEntry(graph, color, stream) {
|
||
var signal = new Signal(color)
|
||
var remove = graph.add(signal)
|
||
|
||
var unsubscribe = stream.onValue(update)
|
||
|
||
this.destroy = function () {
|
||
unsubscribe()
|
||
remove()
|
||
}
|
||
|
||
this.getSignal = function () {
|
||
return signal
|
||
}
|
||
|
||
return this
|
||
|
||
function update(d) {
|
||
if ("wifi" in d)
|
||
signal.set(d.wifi.inactive > inactiveTime ? null : d.wifi.signal)
|
||
}
|
||
}
|
||
|
||
function TableEntry(parent, nodeInfo, color, stream, mgmtBus, signal) {
|
||
var el = document.createElement("tr")
|
||
parent.appendChild(el)
|
||
|
||
var tdHostname = document.createElement("td")
|
||
var tdTQ = document.createElement("td")
|
||
var tdSignal = document.createElement("td")
|
||
var tdDistance = document.createElement("td")
|
||
var tdInactive = document.createElement("td")
|
||
|
||
el.appendChild(tdHostname)
|
||
el.appendChild(tdTQ)
|
||
el.appendChild(tdSignal)
|
||
el.appendChild(tdDistance)
|
||
el.appendChild(tdInactive)
|
||
|
||
var marker = document.createElement("span")
|
||
marker.textContent = "⬤ "
|
||
marker.style.color = color
|
||
tdHostname.appendChild(marker)
|
||
|
||
var hostname = document.createElement("span")
|
||
tdHostname.appendChild(hostname)
|
||
|
||
var infoSet = false
|
||
var unsubscribe = stream.onValue(update)
|
||
|
||
el.onmouseenter = function () {
|
||
el.classList.add("highlight")
|
||
signal.setHighlight(true)
|
||
}
|
||
|
||
el.onmouseleave = function () {
|
||
el.classList.remove("highlight")
|
||
signal.setHighlight(false)
|
||
}
|
||
|
||
el.destroy = function () {
|
||
unsubscribe()
|
||
parent.removeChild(el)
|
||
}
|
||
|
||
return el
|
||
|
||
function update(d) {
|
||
if ("wifi" in d) {
|
||
var signal = d.wifi.signal
|
||
var inactive = d.wifi.inactive
|
||
|
||
el.classList.toggle("inactive", inactive > inactiveTime)
|
||
|
||
tdSignal.textContent = signal
|
||
tdInactive.textContent = Math.round(inactive / 1000) + " s"
|
||
}
|
||
|
||
if ("batadv" in d)
|
||
tdTQ.textContent = Math.round(d.batadv.tq / 2.55) + " %"
|
||
else
|
||
tdTQ.textContent = "‒"
|
||
|
||
if (infoSet)
|
||
return
|
||
|
||
if ("nodeInfo" in d) {
|
||
infoSet = true
|
||
|
||
var link = document.createElement("a")
|
||
link.textContent = d.nodeInfo.hostname
|
||
link.href = "#"
|
||
link.nodeInfo = d.nodeInfo
|
||
link.onclick = function () {
|
||
mgmtBus.pushEvent("goto", this.nodeInfo)
|
||
return false
|
||
}
|
||
|
||
while (hostname.firstChild)
|
||
hostname.removeChild(hostname.firstChild)
|
||
|
||
hostname.appendChild(link)
|
||
|
||
try {
|
||
var distance = Helper.haversine(nodeInfo.location.latitude, nodeInfo.location.longitude,
|
||
d.nodeInfo.location.latitude, d.nodeInfo.location.longitude)
|
||
|
||
tdDistance.textContent = Math.round(distance * 1000) + " m"
|
||
} catch (e) {
|
||
tdDistance.textContent = "‒"
|
||
}
|
||
} else
|
||
hostname.textContent = d.id
|
||
}
|
||
}
|
||
|
||
function Interface(parent, nodeInfo, iface, stream, mgmtBus) {
|
||
var colors = graphColors.slice(0)
|
||
|
||
var el = document.createElement("div")
|
||
el.ifname = iface
|
||
parent.appendChild(el)
|
||
|
||
var h = document.createElement("h3")
|
||
h.textContent = iface
|
||
el.appendChild(h)
|
||
|
||
var table = document.createElement("table")
|
||
var tr = document.createElement("tr")
|
||
table.appendChild(tr)
|
||
table.classList.add("datatable")
|
||
|
||
var th = document.createElement("th")
|
||
th.textContent = "Knoten"
|
||
tr.appendChild(th)
|
||
|
||
th = document.createElement("th")
|
||
th.textContent = "TQ"
|
||
tr.appendChild(th)
|
||
|
||
th = document.createElement("th")
|
||
th.textContent = "dBm"
|
||
tr.appendChild(th)
|
||
|
||
th = document.createElement("th")
|
||
th.textContent = "Entfernung"
|
||
tr.appendChild(th)
|
||
|
||
th = document.createElement("th")
|
||
th.textContent = "Inaktiv"
|
||
tr.appendChild(th)
|
||
|
||
el.appendChild(table)
|
||
|
||
var wrapper = document.createElement("div")
|
||
wrapper.className = "signalgraph"
|
||
el.appendChild(wrapper)
|
||
|
||
var canvas = document.createElement("canvas")
|
||
canvas.className = "signal-history"
|
||
canvas.height = 200
|
||
wrapper.appendChild(canvas)
|
||
|
||
var graph = new SignalGraph(canvas, -100, 0, true)
|
||
|
||
var stopStream = stream.skipDuplicates(sameKeys).onValue(update)
|
||
|
||
var managedNeighbours = {}
|
||
|
||
function update(d) {
|
||
var notUpdated = new Set()
|
||
var id
|
||
|
||
for (id in managedNeighbours)
|
||
notUpdated.add(id)
|
||
|
||
for (id in d) {
|
||
if (!(id in managedNeighbours)) {
|
||
var neighbourStream = stream.map("." + id).filter( function (d) { return d !== undefined })
|
||
var color = colors.shift()
|
||
var signal = new SignalEntry(graph, color, neighbourStream)
|
||
managedNeighbours[id] = { views: [ signal,
|
||
new TableEntry(table, nodeInfo, color, neighbourStream, mgmtBus, signal.getSignal())
|
||
],
|
||
color: color
|
||
}
|
||
}
|
||
|
||
notUpdated.delete(id)
|
||
}
|
||
|
||
notUpdated.forEach(function (id) {
|
||
managedNeighbours[id].views.forEach( function (d) { d.destroy() })
|
||
colors.push(managedNeighbours[id].color)
|
||
delete managedNeighbours[id]
|
||
})
|
||
}
|
||
|
||
|
||
el.destroy = function () {
|
||
stopStream()
|
||
|
||
for (var id in managedNeighbours)
|
||
managedNeighbours[id].views.forEach( function (d) { d.destroy() })
|
||
|
||
el.removeChild(h)
|
||
el.removeChild(wrapper)
|
||
el.removeChild(table)
|
||
}
|
||
}
|
||
|
||
function sameKeys(a, b) {
|
||
a = Object.keys(a).sort()
|
||
b = Object.keys(b).sort()
|
||
|
||
return !(a < b || a > b)
|
||
}
|
||
|
||
function getter(k) {
|
||
return function(obj) {
|
||
return obj[k]
|
||
}
|
||
}
|
||
|
||
return function (nodeInfo, stream, mgmtBus) {
|
||
var stopStream, div
|
||
|
||
function render(el) {
|
||
div = document.createElement("div")
|
||
el.appendChild(div)
|
||
|
||
stopStream = stream.skipDuplicates(sameKeys).onValue(update)
|
||
|
||
function update(d) {
|
||
var have = {}
|
||
var remove = []
|
||
if (div.hasChildNodes()) {
|
||
var children = div.childNodes
|
||
for (var i = 0; i < children.length; i++) {
|
||
var a = children[i]
|
||
if (a.ifname in d)
|
||
have[a.ifname] = true
|
||
else {
|
||
a.destroy()
|
||
remove.push(a)
|
||
}
|
||
}
|
||
}
|
||
|
||
remove.forEach(function (d) { div.removeChild(d) })
|
||
|
||
for (var k in d) {
|
||
if (!(k in have))
|
||
new Interface(div, nodeInfo, k, stream.map(getter(k)), mgmtBus)
|
||
}
|
||
}
|
||
}
|
||
|
||
function destroy() {
|
||
stopStream()
|
||
|
||
while (div.firstChild) {
|
||
div.firstChild.destroy()
|
||
div.removeChild(div.firstChild)
|
||
}
|
||
}
|
||
|
||
return { title: document.createTextNode("Nachbarknoten")
|
||
, render: render
|
||
, destroy: destroy
|
||
}
|
||
}
|
||
})
|