1 $(function() { |
|
2 |
|
3 var colorset = ["#E41A1C", "#377EB8", "#4DAF4A", "#984EA3", "#FF7F00", "#A65628", "#F781BF"]; |
|
4 |
|
5 $(".topics-block").draggable({axis:"y"}) |
|
6 |
|
7 $.getJSON("fakedata/data.json", function(data) { |
|
8 |
|
9 function secsToString(seconds) { |
|
10 var hours = Math.floor(seconds/3600), |
|
11 minutes = Math.floor(seconds/60) % 60, |
|
12 secs = Math.floor(seconds % 60); |
|
13 function pad(n) { |
|
14 var r = n.toString(); |
|
15 while (r.length < 2) { |
|
16 r = "0" + r; |
|
17 } |
|
18 return r; |
|
19 } |
|
20 return (hours ? (hours + ":") : "") + pad(minutes) + ":" + pad(secs); |
|
21 } |
|
22 |
|
23 $(".duration").text(secsToString(data.duration)); |
|
24 |
|
25 $(".topwords-list").on("click", "li", function() { |
|
26 var el = $(this).toggleClass("selected"); |
|
27 wordFilter(); |
|
28 }); |
|
29 |
|
30 var nmmso = data.segments.length; |
|
31 |
|
32 data.topics.forEach(function(topic) { |
|
33 topic.score = 0; |
|
34 topic.weights = []; |
|
35 topic.scores = []; |
|
36 for (var i = 0; i < nmmso; i++) { |
|
37 topic.weights.push(0); |
|
38 topic.scores.push(0); |
|
39 } |
|
40 }); |
|
41 |
|
42 data.segments.forEach(function(mmso, i) { |
|
43 mmso.topics.forEach(function(t) { |
|
44 var score = t.weight * mmso.tweet_count; |
|
45 data.topics[t.topic].weights[i] = t.weight; |
|
46 data.topics[t.topic].scores[i] = score; |
|
47 data.topics[t.topic].score += score; |
|
48 }); |
|
49 mmso.tweet_rate = mmso.tweet_count / mmso.duration; |
|
50 }); |
|
51 |
|
52 var sortedTopics = data.topics.slice().sort(function(a,b) { |
|
53 return b.score - a.score; |
|
54 }); |
|
55 |
|
56 function wordFilter() { |
|
57 var selectedLis = $(".topwords-list li.selected"), |
|
58 searchString = $(".keyword-search").val() || "", |
|
59 useSearchString = (searchString.length > 1), |
|
60 selectedWords = []; |
|
61 selectedLis.each(function() { |
|
62 selectedWords.push($(this).text().trim()); |
|
63 }); |
|
64 if (selectedWords.length || useSearchString) { |
|
65 var topiclist = data.topics.filter(function(topic) { |
|
66 var found = false, |
|
67 relevance = 0; |
|
68 var foundWords = selectedWords.map(function() { return false }); |
|
69 topic.words.forEach(function(topicword) { |
|
70 selectedWords.forEach(function(selectedword, k) { |
|
71 if (selectedword === topicword.word) { |
|
72 found = true; |
|
73 relevance += (.5 + topicword.weight); |
|
74 } |
|
75 }); |
|
76 if (useSearchString && topicword.word.search(searchString) !== -1) { |
|
77 found = true; |
|
78 relevance += (.5 + topicword.weight); |
|
79 } |
|
80 }); |
|
81 topic.relevance = relevance; |
|
82 return found; |
|
83 }).sort(function(a,b) { |
|
84 return b.relevance - a.relevance; |
|
85 }); |
|
86 } else { |
|
87 var topiclist = sortedTopics; |
|
88 } |
|
89 var topicHtmls = ["", "", ""]; |
|
90 if (useSearchString) { |
|
91 var searchStringRx = new RegExp('(' + searchString.replace(/(\W)/g,'\\$1') + ')', "gim"); |
|
92 $(".topwords-list li").each(function() { |
|
93 var el = $(this); |
|
94 el.html(el.text().replace(searchStringRx,'<span class="highlight">$1</span>')); |
|
95 }); |
|
96 } else { |
|
97 $(".topwords-list li").each(function() { |
|
98 var el = $(this); |
|
99 el.text(el.text()); |
|
100 }); |
|
101 } |
|
102 topiclist.forEach(function(topic,i) { |
|
103 var wordsToShow = topic.words.slice(0,5), |
|
104 max = wordsToShow[0].weight, |
|
105 min = Math.min(wordsToShow[wordsToShow.length - 1].weight, max - .01), |
|
106 scale = 10 / (max - min); |
|
107 var li = '<li class="shadow-block topic" data-topic-id="' |
|
108 + topic.index |
|
109 + '" data-timestamp="' |
|
110 + new Date().valueOf() |
|
111 + '"><ul class="topic-words">' |
|
112 + wordsToShow.reduce(function(memwords, word) { |
|
113 return memwords |
|
114 + '<li style="font-size: ' |
|
115 + ( 10 + scale * (word.weight - min) ) |
|
116 + 'px;"' |
|
117 + ( selectedWords.indexOf(word.word) == -1 ? '' : ' class="selected"') |
|
118 + '>' |
|
119 + ( useSearchString |
|
120 ? word.word.replace(searchStringRx,'<span class="highlight">$1</span>') |
|
121 : word.word ) |
|
122 + '</li>'; |
|
123 },"") |
|
124 + '</ul></li>'; |
|
125 topicHtmls[i % 3] += li; |
|
126 }); |
|
127 var tb = $(".topics-block"); |
|
128 tb.html(topicHtmls.reduce(function(mem,html) { |
|
129 return mem + '<ul class="topic-column">' + html + '</ul>' |
|
130 },"")); |
|
131 tb.css("top",0); |
|
132 |
|
133 showTopicViz(); |
|
134 } |
|
135 |
|
136 var topwords = [], globwords = {}; |
|
137 |
|
138 data.topics.forEach(function(topic) { |
|
139 topic.words.forEach(function(word) { |
|
140 globwords[word.word] = word.weight + (globwords[word.word] || 0) |
|
141 }); |
|
142 }) |
|
143 |
|
144 for (var w in globwords) { |
|
145 topwords.push({ |
|
146 word : w, |
|
147 weight : globwords[w] |
|
148 }); |
|
149 } |
|
150 topwords.sort(function(a, b) { |
|
151 return b.weight - a.weight; |
|
152 }); |
|
153 |
|
154 $(".keyword-search").autocomplete({ |
|
155 source: topwords.map(function(w) { return w.word }) |
|
156 }).on("keyup change paste", wordFilter); |
|
157 |
|
158 var wordsToShow = topwords.slice(0,40), |
|
159 max = wordsToShow[0].weight, |
|
160 min = Math.min(wordsToShow[wordsToShow.length - 1].weight, max - .01), |
|
161 scale = 10 / (max - min); |
|
162 |
|
163 $(".topwords-list").html(wordsToShow.reduce(function(mem, d) { |
|
164 return mem |
|
165 + '<li style="font-size: ' |
|
166 + ( 10 + scale * (d.weight - min) ) |
|
167 + 'px;">' |
|
168 + d.word |
|
169 + '</li>' |
|
170 },"")); |
|
171 |
|
172 function showTopicViz() { |
|
173 var selectedBlocks = $(".topic.selected, .topic.hover"), |
|
174 sbl = selectedBlocks.length, |
|
175 topicBlocks = $(".topic"); |
|
176 if (!sbl && topicBlocks.length !== data.topics.length) { |
|
177 topicBlocks.each(function() { |
|
178 |
|
179 }) |
|
180 selectedBlocks = topicBlocks; |
|
181 sbl = selectedBlocks.length; |
|
182 } |
|
183 var topicsAndColors = []; |
|
184 selectedBlocks.map(function() { |
|
185 var el = $(this), |
|
186 topicid = parseInt(el.attr("data-topic-id")); |
|
187 topicsAndColors.push({ |
|
188 "$": el, |
|
189 timestamp: parseInt(el.attr("data-timestamp")), |
|
190 hovered: el.hasClass("hover"), |
|
191 id: topicid, |
|
192 topic: data.topics[topicid] |
|
193 }); |
|
194 }); |
|
195 topicsAndColors.sort(function(a,b) { |
|
196 return (a.hovered |
|
197 ? 1 |
|
198 : ( b.hovered |
|
199 ? -1 |
|
200 : ( a.timestamp - b.timestamp ) || ( a.id - b.id ) |
|
201 ) |
|
202 ) |
|
203 }); |
|
204 topicBlocks.css("background",""); |
|
205 topicsAndColors.forEach(function(topic, i) { |
|
206 topic.color = colorset[i % colorset.length]; |
|
207 topic.$.css("background", topic.color); |
|
208 }); |
|
209 |
|
210 for (var i = 0; i < nmmso; i++) { |
|
211 var opacity = 0, |
|
212 rgb = [0,0,0]; |
|
213 topicsAndColors.forEach(function(topic) { |
|
214 var c = Raphael.getRGB(topic.color), |
|
215 o = topic.topic.weights[i]; |
|
216 rgb[0] += c.r * o; |
|
217 rgb[1] += c.g * o; |
|
218 rgb[2] += c.b * o; |
|
219 opacity += o; |
|
220 }); |
|
221 if (opacity) { |
|
222 color = Raphael.rgb.apply(Raphael, rgb.map(function(c) { |
|
223 return c/opacity; |
|
224 })); |
|
225 segmentrects[i].show(); |
|
226 segmentrects[i].attr({ |
|
227 fill: color, |
|
228 opacity: .2 + .8 * opacity |
|
229 }); |
|
230 } else { |
|
231 segmentrects[i].hide(); |
|
232 } |
|
233 } |
|
234 |
|
235 } |
|
236 |
|
237 var jqsvg = $(".start-svg"); |
|
238 paper = new Raphael(jqsvg[0]), |
|
239 ph = jqsvg.height(), |
|
240 pw = jqsvg.width(), |
|
241 yscale = (ph - 20) / data.duration, |
|
242 mx = Math.max.apply(Math, data.segments.map(function(s) { return s.tweet_rate})), |
|
243 xscale = (pw - 50)/mx; |
|
244 console.log(mx); |
|
245 |
|
246 var segmentrects = data.segments.map(function(mmso) { |
|
247 var rect = paper.rect(0, yscale * mmso.start, pw - 50, yscale * mmso.duration); |
|
248 rect.attr({stroke: "none"}); |
|
249 return rect; |
|
250 }); |
|
251 |
|
252 var d = "M" + data.segments.map(function(s) { |
|
253 var x = xscale * s.tweet_rate; |
|
254 return x |
|
255 + "," |
|
256 + yscale * (s.start + s.duration / 3) |
|
257 + "L" |
|
258 + x |
|
259 + "," |
|
260 + yscale * (s.start + 2 * s.duration / 3); |
|
261 }).join("L"); |
|
262 |
|
263 paper.path(d).attr({ |
|
264 "stroke-width": 4, |
|
265 "stroke": "#000000", |
|
266 opacity: .5 |
|
267 }); |
|
268 paper.path(d).attr({ |
|
269 "stroke-width": 1, |
|
270 "stroke": "#ffffff" |
|
271 }); |
|
272 |
|
273 for (var i=0; i < data.duration; i += 1800) { |
|
274 var y = yscale * i; |
|
275 paper.path("M0," + y + "L" + pw + "," + y).attr({ |
|
276 stroke: "#666" |
|
277 }); |
|
278 paper.text(pw - 2, y + 6, secsToString(i)).attr({ |
|
279 "text-anchor": "end", |
|
280 "fill": "#ffffff" |
|
281 }); |
|
282 } |
|
283 paper.text(pw-2, ph-14, secsToString(data.duration)).attr({ |
|
284 "text-anchor": "end", |
|
285 "fill": "#ffffff" |
|
286 }); |
|
287 paper.path("M0," + (ph-20) + "L" + pw + "," + (ph-20)).attr({ |
|
288 stroke: "#666" |
|
289 }); |
|
290 |
|
291 var x = xscale * 1000 / 60; |
|
292 paper.path("M" + x + ",0L" + x + "," + (ph - 10)).attr({ |
|
293 stroke: "#666" |
|
294 }); |
|
295 |
|
296 paper.text(x-2, ph - 14,"1000 tweets/minute").attr({ |
|
297 "text-anchor": "end", |
|
298 "fill": "#ffffff" |
|
299 }); |
|
300 |
|
301 wordFilter(); |
|
302 |
|
303 $(".topics-block").on("mouseenter", ".topic", function() { |
|
304 var el = $(this); |
|
305 if (!el.hasClass("selected")) { |
|
306 el.addClass("hover"); |
|
307 showTopicViz(); |
|
308 } |
|
309 }).on("mouseleave", ".topic", function() { |
|
310 $(this).removeClass("hover"); |
|
311 showTopicViz(); |
|
312 }).on("click", ".topic", function() { |
|
313 var el = $(this); |
|
314 $(this).toggleClass("selected"); |
|
315 if (el.hasClass("selected")) { |
|
316 el.attr("data-timestamp", new Date().valueOf()) |
|
317 } |
|
318 showTopicViz(); |
|
319 }); |
|
320 |
|
321 |
|
322 }); |
|
323 }); |
|