Graph database Analysis of the Steam 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.

364 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(username)
  35. {
  36. for(var i = 0; i < nodes.length; i++)
  37. {
  38. if(nodes[i].id === username)
  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. addManualToGraph(profileData.id, profileData.avatar);
  53. for(var i = 0; i < profileData.friends.length; i++)
  54. {
  55. addManualToGraph(profileData.friends[i].id,
  56. profileData.friends[i].avatar);
  57. }
  58. }
  59. function addManualToGraph(id,avatar)
  60. {
  61. nodes.push(
  62. {
  63. id:id,
  64. shape: 'circularImage',
  65. image:avatar
  66. });
  67. }
  68. /**
  69. * Adds the followers/following of a person
  70. * to the graph
  71. *
  72. * @param username
  73. * @param apiPath
  74. * @returns {Promise<any>}
  75. */
  76. function addFriends(username)
  77. {
  78. updateProgress();
  79. return new Promise((resolve, reject)=>
  80. {
  81. getPersonAPI(username, (data)=>
  82. {
  83. for(var i = 0; i < data.length; i++)
  84. {
  85. if(!alreadyInGraph(data[i].login))
  86. {
  87. addPersonToGraph(data[i]);
  88. }
  89. }
  90. resolve();
  91. },
  92. (error)=>
  93. {
  94. reject(error);
  95. })
  96. });
  97. }
  98. /**
  99. * Greedy function which checks to see if a edge is in the graphs
  100. *
  101. * @param id1
  102. * @param id2
  103. * @returns {boolean}
  104. */
  105. function edgeInGraph(id1, id2)
  106. {
  107. for(var i = 0;i < edges.length; i++)
  108. {
  109. if((edges[i].to === id1 && edges[i].from === id2) ||
  110. (edges[i].from === id1 && edges[i].to === id2))
  111. {
  112. return true;
  113. }
  114. }
  115. return false;
  116. }
  117. /**
  118. * Adds a connection to the graph
  119. *
  120. * @param person1
  121. * @param person2
  122. */
  123. function addConnection(id1, id2)
  124. {
  125. if(id1 !== id2)
  126. {
  127. if(alreadyInGraph(id2) && !edgeInGraph(id1, id2))
  128. {
  129. network.body.data.edges.add([{
  130. from: id1,
  131. to: id2
  132. }]);
  133. }
  134. }
  135. }
  136. /**
  137. * Processes all the connections of a user and adds them to the graph
  138. *
  139. * @param user has .id and .name
  140. * @returns {Promise<any>}
  141. */
  142. function processUserConnections(node)
  143. {
  144. return new Promise((resolve, reject)=>
  145. {
  146. getPersonAPI(node.id,
  147. (data) => {
  148. updateProgress();
  149. for (var i = 0; i < data.friends.length; i++) {
  150. addConnection(node.id, data.friends[i].id)
  151. }
  152. resolve();
  153. }, (error) => {
  154. console.log(error);
  155. resolve();
  156. });
  157. });
  158. }
  159. function processUserGames(node)
  160. {
  161. return new Promise((resolve, reject)=>
  162. {
  163. getUserGames(node.id,
  164. (data) => {
  165. for (var i = 0; i < data.length; i++) {
  166. addConnection(node.id, "" +data[i].appID)
  167. }
  168. resolve();
  169. }, (error) => {
  170. console.log(error);
  171. resolve();
  172. });
  173. });
  174. }
  175. /**
  176. * Creates connections between all the nodes in
  177. * the graph.
  178. *
  179. * @returns {Promise<any>}
  180. */
  181. async function createConnections() {
  182. for (var i = 0; i < nodes.length; i++)
  183. {
  184. await processUserConnections(nodes[i]);
  185. await processUserGames(nodes[i]);
  186. }
  187. }
  188. /**
  189. * Updates progress bar for loading the JS graph
  190. */
  191. function updateProgress()
  192. {
  193. indexed++;
  194. if(indexed >= total)
  195. {
  196. $("#" + progressID).html("");
  197. }
  198. else
  199. {
  200. const percent = parseInt((indexed/total)*100);
  201. $("#" + progressID).html("<div class=\"progress\">\n" +
  202. " <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" +
  203. "</div>");
  204. }
  205. }
  206. function getSteamImgURL(game)
  207. {
  208. return "http://media.steampowered.com/steamcommunity/public/images/apps/" + game.appID + "/" + game.icon + ".jpg"
  209. }
  210. function addGamesToGraph(games)
  211. {
  212. console.log("adding base player games to graph");
  213. for(var i = 0; i < games.length; i++)
  214. {
  215. var gameLogo = getSteamImgURL(games[i]);
  216. console.log(gameLogo);
  217. nodes.push(
  218. {
  219. id:"" +games[i].appID,
  220. image:gameLogo,
  221. shape: 'image',
  222. size: 30,
  223. });
  224. }
  225. }
  226. var selfData;
  227. /**
  228. * Adds the base person to the graph.
  229. *
  230. * @param username
  231. * @returns {Promise<any>}
  232. */
  233. function addSelfToGraph(id)
  234. {
  235. return new Promise((resolve, reject)=>
  236. {
  237. getPersonAPI(id, (data)=>
  238. {
  239. selfData = data;
  240. baseID = data.id;
  241. total = data.friends.length;
  242. addPersonToGraph(data);
  243. getUserGames(id, (games)=>
  244. {
  245. console.log(games);
  246. addGamesToGraph(games);
  247. resolve();
  248. },
  249. (error2)=>
  250. {
  251. console.log(error2);
  252. reject();
  253. });
  254. },
  255. (error)=>
  256. {
  257. reject(error);
  258. });
  259. });
  260. }
  261. /**
  262. * Used for the on graph click event
  263. *
  264. * @param github id
  265. */
  266. function bringUpProfileView(uname)
  267. {
  268. console.log(uname);
  269. if(uname === selfData.id)
  270. {
  271. profileGen(selfData, "profileGen");
  272. }
  273. else
  274. {
  275. for(var i = 0; i < selfData.friends.length; i++)
  276. {
  277. if(selfData.friends[i].id === uname)
  278. {
  279. profileGen(selfData.friends[i], "profileGen");
  280. }
  281. }
  282. }
  283. }
  284. var network;
  285. nodes = [];
  286. edges = [];
  287. /**
  288. * Creates a graph
  289. * @param username
  290. * @param containerName
  291. * @param progressBarID
  292. */
  293. function createGameGraphs(username, containerName, progressBarID)
  294. {
  295. progressID = progressBarID;
  296. addSelfToGraph(username).then(()=>
  297. {
  298. $("#" + progressID).html("");
  299. var container = document.getElementById(containerName);
  300. var data =
  301. {
  302. nodes: nodes,
  303. edges: edges
  304. };
  305. network = new vis.Network(container, data, options);
  306. bringUpProfileView(selfData.id);
  307. network.on("click", function (params)
  308. {
  309. if(Number(this.getNodeAt(params.pointer.DOM)) !== NaN)
  310. {
  311. bringUpProfileView(this.getNodeAt(params.pointer.DOM));
  312. }
  313. });
  314. createConnections().then(()=>
  315. {
  316. // $("#" + progressID).html("");
  317. console.log("Finished");
  318. })
  319. }).catch((error)=>
  320. {
  321. //$("#" + graphsTitle).html("Error Fetching Data From API");
  322. // alert("Invalid User");
  323. console.log(error);
  324. });
  325. }