graph.js 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400
  1. //
  2. // Rendering of DSL spectrum graphs showing
  3. // US/DS SNR and US/DS bits/tone
  4. //
  5. // This version does depend on an ubus version that support DSL line stattiscis but
  6. // does not depend on chart.js or any other package
  7. class DataSet {
  8. constructor (input, extractFunction) {
  9. this.groupSize = input.groupsize;
  10. this.numData = input.groups;
  11. // needs to be validated with various input
  12. this.maxX = this.numData * this.groupSize;
  13. this.data = input.data.map(extractFunction,
  14. {groupSize: this.groupSize}
  15. );
  16. }
  17. }
  18. function myBitsFunction(value, index, array) {
  19. return({x: index, y: value, error: false});
  20. }
  21. function mySnrFunction(value, index, array) {
  22. let result;
  23. if (value == null) {
  24. result = {
  25. x: index * this.groupSize,
  26. y: -40 ,
  27. error: true
  28. }
  29. } else {
  30. result = {
  31. x: index * this.groupSize,
  32. y: value,
  33. error: false
  34. }
  35. }
  36. return(result);
  37. }
  38. function myQLNFunction(value, index, array) {
  39. let result;
  40. if (value == null) {
  41. result = {
  42. x: index * this.groupSize,
  43. y: - 150,
  44. error: true
  45. }
  46. } else {
  47. result = {
  48. x: index * this.groupSize,
  49. y: value,
  50. error: false
  51. }
  52. }
  53. return(result);
  54. }
  55. function myHLOGFunction(value, index, array) {
  56. let result;
  57. if (value == null) {
  58. result = {
  59. x: index * this.groupSize,
  60. y: -100,
  61. error: true
  62. }
  63. } else {
  64. result = {
  65. x: index * this.groupSize,
  66. y: value,
  67. error: false
  68. }
  69. }
  70. return(result);
  71. }
  72. const usSnrData = new DataSet(window.json['snr']['upstream'], mySnrFunction);
  73. const dsSnrData = new DataSet(window.json['snr']['downstream'], mySnrFunction);
  74. const usBitsData = new DataSet(window.json['bits']['upstream'], myBitsFunction);
  75. const dsBitsData = new DataSet(window.json['bits']['downstream'], myBitsFunction);
  76. const usQLNData = new DataSet(window.json['qln']['upstream'], myQLNFunction);
  77. const dsQLNData = new DataSet(window.json['qln']['downstream'], myQLNFunction);
  78. const usHLOGData = new DataSet(window.json['hlog']['upstream'], myHLOGFunction);
  79. const dsHLOGData = new DataSet(window.json['hlog']['downstream'], myHLOGFunction);
  80. const pilotTonesData = window.json['pilot_tones'] || [];
  81. const marginX = 50;
  82. const marginY = 80;
  83. let darkMode = document.getElementsByTagName("body")[0].parentNode.dataset.darkmode;
  84. let bitsChart = {
  85. "config": {
  86. "canvas": document.getElementById("bitsChart"),
  87. "ctx" : document.getElementById("bitsChart").getContext("2d"),
  88. "minX" : 0,
  89. "maxX" : Math.max(dsBitsData.maxX, usBitsData.maxX),
  90. "stepX": Math.max(dsBitsData.maxX, usBitsData.maxX) / 16,
  91. "graphWidth" : document.getElementById("bitsChart").width - 2 * marginX,
  92. "lineWidth" : 1,
  93. "titleX" : _("Sub-carrier"),
  94. "minY" : 0,
  95. "maxY" : 16,
  96. "stepY": 2,
  97. "graphHeight" : document.getElementById("bitsChart").height - 2 * marginY,
  98. "titleY" : _("bits")
  99. },
  100. "dataSet" : [
  101. {
  102. "data" :usBitsData.data,
  103. "color":"YellowGreen",
  104. "title": ("Upstream bits allocation")
  105. },
  106. {
  107. "data" : dsBitsData.data,
  108. "color": "navy",
  109. "title": _("Downstream bits allocation")
  110. },
  111. {
  112. "lines": true,
  113. "data": pilotTonesData,
  114. "color": "red",
  115. "title": _("Pilot tones")
  116. }
  117. ]
  118. };
  119. let dBChart = {
  120. "config": {
  121. "canvas": document.getElementById("dbChart"),
  122. "ctx" : document.getElementById("dbChart").getContext("2d"),
  123. "minX" : 0,
  124. "maxX" : Math.max(dsSnrData.maxX, usSnrData.maxX),
  125. "stepX": Math.max(dsSnrData.maxX, usSnrData.maxX) / 16,
  126. "graphWidth" : document.getElementById("dbChart").width - 2 * marginX,
  127. "lineWidth": 4,
  128. "titleX" : _("Sub-carrier"),
  129. "minY" : -40,
  130. "maxY" : 100,
  131. "stepY": 10,
  132. "graphHeight" : document.getElementById("dbChart").height - 2 * marginY,
  133. "titleY" : _("dB")
  134. },
  135. "dataSet" : [
  136. {
  137. "data" :usSnrData.data,
  138. "color":"Turquoise",
  139. "title": _("Upstream SNR")
  140. },
  141. {
  142. "data" : dsSnrData.data,
  143. "color": "Coral",
  144. "title" : _("Downstream SNR")
  145. }
  146. ]
  147. };
  148. let qLNChart = {
  149. "config": {
  150. "canvas": document.getElementById("qlnChart"),
  151. "ctx" : document.getElementById("qlnChart").getContext("2d"),
  152. "minX" : 0,
  153. "maxX" : Math.max(dsQLNData.maxX, usQLNData.maxX),
  154. "stepX": Math.max(dsQLNData.maxX, usQLNData.maxX) / 16,
  155. "graphWidth" : document.getElementById("qlnChart").width - 2 * marginX,
  156. "lineWidth": 4,
  157. "titleX" : _("Sub-carrier"),
  158. "minY" : -150,
  159. "maxY" : -20,
  160. "stepY": 10,
  161. "graphHeight" : document.getElementById("qlnChart").height - 2 * marginY,
  162. "titleY" : _("dBm/Hz")
  163. },
  164. "dataSet" : [
  165. {
  166. "data" :usQLNData.data,
  167. "color":"brown",
  168. "title": _("Upstream QLN")
  169. },
  170. {
  171. "data" : dsQLNData.data,
  172. "color": "teal",
  173. "title" : _("Downstream QLN")
  174. }
  175. ]
  176. };
  177. let hLogChart = {
  178. "config": {
  179. "canvas": document.getElementById("hlogChart"),
  180. "ctx" : document.getElementById("hlogChart").getContext("2d"),
  181. "minX" : 0,
  182. "maxX" : Math.max(dsHLOGData.maxX, usHLOGData.maxX),
  183. "stepX": Math.max(dsHLOGData.maxX, usHLOGData.maxX) / 16,
  184. "graphWidth" : document.getElementById("hlogChart").width - 2 * marginX,
  185. "lineWidth": 4,
  186. "titleX" : _("Sub-carrier"),
  187. "minY" : -100,
  188. "maxY" : 14,
  189. "stepY": 10,
  190. "graphHeight" : document.getElementById("hlogChart").height - 2 * marginY,
  191. "titleY" : _("dB")
  192. },
  193. "dataSet" : [
  194. {
  195. "data" :usHLOGData.data,
  196. "color":"#E8E800",
  197. "title": _("Upstream HLOG")
  198. },
  199. {
  200. "data" : dsHLOGData.data,
  201. "color": "darkmagenta",
  202. "title" : _("Downstream HLOG")
  203. }
  204. ]
  205. };
  206. function drawChart (info) {
  207. drawAxisX(info.config, info.config.minX, info.config.maxX, info.config.stepX, info.config.titleX);
  208. drawAxisY(info.config, info.config.minY, info.config.maxY, info.config.stepY, info.config.titleY);
  209. drawLegend(info.config, info.dataSet);
  210. for (let item of info.dataSet) {
  211. if (item.lines === true) {
  212. drawLines(info.config, item.data, item.color);
  213. } else {
  214. drawData(info.config, item.data, item.color);
  215. }
  216. }
  217. }
  218. function drawBlocks(config, dataPoints, color, borders) {
  219. borders.map(drawBlock, {config, dataPoints, color, borders});
  220. }
  221. function drawLines(config, dataPoints, color) {
  222. let ctx = config.ctx;
  223. let len = dataPoints.length;
  224. let minX = config.minX;
  225. let maxX = config.maxX;
  226. let minY = config.minY;
  227. let maxY = config.maxY;
  228. ctx.strokeStyle = color;
  229. ctx.beginPath();
  230. for (let item of dataPoints) {
  231. let relX = (item - minX) / (maxX - minX);
  232. ctx.moveTo(relX * config.graphWidth + marginX, marginY);
  233. ctx.lineTo(relX * config.graphWidth + marginX, marginY + config.graphHeight);
  234. }
  235. ctx.stroke();
  236. }
  237. function drawData(config, dataPoints, color) {
  238. let ctx = config.ctx;
  239. let len = dataPoints.length;
  240. let minX =config.minX;
  241. let maxX = config.maxX;
  242. let minY = config.minY;
  243. let maxY = config.maxY;
  244. let startX = (dataPoints[0].x - config.minX) / (config.maxX - config.minX)
  245. let startY = (config.minY - config.minY) / (config.maxY - config.minY)
  246. ctx.fillStyle = color;
  247. ctx.beginPath();
  248. ctx.moveTo(startX * config.graphWidth + marginX, marginY + config.graphHeight - startY * config.graphHeight);
  249. for (let i = 1 ; i < len ; i++) {
  250. let relX = (dataPoints[i].x - minX) / (maxX - minX);
  251. let relY = (dataPoints[i].y - minY) / (maxY - minY);
  252. ctx.lineTo(relX * config.graphWidth + marginX, marginY + config.graphHeight - relY * config.graphHeight);
  253. }
  254. let endX = (dataPoints[len-1].x - minX) / (maxX - minX)
  255. let endY = (config.minY - minY) / (maxY - minY)
  256. ctx.lineTo(endX * config.graphWidth + marginX, marginY + config.graphHeight - endY * config.graphHeight);
  257. ctx.lineTo(startX * config.graphWidth + marginX, marginY + config.graphHeight - startY * config.graphHeight);
  258. ctx.closePath();
  259. ctx.fill();
  260. }
  261. function drawLegend(config, dataSet){
  262. let ctx = config.ctx;
  263. let graphWidth = config.graphWidth;
  264. let graphHeight = config.graphHeight;
  265. ctx.font = "12px Arial";
  266. let legendWidth = -10;
  267. for (let item of dataSet) {
  268. legendWidth += 50 + ctx.measureText(item.title).width;
  269. }
  270. var x = 0.5 * (graphWidth - legendWidth) + marginX;
  271. var y = config.canvas.height - marginY*1/4;
  272. for (let item of dataSet) {
  273. ctx.fillStyle = item.color;
  274. ctx.fillRect(x, y - 8, 30, 10);
  275. ctx.strokeStyle = "#C0C0C0";
  276. ctx.strokeRect(x, y - 8, 30, 10);
  277. if (darkMode == "true") {
  278. ctx.fillStyle = "#A0A0A0";
  279. } else {
  280. ctx.fillStyle = "#303030";
  281. }
  282. x += 40;
  283. ctx.textAlign = "left"
  284. ctx.fillText(item.title, x, y);
  285. x += ctx.measureText(item.title).width;
  286. x += 10;
  287. }
  288. }
  289. function drawAxisX(config, minValue, maxValue, step, title) {
  290. let ctx = config.ctx;
  291. let graphWidth = config.graphWidth;
  292. let graphHeight = config.graphHeight;
  293. ctx.font = "12px Arial";
  294. ctx.textAlign = "center";
  295. if (darkMode == "true") {
  296. ctx.strokeStyle = "#505050";
  297. ctx.fillStyle = "#A0A0A0";
  298. } else {
  299. ctx.strokeStyle = "#E0E0E0";
  300. ctx.fillStyle = "#303030";
  301. }
  302. for (let x = minValue ; x <= maxValue ; x=x+step) {
  303. let relX = (x - config.minX) / (config.maxX - config.minX);
  304. ctx.fillText(x , relX * graphWidth + marginX, config.canvas.height - marginY*3/4);
  305. ctx.beginPath();
  306. ctx.moveTo(relX * graphWidth + marginX, marginY);
  307. ctx.lineTo(relX * graphWidth + marginX, config.canvas.height - marginY);
  308. ctx.stroke();
  309. }
  310. ctx.font = "12px Arial";
  311. ctx.textAlign = "center";
  312. ctx.fillText(title, config.canvas.width/2, config.canvas.height - marginY*2/4);
  313. }
  314. function drawAxisY(config, minValue, maxValue, step, title) {
  315. let ctx = config.ctx
  316. let graphWidth = config.graphWidth;
  317. let graphHeight = config.graphHeight;
  318. ctx.font = "12px Arial";
  319. ctx.textAlign = "center";
  320. if (darkMode == "true") {
  321. ctx.strokeStyle = "#505050";
  322. ctx.fillStyle = "#A0A0A0";
  323. } else {
  324. ctx.strokeStyle = "#E0E0E0";
  325. ctx.fillStyle = "#303030";
  326. }
  327. for (let y = minValue ; y <= maxValue ; y=y+step) {
  328. let relY = (y - config.minY) / (config.maxY - config.minY);
  329. ctx.fillText(y , marginX *2 / 3, marginY + graphHeight - relY * graphHeight + 4);
  330. ctx.beginPath();
  331. ctx.moveTo(marginX, marginY + graphHeight - relY * graphHeight );
  332. ctx.lineTo(config.canvas.width - marginX, marginY + graphHeight - relY * graphHeight);
  333. ctx.stroke();
  334. }
  335. ctx.font = "12px Arial";
  336. ctx.textAlign = "center";
  337. ctx.translate(marginX/3, marginY + graphHeight / 2);
  338. ctx.rotate(-3.14 /2);
  339. ctx.fillText(title, 0, 0);
  340. ctx.rotate(3.14 /2)
  341. ctx.translate(-marginX/3,-(marginY + graphHeight / 2));
  342. }
  343. drawChart(dBChart);
  344. drawChart(bitsChart);
  345. drawChart(qLNChart);
  346. drawChart(hLogChart);