forked from puripant/moss-viz
-
Notifications
You must be signed in to change notification settings - Fork 0
/
mossViz.js
165 lines (141 loc) · 4.44 KB
/
mossViz.js
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
var svg = d3.select("svg");
var width = +svg.attr("width");
var height = +svg.attr("height");
var nodeRadius = 10;
// Get URL paramters
const url = window.location.search;
const queryStringRegEx = function(query) {
return new RegExp("[?|&]" + query + "=([^&]*)");
};
var matches = url.match(queryStringRegEx("id"));
const id = matches ? matches[1] : undefined;
var mossUrl = id? ("Moss Results" + id + ".html") : "Moss Results.html";
// var mossUrl = id? ("http://moss.stanford.edu/results/" + id) : "Moss Results3.html";
// var mossUrl = "Moss Results.html";
const unwantedChars = ["/"];
d3.html(mossUrl, function(error, data) {
if (error) throw error;
var rows = data.querySelector("tbody").querySelectorAll("tr");
var nodeSet = new Set();
var pairs = [];
var maxWeight = -1;
var sumWeight = 0;
for(var r = 0; r < rows.length; r++) {
var columns = rows.item(r).querySelectorAll("td");
if(columns.length > 0) {
let pair = [];
for(var c = 0; c < 2; c++) { // two student ids
var text = columns.item(c).querySelector("a").textContent;
var nodeId = text.substring(0, text.lastIndexOf(" "));
unwantedChars.forEach(function(c) {
nodeId = nodeId.replace(new RegExp(c, 'g'), "");
});
//TODO use percentage for link weight (but the percentages of two nodes are not necessary the same).
nodeSet.add(nodeId);
pair.push(nodeId);
}
let weight = +columns.item(2).textContent
maxWeight = Math.max(maxWeight, weight);
sumWeight += weight;
pair.push(weight); // #common lines
pairs.push(pair);
}
}
var nodeArray = [...nodeSet];
var commonPrefixLen = longestCommonPrefixLength(nodeArray);
nodes = [];
nodeArray = nodeArray.map(function(node) {
var shortNode = node.substring(commonPrefixLen);
nodes.push({name: shortNode});
return shortNode;
});
var links = [];
for(let pair of pairs) {
if(pair[2] > sumWeight/pairs.length) {
links.push({
source: nodeArray.indexOf(pair[0].substring(commonPrefixLen)),
target: nodeArray.indexOf(pair[1].substring(commonPrefixLen)),
weight: pair[2]/maxWeight
});
}
}
var force = d3.layout.force()
// .gravity(.05)
.distance(function(d) { return (1-d.weight)*width/nodeRadius; })
.charge(-300)
.size([width, height])
.nodes(nodes)
.links(links)
.on("tick", ticked)
.start();
var link = svg.append("g")
.attr("class", "links")
.selectAll("line")
.data(links)
.enter().append("line")
.style("stroke-width", function(d) { return nodeRadius*d.weight; });
// .style("stroke-opacity", function(d) { return d.weight; });
var node = svg.append("g")
.attr("class", "nodes")
.selectAll("circle")
.data(nodes)
.enter().append("g")
node.append("circle")
.attr("r", nodeRadius)
// .call(force.drag);
.call(d3.behavior.drag()
.on("dragstart", dragstarted)
.on("drag", dragged)
.on("dragend", dragended));
node.append("text")
.attr("dy", "-1em")
.text(function(d) { return d.name; });
function ticked() {
node.attr("transform", function(d) {
return "translate(" + Math.max(2*nodeRadius, Math.min(width - 2*nodeRadius, d.x)) + "," +
Math.max(2*nodeRadius, Math.min(height - 2*nodeRadius, d.y)) + ")";
// return "translate(" + d.x + "," + d.y + ")";
});
link
.attr("x1", function(d) { return d.source.x; })
.attr("y1", function(d) { return d.source.y; })
.attr("x2", function(d) { return d.target.x; })
.attr("y2", function(d) { return d.target.y; });
}
function dragstarted(d) {
force.stop()
}
function dragged(d) {
d.px += d3.event.dx;
d.py += d3.event.dy;
d.x += d3.event.dx;
d.y += d3.event.dy;
ticked();
}
function dragended(d) {
d.fixed = true;
ticked();
force.resume();
}
function longestCommonPrefixLength(texts) {
// // Automatic prefix truncation by finding common starting substring https://stackoverflow.com/questions/1916218/find-the-longest-common-starting-substring-in-a-set-of-strings/1917041#1917041
// nodeArray.sort();
// var i = 0;
// while(i < nodeArray[0].length && nodeArray[0].charAt(i) === nodeArray[nodes.length-1].charAt(i)) {
// i++;
// }
if(texts.length == 0) {
return 0;
}
var maxLen = texts[0].length;
for(var len = 0; len < maxLen; len++) {
var currentChar = texts[0].charAt(len);
for (var j = 1; j < texts.length; j++) {
if(len >= texts[j].length || texts[j].charAt(len) != currentChar) { //mismatch
return len;
}
}
}
return maxLen;
}
});