git ssb

0+

cel / ssb-activity



Tree: 8b2bb74986427753f3b1628bd266bcc7bd7693ea

Files: 8b2bb74986427753f3b1628bd266bcc7bd7693ea / index.html

6905 bytesRaw
1<!doctype html>
2<html>
3<head>
4<meta charset=utf-8>
5<title>ssb-activity</title>
6<script src=common.js></script>
7</head>
8<body>
9
10<div style="text-align:center">
11 <h2>Daily active users</h2>
12 <img id=graph src=day.png alt="Graph of daily active feeds">
13</div>
14
15<div id="day-info" style="float:right; text-align:right; visibility:hidden">
16 <div><ins id="day"> </ins></div>
17 <div><ins id="day-users"> </ins> users</div>
18</div>
19
20<div id="user-info" style="visibility:hidden">
21 <div>User: <a id="user-link"><code id="user-id"> </code></a></div>
22 <div>Days active: <ins id="days-active"> </ins></div>
23 <div><ins id="first"> </ins> - <ins id="last"> </ins></div>
24</div>
25
26<script>
27var feedBase = 'https://viewer.scuttlebot.io/'
28var ids, idColors, idsByColor = {}
29var img = document.getElementById('graph')
30var imgData, origImgData
31var width, height
32var userInfo = document.getElementById('user-info')
33var userLink = document.getElementById('user-link')
34var userIdText = document.getElementById('user-id').firstChild
35var dayInfo = document.getElementById('day-info')
36var dayText = document.getElementById('day').firstChild
37var dayUsersText = document.getElementById('day-users').firstChild
38var daysActiveText = document.getElementById('days-active').firstChild
39var firstText = document.getElementById('first').firstChild
40var lastText = document.getElementById('last').firstChild
41
42var colors = {
43 yellow: [255, 255, 0, 255],
44 red: [255, 0, 0, 255],
45 black: [0, 0, 0, 255],
46 grey: [200, 200, 200, 255],
47 bg: [255, 255, 255, 0],
48 highlight: [0, 0, 0, 255]
49}
50
51function getJSON(url, cb) {
52 var req = new XMLHttpRequest()
53 req.open('GET', url, true)
54 req.onload = function () {
55 if (req.readyState !== 4) return
56 if (req.status >= 200 && req.status < 400)
57 cb(null, JSON.parse(req.responseText))
58 else
59 return cb(req)
60 }
61 req.onerror = cb
62 req.send(null)
63}
64
65function printError(err) {
66 var pre = document.createElement('pre')
67 document.body.appendChild(pre)
68 pre.appendChild(document.createTextNode(err.stack))
69}
70
71getJSON('ids-colors.json', function (err, info) {
72 if (err) return printError(err)
73 ids = info.ids
74 idColors = info.colors
75 for (var i = 0; i < ids.length; i++) {
76 var id = ids[i]
77 var color = idColors[id]
78 idsByColor[color] = id
79 }
80})
81
82var canvas = document.createElement('canvas')
83var ctx
84function onImageLoad() {
85 width = canvas.width = img.width
86 height = canvas.height = img.height
87 ctx = canvas.getContext('2d')
88 ctx.drawImage(img, 0, 0)
89 imgData = ctx.getImageData(0, 0, width, height)
90 origImgData = ctx.getImageData(0, 0, width, height)
91 img.parentNode.insertBefore(canvas, img)
92 img.parentNode.removeChild(img)
93 canvas.style.maxWidth = '100%'
94}
95if (img.complete) onImageLoad()
96else img.onload = onImageLoad
97
98function getPoint(e) {
99 return [
100 Math.floor(e.offsetX * width / canvas.offsetWidth),
101 Math.floor(e.offsetY * height / canvas.offsetHeight)
102 ]
103}
104
105function colorEquals(a, b) {
106 return a && b
107 && a[3] === b[3]
108 && (a[3] === 0 || (
109 a[0] === b[0]
110 && a[1] === b[1]
111 && a[2] === b[2]
112 ))
113}
114
115function getPixel(x, y) {
116 var i = (y * width + x) << 2
117 var data = origImgData.data
118 return [
119 data[i],
120 data[i+1],
121 data[i+2],
122 data[i+3]
123 ]
124}
125
126function setPixel(x, y, color) {
127 var i = (y * width + x) << 2
128 var data = imgData.data
129 data[i] = color[0]
130 data[i+1] = color[1]
131 data[i+2] = color[2]
132 data[i+3] = 255
133}
134
135function replaceColor(oldColor, newColor) {
136 for (var x = 0; x < width; x++) {
137 for (var y = height-1; y > 0; y--) {
138 var c = getPixel(x, y)
139 if (colorEquals(c, colors.bg)) break
140 if (colorEquals(c, oldColor)) {
141 setPixel(x, y, newColor)
142 break
143 }
144 }
145 }
146}
147
148function highlightColumn(x, amount) {
149 for (var y = 0; y < height; y++) {
150 var p = getPixel(x, y)
151 if (p[3] === 0) p[0] = p[1] = p[2] = 255
152 setPixel(x, y, common.interpolate(p, colors.grey, amount))
153 }
154}
155
156function pointEquals(a, b) {
157 return a ? b && a[0] === b[0] && a[1] === b[1] : !b
158}
159
160function dayStr(day) {
161 return isNaN(day) ? '' :
162 new Date(common.startTime + day * 86400000).toDateString()
163}
164
165var usersAtInterval = {}
166function countUsersAtInterval(x) {
167 var count = usersAtInterval[x]
168 if (typeof count !== 'undefined') return count
169 count = 0
170 for (var y = height-1; y > 0; y--) {
171 var color = getPixel(x, y)
172 if (colorEquals(color, colors.bg)) break
173 count++
174 }
175 return usersAtInterval[x] = count
176}
177
178var extents = {}
179function getUserExtent(id) {
180 var extent = extents[id]
181 if (extent) return extent
182 extent = extents[id] = {
183 days: 0
184 }
185 var color = idColors[id]
186 if (color) {
187 for (var x = 0; x < width; x++) {
188 for (var y = height-1; y > 0; y--) {
189 var c = getPixel(x, y)
190 if (colorEquals(c, colors.bg)) break
191 if (colorEquals(c, color)) {
192 extent.days++
193 if (!extent.first) extent.first = x
194 extent.last = x
195 break
196 }
197 }
198 }
199 }
200 return extent
201}
202
203var hoverColor, hoverPoint
204var clickedColor, clickedPoint
205
206function highlight(point) {
207 if (pointEquals(point, hoverPoint)) return
208 if (hoverPoint) highlightColumn(hoverPoint[0], 0)
209 if (point) highlightColumn(point[0], 0.7)
210 hoverPoint = point
211
212 var color = point && getPixel(point[0], point[1])
213 if (colorEquals(color, colors.bg)) {
214 if (hoverColor) replaceColor(hoverColor, hoverColor)
215 hoverColor = null
216 userInfo.style.visibility = 'hidden'
217 dayInfo.style.visibility = 'hidden'
218 } else if (!colorEquals(color, hoverColor)) {
219 if (hoverColor) replaceColor(hoverColor, hoverColor)
220 replaceColor(color, colors.highlight)
221 hoverColor = color
222 }
223
224 if (!point) {
225 dayInfo.style.visibility = 'hidden'
226 } else {
227 dayInfo.style.visibility = 'visible'
228 dayText.nodeValue = dayStr(point[0])
229 dayUsersText.nodeValue = countUsersAtInterval(point[0])
230 }
231
232 var id = idsByColor[color]
233 if (!id) {
234 userInfo.style.visibility = 'hidden'
235 } else {
236 userIdText.nodeValue = id
237 userLink.href = feedBase + encodeURIComponent(id)
238 var extent = getUserExtent(id)
239 daysActiveText.nodeValue = extent.days
240 firstText.nodeValue = dayStr(extent.first)
241 lastText.nodeValue = dayStr(extent.last)
242 userInfo.style.visibility = 'visible'
243 }
244
245 ctx.putImageData(imgData, 0, 0)
246}
247
248canvas.addEventListener('mousemove', function (e) {
249 highlight(getPoint(e))
250}, false)
251
252canvas.addEventListener('mousedown', function (e) {
253 var point = getPoint(e)
254 if (pointEquals(point, clickedPoint)) return
255 var color
256 if (point) {
257 color = getPixel(point[0], point[1])
258 if (colorEquals(color, colors.bg)) {
259 color = null
260 point = null
261 }
262 }
263 clickedPoint = point
264 clickedColor = color
265 highlight(point)
266}, false)
267
268canvas.addEventListener('mouseout', function (e) {
269 highlight(clickedPoint)
270}, false)
271
272</script>
273</body>
274</html>
275

Built with git-ssb-web