Website for visualizing a persons github network.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

348 lines
7.4 KiB

  1. /** Nodes in the vis js graph */
  2. var nodes;
  3. /** Edges used to make the Vis JS graph*/
  4. var edges;
  5. /** Used for the loading bar */
  6. var total = 1;
  7. var indexed = 0;
  8. var progressID;
  9. /** Github id of the user being indexed */
  10. var baseID;
  11. /**
  12. * Vis js graph options
  13. */
  14. var options = {
  15. nodes: {
  16. borderWidth:4,
  17. size:30,
  18. color: {
  19. border: '#222222',
  20. background: '#666666'
  21. },
  22. font:{color:'#eeeeee'}
  23. },
  24. edges: {
  25. color: 'lightgray'
  26. }
  27. };
  28. /**
  29. * Checks if a user is a node in the graph
  30. *
  31. * @param userID
  32. * @returns {boolean}
  33. */
  34. function alreadyInGraph(userID)
  35. {
  36. for(var i = 0; i < nodes.length; i++)
  37. {
  38. if(nodes[i].id === userID)
  39. {
  40. return true;
  41. }
  42. }
  43. return false;
  44. }
  45. /**
  46. * adds a person to the nodes list
  47. *
  48. * @param profileData
  49. */
  50. function addPersonToGraph(profileData)
  51. {
  52. nodes.push(
  53. {
  54. id:profileData.id,
  55. name:profileData.login,
  56. shape: 'circularImage',
  57. image:profileData.avatar_url
  58. });
  59. }
  60. /**
  61. * Adds the followers/following of a person
  62. * to the graph
  63. *
  64. * @param username
  65. * @param apiPath
  66. * @returns {Promise<any>}
  67. */
  68. function addFriends(username, apiPath, page)
  69. {
  70. updateProgress();
  71. return new Promise(function(resolve, reject)
  72. {
  73. queryAPIByUser(apiPath + "?page=" + page, username, function(data)
  74. {
  75. for(var i = 0; i < data.length; i++)
  76. {
  77. if(!alreadyInGraph(data[i].id))
  78. {
  79. addPersonToGraph(data[i]);
  80. }
  81. }
  82. if(page < 50 && data.length === 30)
  83. {
  84. addFriends(username, apiPath, page+ 1).then(function()
  85. {
  86. resolve();
  87. })
  88. }
  89. else
  90. {
  91. resolve();
  92. }
  93. },
  94. function(error)
  95. {
  96. reject(error);
  97. })
  98. });
  99. }
  100. /**
  101. * Greedy function which checks to see if a edge is in the graphs
  102. *
  103. * @param id1
  104. * @param id2
  105. * @returns {boolean}
  106. */
  107. function edgeInGraph(id1, id2)
  108. {
  109. for(var i = 0;i < edges.length; i++)
  110. {
  111. if(edges[i].from === id1 && edges[i].to === id2)
  112. {
  113. return true;
  114. }
  115. if(edges[i].to === id1 && edges[i].from === id2)
  116. {
  117. return true;
  118. }
  119. }
  120. return false;
  121. }
  122. /**
  123. * Adds a connection to the graph
  124. *
  125. * @param person1
  126. * @param person2
  127. */
  128. function addConnection(person1, person2)
  129. {
  130. if(person1.id !== person2.id)
  131. {
  132. if(alreadyInGraph(person2.id) && !edgeInGraph(person1.id, person2.id))
  133. {
  134. edges.push(
  135. {
  136. from: person1.id,
  137. to: person2.id
  138. });
  139. }
  140. }
  141. }
  142. function processConnections(user, apiPoint, page)
  143. {
  144. return new Promise(function(resolve, reject)
  145. {
  146. queryAPIByUser(apiPoint + "?page=" + page, user.name,
  147. function(data)
  148. {
  149. for(var i = 0; i < data.length; i++)
  150. {
  151. addConnection(user, data[i])
  152. }
  153. if(page < 50 && data.length === 30)
  154. {
  155. processConnections(user, apiPoint, page + 1).then(function()
  156. {
  157. resolve();
  158. });
  159. }
  160. else
  161. {
  162. resolve();
  163. }
  164. }, function(error)
  165. {
  166. console.log(error);
  167. resolve();
  168. })
  169. })
  170. }
  171. /**
  172. * Processes all the connections of a user and adds them to the graph
  173. *
  174. * @param user has .id and .name
  175. * @returns {Promise<any>}
  176. */
  177. function processUserConnections(user)
  178. {
  179. return new Promise(function(resolve, reject)
  180. {
  181. if(user.id === baseID)
  182. {
  183. processConnections(user, API_FOLLOWING, 1).then(function()
  184. {
  185. processConnections(user, API_FOLLOWERS, 1).then(function()
  186. {
  187. updateProgress();
  188. resolve();
  189. })
  190. })
  191. }
  192. else
  193. {
  194. processConnections(user, API_FOLLOWING, 1).then(function()
  195. {
  196. updateProgress();
  197. resolve();
  198. })
  199. }
  200. });
  201. }
  202. /**
  203. * Creates connections between all the nodes in
  204. * the graph.
  205. *
  206. * @returns {Promise<any>}
  207. */
  208. function createConnections()
  209. {
  210. return new Promise(function(resolve, reject)
  211. {
  212. var prom = [];
  213. for(var i = 0; i < nodes.length; i++)
  214. {
  215. prom.push(processUserConnections(nodes[i]));
  216. }
  217. Promise.all(prom).then(function()
  218. {
  219. resolve();
  220. }).catch(function(error)
  221. {
  222. console.log(error);
  223. resolve();
  224. });
  225. });
  226. }
  227. function updateProgress()
  228. {
  229. indexed++;
  230. const percent = parseInt((indexed/total)*100);
  231. $("#" + progressID).html("<div class=\"progress\">\n" +
  232. " <div class=\"progress-bar progress-bar-striped progress-bar-animated\" role=\"progressbar\" style=\"width: " + percent + "%\" aria-valuenow=\"" + percent + "\" aria-valuemin=\"0\" aria-valuemax=\"100\"></div>\n" +
  233. "</div>");
  234. }
  235. /**
  236. * Adds the base person to the graph.
  237. *
  238. * @param username
  239. * @returns {Promise<any>}
  240. */
  241. function addSelfToGraph(username)
  242. {
  243. return new Promise(function(resolve, reject)
  244. {
  245. queryAPIByUser("", username, function(data)
  246. {
  247. baseID = data.id;
  248. total = (data.followers + data.following);
  249. addPersonToGraph(data);
  250. resolve();
  251. },
  252. function(error)
  253. {
  254. reject(error);
  255. });
  256. });
  257. }
  258. /**
  259. * Used for the on graph click event
  260. *
  261. * @param github id
  262. */
  263. function bringUpProfileView(id)
  264. {
  265. for(var i = 0; i < nodes.length; i++)
  266. {
  267. if(nodes[i].id === id)
  268. {
  269. profileGen(nodes[i].name, "profileGen");
  270. }
  271. }
  272. }
  273. /**
  274. * Creates a graph
  275. * @param username
  276. * @param containerName
  277. * @param progressBarID
  278. */
  279. function createFriendsGraph(username, containerName, progressBarID)
  280. {
  281. progressID = progressBarID;
  282. nodes = [];
  283. edges = [];
  284. addSelfToGraph(username).then(function()
  285. {
  286. addFriends(username, API_FOLLOWERS,1).then(function()
  287. {
  288. addFriends(username, API_FOLLOWING,1).then(function()
  289. {
  290. createConnections().then(function()
  291. {
  292. $("#" + progressID).html("");
  293. var container = document.getElementById(containerName);
  294. var data =
  295. {
  296. nodes: nodes,
  297. edges: edges
  298. };
  299. var network = new vis.Network(container, data, options);
  300. network.on("click", function (params)
  301. {
  302. if(Number(this.getNodeAt(params.pointer.DOM)) !== NaN)
  303. {
  304. bringUpProfileView(Number(this.getNodeAt(params.pointer.DOM)));
  305. }
  306. });
  307. });
  308. });
  309. })
  310. }).catch(function(error)
  311. {
  312. $("#" + graphsTitle).html("Error Fetching Data From API");
  313. alert("Invalid User");
  314. });
  315. }