git ssb

16+

Dominic / patchbay



Tree: 3641823ab81be8b64bfe575a2635cbbd6a5bb05d

Files: 3641823ab81be8b64bfe575a2635cbbd6a5bb05d / app / page / network.js

5052 bytesRaw
1const nest = require('depnest')
2const { h, Value, Dict, onceTrue, computed, watch, watchAll, throttle } = require('mutant')
3const Chart = require('chart.js')
4const pull = require('pull-stream')
5
6const MINUTE = 60 * 1000
7const DAY = 24 * 60 * MINUTE
8
9const GRAPH_Y_STEP = 50
10const GRAPH_Y_MIN = 100
11
12exports.gives = nest({
13 'app.html.menuItem': true,
14 'app.page.network': true
15})
16
17exports.needs = nest({
18 'sbot.obs.connection': 'first'
19})
20
21exports.create = function (api) {
22 return nest({
23 'app.html.menuItem': menuItem,
24 'app.page.network': networkPage
25 })
26
27 function menuItem () {
28 return h('a', {
29 'ev-click': () => api.app.sync.goTo({ page: 'network' })
30 }, '/network')
31 }
32
33 function networkPage (location) {
34 const minsPerStep = 20
35 const scale = 1 * DAY
36
37 const data = Dict({
38 [toTimeBlock(Date.now(), minsPerStep) + minsPerStep * MINUTE]: 0,
39 [toTimeBlock(Date.now(), minsPerStep) + minsPerStep * MINUTE - scale]: 0
40 })
41 onceTrue(api.sbot.obs.connection, server => {
42 getData({ data, server, minsPerStep, scale })
43 })
44
45 const latest = Value(toTimeBlock(Date.now(), minsPerStep))
46 // start of the most recent bar
47 setInterval(() => {
48 latest.set(toTimeBlock(Date.now(), minsPerStep))
49 }, minsPerStep / 4 * MINUTE)
50
51 const range = computed([latest], (latest) => {
52 return {
53 upper: latest + minsPerStep * MINUTE,
54 lower: latest + minsPerStep * MINUTE - scale
55 }
56 })
57
58 //
59
60 const canvas = h('canvas', { height: 500, width: 1200, style: { height: '500px', width: '1200px' } })
61 const page = h('NetworkPage', { title: '/network' }, [
62 h('div.container', [
63 h('h1', 'Network'),
64 h('header', `Messages received per 20-minute block over the last ${scale / DAY} days`),
65 canvas
66 ])
67 ])
68
69 initialiseChart({ canvas, data, range })
70
71 return page
72 }
73}
74
75function getData ({ data, server, minsPerStep, scale }) {
76 const upperEnd = toTimeBlock(Date.now(), minsPerStep) + minsPerStep * MINUTE
77 const lowerBound = upperEnd - scale
78
79 const query = [
80 {
81 $filter: {
82 timestamp: { $gte: lowerBound }
83 }
84 }, {
85 $filter: {
86 value: {
87 author: { $ne: server.id }
88 }
89 }
90 }, {
91 $map: {
92 ts: ['timestamp']
93 }
94 }
95 ]
96
97 pull(
98 server.query.read({ query, live: true }),
99 pull.filter(m => !m.sync),
100 pull.map(m => toTimeBlock(m.ts, minsPerStep)),
101 pull.drain(ts => {
102 if (data.has(ts)) data.put(ts, data.get(ts) + 1)
103 else data.put(ts, 1)
104 })
105 )
106}
107
108function initialiseChart ({ canvas, data, range }) {
109 var chart = new Chart(canvas.getContext('2d'), chartConfig(range))
110
111 watch(range, ({ lower, upper }) => {
112 // set horizontal scale
113 chart.options.scales.xAxes[0].time.min = lower
114 chart.options.scales.xAxes[0].time.max = upper
115 chart.update()
116 })
117
118 watchAll([throttle(data, 300), range], (data, { lower, upper }) => {
119 const _data = Object.keys(data)
120 .sort((a, b) => a < b ? -1 : +1)
121 .map(ts => {
122 return {
123 t: Number(ts), // NOTE - might need to offset by a half-step ?
124 y: data[ts]
125 }
126 })
127
128 // update chard data
129 chart.data.datasets[0].data = _data
130
131 // scales the height of the graph (to the visible data)!
132 const slice = _data
133 .filter(d => d.t >= lower && d.t < upper)
134 .map(d => d.y)
135 .sort((a, b) => a > b ? -1 : +1)
136
137 var h = slice[0]
138 if (!h || h < GRAPH_Y_MIN) h = GRAPH_Y_MIN // min-height
139 else h = h + (GRAPH_Y_STEP - h % GRAPH_Y_STEP) // round height to multiples of GRAPH_Y_STEP
140 chart.options.scales.yAxes[0].ticks.max = h
141
142 chart.update()
143 })
144}
145
146// ///// HELPERS /////
147
148function toTimeBlock (ts, minsPerStep) {
149 return Math.floor(ts / (minsPerStep * MINUTE)) * (minsPerStep * MINUTE)
150}
151
152function chartConfig ({ lower, upper }) {
153 const barColor = 'hsla(215, 57%, 60%, 1)'
154
155 return {
156 type: 'bar',
157 data: {
158 datasets: [{
159 backgroundColor: barColor,
160 borderColor: barColor,
161 data: []
162 }]
163 },
164 options: {
165 legend: {
166 display: false
167 },
168 scales: {
169 xAxes: [{
170 type: 'time',
171 distribution: 'linear',
172 time: {
173 // unit: 'day',
174 // min: lower,
175 // max: upper,
176 // tooltipFormat: 'MMMM D',
177 // stepSize: 7
178 unit: 'minute',
179 min: lower,
180 max: upper,
181 tooltipFormat: 'HH:mm',
182 stepSize: 4 * 60
183 // stepSize: 240
184 },
185 bounds: 'ticks',
186 ticks: {
187 // maxTicksLimit: 4 // already disabled
188 },
189 gridLines: {
190 display: false
191 }
192 // maxBarThickness: 2
193 }],
194
195 yAxes: [{
196 ticks: {
197 min: 0,
198 stepSize: GRAPH_Y_STEP,
199 suggestedMax: GRAPH_Y_MIN
200 }
201 }]
202 },
203 animation: {
204 // duration: 300
205 }
206 }
207 }
208}
209

Built with git-ssb-web