neighbours.js 7.1 KB

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