-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathindex.html
More file actions
269 lines (214 loc) · 8.18 KB
/
index.html
File metadata and controls
269 lines (214 loc) · 8.18 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
<!DOCTYPE html>
<!-- Network/Graph Visualizations (SEE README.md)-->
<!-- Used mike bostock's functions for dragging functionality -->
<html lang = "en">
<head>
<title> d3 Network Visualizations </title>
<!-- meta info -->
<meta charset="utf-8">
<meta name = "description" content = "Network Visualizations (see README)">
<meta name = "author" content = "Shaun Jose">
<!-- refresh document every 10 minutes -->
<meta http-equiv="refresh" content="3000 ">
</head>
<body>
<!-- create a canvas for the graph -->
<canvas id="graph" width="0" height="0" style="border: 2px solid black;"> </canvas>
<!--Create spacing element. Used for spacing b/w graph and info -->
<canvas id="spacing" width="0" height="0"></canvas>
<!-- create a canvas for the user's information -->
<canvas id="info" width="0" height="0" style="border: 2px solid black;"> </canvas>
<!-- import d3.v5.min.js -->
<script src = "https://d3js.org/d3.v5.min.js"> </script>
<!-- import jQuery -->
<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
<!-- do the real stuff -->
<script>
//CONSTANTS DECLARATION
//setting width of information bar and height gap for formatting
var INFO_WIDTH = 350;
var INFO_HEIGHT = 550;
var X_BORDER = 100;
var Y_BORDER = 100;
var REPEL_FORCE = -300; //force with which nodes repel (for spacing)
var INFO_COLOURS = ["red", "green", "purple", "turquoise"];
var INFO_ATTR = ["Userame: ", "Followers: ", "Popularity: ", "Location: "];
//set up width and height for the graph canvas declared before
var canvas = document.getElementById("graph");
canvas.width = window.innerWidth - (INFO_WIDTH + X_BORDER);
canvas.height = window.innerHeight - Y_BORDER;
//set up width for the spacing canvas declared before
canvas = document.getElementById("spacing");
canvas.width = X_BORDER - (X_BORDER/2); //to allow space for info canvas as well
//set up width and height for the info canvas declared before
canvas = document.getElementById("info"); //used later as well!
canvas.width = INFO_WIDTH;
canvas.height = INFO_HEIGHT;
//put heading in Information
var info_context = canvas.getContext("2d"); //used later as well!
info_context.font = "small-caps 30px Courier";
info_context.fillStyle = "blue";
info_context.fillText("User Information:", 25, 25,);
//changing font for later
info_context.font = "16px Arial";
//create the container (canvas) where you're drawing your network, and declare attributes
var container = d3.select("#graph");
var height = container.attr("height");
var width = container.attr("width");
var radius = 5;
var colour = d3.scaleOrdinal(d3.schemeCategory10); //used for colouring nodes
var context = container.node().getContext("2d");
var graph; //
//create simulation object
var sim = d3.forceSimulation();
//do cool stuff with simulation
sim.force("y", d3.forceY(height/2)); //put nodes in the center of container horizontally
sim.force("x", d3.forceX(width/2)); //put nodes in the center of container vertically
sim.force("collide", d3.forceCollide(radius)); //nodes don't overlap
sim.force("charge", d3.forceManyBody().strength(REPEL_FORCE)); //space out nodes
sim.force("linkForce", d3.forceLink().id(function (node) { return node.username; } )); //create a link force, and look at username to find source and target nodes
//loading in data grabbed from Github_Access.py, using jquery on data.JSON
$.getJSON("data.json", function (data) {
graph = data;
sim.nodes(graph.nodes); //perform a simulation on our nodes
sim.on("tick", drawGraph); //call drawGraph everytime graph.nodes has new values
sim.force("linkForce").links(graph.links); //assign the linkForce to graph.links.
//drag functionality
container
.call(d3.drag()
.container(container.node())
.subject(dragsubject)
.on("start", dragstarted)
.on("drag", dragged)
.on("end", dragended));
/**
* Draws the graph's nodes and edges
* NOTE: This function needs to be inside the json function as it uses variable graph
**/
function drawGraph(){
context.clearRect(0, 0, width, height);
//draw each link
context.beginPath(); //signal that we're drawing stuff
context.globalAlpha = 0.4; //make links a little transparent
context.strokeStyle = "#000"; //black links (but transparent-ish)
graph.links.forEach(drawLink); //draw all links
context.stroke(); //adisplay the strokes
context.globalAlpha = 1.0; //everything else is opaque
//draw each node
graph.nodes.forEach(drawNode); //draw all nodes
}
//Source: Mike bostock's function
function dragsubject() {
return sim.find(d3.event.x, d3.event.y);
}
});
//Source: Mike bostock's function
function dragstarted() {
if (!d3.event.active) sim.alphaTarget(0.3).restart();
d3.event.subject.fx = d3.event.subject.x;
d3.event.subject.fy = d3.event.subject.y;
}
//Source: Mike bostock's function
function dragged() {
d3.event.subject.fx = d3.event.x;
d3.event.subject.fy = d3.event.y;
//display information on the info canvas
var node = d3.event.subject;
//display user information
displayInfo(d3.event.subject);
}
//Source: Mike bostock's function
function dragended() {
if (!d3.event.active) sim.alphaTarget(0);
d3.event.subject.fx = null;
d3.event.subject.fy = null;
}
/**
* Displays a node's information on the information canvas
*
* @param node: The node begin dragged by the user
**/
function displayInfo(node)
{
//clear the previous infomartion displayed
info_context.clearRect(25, 30, canvas.width - 30, canvas.height - 25);
//display user iinformation
var location = node.location;
if(location == null)
location = "Unknown";
var attr = [node.username, node.followers, node.popularity, location];
var x_pos = 25, y_pos = 80;
var y_spacing = 30;
for(i = 0; i < INFO_ATTR.length; i++)
{
info_context.fillStyle = INFO_COLOURS[i];
info_context.fillText(INFO_ATTR[i] + attr[i], x_pos, y_pos);
y_pos += y_spacing;
}
//display the workers from the organisation the user has worked with
displayOrgContribs(node.username, x_pos, y_pos, 20);
}
/**
* Displays the people from the organization that an employee (github user) has worked with
*
* @param name: Username of the github user (employee)
* @param x: x positioning of text
* @param y: y positioning of text
* @param y_spacing: space between each contributor
**/
function displayOrgContribs(name, x, y, y_spacing)
{
info_context.fillStyle = "Teal"; //Rebecca Purple, Teal
info_context.fillText("Worked with: ", x, y);
x += 100;
var no_contribs = true;
var encountered = [];
for(i = 0; i < graph.links.length; i++)
{
var source = graph.links[i].source.username;
var target = graph.links[i].target.username;
if(source == name || target == name)
{
var contrib = source != name? source : target;
if(contrib != name && (!encountered.includes(contrib))) //if it's not the same person, or if we have encountered the person before
{
no_contribs = false;
info_context.fillText(contrib, x, y);
y += y_spacing;
encountered.push(contrib)
}
}
}
//if employee has no connections with coworkers
if(no_contribs)
info_context.fillText("Nobody from the organization", x, y);
}
/**
* Draws a node
*
* @param node: a node element (one user)
**/
function drawNode(node){
//signal that we're drawing stuff
context.beginPath();
//draw stuff
context.fillStyle = colour(node.popularity); //colour nodes based on popularity
context.moveTo(node.x, node.y); //set context on node
context.arc(node.x, node.y, radius, 0, Math.PI * 2); //draw the node as a circle
//actually display stuff that's been created
context.fill();
}
/**
* Draws a link from a source node to a target node
*
* @param node: a node element (one user)
**/
function drawLink(link){
//move cursor to source node's position
context.moveTo(link.source.x, link.source.y);
//draw a line to the target node's location
context.lineTo(link.target.x, link.target.y);
}
</script>
</body>
</html>