sigma.plugins.neighborhoods.js 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. /**
  2. * This plugin provides a method to retrieve the neighborhood of a node.
  3. * Basically, it loads a graph and stores it in a headless sigma.classes.graph
  4. * instance, that you can query to retrieve neighborhoods.
  5. *
  6. * It is useful for people who want to provide a neighborhoods navigation
  7. * inside a big graph instead of just displaying it, and without having to
  8. * deploy an API or the list of every neighborhoods.
  9. *
  10. * This plugin also adds to the graph model a method called "neighborhood".
  11. * Check the code for more information.
  12. *
  13. * Here is how to use it:
  14. *
  15. * > var db = new sigma.plugins.neighborhoods();
  16. * > db.load('path/to/my/graph.json', function() {
  17. * > var nodeId = 'anyNodeID';
  18. * > mySigmaInstance
  19. * > .read(db.neighborhood(nodeId))
  20. * > .refresh();
  21. * > });
  22. */
  23. (function() {
  24. 'use strict';
  25. if (typeof sigma === 'undefined')
  26. throw 'sigma is not declared';
  27. /**
  28. * This method takes the ID of node as argument and returns the graph of the
  29. * specified node, with every other nodes that are connected to it and every
  30. * edges that connect two of the previously cited nodes. It uses the built-in
  31. * indexes from sigma's graph model to search in the graph.
  32. *
  33. * @param {string} centerId The ID of the center node.
  34. * @return {object} The graph, as a simple descriptive object, in
  35. * the format required by the "read" graph method.
  36. */
  37. sigma.classes.graph.addMethod(
  38. 'neighborhood',
  39. function(centerId) {
  40. var k1,
  41. k2,
  42. k3,
  43. node,
  44. center,
  45. // Those two local indexes are here just to avoid duplicates:
  46. localNodesIndex = {},
  47. localEdgesIndex = {},
  48. // And here is the resulted graph, empty at the moment:
  49. graph = {
  50. nodes: [],
  51. edges: []
  52. };
  53. // Check that the exists:
  54. if (!this.nodes(centerId))
  55. return graph;
  56. // Add center. It has to be cloned to add it the "center" attribute
  57. // without altering the current graph:
  58. node = this.nodes(centerId);
  59. center = {};
  60. center.center = true;
  61. for (k1 in node)
  62. center[k1] = node[k1];
  63. localNodesIndex[centerId] = true;
  64. graph.nodes.push(center);
  65. // Add neighbors and edges between the center and the neighbors:
  66. for (k1 in this.allNeighborsIndex[centerId]) {
  67. if (!localNodesIndex[k1]) {
  68. localNodesIndex[k1] = true;
  69. graph.nodes.push(this.nodesIndex[k1]);
  70. }
  71. for (k2 in this.allNeighborsIndex[centerId][k1])
  72. if (!localEdgesIndex[k2]) {
  73. localEdgesIndex[k2] = true;
  74. graph.edges.push(this.edgesIndex[k2]);
  75. }
  76. }
  77. // Add edges connecting two neighbors:
  78. for (k1 in localNodesIndex)
  79. if (k1 !== centerId)
  80. for (k2 in localNodesIndex)
  81. if (
  82. k2 !== centerId &&
  83. k1 !== k2 &&
  84. this.allNeighborsIndex[k1][k2]
  85. )
  86. for (k3 in this.allNeighborsIndex[k1][k2])
  87. if (!localEdgesIndex[k3]) {
  88. localEdgesIndex[k3] = true;
  89. graph.edges.push(this.edgesIndex[k3]);
  90. }
  91. // Finally, let's return the final graph:
  92. return graph;
  93. }
  94. );
  95. sigma.utils.pkg('sigma.plugins');
  96. /**
  97. * sigma.plugins.neighborhoods constructor.
  98. */
  99. sigma.plugins.neighborhoods = function() {
  100. var ready = false,
  101. readyCallbacks = [],
  102. graph = new sigma.classes.graph();
  103. /**
  104. * This method just returns the neighborhood of a node.
  105. *
  106. * @param {string} centerNodeID The ID of the center node.
  107. * @return {object} Returns the neighborhood.
  108. */
  109. this.neighborhood = function(centerNodeID) {
  110. return graph.neighborhood(centerNodeID);
  111. };
  112. /**
  113. * This method loads the JSON graph at "path", stores it in the local graph
  114. * instance, and executes the callback.
  115. *
  116. * @param {string} path The path of the JSON graph file.
  117. * @param {?function} callback Eventually a callback to execute.
  118. */
  119. this.load = function(path, callback) {
  120. // Quick XHR polyfill:
  121. var xhr = (function() {
  122. if (window.XMLHttpRequest)
  123. return new XMLHttpRequest();
  124. var names,
  125. i;
  126. if (window.ActiveXObject) {
  127. names = [
  128. 'Msxml2.XMLHTTP.6.0',
  129. 'Msxml2.XMLHTTP.3.0',
  130. 'Msxml2.XMLHTTP',
  131. 'Microsoft.XMLHTTP'
  132. ];
  133. for (i in names)
  134. try {
  135. return new ActiveXObject(names[i]);
  136. } catch (e) {}
  137. }
  138. return null;
  139. })();
  140. if (!xhr)
  141. throw 'XMLHttpRequest not supported, cannot load the data.';
  142. xhr.open('GET', path, true);
  143. xhr.onreadystatechange = function() {
  144. if (xhr.readyState === 4) {
  145. graph.clear().read(JSON.parse(xhr.responseText));
  146. if (callback)
  147. callback();
  148. }
  149. };
  150. // Start loading the file:
  151. xhr.send();
  152. return this;
  153. };
  154. /**
  155. * This method cleans the graph instance "reads" a graph into it.
  156. *
  157. * @param {object} g The graph object to read.
  158. */
  159. this.read = function(g) {
  160. graph.clear().read(g);
  161. };
  162. };
  163. }).call(window);