neighbours.js 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274
  1. "use strict"
  2. define([ "lib/helper", "lib/gui/signalgraph", "lib/gui/signal"],
  3. function (Helper, SignalGraph, Signal) {
  4. var graphColors = ["#396AB1", "#DA7C30", "#3E9651", "#CC2529", "#535154", "#6B4C9A", "#922428", "#948B3D"]
  5. //graphColors = ["#7293CB", "#E1974C", "#84BA5B", "#D35E60", "#808585", "#9067A7", "#AB6857", "#CCC210"];
  6. var inactiveTime = 200
  7. function SignalEntry(graph, color, stream) {
  8. var signal = new Signal(color)
  9. var remove = graph.add(signal)
  10. var unsubscribe = stream.onValue(update)
  11. this.destroy = function () {
  12. unsubscribe()
  13. remove()
  14. }
  15. this.getSignal = function () {
  16. return signal
  17. }
  18. return this
  19. function update(d) {
  20. if ("wifi" in d)
  21. signal.set(d.wifi.inactive > inactiveTime ? null : d.wifi.signal)
  22. }
  23. }
  24. function TableEntry(parent, nodeInfo, color, stream, mgmtBus, signal) {
  25. var el = parent.insertRow()
  26. var tdHostname = el.insertCell()
  27. var tdTQ = el.insertCell()
  28. var tdSignal = el.insertCell()
  29. var tdDistance = el.insertCell()
  30. var tdInactive = el.insertCell()
  31. var marker = document.createElement("span")
  32. marker.textContent = "⬤ "
  33. marker.style.color = color
  34. tdHostname.appendChild(marker)
  35. var hostname = document.createElement("span")
  36. tdHostname.appendChild(hostname)
  37. var infoSet = false
  38. var unsubscribe = stream.onValue(update)
  39. el.onmouseenter = function () {
  40. el.classList.add("highlight")
  41. signal.setHighlight(true)
  42. }
  43. el.onmouseleave = function () {
  44. el.classList.remove("highlight")
  45. signal.setHighlight(false)
  46. }
  47. el.destroy = function () {
  48. unsubscribe()
  49. parent.tBodies[0].removeChild(el)
  50. }
  51. return el
  52. function update(d) {
  53. if ("wifi" in d) {
  54. var signal = d.wifi.signal
  55. var inactive = d.wifi.inactive
  56. el.classList.toggle("inactive", inactive > inactiveTime)
  57. tdSignal.textContent = signal
  58. tdInactive.textContent = Math.round(inactive / 1000) + " s"
  59. }
  60. if ("batadv" in d)
  61. tdTQ.textContent = Math.round(d.batadv.tq / 2.55) + " %"
  62. else
  63. tdTQ.textContent = "‒"
  64. if (infoSet)
  65. return
  66. if ("nodeInfo" in d) {
  67. infoSet = true
  68. var link = document.createElement("a")
  69. link.textContent = d.nodeInfo.hostname
  70. link.href = "#"
  71. link.nodeInfo = d.nodeInfo
  72. link.onclick = function () {
  73. mgmtBus.pushEvent("goto", this.nodeInfo)
  74. return false
  75. }
  76. while (hostname.firstChild)
  77. hostname.removeChild(hostname.firstChild)
  78. hostname.appendChild(link)
  79. try {
  80. var distance = Helper.haversine(nodeInfo.location.latitude, nodeInfo.location.longitude,
  81. d.nodeInfo.location.latitude, d.nodeInfo.location.longitude)
  82. tdDistance.textContent = Math.round(distance * 1000) + " m"
  83. } catch (e) {
  84. tdDistance.textContent = "‒"
  85. }
  86. } else
  87. hostname.textContent = d.id
  88. }
  89. }
  90. function Interface(parent, nodeInfo, iface, stream, mgmtBus) {
  91. var colors = graphColors.slice(0)
  92. var el = document.createElement("div")
  93. el.ifname = iface
  94. parent.appendChild(el)
  95. var h = document.createElement("h3")
  96. h.textContent = iface
  97. el.appendChild(h)
  98. var table = document.createElement("table")
  99. var tr = table.insertRow()
  100. table.classList.add("datatable")
  101. var th = document.createElement("th")
  102. th.textContent = "Knoten"
  103. tr.appendChild(th)
  104. th = document.createElement("th")
  105. th.textContent = "TQ"
  106. tr.appendChild(th)
  107. th = document.createElement("th")
  108. th.textContent = "dBm"
  109. tr.appendChild(th)
  110. th = document.createElement("th")
  111. th.textContent = "Entfernung"
  112. tr.appendChild(th)
  113. th = document.createElement("th")
  114. th.textContent = "Inaktiv"
  115. tr.appendChild(th)
  116. el.appendChild(table)
  117. var wrapper = document.createElement("div")
  118. wrapper.className = "signalgraph"
  119. el.appendChild(wrapper)
  120. var canvas = document.createElement("canvas")
  121. canvas.className = "signal-history"
  122. canvas.height = 200
  123. wrapper.appendChild(canvas)
  124. var graph = new SignalGraph(canvas, -100, 0, true)
  125. var stopStream = stream.skipDuplicates(sameKeys).onValue(update)
  126. var managedNeighbours = {}
  127. function update(d) {
  128. var notUpdated = new Set()
  129. var id
  130. for (id in managedNeighbours)
  131. notUpdated.add(id)
  132. for (id in d) {
  133. if (!(id in managedNeighbours)) {
  134. var neighbourStream = stream.map("." + id).filter( function (d) { return d !== undefined })
  135. var color = colors.shift()
  136. var signal = new SignalEntry(graph, color, neighbourStream)
  137. managedNeighbours[id] = { views: [ signal,
  138. new TableEntry(table, nodeInfo, color, neighbourStream, mgmtBus, signal.getSignal())
  139. ],
  140. color: color
  141. }
  142. }
  143. notUpdated.delete(id)
  144. }
  145. notUpdated.forEach(function (id) {
  146. managedNeighbours[id].views.forEach( function (d) { d.destroy() })
  147. colors.push(managedNeighbours[id].color)
  148. delete managedNeighbours[id]
  149. })
  150. }
  151. el.destroy = function () {
  152. stopStream()
  153. for (var id in managedNeighbours)
  154. managedNeighbours[id].views.forEach( function (d) { d.destroy() })
  155. el.removeChild(h)
  156. el.removeChild(wrapper)
  157. el.removeChild(table)
  158. }
  159. }
  160. function sameKeys(a, b) {
  161. a = Object.keys(a).sort()
  162. b = Object.keys(b).sort()
  163. return !(a < b || a > b)
  164. }
  165. function getter(k) {
  166. return function(obj) {
  167. return obj[k]
  168. }
  169. }
  170. return function (nodeInfo, stream, mgmtBus) {
  171. var stopStream, div
  172. function render(el) {
  173. div = document.createElement("div")
  174. el.appendChild(div)
  175. stopStream = stream.skipDuplicates(sameKeys).onValue(update)
  176. function update(d) {
  177. var have = {}
  178. var remove = []
  179. if (div.hasChildNodes()) {
  180. var children = div.childNodes
  181. for (var i = 0; i < children.length; i++) {
  182. var a = children[i]
  183. if (a.ifname in d)
  184. have[a.ifname] = true
  185. else {
  186. a.destroy()
  187. remove.push(a)
  188. }
  189. }
  190. }
  191. remove.forEach(function (d) { div.removeChild(d) })
  192. for (var k in d) {
  193. if (!(k in have))
  194. new Interface(div, nodeInfo, k, stream.map(getter(k)), mgmtBus)
  195. }
  196. }
  197. }
  198. function destroy() {
  199. stopStream()
  200. while (div.firstChild) {
  201. div.firstChild.destroy()
  202. div.removeChild(div.firstChild)
  203. }
  204. }
  205. return { title: document.createTextNode("Nachbarknoten")
  206. , render: render
  207. , destroy: destroy
  208. }
  209. }
  210. })