certainTrustTViz.js 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338
  1. /**
  2. * CertainTrust SDK
  3. *
  4. * Implements the computational trust model "CertainTrust"
  5. * in JavaScript.
  6. * See <http://www.tk.informatik.tu-darmstadt.de/de/research/smart-security-and-trust/> for further details.
  7. *
  8. *
  9. * Telecooperation Department, Technische Universität Darmstadt
  10. * <http://www.tk.informatik.tu-darmstadt.de/>
  11. *
  12. * Prof. Dr. Max Mühlhäuser <max@informatik.tu-darmstadt.de>
  13. * Florian Volk <florian.volk@cased.de>
  14. *
  15. *
  16. * @author Daniel Dieth
  17. * @author David Kalnischkies
  18. * @author Maria Pelevina
  19. * @version 1.0
  20. */
  21. /* This Source Code Form is subject to the terms of the Mozilla Public
  22. * License, v. 2.0. If a copy of the MPL was not distributed with this
  23. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  24. //##########################################################################################
  25. // CertainTrustTViz constructor
  26. //##########################################################################################
  27. var CertainTrustTViz = function(data, config) {
  28. this.NR = CertainTrustTVizElement.length();
  29. CertainTrustTVizElement.push(this);
  30. this.certainTrusts = [];
  31. this.add(data);
  32. // set sane defaults for config if nothing is set
  33. if (config === undefined) config = {};
  34. if (config.id === undefined) config.id = 'certaintrust-tviz-' + this.NR;
  35. // design your widget
  36. if (config.canvas === undefined) config.canvas = {};
  37. if (config.canvas.height === undefined) config.canvas.height = 440;
  38. if (config.canvas.width === undefined) config.canvas.width = 440;
  39. if (config.canvas.inner === undefined) config.canvas.inner = 30;
  40. if (config.middle === undefined) config.middle = 'AVERAGE';
  41. if (config.onClick === undefined) config.onClick = undefined;
  42. if (config.onMiddleClick === undefined) config.onMiddleClick = undefined;
  43. this.ID = config.id;
  44. this.config = config;
  45. var element = document.getElementById(this.ID);
  46. if(!element) {
  47. element = document.createElement('div');
  48. element.setAttribute('id', this.ID);
  49. }
  50. var dom = this.certainTrusts[0]._insertElement(config, element);
  51. this.update();
  52. if (dom !== undefined)
  53. return dom;
  54. };
  55. CertainTrustTViz.prototype.update = function() {
  56. var xmlns = 'http://www.w3.org/2000/svg';
  57. var dotx = this.config.canvas.height / 2;
  58. var doty = this.config.canvas.width / 2;
  59. var rotate = 360 - 45;
  60. var circle_y = this.config.canvas.inner;
  61. var circle_height = dotx - (2 * circle_y);
  62. var rotationstep = 360 / this.certainTrusts.length;
  63. var element = document.getElementById(this.ID);
  64. // see if we have to redraw thanks to an added/removed CertainTrust element
  65. if (element.hasChildNodes() === true) {
  66. var old_arcs = document.getElementById(this.ID + '-arcs');
  67. if (old_arcs.childNodes.length !== this.certainTrusts.length)
  68. element.removeChild(element.firstChild);
  69. }
  70. var arcs = document.createElementNS(xmlns, 'g');
  71. arcs.setAttribute('stroke', 'none');
  72. arcs.setAttribute('class', 'certaintrust-tviz-arcs');
  73. arcs.setAttribute('id', this.ID + '-arcs');
  74. // first time run or removed by the if above: full build
  75. if (element.hasChildNodes() === false)
  76. {
  77. // prepare the various elements we need
  78. var axes = document.createElementNS(xmlns, 'g');
  79. axes.setAttribute('fill', 'none');
  80. axes.setAttribute('stroke', 'grey');
  81. axes.setAttribute('class', 'certaintrust-tviz-axes');
  82. var desc = document.createElementNS(xmlns, 'g');
  83. for (var a = 0; a < this.certainTrusts.length; ++a) {
  84. var rotation = (rotate + (rotationstep * a)) % 360;
  85. // an axis for each arc to show of how big each arc could be
  86. var axis = this._generateAxis(xmlns, dotx, doty, circle_height, circle_y, rotation);
  87. axes.appendChild(axis);
  88. // the arc representing the CertainTrust element
  89. var arc = this._generateArc(xmlns, this.certainTrusts[a], dotx, doty, circle_height, circle_y, rotation, rotationstep);
  90. arcs.appendChild(arc);
  91. // label for each arc
  92. var label = this._generateArcLabel(xmlns, this.certainTrusts[a], dotx, doty, circle_height, circle_y, rotation, rotationstep);
  93. desc.appendChild(label);
  94. }
  95. if (this.config.middle !== 'NONE') {
  96. var total = this._generateTotalInTheMiddle(xmlns, dotx, doty);
  97. desc.appendChild(total);
  98. }
  99. // draw circles to indicate how large the arcs could be
  100. var circles = this._generateCircles(xmlns, circle_y, circle_height);
  101. // our new tviz
  102. var svg = document.createElementNS(xmlns, 'svg');
  103. svg.setAttribute('height', this.config.canvas.height);
  104. svg.setAttribute('width', this.config.canvas.width);
  105. svg.appendChild(circles);
  106. svg.appendChild(arcs);
  107. svg.appendChild(axes);
  108. svg.appendChild(desc);
  109. // finally, insert tviz
  110. element.appendChild(svg);
  111. } else {
  112. // we have most of the image, so just change what has changed
  113. element = element.firstChild;
  114. // get the new arcs set
  115. for (var a = 0; a < this.certainTrusts.length; ++a) {
  116. var rotation = (rotate + (rotationstep * a)) % 360;
  117. var arc = this._generateArc(xmlns, this.certainTrusts[a], dotx, doty, circle_height, circle_y, rotation, rotationstep);
  118. arcs.appendChild(arc);
  119. }
  120. // find the old arcs set and exchange it with the new set
  121. var old_arcs = document.getElementById(this.ID + '-arcs');
  122. element.insertBefore(arcs, old_arcs);
  123. element.removeChild(old_arcs);
  124. if (this.config.middle !== 'NONE') {
  125. // and now change the text of label in the middle
  126. var total = document.getElementById(this.ID + '-middle');
  127. total.firstChild.nodeValue = this._calcMiddleLabel(this.certainTrusts);
  128. }
  129. }
  130. };
  131. CertainTrustTViz.prototype.add = function() {
  132. for (var i = 0; i < arguments.length; ++i) {
  133. var ct = arguments[i];
  134. if (ct instanceof Array) {
  135. for (var j = 0; j < ct.length; ++j) {
  136. var c = ct[j];
  137. this.certainTrusts.push(c);
  138. c.addObserver(this);
  139. }
  140. } else {
  141. this.certainTrusts.push(ct);
  142. ct.addObserver(this);
  143. }
  144. }
  145. // don't trigger on first call from constructor
  146. if (this.ID !== undefined)
  147. this.update();
  148. };
  149. CertainTrustTViz.prototype.remove = function() {
  150. for (var i = 0; i < arguments.length; ++i) {
  151. var ct = arguments[i];
  152. if (ct instanceof CertainTrust) {
  153. for (var j = 0; j < ct.length; ++j) {
  154. for (var k = 0; k < this.certainTrusts.length; ++k) {
  155. if (this.certainTrusts[k] !== ct[j])
  156. continue;
  157. ct[j].deleteObserver(this);
  158. this.certainTrusts.splice(k, 1);
  159. break;
  160. }
  161. }
  162. } else {
  163. for (var k = 0; k < this.certainTrusts.length; ++k) {
  164. if (this.certainTrusts[k].getName() !== ct)
  165. continue;
  166. this.certainTrusts[k].deleteObserver(this);
  167. this.certainTrusts.splice(k, 1);
  168. break;
  169. }
  170. }
  171. }
  172. this.update();
  173. };
  174. CertainTrustTViz.prototype._generateAxis = function(xmlns, dotx, doty, circle_height, circle_y, rotation) {
  175. var point = this.certainTrusts[0]._pointOnCircle(dotx, doty, rotation, circle_y);
  176. var axis = document.createElementNS(xmlns, 'g');
  177. axis.setAttribute('fill', 'none');
  178. axis.setAttribute('stroke', 'grey');
  179. var placement;
  180. if (rotation >= 270 && rotation < 360 || rotation >= 0 && rotation < 90) {
  181. axis.setAttribute('transform', 'translate(' + point[1] + ',' + point[0] + ') rotate(' + (rotation) + ')');
  182. axis.setAttribute('class', 'certaintrust-tviz-axis-left');
  183. placement = -1;
  184. } else {
  185. axis.setAttribute('transform', 'translate(' + point[1] + ',' + point[0] + ') rotate(' + (rotation - 180) + ')');
  186. axis.setAttribute('class', 'certaintrust-tviz-axis-right');
  187. placement = 1;
  188. }
  189. var axis_line = document.createElementNS(xmlns, 'line');
  190. axis_line.setAttribute('fill', 'inherit');
  191. axis_line.setAttribute('stroke', 'inherit');
  192. axis_line.setAttribute('x1', 0);
  193. axis_line.setAttribute('y1', 0);
  194. axis_line.setAttribute('x2', 0);
  195. axis_line.setAttribute('y2', placement * circle_height);
  196. axis.appendChild(axis_line);
  197. for (var t = 0; t < 6; ++t) {
  198. var y = placement * (circle_height * (t / 5));
  199. var tick_line = document.createElementNS(xmlns, 'line');
  200. tick_line.setAttribute('fill', 'inherit');
  201. tick_line.setAttribute('stroke', 'inherit');
  202. tick_line.setAttribute('x1', 0);
  203. tick_line.setAttribute('y1', y);
  204. tick_line.setAttribute('x2', placement * 6);
  205. tick_line.setAttribute('y2', y);
  206. var tick_text = document.createElementNS(xmlns, 'text');
  207. tick_text.setAttribute('fill', 'grey');
  208. tick_text.setAttribute('x', placement * 9);
  209. tick_text.setAttribute('y', y);
  210. tick_text.setAttribute('dy', '.5em');
  211. tick_text.setAttribute('font-size', '.5em');
  212. var msg = document.createTextNode(t * 20);
  213. tick_text.appendChild(msg);
  214. var tick = document.createElementNS(xmlns, 'g');
  215. tick.setAttribute('fill', 'inherit');
  216. tick.setAttribute('stroke', 'inherit');
  217. tick.appendChild(tick_line);
  218. tick.appendChild(tick_text);
  219. axis.appendChild(tick);
  220. }
  221. return axis;
  222. };
  223. CertainTrustTViz.prototype._generateArc = function(xmlns, certainTrust, dotx, doty, circle_height, circle_y, rotation, rotationstep) {
  224. var arc_width = rotationstep * certainTrust.getC();
  225. var arc_free = (rotationstep - arc_width) / 2;
  226. var arc_low_left = certainTrust._pointOnCircle(dotx, doty, (rotation + arc_free), circle_y);
  227. var arc_low_right = certainTrust._pointOnCircle(dotx, doty, (rotation + rotationstep - arc_free), circle_y);
  228. var arc_height = (circle_height * certainTrust.getT()) + circle_y;
  229. var arc_high_left = certainTrust._pointOnCircle(dotx, doty, (rotation + arc_free), arc_height);
  230. var arc_high_right = certainTrust._pointOnCircle(dotx, doty, (rotation + rotationstep - arc_free), arc_height);
  231. var color = certainTrust._getColor(certainTrust.getC(), certainTrust.getT(), certainTrust.getF());
  232. var arc = document.createElementNS(xmlns, 'path');
  233. arc.setAttribute('fill', 'rgb(' + Math.round(color[0]) + ',' + Math.round(color[1]) + ',' + Math.round(color[2]) + ')');
  234. arc.setAttribute('stroke', 'inherit');
  235. arc.setAttribute('d', 'M' + arc_low_left[1] + ' ' + arc_low_left[0] +
  236. 'A' + circle_y + ',' + circle_y + ' 0 0,1 ' + arc_low_right[1] + ',' + arc_low_right[0] +
  237. 'L' + arc_high_right[1] + ' ' + arc_high_right[0] +
  238. 'A' + arc_height + ',' + arc_height + ' 0 0,0 ' + arc_high_left[1] + ',' + arc_high_left[0] +
  239. 'z');
  240. arc.setAttribute('title', 'Trust: ' + certainTrust.getT() + '\nCertainty: ' + certainTrust.getC());
  241. if (this.config.onClick !== undefined)
  242. {
  243. var onClick = this.config.onClick;
  244. arc.addEventListener("click", function(e) { onClick(certainTrust); }, false);
  245. }
  246. return arc;
  247. };
  248. CertainTrustTViz.prototype._generateArcLabel = function(xmlns, certainTrust, dotx, doty, circle_height, circle_y, rotation, rotationstep) {
  249. var label = document.createElementNS(xmlns, 'text');
  250. label.setAttribute('fill', 'black');
  251. var outerpoint = this.certainTrusts[0]._pointOnCircle(dotx, doty, (rotation + (rotationstep / 2)), (circle_height + circle_y));
  252. label.setAttribute('x', outerpoint[1]);
  253. label.setAttribute('y', outerpoint[0]);
  254. label.setAttribute('dy', '.5em');
  255. label.setAttribute('text-anchor', 'middle');
  256. var msg = document.createTextNode(certainTrust.getName());
  257. label.appendChild(msg);
  258. return label;
  259. };
  260. CertainTrustTViz.prototype._generateTotalInTheMiddle = function(xmlns, dotx, doty) {
  261. var total = document.createElementNS(xmlns, 'text');
  262. total.setAttribute('fill', 'grey');
  263. total.setAttribute('x', dotx);
  264. total.setAttribute('y', doty);
  265. total.setAttribute('dy', '.5em');
  266. total.setAttribute('text-anchor', 'middle');
  267. total.setAttribute('id', this.ID + '-middle');
  268. var msg = document.createTextNode(this._calcMiddleLabel(this.certainTrusts));
  269. total.appendChild(msg);
  270. if (this.config.onMiddleClick !== undefined)
  271. {
  272. var onMiddleClick = this.config.onMiddleClick;
  273. total.addEventListener("click", function(e) { onMiddleClick(); }, false);
  274. }
  275. return total;
  276. };
  277. CertainTrustTViz.prototype._generateCircles = function(xmlns, circle_y, circle_height) {
  278. var circles = document.createElementNS(xmlns, 'g');
  279. circles.setAttribute('fill', 'none');
  280. circles.setAttribute('stroke', 'lightgrey');
  281. circles.setAttribute('class', 'certaintrust-tviz-circles');
  282. for (var i = 0; i < 11; ++i) {
  283. var circle = document.createElementNS(xmlns, 'circle');
  284. circle.setAttribute('cx', '50%');
  285. circle.setAttribute('cy', '50%');
  286. var r = circle_y + (circle_height * (i / 10));
  287. circle.setAttribute('r', r);
  288. circle.setAttribute('fill', 'inherit');
  289. circle.setAttribute('stroke', 'inherit');
  290. circles.appendChild(circle);
  291. }
  292. return circles;
  293. };
  294. // Calculate the average over all included CertainTrusts
  295. CertainTrustTViz.prototype._calcMiddleLabel = function(indata) {
  296. if (this.config.middle === "NONE")
  297. return "";
  298. else if (this.config.middle === "AVERAGE") {
  299. var avg = 0.0;
  300. for (var i = 0; i < indata.length; i++) {
  301. avg += indata[i].getExpectation();
  302. }
  303. return (Math.round(avg/indata.length*1000)/10) + "%";
  304. } else if (this.config.middle === "AND") {
  305. var result = indata[0];
  306. for (var i = 1; i < indata.length; i++) {
  307. result = result.AND(indata[i]);
  308. }
  309. return (Math.round(result.getExpectation()*1000)/10) + "%";
  310. } else
  311. return this.config.middle(indata);
  312. };
  313. // global var for storing and accessing all the widgets
  314. var CertainTrustTVizElement = { _elements: [],
  315. ById: function(id) {
  316. for (var i = 0; i < CertainTrustTVizElement._elements.length; ++i) {
  317. if (CertainTrustTVizElement._elements[i].ID === id)
  318. return CertainTrustTVizElement._elements[i];
  319. }
  320. return null;
  321. },
  322. ByNr: function(nr) { return CertainTrustTVizElement._elements[nr]; },
  323. push: function(cte) { CertainTrustTVizElement._elements.push(cte); },
  324. length: function() { return CertainTrustTVizElement._elements.length; }
  325. };