Mercurial > code > home > repos > homeauto
annotate service/beacon/beaconmap.html @ 1462:2b29f14eb6bd
try new graph+view widget
Ignore-this: d5f9c5dc52f04324368716ba2f604fdb
darcs-hash:44e85a5c075ef73c34a58deaa3a3c1e8390dae52
author | drewp <drewp@bigasterisk.com> |
---|---|
date | Sun, 24 Nov 2019 00:01:00 -0800 |
parents | f38fb6956d8e |
children |
rev | line source |
---|---|
1096 | 1 <!doctype html> |
2 <html> | |
3 <head> | |
4 <title>beaconmap</title> | |
5 <meta charset="utf-8" /> | |
6 <script src="/lib/polymer/1.0.9/webcomponentsjs/webcomponents-lite.min.js"></script> | |
7 <script> | |
8 window.Polymer = { | |
9 dom: 'shadow', | |
10 }; | |
11 </script> | |
12 <link rel="import" href="/lib/polymer/1.0.9/polymer/polymer.html"> | |
13 <link rel="import" href="/lib/polymer/1.0.9/iron-ajax/iron-ajax.html"> | |
14 <link rel="import" href="/lib/polymer/1.0.9/iron-list/iron-list.html"> | |
15 <link rel="import" href="/lib/polymer/1.0.9/paper-header-panel/paper-header-panel.html"> | |
16 <link rel="import" href="/lib/polymer/1.0.9/iron-flex-layout/iron-flex-layout-classes.html"> | |
17 <style is="custom-style" include="iron-flex iron-flex-alignment iron-positioning"></style> | |
18 | |
19 <script src="dat.gui.min.js"></script> | |
20 <link rel="import" href="house-model.html"> | |
21 </head> | |
22 <body class="fullbleed layout vertical"> | |
23 <dom-module id="beacon-devices"> | |
24 <template> | |
25 | |
26 <style> | |
27 iron-list { height: 100%; } | |
28 .row { border: 1px outset #dadada; margin: 2px; background: #f7f7f7;} | |
1115
f38fb6956d8e
beaconmap rewrites with influxdb
drewp <drewp@bigasterisk.com>
parents:
1096
diff
changeset
|
29 .selected { |
f38fb6956d8e
beaconmap rewrites with influxdb
drewp <drewp@bigasterisk.com>
parents:
1096
diff
changeset
|
30 background: #9191ff; |
f38fb6956d8e
beaconmap rewrites with influxdb
drewp <drewp@bigasterisk.com>
parents:
1096
diff
changeset
|
31 } |
1096 | 32 </style> |
33 <iron-ajax url="devices" | |
34 auto | |
35 last-response="{{response}}"></iron-ajax> | |
36 <iron-list items="[[response.devices]]" | |
37 selection-enabled="true" | |
1115
f38fb6956d8e
beaconmap rewrites with influxdb
drewp <drewp@bigasterisk.com>
parents:
1096
diff
changeset
|
38 selected-item="{{selected}}" |
f38fb6956d8e
beaconmap rewrites with influxdb
drewp <drewp@bigasterisk.com>
parents:
1096
diff
changeset
|
39 selected-as="isSelected" |
f38fb6956d8e
beaconmap rewrites with influxdb
drewp <drewp@bigasterisk.com>
parents:
1096
diff
changeset
|
40 > |
1096 | 41 <template> |
1115
f38fb6956d8e
beaconmap rewrites with influxdb
drewp <drewp@bigasterisk.com>
parents:
1096
diff
changeset
|
42 <div class$="row {{rowClass(isSelected)}}"> |
f38fb6956d8e
beaconmap rewrites with influxdb
drewp <drewp@bigasterisk.com>
parents:
1096
diff
changeset
|
43 {{item.addr}} {{item.name}} |
1096 | 44 </div> |
45 </template> | |
46 </iron-list> | |
47 </template> | |
48 <script> | |
49 HTMLImports.whenReady(function () { | |
50 Polymer({ | |
51 is: "beacon-devices", | |
52 properties: { | |
53 response: { type: Object, notify: true }, | |
54 selected: { type: Object, notify: true }, | |
1115
f38fb6956d8e
beaconmap rewrites with influxdb
drewp <drewp@bigasterisk.com>
parents:
1096
diff
changeset
|
55 }, |
f38fb6956d8e
beaconmap rewrites with influxdb
drewp <drewp@bigasterisk.com>
parents:
1096
diff
changeset
|
56 rowClass: function (isSelected) { |
f38fb6956d8e
beaconmap rewrites with influxdb
drewp <drewp@bigasterisk.com>
parents:
1096
diff
changeset
|
57 return isSelected ? 'selected' : ''; |
1096 | 58 } |
59 }); | |
60 }); | |
61 </script> | |
62 </dom-module> | |
63 | |
64 <script src="/lib/rickshaw/90852d8/vendor/d3.min.js"></script> | |
65 <script> | |
66 var hashCode = function(s){ | |
67 var hash = 0; | |
68 if (s.length == 0) return hash; | |
69 for (var i = 0; i < s.length; i++) { | |
70 var character = s.charCodeAt(i); | |
71 hash = ((hash<<5)-hash)+character; | |
72 hash = hash & hash; // Convert to 32bit integer | |
73 } | |
74 return hash; | |
75 }; | |
76 var colorForAddr = function(addr) { | |
77 var hue = hashCode(addr) % 360; | |
78 return d3.hsl(hue, 1, 0.5) + ""; | |
79 }; | |
80 var colorForSensor = function(from) { | |
81 var hue = hashCode(from) % 360; | |
82 return d3.hsl(hue, .7, 0.7) + ""; | |
83 }; | |
84 </script> | |
85 | |
86 <dom-module id="beacon-sensor-graph"> | |
87 <link rel="import" type="css" href="/lib/rickshaw/90852d8/src/css/graph.css"> | |
88 <link rel="import" type="css" href="/lib/rickshaw/90852d8/src/css/detail.css"> | |
89 <link rel="import" type="css" href="/lib/rickshaw/90852d8/src/css/legend.css"> | |
90 | |
91 <template> | |
92 <iron-ajax id="get" url="sensor" params='{{params}}' auto last-response="{{response}}"></iron-ajax> | |
93 <div>{{sensor.from}}</div> | |
94 <div id="chart_container" on-click="onClick"> | |
95 <div id="chart"></div> | |
96 </div> | |
97 | |
98 </template> | |
99 <script src="/lib/jquery-2.0.3.min.js"></script> | |
100 <script src="/lib/rickshaw/90852d8/vendor/d3.min.js"></script> | |
101 <script src="/lib/rickshaw/90852d8/rickshaw.min.js"></script> | |
102 <script> | |
103 HTMLImports.whenReady(function () { | |
104 Polymer({ | |
105 is: "beacon-sensor-graph", | |
106 properties: { | |
107 sensor: {type: Object}, | |
108 response: {type: Object, notify: true}, | |
109 params: {computed: '_params(sensor.from)'} | |
110 }, | |
111 _params: function(from) { | |
112 return {from: from, secs: 60*5}; | |
113 }, | |
114 observers: [ | |
115 'onResponse(response)' | |
116 ], | |
117 ready: function() { | |
118 this.scopeSubtree(this.$.chart_container, true); | |
119 | |
120 }, | |
121 onClick: function() { | |
122 this.$.get.generateRequest(); | |
123 }, | |
124 redraw: function() { | |
125 var serieses = []; | |
126 | |
127 for (var addr of Object.keys(this.points)) { | |
128 var pts = this.points[addr]; | |
129 var transformed = pts.map(function(p) { | |
130 return {x: p[0] + this.startTime, | |
131 y: .5 * (p[1]-(-120)) / (-60+120)}; | |
132 }.bind(this)); | |
133 serieses.push({ | |
134 name: addr, | |
135 data: transformed, | |
136 color: colorForAddr(addr), | |
137 }); | |
138 } | |
139 | |
140 this.$.chart.innerHTML = ''; | |
141 var graph = new Rickshaw.Graph( { | |
142 element: this.$.chart, | |
143 width: 400, | |
144 height: 60, | |
145 renderer: 'line', | |
146 series: serieses, | |
147 } ); | |
148 | |
149 graph.render(); | |
150 | |
151 var hoverDetail = new Rickshaw.Graph.HoverDetail( { | |
152 graph: graph | |
153 } ); | |
154 | |
155 var axes = new Rickshaw.Graph.Axis.Time( { | |
156 graph: graph | |
157 } ); | |
158 axes.render(); | |
159 | |
160 | |
161 var yAxis = new Rickshaw.Graph.Axis.Y( { | |
162 graph: graph, | |
163 tickFormat: Rickshaw.Fixtures.Number.formatKMBT, | |
164 } ); | |
165 | |
166 yAxis.render(); | |
167 | |
168 this.graph = graph; | |
169 }, | |
170 onResponse: function(response) { | |
171 this.points = response.points; | |
172 this.startTime = response.startTime; | |
173 this.redraw(); | |
174 | |
175 } | |
176 }); | |
177 }); | |
178 </script> | |
179 </dom-module> | |
180 | |
181 <dom-module id="beacon-device-graph"> | |
182 <link rel="import" type="css" href="/lib/rickshaw/90852d8/src/css/graph.css"> | |
183 <link rel="import" type="css" href="/lib/rickshaw/90852d8/src/css/detail.css"> | |
184 <link rel="import" type="css" href="/lib/rickshaw/90852d8/src/css/legend.css"> | |
185 <template> | |
186 | |
187 <div>{{addr}} (continuous update)</div> | |
188 <div id="chart_container" on-click="onClick"> | |
189 <div id="chart"></div> | |
190 </div> | |
191 <div>{{latest}}</div> | |
192 </template> | |
193 <script src="/lib/jquery-2.0.3.min.js"></script> | |
194 <script src="/lib/rickshaw/90852d8/vendor/d3.min.js"></script> | |
195 <script src="/lib/rickshaw/90852d8/rickshaw.min.js"></script> | |
196 <script> | |
197 HTMLImports.whenReady(function () { | |
198 Polymer({ | |
199 is: "beacon-device-graph", | |
200 properties: { | |
201 addr: {type: String, notify: true}, | |
202 params: {computed: '_params(addr)'} | |
203 | |
204 }, | |
205 _params: function(from) { | |
206 return {addr: this.addr}; | |
207 }, | |
208 observers: [ | |
209 'onResponse(response)', | |
210 'startEvents(addr)', | |
211 ], | |
212 ready: function() { | |
213 this.scopeSubtree(this.$.chart_container, true); | |
214 }, | |
215 startEvents: function(addr) { | |
216 if (this.events) { | |
217 this.events.close(); | |
218 } | |
219 if (addr) { | |
220 console.log('new es', addr); | |
221 this.events = new EventSource('points?addr=' + encodeURIComponent(addr)); | |
222 this.events.addEventListener('message', function(e) { | |
223 var body = JSON.parse(e.data); | |
224 this.points = body.points; | |
225 this.startTime = body.startTime; | |
226 this.redraw(); | |
227 }.bind(this)); | |
228 } | |
229 }, | |
230 | |
231 onClick: function() { | |
232 this.$.get.generateRequest(); | |
233 }, | |
234 redraw: function() { | |
235 var serieses = []; | |
236 var latestForSensor = {}; | |
237 for (var row of this.points) { | |
238 var transformed = row.points.map(function(p) { | |
239 return {x: p[0] + this.startTime, | |
240 y: .5 * (p[1]-(-120)) / (-60+120)}; | |
241 }.bind(this)); | |
242 serieses.push({ | |
243 name: row.from, | |
244 data: transformed, | |
245 color: colorForSensor(row.from), | |
246 }); | |
247 latestForSensor[row.from] = row.points[row.points.length - 1][1]; | |
248 } | |
249 this.latest = JSON.stringify(latestForSensor); | |
250 this.$.chart.innerHTML = ''; | |
251 var graph = new Rickshaw.Graph( { | |
252 element: this.$.chart, | |
253 width: 640, | |
254 height: 300, | |
255 renderer: 'line', | |
256 series: serieses, | |
257 } ); | |
258 | |
259 graph.render(); | |
260 | |
261 var hoverDetail = new Rickshaw.Graph.HoverDetail( { | |
262 graph: graph | |
263 } ); | |
264 | |
265 var axes = new Rickshaw.Graph.Axis.Time( { | |
266 graph: graph | |
267 } ); | |
268 axes.render(); | |
269 | |
270 var yAxis = new Rickshaw.Graph.Axis.Y( { | |
271 graph: graph, | |
272 tickFormat: Rickshaw.Fixtures.Number.formatKMBT, | |
273 } ); | |
274 | |
275 yAxis.render(); | |
276 | |
277 this.graph = graph; | |
278 }, | |
279 | |
280 }); | |
281 }); | |
282 </script> | |
283 </dom-module> | |
284 | |
285 <dom-module id="beacon-page"> | |
286 <template> | |
287 <link rel="import" href="/lib/polymer/1.0.9/iron-flex-layout/iron-flex-layout-classes.html"> | |
288 <style is="custom-style" include="iron-flex iron-flex-alignment iron-flex-factors"></style> | |
289 <style> | |
290 </style> | |
291 <paper-header-panel class="flex"> | |
292 <div class="paper-header">beacon map</div> | |
293 <div class="layout horizontal"> | |
294 | |
295 <beacon-devices style="height: 500px" | |
1115
f38fb6956d8e
beaconmap rewrites with influxdb
drewp <drewp@bigasterisk.com>
parents:
1096
diff
changeset
|
296 class="layout justified flex-2" |
1096 | 297 selected="{{sel}}"></beacon-devices> |
298 <div class="layout vertical" style="flex-grow: 2"> | |
299 <house-model position-estimates="{{positionEstimates}}" beacons="{{beacons}}"></house-model> | |
300 <beacon-device-graph addr="{{sel.addr}}"></beacon-device-graph> | |
301 <div> | |
302 save white levels: | |
303 <iron-ajax url="save" | |
304 method="POST" | |
305 id="save" | |
306 verbose="true" | |
307 handle-as="text" | |
308 last-response="{{saveResponse}}"></iron-ajax> | |
309 <button on-click="onSave" style="padding: 20px">save</button> {{saveResponse}} | |
310 </div> | |
311 | |
312 <div id="sensors"> | |
313 <iron-ajax url="sensors" | |
314 auto | |
315 last-response="{{sensorsResponse}}"></iron-ajax> | |
316 <template is="dom-repeat" items="{{sensorsResponse.sensors}}"> | |
1115
f38fb6956d8e
beaconmap rewrites with influxdb
drewp <drewp@bigasterisk.com>
parents:
1096
diff
changeset
|
317 <div>sensor detail {{item}}</div> |
1096 | 318 </template> |
319 </div> | |
1115
f38fb6956d8e
beaconmap rewrites with influxdb
drewp <drewp@bigasterisk.com>
parents:
1096
diff
changeset
|
320 |
1096 | 321 </div> |
322 </div> | |
323 </paper-header-panel> | |
324 beacon page gets this | |
325 | |
326 </template> | |
327 <script> | |
328 HTMLImports.whenReady(function () { | |
329 Polymer({ | |
330 is: "beacon-page", | |
331 properties: { | |
332 sel: { type: Object, notify: true }, | |
333 saveResponse: { type: String, notify: true}, | |
334 }, | |
335 onSave: function() { | |
336 this.$.save.generateRequest(); | |
337 }, | |
338 ready: function() { | |
339 | |
340 this.sel = {addr: '00:ea:23:23:c6:c4'}; | |
341 | |
342 var events = new EventSource('positionEstimates?addr=' + | |
343 encodeURIComponent('00:ea:23:23:c6:c4')); | |
344 events.addEventListener('message', function(e) { | |
345 var body = JSON.parse(e.data); | |
346 this.positionEstimates = body.nearest; | |
347 this.set('beacons', [{label: 'apollo', pos: body.weightedCoord}]); | |
348 }.bind(this)); | |
349 }, | |
350 }); | |
351 }); | |
352 | |
353 </script> | |
354 </dom-module> | |
355 | |
356 <style> | |
357 .paper-header { | |
358 background-color: var(--paper-light-blue-500); | |
359 } | |
360 </style> | |
361 | |
362 <beacon-page class="layout fit"></beacon-page> | |
363 </body> | |
364 </html> |